Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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.
  • Loading branch information...
commit 0d0f4f020afe516f23fd2305f13ff0a6a539b344 1 parent 8e2029f
Bouke Haarsma authored timgraham committed
10  django/middleware/locale.py
@@ -56,8 +56,14 @@ def process_response(self, request, response):
56 56
                 return self.response_redirect_class(language_url)
57 57
 
58 58
         # Store language back into session if it is not present
59  
-        if hasattr(request, 'session'):
60  
-            request.session.setdefault('django_language', language)
  59
+        if hasattr(request, 'session') and '_language' not in request.session:
  60
+            # Backwards compatibility check on django_language (remove in 1.8);
  61
+            # revert to: `request.session.setdefault('_language', language)`.
  62
+            if 'django_language' in request.session:
  63
+                request.session['_language'] = request.session['django_language']
  64
+                del request.session['django_language']
  65
+            else:
  66
+                request.session['_language'] = language
61 67
 
62 68
         if not (self.is_language_prefix_patterns_used()
63 69
                 and language_from_path):
3  django/utils/translation/trans_real.py
@@ -426,7 +426,8 @@ def get_language_from_request(request, check_path=False):
426 426
             return lang_code
427 427
 
428 428
     if hasattr(request, 'session'):
429  
-        lang_code = request.session.get('django_language', None)
  429
+        # for backwards compatibility django_language is also checked (remove in 1.8)
  430
+        lang_code = request.session.get('_language', request.session.get('django_language'))
430 431
         if lang_code in supported and lang_code is not None and check_for_language(lang_code):
431 432
             return lang_code
432 433
 
2  django/views/i18n.py
@@ -34,7 +34,7 @@ def set_language(request):
34 34
         lang_code = request.POST.get('language', None)
35 35
         if lang_code and check_for_language(lang_code):
36 36
             if hasattr(request, 'session'):
37  
-                request.session['django_language'] = lang_code
  37
+                request.session['_language'] = lang_code
38 38
             else:
39 39
                 response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang_code)
40 40
     return response
3  docs/internals/deprecation.txt
@@ -410,6 +410,9 @@ these changes.
410 410
 * The ``Model._meta.get_(add|change|delete)_permission`` methods will
411 411
   be removed.
412 412
 
  413
+* The session key ``django_language`` will no longer be read for backwards
  414
+  compatibility.
  415
+
413 416
 1.9
414 417
 ---
415 418
 
7  docs/releases/1.7.txt
@@ -302,6 +302,13 @@ Internationalization
302 302
 * The :attr:`django.middleware.locale.LocaleMiddleware.response_redirect_class`
303 303
   attribute allows you to customize the redirects issued by the middleware.
304 304
 
  305
+* The :class:`~django.middleware.locale.LocaleMiddleware` now stores the user's
  306
+  selected language with the session key ``_language``. Previously it was
  307
+  stored with the key ``django_language``, but keys reserved for Django should
  308
+  start with an underscore. For backwards compatibility ``django_language`` is
  309
+  still read from in 1.7. Sessions will be migrated to the new ``_language``
  310
+  key as they are written.
  311
+
305 312
 Management Commands
306 313
 ^^^^^^^^^^^^^^^^^^^
307 314
 
9  docs/topics/i18n/translation.txt
@@ -1594,8 +1594,13 @@ following this algorithm:
1594 1594
   root URLconf. See :ref:`url-internationalization` for more information
1595 1595
   about the language prefix and how to internationalize URL patterns.
1596 1596
 
1597  
-* Failing that, it looks for a ``django_language`` key in the current
1598  
-  user's session.
  1597
+* Failing that, it looks for a ``_language`` key in the current user's session.
  1598
+
  1599
+  .. versionchanged:: 1.7
  1600
+
  1601
+      In previous versions, the key was named ``django_language`` but it was
  1602
+      renamed to start with an underscore to denote a Django reserved session
  1603
+      key.
1599 1604
 
1600 1605
 * Failing that, it looks for a cookie.
1601 1606
 
34  tests/i18n/tests.py
@@ -1190,17 +1190,39 @@ def test_session_language(self):
1190 1190
 
1191 1191
         # Clear the session data before request
1192 1192
         session.save()
1193  
-        self.client.get('/en/simple/')
1194  
-        self.assertEqual(self.client.session['django_language'], 'en')
  1193
+        response = self.client.get('/en/simple/')
  1194
+        self.assertEqual(self.client.session['_language'], 'en')
1195 1195
 
1196 1196
         # Clear the session data before request
1197 1197
         session.save()
1198  
-        self.client.get('/fr/simple/')
1199  
-        self.assertEqual(self.client.session['django_language'], 'fr')
  1198
+        response = self.client.get('/fr/simple/')
  1199
+        self.assertEqual(self.client.session['_language'], 'fr')
1200 1200
 
1201 1201
         # Check that language is not changed in session
1202  
-        self.client.get('/en/simple/')
1203  
-        self.assertEqual(self.client.session['django_language'], 'fr')
  1202
+        response = self.client.get('/en/simple/')
  1203
+        self.assertEqual(self.client.session['_language'], 'fr')
  1204
+
  1205
+    @override_settings(
  1206
+        MIDDLEWARE_CLASSES=(
  1207
+            'django.contrib.sessions.middleware.SessionMiddleware',
  1208
+            'django.middleware.locale.LocaleMiddleware',
  1209
+            'django.middleware.common.CommonMiddleware',
  1210
+        ),
  1211
+    )
  1212
+    def test_backwards_session_language(self):
  1213
+        """
  1214
+        Check that language is stored in session if missing.
  1215
+        """
  1216
+        # Create session with old language key name
  1217
+        engine = import_module(settings.SESSION_ENGINE)
  1218
+        session = engine.SessionStore()
  1219
+        session['django_language'] = 'en'
  1220
+        session.save()
  1221
+        self.client.cookies[settings.SESSION_COOKIE_NAME] = session.session_key
  1222
+
  1223
+        # request other language; should default to old language key value
  1224
+        response = self.client.get('/fr/simple/')
  1225
+        self.assertEqual(self.client.session['_language'], 'en')
1204 1226
 
1205 1227
 
1206 1228
 @override_settings(
4  tests/view_tests/tests/test_i18n.py
@@ -34,7 +34,7 @@ def test_setlang(self):
34 34
             post_data = dict(language=lang_code, next='/views/')
35 35
             response = self.client.post('/views/i18n/setlang/', data=post_data)
36 36
             self.assertRedirects(response, 'http://testserver/views/')
37  
-            self.assertEqual(self.client.session['django_language'], lang_code)
  37
+            self.assertEqual(self.client.session['_language'], lang_code)
38 38
 
39 39
     def test_setlang_unsafe_next(self):
40 40
         """
@@ -45,7 +45,7 @@ def test_setlang_unsafe_next(self):
45 45
         post_data = dict(language=lang_code, next='//unsafe/redirection/')
46 46
         response = self.client.post('/views/i18n/setlang/', data=post_data)
47 47
         self.assertEqual(response.url, 'http://testserver/')
48  
-        self.assertEqual(self.client.session['django_language'], lang_code)
  48
+        self.assertEqual(self.client.session['_language'], lang_code)
49 49
 
50 50
     def test_setlang_reversal(self):
51 51
         self.assertEqual(reverse('set_language'), '/views/i18n/setlang/')

0 notes on commit 0d0f4f0

Please sign in to comment.
Something went wrong with that request. Please try again.