"""i18n module — loads translations from app/locales/*.json. Usage in templates: {{ 'key'|t(user.language) }} Usage in Python: from app.i18n import t; t("key", lang) To add a new language: 1. Create app/locales/.json with translation keys 2. Done — it will be auto-detected and available in the UI """ import json from pathlib import Path _LOCALES_DIR = Path(__file__).resolve().parent / "locales" _cache: dict[str, dict[str, str]] = {} _loaded = False def _load() -> None: global _loaded if _loaded: return _LOCALES_DIR.mkdir(exist_ok=True) for f in _LOCALES_DIR.glob("*.json"): lang = f.stem # e.g. "zh", "en", "ja" with open(f, encoding="utf-8") as fh: _cache[lang] = json.load(fh) _loaded = True def t(key: str, lang: str = "zh") -> str: """Translate *key* to *lang*. Falls back to zh, then to the raw key.""" _load() # Try requested language val = _cache.get(lang, {}).get(key) if val is not None: return val # Fallback to zh if lang != "zh": val = _cache.get("zh", {}).get(key) if val is not None: return val # Fallback to any available language for translations in _cache.values(): if key in translations: return translations[key] return key def get_languages() -> dict[str, str]: """Return available languages as {code: native_name}. Each JSON file can optionally include a top-level ``_meta`` key with ``{"name": "语言名称"}`` to set the display name. If absent, the language code is used as-is. """ _load() result: dict[str, str] = {} for lang in sorted(_cache): meta = _cache[lang].get("_meta", {}) result[lang] = meta.get("name", lang) return result