#30272 closed Bug (wontfix)
get_language_from_request(..., check_path=True) not respecting i18n_patterns prefix_default_language=False
Reported by: | Stefan Wehrmeyer | Owned by: | nobody |
---|---|---|---|
Component: | Internationalization | Version: | 2.1 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Starting in Django 1.10 django.conf.urls.i18n.i18n_patterns
accepts an option prefix_default_language
that can be set to False
. This adds no language prefix for the the default language when reversing URLs.
django.utils.translation.get_language_from_path
is supposed to detect the language from the URL path. At the moment it returns None
when no language URL prefix is found. I would argue that if the path is resolved by i18n_patterns
with prefix_default_language=False
get_language_from_path
should return the default language (settings.LANGUAGE_CODE
)
I believe the intention of using i18n_patterns
and setting prefix_default_language=False
is two-fold:
- construct URLs in the default language without a language prefix (this works now)
- detect non-prefixed URLs as using the default language (currently *not* working, falls back to session, cookie, HTTP headers)
Let me know if you consider this a bug.
Change History (12)
comment:1 by , 6 years ago
Resolution: | → wontfix |
---|---|
Status: | new → closed |
comment:2 by , 6 years ago
Hey Carlton, thanks for reviewing.
The problem with get_language_from_request
is that the browser Accept-Language
header is very likely set and will determine the language. However, I want the language to be determined by the path – even when prefix_default_language=False
. This works with prefix_default_language=True
.
LocaleMiddleware
actually does this, but does it around get_language_from_request
:
So maybe an idea could be to move these lines into get_language_from_request
in order to make this logic available to other Django apps that rely on this API (in my case django cms). Not sure if this would be a backwards-incompatible change though.
comment:3 by , 6 years ago
Why wouldn't get_language_from_path() or settings.LANGUAGE_CODE
do you? (Just trying to understand the use-case.)
comment:4 by , 6 years ago
Sorry, some more details about the use case.
I'm running a Django CMS instance with their URLs included via i18n_patterns
and prefix_default_language=False
. I want the URL path to determine what language to serve (and LocaleMiddleware
set this language correctly!).
The problem is that Django CMS relies on get_language_from_request
(e.g. here) to detect which language to serve without the additional logic that is included in LocaleMiddleware
to special case prefix_default_language=False
.
Example URLs with default language "en":
/de/ueber/
–LocaleMiddleware
sets "de",get_language_from_request
withcheck_path=True
returns "de"/about/
–LocaleMiddleware
sets "en",get_language_from_request
withcheck_path=True
returns whatever is in session, language cookie or HTTPAccept-Language
header, but should return "en" likeLocaleMiddleware
This leads in turn to the wrong language being served. This could certainly be solved in Django CMS as well.
But currently there are cases when LocaleMiddleware
will set a different language on the request than is returned by get_language_from_request
– which makes this public API inconsistent IMHO.
Thanks for taking the time to look into this. I can try to provide a test case if this makes it clearer.
comment:5 by , 6 years ago
Resolution: | wontfix |
---|---|
Status: | closed → new |
OK, I'll re-open to have another look. (If you do have that test case, that would be super.)
comment:6 by , 6 years ago
I added a test case here:
https://github.com/django/django/pull/11123
I created the new UnprefixedDefaultLanguageUtilsTests
based on the UnprefixedDefaultLanguageTests
class (which is testing LocaleMiddleware
behaviour on i18n URLs without prefix). All methods pass except test_default_lang_without_prefix
(e.g. one test on DjangoCI).
This could be resolved by making the language detection of LocaleMiddleware
and get_language_from_request
behave the same way.
comment:7 by , 6 years ago
Has patch: | set |
---|---|
Patch needs improvement: | set |
Summary: | get_language_from_path not respecting i18n_patterns prefix_default_language=False → get_language_from_request(..., check_path=True) not respecting i18n_patterns prefix_default_language=False |
Triage Stage: | Unreviewed → Accepted |
Hi Stefan,
I'm going to provisionally accept this, but ask for a review from others.
Looking at 85a4844f8a8e628b90fa30ba7074f162a2d188ef, it's clear that we should (and do) serve the default language, ignoring Accept-Language
in this kind of case, so, yes, plausibly, matching that in get_language_from_request()
, when using check_path
, would be correct.
I've added a very minimal port of the logic from `LocaleMiddleware` to `get_language_from_request()` on your PR. Suitably tidied this might resolve the issue. (We'll see what CI says, but the change looks like it doesn't break anything...)
I've retitled the issue: get_language_from_path()
doesn't have access to e.g. the request
, so can't house the right logic here. get_language_from_request()
is our target.
Thanks for taking the time to explain the issue.
comment:9 by , 4 years ago
Patch needs improvement: | unset |
---|
Landed here from surfing GitHub. Don't see comments here or on the PR for the author to address, so resetting review flags for now. (Forgive me Carlton if I missed something!)
comment:10 by , 4 years ago
Cc: | added |
---|
comment:11 by , 4 years ago
Resolution: | → wontfix |
---|---|
Status: | new → closed |
OK, with time to come back to this I'm going to say wontfix
here. The current behaviour is correct.
But currently there are cases when LocaleMiddleware will set a different language on the request than is returned by get_language_from_request – which makes this public API inconsistent IMHO.
Right, sure, but get_language_from_request()
operates over just the request whereas LocaleMiddleware
operates over the request plus your site configuration. These aren't the same inputs, so it's not expected that they have the same results.
This could certainly be solved in Django CMS as well.
Yes. I think that's the correct response, and indeed, that's what they've done.
comment:12 by , 4 years ago
Cc: | removed |
---|---|
Triage Stage: | Accepted → Unreviewed |
Hi Stefan.
I think this is intended behaviour: doing clever things, like falling back to the default
LANGUAGE_CODE
is out of scope for this function. It's job it just (literally) to get the language code from the path. If it's not there thenNone
is the desired response.The more sophisticated
get_language_from_request()
will do the right thing here and, ultimately, returnsettings.LANGUAGE_CODE
if nothing else preempts it.(Was there an incorrect behaviour you observed here, beyond this?)
Thanks.