Fixed #34069 -- Made LocaleMiddleware respect language from requests when i18n patterns are used.

This commit is contained in:
Sergio 2022-10-02 13:59:13 +03:00 committed by Mariusz Felisiak
parent 004f985b91
commit 94e7f471c4
5 changed files with 43 additions and 23 deletions

View File

@ -16,28 +16,37 @@ class LocaleMiddleware(MiddlewareMixin):
response_redirect_class = HttpResponseRedirect response_redirect_class = HttpResponseRedirect
def get_fallback_language(self, request):
"""
Return the fallback language for the current request based on the
settings. If LANGUAGE_CODE is a variant not included in the supported
languages, get_fallback_language() will try to fallback to a supported
generic variant.
Can be overridden to have a fallback language depending on the request,
e.g. based on top level domain.
"""
try:
return translation.get_supported_language_variant(settings.LANGUAGE_CODE)
except LookupError:
return settings.LANGUAGE_CODE
def process_request(self, request): def process_request(self, request):
urlconf = getattr(request, "urlconf", settings.ROOT_URLCONF) urlconf = getattr(request, "urlconf", settings.ROOT_URLCONF)
( i18n_patterns_used, _ = is_language_prefix_patterns_used(urlconf)
i18n_patterns_used,
prefixed_default_language,
) = is_language_prefix_patterns_used(urlconf)
language = translation.get_language_from_request( language = translation.get_language_from_request(
request, check_path=i18n_patterns_used request, check_path=i18n_patterns_used
) )
language_from_path = translation.get_language_from_path(request.path_info) if not language:
if ( language = self.get_fallback_language(request)
not language_from_path
and i18n_patterns_used
and not prefixed_default_language
):
language = settings.LANGUAGE_CODE
translation.activate(language) translation.activate(language)
request.LANGUAGE_CODE = translation.get_language() request.LANGUAGE_CODE = translation.get_language()
def process_response(self, request, response): def process_response(self, request, response):
language = translation.get_language() language = translation.get_language()
language_from_path = translation.get_language_from_path(request.path_info) language_from_path = translation.get_language_from_path(request.path_info)
language_from_request = translation.get_language_from_request(request)
urlconf = getattr(request, "urlconf", settings.ROOT_URLCONF) urlconf = getattr(request, "urlconf", settings.ROOT_URLCONF)
( (
i18n_patterns_used, i18n_patterns_used,
@ -48,7 +57,7 @@ class LocaleMiddleware(MiddlewareMixin):
response.status_code == 404 response.status_code == 404
and not language_from_path and not language_from_path
and i18n_patterns_used and i18n_patterns_used
and prefixed_default_language and (prefixed_default_language or language_from_request)
): ):
# Maybe the language code is missing in the URL? Try adding the # Maybe the language code is missing in the URL? Try adding the
# language prefix and redirecting to that URL. # language prefix and redirecting to that URL.

View File

@ -53,7 +53,7 @@ def check_for_language(x):
def get_language_from_request(request, check_path=False): def get_language_from_request(request, check_path=False):
return settings.LANGUAGE_CODE return None
def get_language_from_path(request): def get_language_from_path(request):

View File

@ -578,11 +578,7 @@ def get_language_from_request(request, check_path=False):
return get_supported_language_variant(accept_lang) return get_supported_language_variant(accept_lang)
except LookupError: except LookupError:
continue continue
return None
try:
return get_supported_language_variant(settings.LANGUAGE_CODE)
except LookupError:
return settings.LANGUAGE_CODE
@functools.lru_cache(maxsize=1000) @functools.lru_cache(maxsize=1000)

View File

@ -186,6 +186,10 @@ Internationalization
* Added support and translations for the Central Kurdish (Sorani) language. * Added support and translations for the Central Kurdish (Sorani) language.
* The :class:`~django.middleware.locale.LocaleMiddleware` now respects a
language from the request when :func:`~django.conf.urls.i18n.i18n_patterns`
is used with the ``prefix_default_language`` argument set to ``False``.
Logging Logging
~~~~~~~ ~~~~~~~

View File

@ -2137,8 +2137,22 @@ class UnprefixedDefaultLanguageTests(SimpleTestCase):
response = self.client.get("/fr/simple/") response = self.client.get("/fr/simple/")
self.assertEqual(response.content, b"Oui") self.assertEqual(response.content, b"Oui")
def test_unprefixed_language_other_than_accept_language(self): def test_unprefixed_language_with_accept_language(self):
"""'Accept-Language' is respected."""
response = self.client.get("/simple/", HTTP_ACCEPT_LANGUAGE="fr") response = self.client.get("/simple/", HTTP_ACCEPT_LANGUAGE="fr")
self.assertRedirects(response, "/fr/simple/")
def test_unprefixed_language_with_cookie_language(self):
"""A language set in the cookies is respected."""
self.client.cookies.load({settings.LANGUAGE_COOKIE_NAME: "fr"})
response = self.client.get("/simple/")
self.assertRedirects(response, "/fr/simple/")
def test_unprefixed_language_with_non_valid_language(self):
response = self.client.get("/simple/", HTTP_ACCEPT_LANGUAGE="fi")
self.assertEqual(response.content, b"Yes")
self.client.cookies.load({settings.LANGUAGE_COOKIE_NAME: "fi"})
response = self.client.get("/simple/")
self.assertEqual(response.content, b"Yes") self.assertEqual(response.content, b"Yes")
def test_page_with_dash(self): def test_page_with_dash(self):
@ -2214,10 +2228,7 @@ class CountrySpecificLanguageTests(SimpleTestCase):
def test_get_language_from_request_null(self): def test_get_language_from_request_null(self):
lang = trans_null.get_language_from_request(None) lang = trans_null.get_language_from_request(None)
self.assertEqual(lang, "en") self.assertEqual(lang, None)
with override_settings(LANGUAGE_CODE="de"):
lang = trans_null.get_language_from_request(None)
self.assertEqual(lang, "de")
def test_specific_language_codes(self): def test_specific_language_codes(self):
# issue 11915 # issue 11915