Loading django/middleware/locale.py +10 −9 Original line number Diff line number Diff line Loading @@ -5,9 +5,8 @@ from django.http import HttpResponseRedirect from django.urls import ( LocaleRegexURLResolver, get_resolver, get_script_prefix, is_valid_path, ) from django.utils import translation from django.utils import lru_cache, translation from django.utils.cache import patch_vary_headers from django.utils.functional import cached_property class LocaleMiddleware(object): Loading @@ -21,17 +20,19 @@ class LocaleMiddleware(object): response_redirect_class = HttpResponseRedirect def process_request(self, request): urlconf = getattr(request, 'urlconf', settings.ROOT_URLCONF) language = translation.get_language_from_request( request, check_path=self.is_language_prefix_patterns_used) request, check_path=self.is_language_prefix_patterns_used(urlconf) ) 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) urlconf = getattr(request, 'urlconf', settings.ROOT_URLCONF) if (response.status_code == 404 and not language_from_path and self.is_language_prefix_patterns_used): urlconf = getattr(request, 'urlconf', None) and self.is_language_prefix_patterns_used(urlconf)): language_path = '/%s%s' % (language, request.path_info) path_valid = is_valid_path(language_path, urlconf) path_needs_slash = ( Loading @@ -52,20 +53,20 @@ class LocaleMiddleware(object): ) return self.response_redirect_class(language_url) if not (self.is_language_prefix_patterns_used if not (self.is_language_prefix_patterns_used(urlconf) and language_from_path): patch_vary_headers(response, ('Accept-Language',)) if 'Content-Language' not in response: response['Content-Language'] = language return response @cached_property def is_language_prefix_patterns_used(self): @lru_cache.lru_cache(maxsize=None) def is_language_prefix_patterns_used(self, urlconf): """ Returns `True` if the `LocaleRegexURLResolver` is used at root level of the urlpatterns, else it returns `False`. """ for url_pattern in get_resolver(None).url_patterns: for url_pattern in get_resolver(urlconf).url_patterns: if isinstance(url_pattern, LocaleRegexURLResolver): return True return False docs/releases/1.10.txt +3 −1 Original line number Diff line number Diff line Loading @@ -244,7 +244,9 @@ Generic Views Internationalization ~~~~~~~~~~~~~~~~~~~~ * ... * The :func:`~django.conf.urls.i18n.i18n_patterns` helper function can now be used in a root URLConf specified using :attr:`request.urlconf <django.http.HttpRequest.urlconf>`. Management Commands ~~~~~~~~~~~~~~~~~~~ Loading docs/topics/i18n/translation.txt +8 −2 Original line number Diff line number Diff line Loading @@ -1328,7 +1328,7 @@ Language prefix in URL patterns .. function:: i18n_patterns(*pattern_list) This function can be used in your root URLconf and Django will automatically This function can be used in a root URLconf and Django will automatically prepend the current active language code to all url patterns defined within :func:`~django.conf.urls.i18n.i18n_patterns`. Example URL patterns:: Loading Loading @@ -1373,10 +1373,16 @@ function. Example:: .. warning:: :func:`~django.conf.urls.i18n.i18n_patterns` is only allowed in your root :func:`~django.conf.urls.i18n.i18n_patterns` is only allowed in a root URLconf. Using it within an included URLconf will throw an :exc:`~django.core.exceptions.ImproperlyConfigured` exception. .. versionchanged:: 1.10 In older version, using ``i18n_patterns`` in a root URLconf different from :setting:`ROOT_URLCONF` by setting :attr:`request.urlconf <django.http.HttpRequest.urlconf>` wasn't supported. .. warning:: Ensure that you don't have non-prefixed URL patterns that might collide Loading tests/i18n/patterns/tests.py +13 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ from django.http import HttpResponsePermanentRedirect from django.middleware.locale import LocaleMiddleware from django.template import Context, Template from django.test import SimpleTestCase, override_settings from django.test.client import RequestFactory from django.test.utils import override_script_prefix from django.urls import clear_url_caches, reverse, translate_url from django.utils import translation Loading Loading @@ -92,6 +93,18 @@ class URLDisabledTests(URLTestCaseBase): self.assertEqual(reverse('prefixed'), '/prefixed/') class RequestURLConfTests(SimpleTestCase): @override_settings(ROOT_URLCONF='i18n.patterns.urls.path_unused') def test_request_urlconf_considered(self): request = RequestFactory().get('/nl/') request.urlconf = 'i18n.patterns.urls.default' middleware = LocaleMiddleware() with translation.override('nl'): middleware.process_request(request) self.assertEqual(request.LANGUAGE_CODE, 'nl') @override_settings(ROOT_URLCONF='i18n.patterns.urls.path_unused') class PathUnusedTests(URLTestCaseBase): """ Loading Loading
django/middleware/locale.py +10 −9 Original line number Diff line number Diff line Loading @@ -5,9 +5,8 @@ from django.http import HttpResponseRedirect from django.urls import ( LocaleRegexURLResolver, get_resolver, get_script_prefix, is_valid_path, ) from django.utils import translation from django.utils import lru_cache, translation from django.utils.cache import patch_vary_headers from django.utils.functional import cached_property class LocaleMiddleware(object): Loading @@ -21,17 +20,19 @@ class LocaleMiddleware(object): response_redirect_class = HttpResponseRedirect def process_request(self, request): urlconf = getattr(request, 'urlconf', settings.ROOT_URLCONF) language = translation.get_language_from_request( request, check_path=self.is_language_prefix_patterns_used) request, check_path=self.is_language_prefix_patterns_used(urlconf) ) 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) urlconf = getattr(request, 'urlconf', settings.ROOT_URLCONF) if (response.status_code == 404 and not language_from_path and self.is_language_prefix_patterns_used): urlconf = getattr(request, 'urlconf', None) and self.is_language_prefix_patterns_used(urlconf)): language_path = '/%s%s' % (language, request.path_info) path_valid = is_valid_path(language_path, urlconf) path_needs_slash = ( Loading @@ -52,20 +53,20 @@ class LocaleMiddleware(object): ) return self.response_redirect_class(language_url) if not (self.is_language_prefix_patterns_used if not (self.is_language_prefix_patterns_used(urlconf) and language_from_path): patch_vary_headers(response, ('Accept-Language',)) if 'Content-Language' not in response: response['Content-Language'] = language return response @cached_property def is_language_prefix_patterns_used(self): @lru_cache.lru_cache(maxsize=None) def is_language_prefix_patterns_used(self, urlconf): """ Returns `True` if the `LocaleRegexURLResolver` is used at root level of the urlpatterns, else it returns `False`. """ for url_pattern in get_resolver(None).url_patterns: for url_pattern in get_resolver(urlconf).url_patterns: if isinstance(url_pattern, LocaleRegexURLResolver): return True return False
docs/releases/1.10.txt +3 −1 Original line number Diff line number Diff line Loading @@ -244,7 +244,9 @@ Generic Views Internationalization ~~~~~~~~~~~~~~~~~~~~ * ... * The :func:`~django.conf.urls.i18n.i18n_patterns` helper function can now be used in a root URLConf specified using :attr:`request.urlconf <django.http.HttpRequest.urlconf>`. Management Commands ~~~~~~~~~~~~~~~~~~~ Loading
docs/topics/i18n/translation.txt +8 −2 Original line number Diff line number Diff line Loading @@ -1328,7 +1328,7 @@ Language prefix in URL patterns .. function:: i18n_patterns(*pattern_list) This function can be used in your root URLconf and Django will automatically This function can be used in a root URLconf and Django will automatically prepend the current active language code to all url patterns defined within :func:`~django.conf.urls.i18n.i18n_patterns`. Example URL patterns:: Loading Loading @@ -1373,10 +1373,16 @@ function. Example:: .. warning:: :func:`~django.conf.urls.i18n.i18n_patterns` is only allowed in your root :func:`~django.conf.urls.i18n.i18n_patterns` is only allowed in a root URLconf. Using it within an included URLconf will throw an :exc:`~django.core.exceptions.ImproperlyConfigured` exception. .. versionchanged:: 1.10 In older version, using ``i18n_patterns`` in a root URLconf different from :setting:`ROOT_URLCONF` by setting :attr:`request.urlconf <django.http.HttpRequest.urlconf>` wasn't supported. .. warning:: Ensure that you don't have non-prefixed URL patterns that might collide Loading
tests/i18n/patterns/tests.py +13 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ from django.http import HttpResponsePermanentRedirect from django.middleware.locale import LocaleMiddleware from django.template import Context, Template from django.test import SimpleTestCase, override_settings from django.test.client import RequestFactory from django.test.utils import override_script_prefix from django.urls import clear_url_caches, reverse, translate_url from django.utils import translation Loading Loading @@ -92,6 +93,18 @@ class URLDisabledTests(URLTestCaseBase): self.assertEqual(reverse('prefixed'), '/prefixed/') class RequestURLConfTests(SimpleTestCase): @override_settings(ROOT_URLCONF='i18n.patterns.urls.path_unused') def test_request_urlconf_considered(self): request = RequestFactory().get('/nl/') request.urlconf = 'i18n.patterns.urls.default' middleware = LocaleMiddleware() with translation.override('nl'): middleware.process_request(request) self.assertEqual(request.LANGUAGE_CODE, 'nl') @override_settings(ROOT_URLCONF='i18n.patterns.urls.path_unused') class PathUnusedTests(URLTestCaseBase): """ Loading