52 lines
1.4 KiB
Python
52 lines
1.4 KiB
Python
|
|
import json
|
||
|
|
from pathlib import Path
|
||
|
|
from functools import lru_cache
|
||
|
|
from typing import Any, Dict
|
||
|
|
|
||
|
|
|
||
|
|
FALLBACK_LANG = "ru"
|
||
|
|
|
||
|
|
|
||
|
|
@lru_cache(maxsize=16)
|
||
|
|
def _load_lang(lang: str) -> Dict[str, Any]:
|
||
|
|
base_dir = Path(__file__).resolve().parents[1] / "locales"
|
||
|
|
file_path = base_dir / f"{lang}.json"
|
||
|
|
if not file_path.exists():
|
||
|
|
# fallback to default
|
||
|
|
if lang != FALLBACK_LANG:
|
||
|
|
return _load_lang(FALLBACK_LANG)
|
||
|
|
return {}
|
||
|
|
try:
|
||
|
|
return json.loads(file_path.read_text(encoding="utf-8"))
|
||
|
|
except Exception:
|
||
|
|
return {}
|
||
|
|
|
||
|
|
|
||
|
|
def _resolve_key(data: Dict[str, Any], dotted_key: str) -> Any:
|
||
|
|
cur: Any = data
|
||
|
|
for part in dotted_key.split("."):
|
||
|
|
if not isinstance(cur, dict) or part not in cur:
|
||
|
|
return None
|
||
|
|
cur = cur[part]
|
||
|
|
return cur
|
||
|
|
|
||
|
|
|
||
|
|
def t(lang: str, key: str, **kwargs) -> str:
|
||
|
|
"""Translate key for given lang; fallback to ru and to key itself.
|
||
|
|
|
||
|
|
Supports dotted keys and str.format(**kwargs) placeholders.
|
||
|
|
"""
|
||
|
|
data = _load_lang(lang or FALLBACK_LANG)
|
||
|
|
value = _resolve_key(data, key)
|
||
|
|
if value is None and lang != FALLBACK_LANG:
|
||
|
|
value = _resolve_key(_load_lang(FALLBACK_LANG), key)
|
||
|
|
if value is None:
|
||
|
|
value = key # last resort: return the key
|
||
|
|
try:
|
||
|
|
if isinstance(value, str) and kwargs:
|
||
|
|
return value.format(**kwargs)
|
||
|
|
except Exception:
|
||
|
|
pass
|
||
|
|
return value if isinstance(value, str) else str(value)
|
||
|
|
|