From f42c61f9c56467beba5c968be65295f956c5fefd Mon Sep 17 00:00:00 2001 From: Steve Jalim Date: Mon, 18 Mar 2024 20:39:12 +0000 Subject: [PATCH] Monkeypatch Django's check_for_language() because it looks in the wrong place for us By default check_for_language() seeks gettext-compatible files in locale/ directories in the project, but we don't have those because our l10n is handled using Fluent strings in the www-l10n-team directory, cloned from their git repo. So, instead, we just perform a light check to see whether a given lang is among the langs that shold be available. The actual decision about whether we have have (enough) Fluent strings available for that locale happens in lib.l10n_utils.render() --- bedrock/base/i18n.py | 4 ++++ bedrock/base/middleware.py | 28 ++++++++++++++++++++++++++-- bedrock/base/tests/test_i18n.py | 24 ++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/bedrock/base/i18n.py b/bedrock/base/i18n.py index 34f17bad6f1..cc9fa34e159 100644 --- a/bedrock/base/i18n.py +++ b/bedrock/base/i18n.py @@ -159,3 +159,7 @@ def get_best_language(accept_lang): supported = normalize_language(lang) if supported: return supported + + +def check_for_bedrock_language(lang_code): + return lang_code in [x[0] for x in settings.LANGUAGES] diff --git a/bedrock/base/middleware.py b/bedrock/base/middleware.py index 261db87053f..b95aa006d86 100644 --- a/bedrock/base/middleware.py +++ b/bedrock/base/middleware.py @@ -21,11 +21,13 @@ from django.middleware.locale import LocaleMiddleware as DjangoLocaleMiddleware from django.utils import translation from django.utils.deprecation import MiddlewareMixin +from django.utils.translation import trans_real from commonware.middleware import FrameOptionsHeader as OldFrameOptionsHeader from bedrock.base import metrics from bedrock.base.i18n import ( + check_for_bedrock_language, get_language_from_headers, normalize_language, path_needs_lang_code, @@ -98,11 +100,13 @@ class BedrockLocaleMiddleware(DjangoLocaleMiddleware): def process_request(self, request): with normalized_get_language(): - return super().process_request(request) + with simplified_check_for_language(): + return super().process_request(request) def process_response(self, request, response): with normalized_get_language(): - return super().process_response(request, response) + with simplified_check_for_language(): + return super().process_response(request, response) @contextlib.contextmanager @@ -132,6 +136,26 @@ def get_normalized_language(): translation.get_language = get_language +@contextlib.contextmanager +def simplified_check_for_language(): + """Ensures that calls to trans_real.check_for_language within + its context will not check for the existence of files in + `appname/LANG_CODE/locale` and therefore avoid a false negative about + the langs we support (our lang files are in ./data/l10n-team/LANG_CODE) + but check_for_language is opinionated and expects only the Django directory + pattern for lang files.""" + + check_for_language = trans_real.check_for_language + + @wraps(check_for_language) + def simpler_check_for_language(lang_code): + return check_for_bedrock_language(lang_code) + + trans_real.check_for_language = simpler_check_for_language + + yield + + class BasicAuthMiddleware: """ Middleware to protect the entire site with a single basic-auth username and password. diff --git a/bedrock/base/tests/test_i18n.py b/bedrock/base/tests/test_i18n.py index ded7607a373..3af9e6c7649 100644 --- a/bedrock/base/tests/test_i18n.py +++ b/bedrock/base/tests/test_i18n.py @@ -8,6 +8,7 @@ from bedrock.base.i18n import ( LocalePrefixPattern, + check_for_bedrock_language, normalize_language, path_needs_lang_code, split_path_and_polish_lang, @@ -226,3 +227,26 @@ def test_locale_prefix_pattern_works(language_to_activate, expected_prefix): assert pattern.language_prefix == expected_prefix translation.deactivate() + + +@override_settings( + LANGUAGES=[ + ("en-US", "English"), + ("fr", "French"), + ("sco", "Scots"), + ("hsb", "Hornjoserbsce"), + ] +) +@pytest.mark.parametrize( + "lang_code, expected_result", + ( + ("en-US", True), + ("fr", True), + ("sco", True), + ("hsb", True), + ("ach", False), + ("de", False), + ), +) +def test_check_for_bedrock_language(lang_code, expected_result): + assert check_for_bedrock_language(lang_code) == expected_result