mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #24122 -- Redirected to translated url after setting language
Thanks gbdlin for the initial patch and Tim Graham for the review.
This commit is contained in:
		| @@ -24,7 +24,8 @@ from django.utils.functional import cached_property, lazy | ||||
| from django.utils.http import RFC3986_SUBDELIMS, urlquote | ||||
| from django.utils.module_loading import module_has_submodule | ||||
| from django.utils.regex_helper import normalize | ||||
| from django.utils.translation import get_language | ||||
| from django.utils.six.moves.urllib.parse import urlsplit, urlunsplit | ||||
| from django.utils.translation import get_language, override | ||||
|  | ||||
| # SCRIPT_NAME prefixes for each thread are stored here. If there's no entry for | ||||
| # the current thread (which is the only one we ever access), it is assumed to | ||||
| @@ -652,3 +653,26 @@ def is_valid_path(path, urlconf=None): | ||||
|         return True | ||||
|     except Resolver404: | ||||
|         return False | ||||
|  | ||||
|  | ||||
| def translate_url(url, lang_code): | ||||
|     """ | ||||
|     Given a URL (absolute or relative), try to get its translated version in | ||||
|     the `lang_code` language (either by i18n_patterns or by translated regex). | ||||
|     Return the original URL if no translated version is found. | ||||
|     """ | ||||
|     parsed = urlsplit(url) | ||||
|     try: | ||||
|         match = resolve(parsed.path) | ||||
|     except Resolver404: | ||||
|         pass | ||||
|     else: | ||||
|         to_be_reversed = "%s:%s" % (match.namespace, match.url_name) if match.namespace else match.url_name | ||||
|         with override(lang_code): | ||||
|             try: | ||||
|                 url = reverse(to_be_reversed, args=match.args, kwargs=match.kwargs) | ||||
|             except NoReverseMatch: | ||||
|                 pass | ||||
|             else: | ||||
|                 url = urlunsplit((parsed.scheme, parsed.netloc, url, parsed.query, parsed.fragment)) | ||||
|     return url | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import os | ||||
| from django import http | ||||
| from django.apps import apps | ||||
| from django.conf import settings | ||||
| from django.core.urlresolvers import translate_url | ||||
| from django.template import Context, Engine | ||||
| from django.utils import six | ||||
| from django.utils._os import upath | ||||
| @@ -37,6 +38,9 @@ def set_language(request): | ||||
|     if request.method == 'POST': | ||||
|         lang_code = request.POST.get('language', None) | ||||
|         if lang_code and check_for_language(lang_code): | ||||
|             next_trans = translate_url(next, lang_code) | ||||
|             if next_trans != next: | ||||
|                 response = http.HttpResponseRedirect(next_trans) | ||||
|             if hasattr(request, 'session'): | ||||
|                 request.session[LANGUAGE_SESSION_KEY] = lang_code | ||||
|             else: | ||||
|   | ||||
| @@ -127,7 +127,8 @@ Generic Views | ||||
| Internationalization | ||||
| ^^^^^^^^^^^^^^^^^^^^ | ||||
|  | ||||
| * ... | ||||
| * The :func:`django.views.i18n.set_language` view now properly redirects to | ||||
|   :ref:`translated URLs <url-internationalization>`, when available. | ||||
|  | ||||
| Management Commands | ||||
| ^^^^^^^^^^^^^^^^^^^ | ||||
|   | ||||
| @@ -4,7 +4,7 @@ import os | ||||
|  | ||||
| from django.core.exceptions import ImproperlyConfigured | ||||
| from django.core.urlresolvers import ( | ||||
|     clear_url_caches, reverse, set_script_prefix, | ||||
|     clear_url_caches, reverse, set_script_prefix, translate_url, | ||||
| ) | ||||
| from django.http import HttpResponsePermanentRedirect | ||||
| from django.middleware.locale import LocaleMiddleware | ||||
| @@ -135,6 +135,18 @@ class URLTranslationTests(URLTestCaseBase): | ||||
|         with translation.override('pt-br'): | ||||
|             self.assertEqual(reverse('users'), '/pt-br/usuarios/') | ||||
|  | ||||
|     def test_translate_url_utility(self): | ||||
|         with translation.override('en'): | ||||
|             self.assertEqual(translate_url('/en/non-existent/', 'nl'), '/en/non-existent/') | ||||
|             self.assertEqual(translate_url('/en/users/', 'nl'), '/nl/gebruikers/') | ||||
|             # Namespaced URL | ||||
|             self.assertEqual(translate_url('/en/account/register/', 'nl'), '/nl/profiel/registeren/') | ||||
|             self.assertEqual(translation.get_language(), 'en') | ||||
|  | ||||
|         with translation.override('nl'): | ||||
|             self.assertEqual(translate_url('/nl/gebruikers/', 'en'), '/en/users/') | ||||
|             self.assertEqual(translation.get_language(), 'nl') | ||||
|  | ||||
|  | ||||
| class URLNamespaceTests(URLTestCaseBase): | ||||
|     """ | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							| @@ -16,6 +16,10 @@ msgstr "" | ||||
| "Content-Type: text/plain; charset=UTF-8\n" | ||||
| "Content-Transfer-Encoding: 8bit\n" | ||||
|  | ||||
| #: urls.py:78 | ||||
| msgid "^translated/$" | ||||
| msgstr "^vertaald/$" | ||||
|  | ||||
| #: views/csrf.py:98 | ||||
| msgid "Forbidden" | ||||
| msgstr "Verboden" | ||||
|   | ||||
| @@ -67,6 +67,23 @@ class I18NTests(TestCase): | ||||
|             self.assertEqual(language_cookie['path'], '/test/') | ||||
|             self.assertEqual(language_cookie['max-age'], 3600 * 7 * 2) | ||||
|  | ||||
|     @modify_settings(MIDDLEWARE_CLASSES={ | ||||
|         'append': 'django.middleware.locale.LocaleMiddleware', | ||||
|     }) | ||||
|     def test_lang_from_translated_i18n_pattern(self): | ||||
|         response = self.client.post( | ||||
|             '/i18n/setlang/', data={'language': 'nl'}, | ||||
|             follow=True, HTTP_REFERER='/en/translated/' | ||||
|         ) | ||||
|         self.assertEqual(self.client.session[LANGUAGE_SESSION_KEY], 'nl') | ||||
|         self.assertRedirects(response, 'http://testserver/nl/vertaald/') | ||||
|         # And reverse | ||||
|         response = self.client.post( | ||||
|             '/i18n/setlang/', data={'language': 'en'}, | ||||
|             follow=True, HTTP_REFERER='/nl/vertaald/' | ||||
|         ) | ||||
|         self.assertRedirects(response, 'http://testserver/en/translated/') | ||||
|  | ||||
|     def test_jsi18n(self): | ||||
|         """The javascript_catalog can be deployed with language settings""" | ||||
|         for lang_code in ['es', 'fr', 'ru']: | ||||
|   | ||||
| @@ -2,7 +2,9 @@ | ||||
| from os import path | ||||
|  | ||||
| from django.conf.urls import include, url | ||||
| from django.conf.urls.i18n import i18n_patterns | ||||
| from django.utils._os import upath | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| from django.views import defaults, i18n, static | ||||
|  | ||||
| from . import views | ||||
| @@ -73,6 +75,10 @@ urlpatterns = [ | ||||
|     url(r'^site_media/(?P<path>.*)$', static.serve, {'document_root': media_dir}), | ||||
| ] | ||||
|  | ||||
| urlpatterns += i18n_patterns( | ||||
|     url(_(r'^translated/$'), views.index_page, name='i18n_prefixed'), | ||||
| ) | ||||
|  | ||||
| urlpatterns += [ | ||||
|     url(r'view_exception/(?P<n>[0-9]+)/$', views.view_exception, name='view_exception'), | ||||
|     url(r'template_exception/(?P<n>[0-9]+)/$', views.template_exception, name='template_exception'), | ||||
|   | ||||
		Reference in New Issue
	
	Block a user