diff --git a/openedx/core/djangoapps/dark_lang/middleware.py b/openedx/core/djangoapps/dark_lang/middleware.py index 36c4798a79..325c7b1e7c 100644 --- a/openedx/core/djangoapps/dark_lang/middleware.py +++ b/openedx/core/djangoapps/dark_lang/middleware.py @@ -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 diff --git a/openedx/core/djangoapps/dark_lang/tests.py b/openedx/core/djangoapps/dark_lang/tests.py index 8ef114ad78..836376ee7d 100644 --- a/openedx/core/djangoapps/dark_lang/tests.py +++ b/openedx/core/djangoapps/dark_lang/tests.py @@ -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('/') diff --git a/openedx/core/djangoapps/lang_pref/middleware.py b/openedx/core/djangoapps/lang_pref/middleware.py index d0a787c5da..e36685fd0a 100644 --- a/openedx/core/djangoapps/lang_pref/middleware.py +++ b/openedx/core/djangoapps/lang_pref/middleware.py @@ -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, diff --git a/openedx/core/djangoapps/lang_pref/tests/test_middleware.py b/openedx/core/djangoapps/lang_pref/tests/test_middleware.py index b62b05b7d9..6ab218b654 100644 --- a/openedx/core/djangoapps/lang_pref/tests/test_middleware.py +++ b/openedx/core/djangoapps/lang_pref/tests/test_middleware.py @@ -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('/')