[MVP][READY] #225 Backend i18n baseline (resolver + fallback) follow-up #245

Merged
integrator-bot merged 2 commits from feat/issue-225-backend-i18n-baseline into main 2026-03-02 01:45:04 +01:00
2 changed files with 54 additions and 4 deletions

View File

@@ -34,13 +34,30 @@ def lobby_i18n_error_messages() -> dict:
return lobby_i18n_catalog().get("backend", {}).get("errors", {})
def _quality_value(language_candidate: str) -> float | None:
for parameter in language_candidate.split(";")[1:]:
key, separator, value = parameter.partition("=")
if separator and key.strip().lower() == "q":
try:
return float(value.strip())
except ValueError:
return None
return None
def resolve_locale(request: HttpRequest) -> str:
default_locale, supported_locales = i18n_locale_config()
raw_accept_language = (request.META.get("HTTP_ACCEPT_LANGUAGE") or "").split(",", 1)[0]
raw_requested = raw_accept_language.split(";", 1)[0].strip().replace("_", "-").split("-", 1)[0].lower()
if raw_requested in supported_locales:
return raw_requested
accept_language = request.META.get("HTTP_ACCEPT_LANGUAGE") or ""
for candidate in accept_language.split(","):
quality = _quality_value(candidate)
if quality is not None and quality <= 0:
continue
tag = candidate.split(";", 1)[0]
normalized = tag.strip().replace("_", "-").split("-", 1)[0].lower()
if normalized in supported_locales:
return normalized
requested = (get_language_from_request(request) or "").replace("_", "-").split("-", 1)[0].lower()
if requested in supported_locales:

View File

@@ -1274,6 +1274,39 @@ class I18nResolverTests(TestCase):
self.assertEqual(response.status_code, 400)
self.assertEqual(resolve_locale(response.wsgi_request), "da")
def test_resolve_locale_uses_next_supported_language_when_primary_is_unsupported(self):
response = self.client.post(
reverse("lobby:join_session"),
data={"code": "", "nickname": "Luna"},
content_type="application/json",
HTTP_ACCEPT_LANGUAGE="fr-FR, da;q=0.9, en;q=0.8",
)
self.assertEqual(response.status_code, 400)
self.assertEqual(resolve_locale(response.wsgi_request), "da")
def test_resolve_locale_skips_q0_languages_and_falls_back_to_next_supported(self):
response = self.client.post(
reverse("lobby:join_session"),
data={"code": "", "nickname": "Luna"},
content_type="application/json",
HTTP_ACCEPT_LANGUAGE="da;q=0, en;q=0.8",
)
self.assertEqual(response.status_code, 400)
self.assertEqual(resolve_locale(response.wsgi_request), "en")
def test_resolve_locale_keeps_q08_languages_eligible_in_accept_language_loop(self):
response = self.client.post(
reverse("lobby:join_session"),
data={"code": "", "nickname": "Luna"},
content_type="application/json",
HTTP_ACCEPT_LANGUAGE="da;q=0.8, en;q=0.9",
)
self.assertEqual(response.status_code, 400)
self.assertEqual(resolve_locale(response.wsgi_request), "da")
def test_resolve_locale_defaults_to_en_when_header_missing(self):
response = self.client.post(
reverse("lobby:join_session"),