#34515 closed Bug (fixed)
Translatable URL patterns raise 404 for non-English default language when prefix_default_language=False is used.
Reported by: | ab | Owned by: | Sarah Boyce |
---|---|---|---|
Component: | Internationalization | Version: | 4.2 |
Severity: | Release blocker | Keywords: | internationalization, i18n, prefix_default_language, i18n_patterns |
Cc: | Sarah Boyce, Claude Paroz, sergioisidoro | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
A simple django project with instruction to replicate the bug can be found here:
github repo
In brief: prefix_default_language = False
raises HTTP 404 for the default unprefixed pages if LANGUAGE_CODE
is not "en".
I think the problem is that the function get_language_from_path
in django/utils/translation/trans_real.py
returns None
in case of failure instead of LANGUAGE_CODE
: diff in 4.2
Consequently, other mechanisms are used to get the language (cookies or headers) that do not work neither.
Related issue with my last comment adding some extra context: https://code.djangoproject.com/ticket/34455
It is the first time I contribute to django, I hope the bug report is OK. I am also willing to write the patch and test if required.
Change History (18)
follow-up: 4 comment:1 by , 19 months ago
comment:2 by , 19 months ago
Cc: | added; removed |
---|---|
Component: | Core (Other) → Internationalization |
Severity: | Normal → Release blocker |
Summary: | prefix_default_language=False raises HTTP 404 for default language if LANGUAGE_CODE != 'en' → Translatable URL patterns raise 404 for non-English default language when prefix_default_language=False is used. |
Triage Stage: | Unreviewed → Accepted |
Thanks for the report. The use of URL patterns marked as translatable is crucial for this bug.
Regression in 94e7f471c4edef845a4fe5e3160132997b4cca81.
Reproduced at c24cd6575f948661fa0ed8b27b79098610dc3ccc.
comment:3 by , 19 months ago
Cc: | removed |
---|
follow-up: 5 comment:4 by , 19 months ago
Replying to ab:
Expected behavior: django 4.2 documentation
LocaleMiddleware tries to determine the user’s language preference by following this algorithm:
- First, it looks for the language prefix in the requested URL. This is only performed when you are using the i18n_patterns function in your root URLconf. See Internationalization: in URL patterns for more information about the language prefix and how to internationalize URL patterns.
- Failing that, it looks for a cookie. The name of the cookie used is set by the LANGUAGE_COOKIE_NAME setting. (The default name is django_language.)
- Failing that, it looks at the Accept-Language HTTP header. This header is sent by your browser and tells the server which language(s) you prefer, in order by priority. Django tries each language in the header until it finds one with available translations.
- Failing that, it uses the global LANGUAGE_CODE setting.
IMO it still works that way. However, in Django 4.2 get_language_from_request()
returns the language from a request (en
for me) which is activated and the default path about/
is no longer translated to the a-propos/
. This is definitely a change from the previous behavior.
comment:5 by , 19 months ago
Replying to Mariusz Felisiak:
IMO it still works that way. However, in Django 4.2
get_language_from_request()
returns the language from a request (en
for me) which is activated and the default pathabout/
is no longer translated to thea-propos/
. This is definitely a change from the previous behavior.
Thank you Mariusz for the quick reaction.
I agree it still globally works that way, nevertheless, in the case I describe, when django looks for the language prefix in the requested URL and there is not language prefix, I would expect django to return "fr", not to go to the next steps of the algorithm. Because I want prefix_default_language = False
to take precedence on cookies or headers. Does it make sense?
I need to add that I use translate_url
to build the links in my templates.
Consequently, my URLs are translated in the template only (hence the 404).
So you're right about the default path not being translated anymore.
comment:6 by , 19 months ago
Cc: | added |
---|
comment:7 by , 19 months ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:8 by , 19 months ago
Owner: | changed from | to
---|
I have a PR with what I think the issue is, but not confident https://github.com/django/django/pull/16797
@ab I think what you're saying makes sense
comment:9 by , 19 months ago
Has patch: | set |
---|
comment:10 by , 19 months ago
I agree it still globally works that way, nevertheless, in the case I describe, when django looks for the language prefix in the requested URL and there is not language prefix, I would expect django to return "fr", not to go to the next steps of the algorithm. Because I want prefix_default_language = False to take precedence on cookies or headers. Does it make sense?
My 2¢: Is ignoring the process for determining the language the least surprising choice here though? It all depends on whether no-prefix URL should refer to a user setting or the site's default language. I mean imho navigating to a URL I might expect it to show the language I chose 🤷♂️
comment:11 by , 19 months ago
Keywords: | i18n_patterns added |
---|
@Sarah: yes, it is the same problem. After investigating the code, the change in behavior is linked to the fact that get_language_from_path
returns None
when the url is not prefixed. So, the cookie is used or the Accept-Language
header sent by the browser. In my case, I think it is the HTTP header.
@David: thanks for your contribution, but I do not fully agree. If prefix_default_url
is True
, the language is correctly detected by django based on the URL. If I set prefix_default_url
to False
I expect the same behavior for the default language without prefix. When I decide do use i18n_patterns
at least (I have just added this tag to the ticket).
When i18n_patterns
is not used, I agree with you.
So the problem might come from i18n_patterns not calling/handling correctly the calls to the new get_language_*
functions.
comment:12 by , 19 months ago
@sarah: I'll test your patch because your edits might solve the problem with HTTP headers too. Thanks!
comment:13 by , 19 months ago
Just to keep track of the current work on this issue, there is a discussion about how django should behave here: https://github.com/django/django/pull/16797#issuecomment-1524958085
As suggested by Sarah, I'll post to django-developers for a wider range of opinions.
Expected behavior: django 4.2 documentation
LocaleMiddleware tries to determine the user’s language preference by following this algorithm: