Commit aa5ab114 authored by Claude Paroz's avatar Claude Paroz
Browse files

Fixed #24122 -- Redirected to translated url after setting language

Thanks gbdlin for the initial patch and Tim Graham for the review.
parent a8991b9b
Loading
Loading
Loading
Loading
+25 −1
Original line number Diff line number Diff line
@@ -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
+4 −0
Original line number Diff line number Diff line
@@ -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:
+2 −1
Original line number Diff line number Diff line
@@ -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
^^^^^^^^^^^^^^^^^^^
+13 −1
Original line number Diff line number Diff line
@@ -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):
    """
Loading