diff --git a/zerver/lib/i18n.py b/zerver/lib/i18n.py index 7198d3ddea..21f45672be 100644 --- a/zerver/lib/i18n.py +++ b/zerver/lib/i18n.py @@ -9,6 +9,7 @@ import orjson from django.conf import settings from django.http import HttpRequest from django.utils import translation +from django.utils.translation.trans_real import parse_accept_lang_header from zerver.lib.request import RequestNotes @@ -67,3 +68,17 @@ def get_and_set_request_language( RequestNotes.get_notes(request).set_language = translation.get_language() return request_language + + +def get_browser_language_code(request: HttpRequest) -> Optional[str]: + accept_lang_header = request.META.get("HTTP_ACCEPT_LANGUAGE") + if accept_lang_header is None: + return None + + available_language_codes = get_available_language_codes() + for accept_lang, priority in parse_accept_lang_header(request.META.get("HTTP_ACCEPT_LANGUAGE")): + if accept_lang == "*": + return None + if accept_lang in available_language_codes: + return accept_lang + return None diff --git a/zerver/tests/test_i18n.py b/zerver/tests/test_i18n.py index 93e026e68c..b83e4ad617 100644 --- a/zerver/tests/test_i18n.py +++ b/zerver/tests/test_i18n.py @@ -9,7 +9,9 @@ from django.http import HttpResponse from django.utils import translation from zerver.lib.email_notifications import enqueue_welcome_emails +from zerver.lib.i18n import get_browser_language_code from zerver.lib.test_classes import ZulipTestCase +from zerver.lib.test_helpers import HostRequestMock from zerver.management.commands import makemessages from zerver.models import get_realm_stream @@ -128,6 +130,28 @@ class TranslationTestCase(ZulipTestCase): response = self.fetch("get", f"/{lang}/integrations/", 200) self.assert_in_response(word, response) + def test_get_browser_language_code(self) -> None: + req = HostRequestMock() + + self.assertIsNone(get_browser_language_code(req)) + + req.META["HTTP_ACCEPT_LANGUAGE"] = "de" + self.assertEqual(get_browser_language_code(req), "de") + + req.META["HTTP_ACCEPT_LANGUAGE"] = "en-GB,en;q=0.8" + self.assertEqual(get_browser_language_code(req), "en-gb") + + # Case when unsupported language has higher weight. + req.META["HTTP_ACCEPT_LANGUAGE"] = "en-IND;q=0.9,de;q=0.8" + self.assertEqual(get_browser_language_code(req), "de") + + # Browser locale is set to unsupported language. + req.META["HTTP_ACCEPT_LANGUAGE"] = "en-IND" + self.assertIsNone(get_browser_language_code(req)) + + req.META["HTTP_ACCEPT_LANGUAGE"] = "*" + self.assertIsNone(get_browser_language_code(req)) + class JsonTranslationTestCase(ZulipTestCase): def tearDown(self) -> None: