63 lines
2.1 KiB
Python
63 lines
2.1 KiB
Python
"""Load per-call translation history templates from data/translation_contexts.json."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
from typing import Any
|
|
|
|
from util.paths import TRANSLATION_CONTEXTS_PATH
|
|
|
|
_cache: dict[str, Any] | None = None
|
|
_cache_mtime: float | None = None
|
|
|
|
|
|
def _load() -> dict[str, Any]:
|
|
global _cache, _cache_mtime
|
|
path = TRANSLATION_CONTEXTS_PATH
|
|
if not path.is_file():
|
|
raise FileNotFoundError(f"Translation contexts file missing: {path}")
|
|
mtime = path.stat().st_mtime
|
|
if _cache is not None and _cache_mtime == mtime:
|
|
return _cache
|
|
data = json.loads(path.read_text(encoding="utf-8"))
|
|
if not isinstance(data, dict):
|
|
raise ValueError(f"translation_contexts.json must be an object: {path}")
|
|
_cache = data
|
|
_cache_mtime = mtime
|
|
return data
|
|
|
|
|
|
def ctx(path: str, *, language: str | None = None, **kwargs: Any) -> str:
|
|
"""Return a formatted history string for ``section.key``.
|
|
|
|
``{language}`` defaults to the ``language`` env / argument (capitalized).
|
|
Extra kwargs fill other ``{placeholders}`` (e.g. ``context``).
|
|
"""
|
|
if not path or "." not in path:
|
|
raise KeyError(f"Context path must be 'section.key', got {path!r}")
|
|
section_name, key = path.split(".", 1)
|
|
data = _load()
|
|
section = data.get(section_name)
|
|
if not isinstance(section, dict):
|
|
raise KeyError(f"Unknown translation context section: {section_name!r}")
|
|
template = section.get(key)
|
|
if not isinstance(template, str) or not template.strip():
|
|
raise KeyError(f"Unknown translation context key: {path!r}")
|
|
|
|
lang = language or os.getenv("language", "English")
|
|
lang = str(lang).capitalize()
|
|
values = {"language": lang, **kwargs}
|
|
try:
|
|
return template.format(**values)
|
|
except KeyError as exc:
|
|
raise KeyError(
|
|
f"Missing placeholder {exc.args[0]!r} for context {path!r}"
|
|
) from exc
|
|
|
|
|
|
def reload_contexts() -> None:
|
|
"""Clear the in-memory cache so the next ctx() re-reads from disk."""
|
|
global _cache, _cache_mtime
|
|
_cache = None
|
|
_cache_mtime = None
|