import logging 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__) def lobby_i18n_catalog() -> dict: return shared_i18n_catalog() def i18n_locale_config() -> tuple[str, tuple[str, ...]]: return locale_config() def lobby_i18n_errors() -> dict: return shared_i18n_catalog().get("backend", {}).get("error_codes", {}) def lobby_i18n_error_messages() -> dict: return shared_i18n_catalog().get("backend", {}).get("errors", {}) def resolve_error_key(code: str) -> str: resolved = lobby_i18n_errors().get(code) if isinstance(resolved, str) and resolved: return resolved LOGGER.warning("i18n error code missing in shared catalog", extra={"code": code}) return code 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() accept_language = request.META.get("HTTP_ACCEPT_LANGUAGE") or "" ranked_candidates: list[tuple[float, int, str]] = [] for index, candidate in enumerate(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 not in supported_locales: continue ranked_candidates.append((quality if quality is not None else 1.0, index, normalized)) if ranked_candidates: ranked_candidates.sort(key=lambda entry: (-entry[0], entry[1])) return ranked_candidates[0][2] requested = (get_language_from_request(request) or "").replace("_", "-").split("-", 1)[0].lower() if requested in supported_locales: return requested return default_locale def resolve_error_message(*, key: str, locale: str) -> str: default_locale, _supported_locales = i18n_locale_config() translations = lobby_i18n_error_messages().get(key) if not isinstance(translations, dict): LOGGER.warning("i18n key missing in shared catalog", extra={"key": key, "locale": locale}) return key if locale in translations and translations[locale]: return translations[locale] if default_locale in translations and translations[default_locale]: return translations[default_locale] LOGGER.warning("i18n translation missing for key", extra={"key": key, "locale": locale}) return key def api_error(request: HttpRequest, *, code: str, status: int) -> JsonResponse: locale = resolve_locale(request) key = resolve_error_key(code) return JsonResponse( { "error": resolve_error_message(key=key, locale=locale), "error_code": code, "locale": locale, }, status=status, )