From 0d0f4f020afe516f23fd2305f13ff0a6a539b344 Mon Sep 17 00:00:00 2001 From: Bouke Haarsma Date: Fri, 18 Oct 2013 13:56:32 +0200 Subject: [PATCH] Fixed #5789 -- Changed LocaleMiddleware session variable to '_language'. The old 'django_language' variable will still be read from in order to migrate users. The backwards-compatability shim will be removed in Django 1.8. Thanks to jdunck for the report and stugots for the initial patch. --- django/middleware/locale.py | 10 ++++++-- django/utils/translation/trans_real.py | 3 ++- django/views/i18n.py | 2 +- docs/internals/deprecation.txt | 3 +++ docs/releases/1.7.txt | 7 ++++++ docs/topics/i18n/translation.txt | 9 +++++-- tests/i18n/tests.py | 34 +++++++++++++++++++++----- tests/view_tests/tests/test_i18n.py | 4 +-- 8 files changed, 58 insertions(+), 14 deletions(-) diff --git a/django/middleware/locale.py b/django/middleware/locale.py index bcdead5897..87f904d7dd 100644 --- a/django/middleware/locale.py +++ b/django/middleware/locale.py @@ -56,8 +56,14 @@ class LocaleMiddleware(object): return self.response_redirect_class(language_url) # Store language back into session if it is not present - if hasattr(request, 'session'): - request.session.setdefault('django_language', language) + if hasattr(request, 'session') and '_language' not in request.session: + # Backwards compatibility check on django_language (remove in 1.8); + # revert to: `request.session.setdefault('_language', language)`. + if 'django_language' in request.session: + request.session['_language'] = request.session['django_language'] + del request.session['django_language'] + else: + request.session['_language'] = language if not (self.is_language_prefix_patterns_used() and language_from_path): diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py index c7b41fa373..c8c7bddb14 100644 --- a/django/utils/translation/trans_real.py +++ b/django/utils/translation/trans_real.py @@ -426,7 +426,8 @@ def get_language_from_request(request, check_path=False): return lang_code if hasattr(request, 'session'): - lang_code = request.session.get('django_language', None) + # for backwards compatibility django_language is also checked (remove in 1.8) + lang_code = request.session.get('_language', request.session.get('django_language')) if lang_code in supported and lang_code is not None and check_for_language(lang_code): return lang_code diff --git a/django/views/i18n.py b/django/views/i18n.py index 86acb9c032..2623a00d6a 100644 --- a/django/views/i18n.py +++ b/django/views/i18n.py @@ -34,7 +34,7 @@ def set_language(request): lang_code = request.POST.get('language', None) if lang_code and check_for_language(lang_code): if hasattr(request, 'session'): - request.session['django_language'] = lang_code + request.session['_language'] = lang_code else: response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang_code) return response diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index bf26d8d855..42b81419ec 100644 --- a/docs/internals/deprecation.txt +++ b/docs/internals/deprecation.txt @@ -410,6 +410,9 @@ these changes. * The ``Model._meta.get_(add|change|delete)_permission`` methods will be removed. +* The session key ``django_language`` will no longer be read for backwards + compatibility. + 1.9 --- diff --git a/docs/releases/1.7.txt b/docs/releases/1.7.txt index d5c1f886da..699566f1d3 100644 --- a/docs/releases/1.7.txt +++ b/docs/releases/1.7.txt @@ -302,6 +302,13 @@ Internationalization * The :attr:`django.middleware.locale.LocaleMiddleware.response_redirect_class` attribute allows you to customize the redirects issued by the middleware. +* The :class:`~django.middleware.locale.LocaleMiddleware` now stores the user's + selected language with the session key ``_language``. Previously it was + stored with the key ``django_language``, but keys reserved for Django should + start with an underscore. For backwards compatibility ``django_language`` is + still read from in 1.7. Sessions will be migrated to the new ``_language`` + key as they are written. + Management Commands ^^^^^^^^^^^^^^^^^^^ diff --git a/docs/topics/i18n/translation.txt b/docs/topics/i18n/translation.txt index d8c2b49724..08e87b1425 100644 --- a/docs/topics/i18n/translation.txt +++ b/docs/topics/i18n/translation.txt @@ -1594,8 +1594,13 @@ following this algorithm: root URLconf. See :ref:`url-internationalization` for more information about the language prefix and how to internationalize URL patterns. -* Failing that, it looks for a ``django_language`` key in the current - user's session. +* Failing that, it looks for a ``_language`` key in the current user's session. + + .. versionchanged:: 1.7 + + In previous versions, the key was named ``django_language`` but it was + renamed to start with an underscore to denote a Django reserved session + key. * Failing that, it looks for a cookie. diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py index 7cef9e1716..fbb3476f91 100644 --- a/tests/i18n/tests.py +++ b/tests/i18n/tests.py @@ -1190,17 +1190,39 @@ class LocaleMiddlewareTests(TransRealMixin, TestCase): # Clear the session data before request session.save() - self.client.get('/en/simple/') - self.assertEqual(self.client.session['django_language'], 'en') + response = self.client.get('/en/simple/') + self.assertEqual(self.client.session['_language'], 'en') # Clear the session data before request session.save() - self.client.get('/fr/simple/') - self.assertEqual(self.client.session['django_language'], 'fr') + response = self.client.get('/fr/simple/') + self.assertEqual(self.client.session['_language'], 'fr') # Check that language is not changed in session - self.client.get('/en/simple/') - self.assertEqual(self.client.session['django_language'], 'fr') + response = self.client.get('/en/simple/') + self.assertEqual(self.client.session['_language'], 'fr') + + @override_settings( + MIDDLEWARE_CLASSES=( + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.locale.LocaleMiddleware', + 'django.middleware.common.CommonMiddleware', + ), + ) + def test_backwards_session_language(self): + """ + Check that language is stored in session if missing. + """ + # Create session with old language key name + engine = import_module(settings.SESSION_ENGINE) + session = engine.SessionStore() + session['django_language'] = 'en' + session.save() + self.client.cookies[settings.SESSION_COOKIE_NAME] = session.session_key + + # request other language; should default to old language key value + response = self.client.get('/fr/simple/') + self.assertEqual(self.client.session['_language'], 'en') @override_settings( diff --git a/tests/view_tests/tests/test_i18n.py b/tests/view_tests/tests/test_i18n.py index 680cd25d6a..777fc24bb1 100644 --- a/tests/view_tests/tests/test_i18n.py +++ b/tests/view_tests/tests/test_i18n.py @@ -34,7 +34,7 @@ class I18NTests(TestCase): post_data = dict(language=lang_code, next='/views/') response = self.client.post('/views/i18n/setlang/', data=post_data) self.assertRedirects(response, 'http://testserver/views/') - self.assertEqual(self.client.session['django_language'], lang_code) + self.assertEqual(self.client.session['_language'], lang_code) def test_setlang_unsafe_next(self): """ @@ -45,7 +45,7 @@ class I18NTests(TestCase): post_data = dict(language=lang_code, next='//unsafe/redirection/') response = self.client.post('/views/i18n/setlang/', data=post_data) self.assertEqual(response.url, 'http://testserver/') - self.assertEqual(self.client.session['django_language'], lang_code) + self.assertEqual(self.client.session['_language'], lang_code) def test_setlang_reversal(self): self.assertEqual(reverse('set_language'), '/views/i18n/setlang/')