fix: use language specified in SiteConfiguration
This feature was implemented inb01544d690to replace the session's language in the request.44ddbdf925moved the process from the request to the response, which made this feature unusable (because the request was already processed).44ddbdf925also made this feature set the language cookie. However, it is overwritten by user preferences. To fix this, we could overwrite the cookie of the response after it's set from user preferences. However, it is not an ideal solution because when users switch between Sites with different languages, the first response will use the language of the previous page. Therefore, this ignores user preferences and alters the cookie of a request instead.
This commit is contained in:
@@ -17,7 +17,6 @@ from django.utils.deprecation import MiddlewareMixin
|
||||
from openedx.core.djangoapps.dark_lang import DARK_LANGUAGE_KEY
|
||||
from openedx.core.djangoapps.dark_lang.models import DarkLangConfig
|
||||
from openedx.core.djangoapps.lang_pref.helpers import set_language_cookie
|
||||
from openedx.core.djangoapps.site_configuration.helpers import get_value
|
||||
from openedx.core.djangoapps.user_api.preferences.api import get_user_preference
|
||||
|
||||
# If django 1.7 or higher is used, the right-side can be updated with new-style codes.
|
||||
@@ -98,20 +97,10 @@ class DarkLangMiddleware(MiddlewareMixin):
|
||||
Apply user's dark lang preference as a cookie for future requests.
|
||||
"""
|
||||
if DarkLangConfig.current().enabled:
|
||||
self._set_site_or_microsite_language(request, response)
|
||||
self._activate_preview_language(request, response)
|
||||
|
||||
return response
|
||||
|
||||
def _set_site_or_microsite_language(self, request, response):
|
||||
"""
|
||||
Apply language specified in site configuration.
|
||||
"""
|
||||
language = get_value('LANGUAGE_CODE', None)
|
||||
if language:
|
||||
request.session[LANGUAGE_SESSION_KEY] = language
|
||||
set_language_cookie(request, response, language)
|
||||
|
||||
def _fuzzy_match(self, lang_code):
|
||||
"""Returns a fuzzy match for lang_code"""
|
||||
match = None
|
||||
|
||||
@@ -14,7 +14,10 @@ from django.utils.translation import LANGUAGE_SESSION_KEY
|
||||
|
||||
from openedx.core.djangoapps.dark_lang.middleware import DarkLangMiddleware
|
||||
from openedx.core.djangoapps.dark_lang.models import DarkLangConfig
|
||||
from openedx.core.djangoapps.site_configuration.tests.test_util import with_site_configuration
|
||||
from openedx.core.djangoapps.site_configuration.tests.test_util import (
|
||||
with_site_configuration,
|
||||
with_site_configuration_context,
|
||||
)
|
||||
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
|
||||
@@ -258,16 +261,6 @@ class DarkLangMiddlewareTests(CacheIsolationTestCase):
|
||||
session[LANGUAGE_SESSION_KEY] = session_language
|
||||
session.save()
|
||||
|
||||
@with_site_configuration(configuration={'LANGUAGE_CODE': 'rel'})
|
||||
def test_site_configuration_language(self):
|
||||
# `LANGUAGE_CODE` in site configuration should override session lang
|
||||
self._set_client_session_language('notrel')
|
||||
self.client.get('/home')
|
||||
self.assert_session_lang_equals(
|
||||
'rel',
|
||||
self.client.session
|
||||
)
|
||||
|
||||
def test_preview_lang_with_released_language(self):
|
||||
# Preview lang should always override selection
|
||||
self._post_set_preview_lang('rel')
|
||||
@@ -404,3 +397,25 @@ class DarkLangMiddlewareTests(CacheIsolationTestCase):
|
||||
assert settings.LANGUAGE_COOKIE_NAME in response.cookies
|
||||
assert response.cookies.get(settings.LANGUAGE_COOKIE_NAME).value == ''
|
||||
assert response['Content-Language'] == site_lang
|
||||
|
||||
@with_site_configuration(configuration={'LANGUAGE_CODE': 'es'})
|
||||
def test_preview_language_ignores_site_configuration(self):
|
||||
"""
|
||||
Test that the preview language has a higher priority than the language set in SiteConfiguration.
|
||||
"""
|
||||
response = self.client.get('/')
|
||||
assert response['Content-Language'] == 'es-419'
|
||||
|
||||
# Set preview language.
|
||||
self._post_set_preview_lang('eo')
|
||||
response = self.client.get('/')
|
||||
assert response['Content-Language'] == 'eo'
|
||||
|
||||
# Reset preview language.
|
||||
self._post_clear_preview_lang()
|
||||
response = self.client.get('/')
|
||||
assert response['Content-Language'] == 'es-419'
|
||||
|
||||
# Clean up by making a request to a Site without specific configuration.
|
||||
with with_site_configuration_context():
|
||||
self.client.get('/')
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
"""
|
||||
Middleware for Language Preferences
|
||||
"""
|
||||
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.deprecation import MiddlewareMixin
|
||||
from django.utils.translation import LANGUAGE_SESSION_KEY
|
||||
from django.utils.translation.trans_real import parse_accept_lang_header
|
||||
@@ -11,6 +10,7 @@ from openedx.core.djangoapps.dark_lang import DARK_LANGUAGE_KEY
|
||||
from openedx.core.djangoapps.dark_lang.models import DarkLangConfig
|
||||
from openedx.core.djangoapps.lang_pref import LANGUAGE_HEADER, LANGUAGE_KEY
|
||||
from openedx.core.djangoapps.lang_pref import helpers as lang_pref_helpers
|
||||
from openedx.core.djangoapps.site_configuration.helpers import get_value
|
||||
from openedx.core.djangoapps.user_api.errors import UserAPIInternalError, UserAPIRequestError
|
||||
from openedx.core.djangoapps.user_api.preferences.api import get_user_preference, set_user_preference
|
||||
from openedx.core.lib.mobile_utils import is_request_from_mobile_app
|
||||
@@ -28,6 +28,9 @@ class LanguagePreferenceMiddleware(MiddlewareMixin):
|
||||
"""
|
||||
If a user's UserPreference contains a language preference, use the user's preference.
|
||||
Save the current language preference cookie as the user's preferred language.
|
||||
|
||||
If you specify the LANGUAGE_CODE in SiteConfiguration, it will have a higher priority than the user's language
|
||||
preference.
|
||||
"""
|
||||
cookie_lang = lang_pref_helpers.get_language_cookie(request)
|
||||
if cookie_lang:
|
||||
@@ -54,6 +57,10 @@ class LanguagePreferenceMiddleware(MiddlewareMixin):
|
||||
if LANGUAGE_SESSION_KEY in request.session and request.session[LANGUAGE_SESSION_KEY] != cookie_lang:
|
||||
del request.session[LANGUAGE_SESSION_KEY]
|
||||
|
||||
# Apply language specified in SiteConfiguration, ignoring user preferences.
|
||||
if language := get_value('LANGUAGE_CODE'):
|
||||
request.COOKIES[settings.LANGUAGE_COOKIE_NAME] = language
|
||||
|
||||
def process_response(self, request, response): # lint-amnesty, pylint: disable=missing-function-docstring
|
||||
# If the user is logged in, check for their language preference. Also check for real user
|
||||
# if current user is a masquerading user,
|
||||
|
||||
@@ -14,8 +14,13 @@ from django.test.client import Client, RequestFactory
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import LANGUAGE_SESSION_KEY
|
||||
from django.utils.translation.trans_real import parse_accept_lang_header
|
||||
|
||||
from openedx.core.djangoapps.lang_pref import COOKIE_DURATION, LANGUAGE_KEY
|
||||
from openedx.core.djangoapps.lang_pref.middleware import LanguagePreferenceMiddleware
|
||||
from openedx.core.djangoapps.site_configuration.tests.test_util import (
|
||||
with_site_configuration,
|
||||
with_site_configuration_context,
|
||||
)
|
||||
from openedx.core.djangoapps.user_api.preferences.api import (
|
||||
delete_user_preference,
|
||||
get_user_preference,
|
||||
@@ -267,3 +272,31 @@ class TestUserPreferenceMiddleware(CacheIsolationTestCase):
|
||||
mock_is_mobile_request.return_value = True
|
||||
response = self.middleware.process_response(self.request, response)
|
||||
response.delete_cookie.assert_called()
|
||||
|
||||
@with_site_configuration(configuration={'LANGUAGE_CODE': 'eo'})
|
||||
@ddt.data(None, 'es', 'en')
|
||||
def test_site_language_ignores_user_preferences(self, user_preference):
|
||||
"""
|
||||
Test that the language set in SiteConfiguration has a higher priority than user preferences.
|
||||
It also does not create or update user preferences.
|
||||
"""
|
||||
self.request.COOKIES[settings.LANGUAGE_COOKIE_NAME] = user_preference
|
||||
self.middleware.process_request(self.request)
|
||||
|
||||
# Do not alter user preferences.
|
||||
assert get_user_preference(self.user, LANGUAGE_KEY) == user_preference
|
||||
# Change the request's cookie instead.
|
||||
assert self.request.COOKIES[settings.LANGUAGE_COOKIE_NAME] == 'eo'
|
||||
|
||||
# Use an actual call to determine the language of the response.
|
||||
response = self.client.get('/')
|
||||
|
||||
assert get_user_preference(self.user, LANGUAGE_KEY) == user_preference
|
||||
assert response['Content-Language'] == 'eo'
|
||||
# `LocaleMiddleware` no longer looks for language in the session since Django 3.2. It checks the cookie instead.
|
||||
# See: https://docs.djangoproject.com/en/3.2/releases/3.0/#miscellaneous
|
||||
assert self.client.session.get(LANGUAGE_SESSION_KEY) is None
|
||||
|
||||
# Clean up by making a request to a Site without specific configuration.
|
||||
with with_site_configuration_context():
|
||||
self.client.get('/')
|
||||
|
||||
Reference in New Issue
Block a user