From f76202dd59f586d5cb1d372a979b8d6384ac021b Mon Sep 17 00:00:00 2001 From: Mateusz Mandera Date: Wed, 23 Dec 2020 13:45:24 +0100 Subject: [PATCH] django3: Save language preference in a cookie rather than the session. Support for saving it in the session is dropped in django3, the cookie is the mechanism that needs to be used. The relevant i18n code doesn't have access to the response objects and thus needs to delegate setting the cookie to LocaleMiddleware. Fixes the LocaleMiddleware point of #16030. --- docs/translating/translating.md | 6 ++---- zerver/lib/i18n.py | 6 ++++-- zerver/middleware.py | 8 ++++++++ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/docs/translating/translating.md b/docs/translating/translating.md index 3a9b023998..7c0c9388d7 100644 --- a/docs/translating/translating.md +++ b/docs/translating/translating.md @@ -100,11 +100,9 @@ There are a few ways to see your translations in the Zulip UI: prioritization (mostly copied from the Django docs): 1. It looks for the language code as a URL prefix (e.g. `/de/login/`). - 2. It looks for the `LANGUAGE_SESSION_KEY` key in the current user's - session (the Zulip language UI option ends up setting this). - 3. It looks for the cookie named 'django_language'. You can set a + 1. It looks for the cookie named 'django_language'. You can set a different name through the `LANGUAGE_COOKIE_NAME` setting. - 4. It looks for the `Accept-Language` HTTP header in the HTTP request + 1. It looks for the `Accept-Language` HTTP header in the HTTP request (this is how browsers tell Zulip about the OS/browser language). * Using an HTTP client library like `requests`, `cURL` or `urllib`, diff --git a/zerver/lib/i18n.py b/zerver/lib/i18n.py index b77d6e93cb..65dbf97d4e 100644 --- a/zerver/lib/i18n.py +++ b/zerver/lib/i18n.py @@ -95,8 +95,10 @@ def get_and_set_request_language( request_language = user_configured_language translation.activate(request_language) - # We also save the language to the user's session, so that + # We also want to save the language to the user's cookies, so that # something reasonable will happen in logged-in portico pages. - request.session[translation.LANGUAGE_SESSION_KEY] = translation.get_language() + # We accomplish that by setting a flag on the request which signals + # to LocaleMiddleware to set the cookie on the response. + request._set_language = translation.get_language() return request_language diff --git a/zerver/middleware.py b/zerver/middleware.py index 05c0b48f0d..11d65b7ffc 100644 --- a/zerver/middleware.py +++ b/zerver/middleware.py @@ -371,6 +371,7 @@ def csrf_failure(request: HttpRequest, reason: str="") -> HttpResponse: class LocaleMiddleware(DjangoLocaleMiddleware): def process_response(self, request: HttpRequest, response: HttpResponse) -> HttpResponse: + # This is the same as the default LocaleMiddleware, minus the # logic that redirects 404's that lack a prefixed language in # the path into having a language. See @@ -382,6 +383,13 @@ class LocaleMiddleware(DjangoLocaleMiddleware): if not (i18n_patterns_used and language_from_path): patch_vary_headers(response, ('Accept-Language',)) response.setdefault('Content-Language', language) + + # An additional responsibility of our override of this middleware is to save the user's language + # preference in a cookie. That determination is made by code handling the request + # and saved in the _set_language flag so that it can be used here. + if hasattr(request, '_set_language'): + response.set_cookie(settings.LANGUAGE_COOKIE_NAME, request._set_language) + return response class RateLimitMiddleware(MiddlewareMixin):