From 6838cc0efcb43cca86d256cde787cccd5483299e Mon Sep 17 00:00:00 2001 From: Asger Geel Weirsoee Date: Mon, 2 Mar 2026 01:30:23 +0000 Subject: [PATCH] feat(#248): bootstrap django i18n from shared locale contract --- lobby/i18n.py | 22 ++++++---------------- partyhub/i18n_bootstrap.py | 30 ++++++++++++++++++++++++++++++ partyhub/settings.py | 9 ++++----- partyhub/tests_i18n_bootstrap.py | 28 ++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 21 deletions(-) create mode 100644 partyhub/i18n_bootstrap.py create mode 100644 partyhub/tests_i18n_bootstrap.py diff --git a/lobby/i18n.py b/lobby/i18n.py index 82fdc0d..bb449a8 100644 --- a/lobby/i18n.py +++ b/lobby/i18n.py @@ -1,37 +1,27 @@ -import json import logging -from functools import lru_cache -from pathlib import Path from django.http import HttpRequest, JsonResponse from django.utils.translation import get_language_from_request +from partyhub.i18n_bootstrap import locale_config, shared_i18n_catalog + LOGGER = logging.getLogger(__name__) -@lru_cache(maxsize=1) def lobby_i18n_catalog() -> dict: - catalog_path = Path(__file__).resolve().parents[1] / "shared" / "i18n" / "lobby.json" - with catalog_path.open(encoding="utf-8") as handle: - return json.load(handle) + return shared_i18n_catalog() -@lru_cache(maxsize=1) def i18n_locale_config() -> tuple[str, tuple[str, ...]]: - locales = lobby_i18n_catalog().get("locales", {}) - default_locale = str(locales.get("default", "en")).strip().lower() or "en" - supported_locales = tuple( - locale.strip().lower() for locale in locales.get("supported", ["en", "da"]) if str(locale).strip() - ) or ("en", "da") - return default_locale, supported_locales + return locale_config() def lobby_i18n_errors() -> dict: - return lobby_i18n_catalog().get("backend", {}).get("error_codes", {}) + return shared_i18n_catalog().get("backend", {}).get("error_codes", {}) def lobby_i18n_error_messages() -> dict: - return lobby_i18n_catalog().get("backend", {}).get("errors", {}) + return shared_i18n_catalog().get("backend", {}).get("errors", {}) def _quality_value(language_candidate: str) -> float | None: diff --git a/partyhub/i18n_bootstrap.py b/partyhub/i18n_bootstrap.py new file mode 100644 index 0000000..fcbeee8 --- /dev/null +++ b/partyhub/i18n_bootstrap.py @@ -0,0 +1,30 @@ +import json +from functools import lru_cache +from pathlib import Path + +_LOCALE_LABELS = { + "en": "English", + "da": "Danish", +} + + +@lru_cache(maxsize=1) +def shared_i18n_catalog() -> dict: + catalog_path = Path(__file__).resolve().parents[1] / "shared" / "i18n" / "lobby.json" + with catalog_path.open(encoding="utf-8") as handle: + return json.load(handle) + + +@lru_cache(maxsize=1) +def locale_config() -> tuple[str, tuple[str, ...]]: + locales = shared_i18n_catalog().get("locales", {}) + default_locale = str(locales.get("default", "en")).strip().lower() or "en" + supported_locales = tuple( + locale.strip().lower() for locale in locales.get("supported", ["en", "da"]) if str(locale).strip() + ) or ("en", "da") + return default_locale, supported_locales + + +def django_languages() -> list[tuple[str, str]]: + _default_locale, supported_locales = locale_config() + return [(locale, _LOCALE_LABELS.get(locale, locale.upper())) for locale in supported_locales] diff --git a/partyhub/settings.py b/partyhub/settings.py index 7ba1b97..70ae90c 100644 --- a/partyhub/settings.py +++ b/partyhub/settings.py @@ -1,6 +1,8 @@ from pathlib import Path import os +from partyhub.i18n_bootstrap import django_languages, locale_config + BASE_DIR = Path(__file__).resolve().parent.parent @@ -90,11 +92,8 @@ AUTH_PASSWORD_VALIDATORS = [ {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'}, ] -LANGUAGE_CODE = 'en' -LANGUAGES = [ - ('en', 'English'), - ('da', 'Danish'), -] +LANGUAGE_CODE, _SUPPORTED_LOCALES = locale_config() +LANGUAGES = django_languages() LOCALE_PATHS = [BASE_DIR / 'locale'] TIME_ZONE = 'Europe/Copenhagen' USE_I18N = True diff --git a/partyhub/tests_i18n_bootstrap.py b/partyhub/tests_i18n_bootstrap.py new file mode 100644 index 0000000..73b2fa8 --- /dev/null +++ b/partyhub/tests_i18n_bootstrap.py @@ -0,0 +1,28 @@ +from django.conf import settings +from django.test import TestCase + +from partyhub.i18n_bootstrap import django_languages, locale_config, shared_i18n_catalog + + +class I18nBootstrapTests(TestCase): + def test_shared_catalog_bootstraps_default_and_supported_locales(self): + default_locale, supported_locales = locale_config() + + self.assertEqual(default_locale, "en") + self.assertEqual(supported_locales, ("en", "da")) + + def test_django_language_settings_bootstrap_from_shared_i18n_catalog(self): + default_locale, supported_locales = locale_config() + + self.assertEqual(settings.LANGUAGE_CODE, default_locale) + self.assertEqual(tuple(code for code, _ in settings.LANGUAGES), supported_locales) + self.assertEqual(settings.LANGUAGES, django_languages()) + + def test_locale_contract_in_catalog_matches_django_language_codes(self): + catalog_locales = shared_i18n_catalog()["locales"] + + self.assertEqual(settings.LANGUAGE_CODE, catalog_locales["default"]) + self.assertEqual( + [code for code, _ in settings.LANGUAGES], + catalog_locales["supported"], + )