baf3c0ab64
Add language dictionaries: English, French, Korean, Japanese, Spanish,
German, Simplified Chinese, Traditional Chinese.
Each language is a single JSON file with:
- Localized terms (palace, wing, closet, drawer, etc.)
- CLI output strings with {var} interpolation
- AAAK compression instructions in that language
- Regex patterns for offline topic/quote/action extraction
Usage: Dialect(lang="ko") or set "language": "ko" in config.
Contributors can add new languages by copying en.json and translating.
Dialect class now accepts lang param and loads AAAK instruction +
regex patterns from the i18n dictionary automatically.
Tests: mempalace/i18n/test_i18n.py — all 8 languages pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
77 lines
2.0 KiB
Python
77 lines
2.0 KiB
Python
"""i18n — Language dictionaries for MemPalace.
|
|
|
|
Usage:
|
|
from mempalace.i18n import load_lang, t
|
|
|
|
load_lang("fr") # load French
|
|
print(t("cli.mine_start", path="/docs")) # "Extraction de /docs..."
|
|
print(t("terms.wing")) # "aile"
|
|
print(t("aaak.instruction")) # AAAK compression instruction in French
|
|
"""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
_LANG_DIR = Path(__file__).parent
|
|
_strings: dict = {}
|
|
_current_lang: str = "en"
|
|
|
|
|
|
def available_languages() -> list[str]:
|
|
"""Return list of available language codes."""
|
|
return sorted(p.stem for p in _LANG_DIR.glob("*.json"))
|
|
|
|
|
|
def load_lang(lang: str = "en") -> dict:
|
|
"""Load a language dictionary. Falls back to English if not found."""
|
|
global _strings, _current_lang
|
|
lang_file = _LANG_DIR / f"{lang}.json"
|
|
if not lang_file.exists():
|
|
lang_file = _LANG_DIR / "en.json"
|
|
lang = "en"
|
|
_strings = json.loads(lang_file.read_text(encoding="utf-8"))
|
|
_current_lang = lang
|
|
return _strings
|
|
|
|
|
|
def t(key: str, **kwargs) -> str:
|
|
"""Get a translated string by dotted key. Supports {var} interpolation.
|
|
|
|
t("cli.mine_complete", closets=5, drawers=20)
|
|
→ "Done. 5 closets, 20 drawers created."
|
|
"""
|
|
if not _strings:
|
|
load_lang("en")
|
|
parts = key.split(".", 1)
|
|
if len(parts) == 2:
|
|
section, name = parts
|
|
val = _strings.get(section, {}).get(name, key)
|
|
else:
|
|
val = _strings.get(key, key)
|
|
if kwargs and isinstance(val, str):
|
|
try:
|
|
val = val.format(**kwargs)
|
|
except (KeyError, IndexError):
|
|
pass
|
|
return val
|
|
|
|
|
|
def current_lang() -> str:
|
|
"""Return current language code."""
|
|
return _current_lang
|
|
|
|
|
|
def get_regex() -> dict:
|
|
"""Return the regex patterns for the current language.
|
|
|
|
Keys: topic_pattern, stop_words, quote_pattern, action_pattern.
|
|
Returns empty dict if no regex section in the language file.
|
|
"""
|
|
if not _strings:
|
|
load_lang("en")
|
|
return _strings.get("regex", {})
|
|
|
|
|
|
# Auto-load English on import
|
|
load_lang("en")
|