summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2023-04-28 08:05:43 +0200
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2023-05-02 06:04:18 +0200
commit0e444e84f87d174713a2aef0c4f9704ce2865586 (patch)
tree5fd8693f08332b5e57765a5464b8bb66eb1d10c2
parent191f6a9a4586b5e5f79f4f42f190e7ad4bbacc84 (diff)
downloaddjango-0e444e84f87d174713a2aef0c4f9704ce2865586.tar.gz
Fixed #34515 -- Made LocaleMiddleware prefer language from paths when i18n patterns are used.
Regression in 94e7f471c4edef845a4fe5e3160132997b4cca81. This reverts commit 94e7f471c4edef845a4fe5e3160132997b4cca81 (refs #34069) and partly reverts commit 3b4728310a7a64f8fcc548163b0aa5f98a5c78f5. Thanks Anthony Baillard for the report. Co-Authored-By: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com>
-rw-r--r--django/middleware/locale.py33
-rw-r--r--django/urls/resolvers.py5
-rw-r--r--django/utils/translation/__init__.py1
-rw-r--r--django/utils/translation/trans_null.py2
-rw-r--r--django/utils/translation/trans_real.py6
-rw-r--r--docs/releases/4.2.1.txt5
-rw-r--r--docs/releases/4.2.txt4
-rw-r--r--tests/i18n/patterns/tests.py21
-rw-r--r--tests/i18n/tests.py23
-rw-r--r--tests/i18n/urls_default_unprefixed.py1
10 files changed, 53 insertions, 48 deletions
diff --git a/django/middleware/locale.py b/django/middleware/locale.py
index bc1d862574..71db230da2 100644
--- a/django/middleware/locale.py
+++ b/django/middleware/locale.py
@@ -16,37 +16,28 @@ class LocaleMiddleware(MiddlewareMixin):
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):
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(
request, check_path=i18n_patterns_used
)
- if not language:
- language = self.get_fallback_language(request)
-
+ language_from_path = translation.get_language_from_path(request.path_info)
+ if (
+ not language_from_path
+ and i18n_patterns_used
+ and not prefixed_default_language
+ ):
+ language = settings.LANGUAGE_CODE
translation.activate(language)
request.LANGUAGE_CODE = translation.get_language()
def process_response(self, request, response):
language = translation.get_language()
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)
(
i18n_patterns_used,
@@ -57,7 +48,7 @@ class LocaleMiddleware(MiddlewareMixin):
response.status_code == 404
and not language_from_path
and i18n_patterns_used
- and (prefixed_default_language or language_from_request)
+ and prefixed_default_language
):
# Maybe the language code is missing in the URL? Try adding the
# language prefix and redirecting to that URL.
diff --git a/django/urls/resolvers.py b/django/urls/resolvers.py
index 658a6a6f97..b021673772 100644
--- a/django/urls/resolvers.py
+++ b/django/urls/resolvers.py
@@ -23,7 +23,7 @@ from django.utils.datastructures import MultiValueDict
from django.utils.functional import cached_property
from django.utils.http import RFC3986_SUBDELIMS, escape_leading_slashes
from django.utils.regex_helper import _lazy_re_compile, normalize
-from django.utils.translation import get_language, get_supported_language_variant
+from django.utils.translation import get_language
from .converters import get_converter
from .exceptions import NoReverseMatch, Resolver404
@@ -351,8 +351,7 @@ class LocalePrefixPattern:
@property
def language_prefix(self):
language_code = get_language() or settings.LANGUAGE_CODE
- default_language = get_supported_language_variant(settings.LANGUAGE_CODE)
- if language_code == default_language and not self.prefix_default_language:
+ if language_code == settings.LANGUAGE_CODE and not self.prefix_default_language:
return ""
else:
return "%s/" % language_code
diff --git a/django/utils/translation/__init__.py b/django/utils/translation/__init__.py
index 69820a2fc4..0b3f78e486 100644
--- a/django/utils/translation/__init__.py
+++ b/django/utils/translation/__init__.py
@@ -17,7 +17,6 @@ __all__ = [
"get_language_from_request",
"get_language_info",
"get_language_bidi",
- "get_supported_language_variant",
"check_for_language",
"to_language",
"to_locale",
diff --git a/django/utils/translation/trans_null.py b/django/utils/translation/trans_null.py
index 595a705e2b..c8bfb1256e 100644
--- a/django/utils/translation/trans_null.py
+++ b/django/utils/translation/trans_null.py
@@ -53,7 +53,7 @@ def check_for_language(x):
def get_language_from_request(request, check_path=False):
- return None
+ return settings.LANGUAGE_CODE
def get_language_from_path(request):
diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py
index 46a94b99ff..872c80b00f 100644
--- a/django/utils/translation/trans_real.py
+++ b/django/utils/translation/trans_real.py
@@ -583,7 +583,11 @@ def get_language_from_request(request, check_path=False):
return get_supported_language_variant(accept_lang)
except LookupError:
continue
- return None
+
+ try:
+ return get_supported_language_variant(settings.LANGUAGE_CODE)
+ except LookupError:
+ return settings.LANGUAGE_CODE
@functools.lru_cache(maxsize=1000)
diff --git a/docs/releases/4.2.1.txt b/docs/releases/4.2.1.txt
index 151d16466f..a1130effe8 100644
--- a/docs/releases/4.2.1.txt
+++ b/docs/releases/4.2.1.txt
@@ -31,6 +31,11 @@ Bugfixes
``prefix_default_language`` argument when a fallback language of the default
language was used (:ticket:`34455`).
+* Fixed a regression in Django 4.2 where translated URLs of the default
+ language from ``i18n_patterns()`` with ``prefix_default_language`` set to
+ ``False`` raised 404 errors for a request with a different language
+ (:ticket:`34515`).
+
* Fixed a regression in Django 4.2 where creating copies and deep copies of
``HttpRequest``, ``HttpResponse``, and their subclasses didn't always work
correctly (:ticket:`34482`, :ticket:`34484`).
diff --git a/docs/releases/4.2.txt b/docs/releases/4.2.txt
index b113f3d217..d923be55b8 100644
--- a/docs/releases/4.2.txt
+++ b/docs/releases/4.2.txt
@@ -248,10 +248,6 @@ Internationalization
* 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
~~~~~~~
diff --git a/tests/i18n/patterns/tests.py b/tests/i18n/patterns/tests.py
index ad7b8ed1d4..df55a1ee13 100644
--- a/tests/i18n/patterns/tests.py
+++ b/tests/i18n/patterns/tests.py
@@ -431,6 +431,27 @@ class URLResponseTests(URLTestCaseBase):
self.assertEqual(response.context["LANGUAGE_CODE"], "nl")
+@override_settings(ROOT_URLCONF="i18n.urls_default_unprefixed", LANGUAGE_CODE="nl")
+class URLPrefixedFalseTranslatedTests(URLTestCaseBase):
+ def test_translated_path_unprefixed_language_other_than_accepted_header(self):
+ response = self.client.get("/gebruikers/", headers={"accept-language": "en"})
+ self.assertEqual(response.status_code, 200)
+
+ def test_translated_path_unprefixed_language_other_than_cookie_language(self):
+ self.client.cookies.load({settings.LANGUAGE_COOKIE_NAME: "en"})
+ response = self.client.get("/gebruikers/")
+ self.assertEqual(response.status_code, 200)
+
+ def test_translated_path_prefixed_language_other_than_accepted_header(self):
+ response = self.client.get("/en/users/", headers={"accept-language": "nl"})
+ self.assertEqual(response.status_code, 200)
+
+ def test_translated_path_prefixed_language_other_than_cookie_language(self):
+ self.client.cookies.load({settings.LANGUAGE_COOKIE_NAME: "nl"})
+ response = self.client.get("/en/users/")
+ self.assertEqual(response.status_code, 200)
+
+
class URLRedirectWithScriptAliasTests(URLTestCaseBase):
"""
#21579 - LocaleMiddleware should respect the script prefix.
diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py
index 01a729ed7b..d44ddb9f83 100644
--- a/tests/i18n/tests.py
+++ b/tests/i18n/tests.py
@@ -1926,22 +1926,8 @@ class UnprefixedDefaultLanguageTests(SimpleTestCase):
response = self.client.get("/fr/simple/")
self.assertEqual(response.content, b"Oui")
- def test_unprefixed_language_with_accept_language(self):
- """'Accept-Language' is respected."""
- response = self.client.get("/simple/", headers={"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/", headers={"accept-language": "fi"})
- self.assertEqual(response.content, b"Yes")
- self.client.cookies.load({settings.LANGUAGE_COOKIE_NAME: "fi"})
- response = self.client.get("/simple/")
+ def test_unprefixed_language_other_than_accept_language(self):
+ response = self.client.get("/simple/", HTTP_ACCEPT_LANGUAGE="fr")
self.assertEqual(response.content, b"Yes")
def test_page_with_dash(self):
@@ -2017,7 +2003,10 @@ class CountrySpecificLanguageTests(SimpleTestCase):
def test_get_language_from_request_null(self):
lang = trans_null.get_language_from_request(None)
- self.assertEqual(lang, None)
+ self.assertEqual(lang, "en")
+ with override_settings(LANGUAGE_CODE="de"):
+ lang = trans_null.get_language_from_request(None)
+ self.assertEqual(lang, "de")
def test_specific_language_codes(self):
# issue 11915
diff --git a/tests/i18n/urls_default_unprefixed.py b/tests/i18n/urls_default_unprefixed.py
index f14b059d37..d4ab5a7e1d 100644
--- a/tests/i18n/urls_default_unprefixed.py
+++ b/tests/i18n/urls_default_unprefixed.py
@@ -7,5 +7,6 @@ urlpatterns = i18n_patterns(
re_path(r"^(?P<arg>[\w-]+)-page", lambda request, **arg: HttpResponse(_("Yes"))),
path("simple/", lambda r: HttpResponse(_("Yes"))),
re_path(r"^(.+)/(.+)/$", lambda *args: HttpResponse()),
+ re_path(_(r"^users/$"), lambda *args: HttpResponse(), name="users"),
prefix_default_language=False,
)