summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErik Romijn <eromijn@solidlinks.nl>2014-02-22 14:27:57 +0100
committerBaptiste Mispelon <bmispelon@gmail.com>2014-02-22 18:29:06 +0100
commit8cd32f09659cc271050a62b978f244b8a3445315 (patch)
tree1977c53088acef79e6ce0df237ade0899b1b4993
parent09b725f51bbfa0f01b27ee2d718889926d409519 (diff)
Fixed #22120 -- Documented persistent activation of languages and cleaned up language session key use
-rw-r--r--django/contrib/auth/__init__.py5
-rw-r--r--django/contrib/auth/tests/test_views.py5
-rw-r--r--django/utils/translation/__init__.py1
-rw-r--r--django/utils/translation/trans_real.py4
-rw-r--r--django/views/i18n.py4
-rw-r--r--docs/ref/utils.txt4
-rw-r--r--docs/releases/1.7.txt12
-rw-r--r--docs/topics/i18n/translation.txt40
-rw-r--r--tests/i18n/tests.py4
-rw-r--r--tests/view_tests/tests/test_i18n.py6
10 files changed, 63 insertions, 22 deletions
diff --git a/django/contrib/auth/__init__.py b/django/contrib/auth/__init__.py
index c3a1253564..1ae323e902 100644
--- a/django/contrib/auth/__init__.py
+++ b/django/contrib/auth/__init__.py
@@ -5,6 +5,7 @@ from django.apps import apps as django_apps
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
from django.utils.module_loading import import_string
+from django.utils.translation import LANGUAGE_SESSION_KEY
from django.middleware.csrf import rotate_token
from .signals import user_logged_in, user_logged_out, user_login_failed
@@ -108,12 +109,12 @@ def logout(request):
# remember language choice saved to session
# for backwards compatibility django_language is also checked (remove in 1.8)
- language = request.session.get('_language', request.session.get('django_language'))
+ language = request.session.get(LANGUAGE_SESSION_KEY, request.session.get('django_language'))
request.session.flush()
if language is not None:
- request.session['_language'] = language
+ request.session[LANGUAGE_SESSION_KEY] = language
if hasattr(request, 'user'):
from django.contrib.auth.models import AnonymousUser
diff --git a/django/contrib/auth/tests/test_views.py b/django/contrib/auth/tests/test_views.py
index d37afa3eee..605ed4462e 100644
--- a/django/contrib/auth/tests/test_views.py
+++ b/django/contrib/auth/tests/test_views.py
@@ -14,6 +14,7 @@ from django.http import QueryDict, HttpRequest
from django.utils.encoding import force_text
from django.utils.http import urlquote
from django.utils.six.moves.urllib.parse import urlparse, ParseResult
+from django.utils.translation import LANGUAGE_SESSION_KEY
from django.utils._os import upath
from django.test import TestCase, override_settings
from django.test.utils import patch_logger
@@ -718,12 +719,12 @@ class LogoutTest(AuthViewsTestCase):
# Create a new session with language
engine = import_module(settings.SESSION_ENGINE)
session = engine.SessionStore()
- session['_language'] = 'pl'
+ session[LANGUAGE_SESSION_KEY] = 'pl'
session.save()
self.client.cookies[settings.SESSION_COOKIE_NAME] = session.session_key
self.client.get('/logout/')
- self.assertEqual(self.client.session['_language'], 'pl')
+ self.assertEqual(self.client.session[LANGUAGE_SESSION_KEY], 'pl')
@skipIfCustomUser
diff --git a/django/utils/translation/__init__.py b/django/utils/translation/__init__.py
index 9d46ce67e4..54e1244c23 100644
--- a/django/utils/translation/__init__.py
+++ b/django/utils/translation/__init__.py
@@ -21,6 +21,7 @@ __all__ = [
'npgettext', 'npgettext_lazy',
]
+LANGUAGE_SESSION_KEY = '_language'
class TranslatorCommentWarning(SyntaxWarning):
pass
diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py
index 29c133006e..ea872e1ec9 100644
--- a/django/utils/translation/trans_real.py
+++ b/django/utils/translation/trans_real.py
@@ -18,7 +18,7 @@ from django.utils._os import upath
from django.utils.safestring import mark_safe, SafeData
from django.utils import six, lru_cache
from django.utils.six import StringIO
-from django.utils.translation import TranslatorCommentWarning, trim_whitespace
+from django.utils.translation import TranslatorCommentWarning, trim_whitespace, LANGUAGE_SESSION_KEY
# Translations are cached in a dictionary for every language+app tuple.
@@ -478,7 +478,7 @@ def get_language_from_request(request, check_path=False):
if hasattr(request, 'session'):
# for backwards compatibility django_language is also checked (remove in 1.8)
- lang_code = request.session.get('_language', request.session.get('django_language'))
+ lang_code = request.session.get(LANGUAGE_SESSION_KEY, 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 7182f4f3cd..a62ca29e54 100644
--- a/django/views/i18n.py
+++ b/django/views/i18n.py
@@ -7,7 +7,7 @@ from django import http
from django.apps import apps
from django.conf import settings
from django.template import Context, Template
-from django.utils.translation import check_for_language, to_locale, get_language
+from django.utils.translation import check_for_language, to_locale, get_language, LANGUAGE_SESSION_KEY
from django.utils.encoding import smart_text
from django.utils.formats import get_format_modules, get_format
from django.utils._os import upath
@@ -36,7 +36,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['_language'] = lang_code
+ request.session[LANGUAGE_SESSION_KEY] = lang_code
else:
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang_code)
return response
diff --git a/docs/ref/utils.txt b/docs/ref/utils.txt
index 5313a1de19..15242f030f 100644
--- a/docs/ref/utils.txt
+++ b/docs/ref/utils.txt
@@ -937,6 +937,10 @@ For a complete discussion on the usage of the following see the
so by translating the Django translation tags into standard gettext function
invocations.
+.. data:: LANGUAGE_SESSION_KEY
+
+ Session key under which the active language for the current session is stored.
+
.. _time-zone-selection-functions:
``django.utils.timezone``
diff --git a/docs/releases/1.7.txt b/docs/releases/1.7.txt
index 400c5d0759..c7b545b501 100644
--- a/docs/releases/1.7.txt
+++ b/docs/releases/1.7.txt
@@ -537,11 +537,13 @@ Internationalization
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.
+ selected language with the session key ``_language``. This should only be
+ accessed using the :data:`~django.utils.translation.LANGUAGE_SESSION_KEY`
+ constant. Previously it was stored with the key ``django_language`` and the
+ ``LANGUAGE_SESSION_KEY`` constant did not exist, 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 key
+ as they are written.
* The :ttag:`blocktrans` now supports a ``trimmed`` option. This
option will remove newline characters from the beginning and the end of the
diff --git a/docs/topics/i18n/translation.txt b/docs/topics/i18n/translation.txt
index 62729d55da..0a5fa925bc 100644
--- a/docs/topics/i18n/translation.txt
+++ b/docs/topics/i18n/translation.txt
@@ -1510,6 +1510,38 @@ Here's example HTML template code:
In this example, Django looks up the URL of the page to which the user will be
redirected in the ``redirect_to`` context variable.
+Explicitly setting the active language
+--------------------------------------
+
+.. highlightlang:: python
+
+You may want to set the active language for the current session explicitly. Perhaps
+a user's language preference is retrieved from another system, for example.
+You've already been introduced to :func:`django.utils.translation.activate()`. That
+applies to the current thread only. To persist the language for the entire
+session, also modify :data:`~django.utils.translation.LANGUAGE_SESSION_KEY`
+in the session::
+
+ from django.utils import translation
+ user_language = 'fr'
+ translation.activate(user_language)
+ request.session[translation.LANGUAGE_SESSION_KEY] = user_language
+
+You would typically want to use both: :func:`django.utils.translation.activate()`
+will change the language for this thread, and modifying the session makes this
+preference persist in future requests.
+
+If you are not using sessions, the language will persist in a cookie, whose name
+is configured in :setting:`LANGUAGE_COOKIE_NAME`. For example::
+
+ from django.utils import translation
+ from django import http
+ from django.conf import settings
+ user_language = 'fr'
+ translation.activate(user_language)
+ response = http.HttpResponse(...)
+ response.set_cookie(settings.LANGUAGE_COOKIE_NAME, user_language)
+
Using translations outside views and templates
----------------------------------------------
@@ -1621,13 +1653,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 ``_language`` key in the current user's session.
+* Failing that, it looks for the :data:`~django.utils.translation.LANGUAGE_SESSION_KEY`
+ 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.
+ In previous versions, the key was named ``django_language``, and the
+ ``LANGUAGE_SESSION_KEY`` constant did not exist.
* Failing that, it looks for a cookie.
diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py
index c7179d6117..56c3f63316 100644
--- a/tests/i18n/tests.py
+++ b/tests/i18n/tests.py
@@ -31,7 +31,7 @@ from django.utils.translation import (activate, deactivate,
pgettext,
npgettext, npgettext_lazy,
check_for_language,
- string_concat)
+ string_concat, LANGUAGE_SESSION_KEY)
from .forms import I18nForm, SelectDateForm, SelectDateWidget, CompanyForm
from .models import Company, TestModel
@@ -1267,7 +1267,7 @@ class LocaleMiddlewareTests(TestCase):
session on every request."""
# Regression test for #21473
self.client.get('/fr/simple/')
- self.assertNotIn('_language', self.client.session)
+ self.assertNotIn(LANGUAGE_SESSION_KEY, self.client.session)
@override_settings(
diff --git a/tests/view_tests/tests/test_i18n.py b/tests/view_tests/tests/test_i18n.py
index 72da88e92c..7d6466d44f 100644
--- a/tests/view_tests/tests/test_i18n.py
+++ b/tests/view_tests/tests/test_i18n.py
@@ -11,7 +11,7 @@ from django.test import (
LiveServerTestCase, TestCase, modify_settings, override_settings)
from django.utils import six
from django.utils._os import upath
-from django.utils.translation import override
+from django.utils.translation import override, LANGUAGE_SESSION_KEY
try:
from selenium.webdriver.firefox import webdriver as firefox
@@ -35,7 +35,7 @@ class I18NTests(TestCase):
post_data = dict(language=lang_code, next='/')
response = self.client.post('/i18n/setlang/', data=post_data)
self.assertRedirects(response, 'http://testserver/')
- self.assertEqual(self.client.session['_language'], lang_code)
+ self.assertEqual(self.client.session[LANGUAGE_SESSION_KEY], lang_code)
def test_setlang_unsafe_next(self):
"""
@@ -46,7 +46,7 @@ class I18NTests(TestCase):
post_data = dict(language=lang_code, next='//unsafe/redirection/')
response = self.client.post('/i18n/setlang/', data=post_data)
self.assertEqual(response.url, 'http://testserver/')
- self.assertEqual(self.client.session['_language'], lang_code)
+ self.assertEqual(self.client.session[LANGUAGE_SESSION_KEY], lang_code)
def test_setlang_reversal(self):
self.assertEqual(reverse('set_language'), '/i18n/setlang/')