"""Static checks: translation keys and preference defaults stay in sync.""" from __future__ import annotations import json import re from pathlib import Path APP_ROOT = Path(__file__).resolve().parents[1] SRC_DIR = APP_ROOT / "src" LOCALES_DIR = APP_ROOT / "config" / "locales" DEFAULTS_JSON = APP_ROOT / "config" / "preferences.default.json" REPO_ROOT = APP_ROOT.parents[1] STORE_PY = REPO_ROOT / "shared" / "src" / "orisys_app_shared" / "prefs" / "store.py" _T_CALL = re.compile(r"""\bt\(\s*["']([A-Za-z0-9_.]+)["']""") _DEFAULT_BLOCK = re.compile(r"_DEFAULTS[^=]*=\s*\{(?P.*?)\n\}", re.DOTALL) _KEY = re.compile(r"""["']([A-Za-z0-9_]+)["']\s*:""") def _load_locale(name: str) -> dict: return json.loads((LOCALES_DIR / f"{name}.json").read_text(encoding="utf-8")) def _flatten(data: dict, prefix: str = "") -> set[str]: keys: set[str] = set() for key, value in data.items(): dotted = f"{prefix}{key}" if isinstance(value, dict): keys |= _flatten(value, f"{dotted}.") else: keys.add(dotted) return keys def _referenced_keys() -> set[str]: found: set[str] = set() for path in sorted(SRC_DIR.rglob("*.py")): found |= set(_T_CALL.findall(path.read_text(encoding="utf-8"))) return found def test_locales_parity_and_used_keys(): zh = _flatten(_load_locale("zh_CN")) en = _flatten(_load_locale("en_US")) assert zh == en, { "zh_only": sorted(zh - en), "en_only": sorted(en - zh), } referenced = _referenced_keys() assert referenced, "no t() calls found — the source scan is broken" missing = sorted(key for key in referenced if key not in zh) assert not missing, f"t() keys missing from locale files: {missing}" def test_preference_defaults_match_store_defaults(): json_keys = set(json.loads(DEFAULTS_JSON.read_text(encoding="utf-8"))) source = STORE_PY.read_text(encoding="utf-8") match = _DEFAULT_BLOCK.search(source) assert match, "could not locate _DEFAULTS in prefs/store.py" store_keys = set(_KEY.findall(match.group("body"))) assert json_keys == store_keys, { "json_only": sorted(json_keys - store_keys), "store_only": sorted(store_keys - json_keys), } def test_locale_files_are_valid_utf8_json(): for name in ("zh_CN", "en_US"): data = _load_locale(name) assert isinstance(data, dict) assert data.get("app", {}).get("title") #: Sequences that only ever appear when UTF-8 text was decoded as a single-byte #: codepage and then re-encoded. A ``Get-Content -Raw | Set-Content`` round trip #: in Windows PowerShell does exactly that and silently mangles every non-ASCII #: string, which is how the Chinese UI once ended up unreadable. #: #: Written as escapes, with no literal examples in the comments, so that this #: guard cannot itself be corrupted by the same mistake. _MOJIBAKE = ( "\u00c3", "\u00c2", "\u00e2\u20ac", "\u00e3\u20ac", "\u00ef\u00bf\u00bd", ) def test_locale_files_are_utf8_without_bom_and_not_mojibake(): for name in ("zh_CN", "en_US"): path = LOCALES_DIR / f"{name}.json" raw = path.read_bytes() assert not raw.startswith(b"\xef\xbb\xbf"), f"{name}.json starts with a BOM" text = raw.decode("utf-8") # raises if it is not valid UTF-8 for sequence in _MOJIBAKE: assert sequence not in text, ( f"{name}.json contains {sequence!r}: the file was decoded with the " "wrong encoding. Rewrite it with an explicit UTF-8 writer instead " "of a PowerShell Get-Content/Set-Content round trip." ) def test_chinese_locale_actually_contains_chinese(): """A corrupted zh_CN.json still parses as JSON, so check the content.""" data = _load_locale("zh_CN") for key in ("menu/theme_dark", "app/about_title", "chart/mode_follow"): node = data for part in key.split("/"): node = node[part] assert any("\u4e00" <= char <= "\u9fff" for char in node), ( f"zh_CN.{key} has no Chinese characters: {node!r}" )