#!/usr/bin/env python3 """Schreibt Locale-Overrides aus Cache + EN-Fallback – ohne API-Aufrufe.""" from __future__ import annotations import json import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[1] LOCALES_DIR = ROOT / "frontend" / "src" / "i18n" / "locales" CACHE_FILE = Path(__file__).resolve().parent / ".i18n-translate-cache.json" TARGETS = { "fr": "fr", "es": "es", "it": "it", "pl": "pl", "ja": "ja", "zh": "zh-CN", "th": "th", "tl": "tl", "fil": "tl", } def deep_merge(base, override): if not isinstance(base, dict) or isinstance(base, list): return override if override is not None else base result = dict(base) for key, value in (override or {}).items(): if ( isinstance(value, dict) and not isinstance(value, list) and isinstance(result.get(key), dict) and not isinstance(result.get(key), list) ): result[key] = deep_merge(result[key], value) else: result[key] = value return result def flatten(obj, prefix=""): out = {} for key, value in (obj or {}).items(): next_key = f"{prefix}.{key}" if prefix else key if isinstance(value, dict) and not isinstance(value, list): out.update(flatten(value, next_key)) elif isinstance(value, str): out[next_key] = value return out def set_by_path(obj, dot_path, value): parts = dot_path.split(".") cur = obj for part in parts[:-1]: if part not in cur or not isinstance(cur[part], dict): cur[part] = {} cur = cur[part] cur[parts[-1]] = value def build_overrides(de_flat, target_flat): out = {} for key, value in target_flat.items(): if value != de_flat.get(key): set_by_path(out, key, value) return out def apply_locale(code: str, cache: dict, en_flat: dict, de_flat: dict) -> None: target = TARGETS[code] locale_path = LOCALES_DIR / f"{code}.json" locale_json = json.loads(locale_path.read_text(encoding="utf-8")) de = json.loads((LOCALES_DIR / "de.json").read_text(encoding="utf-8")) merged = flatten(deep_merge(json.loads(json.dumps(de)), locale_json)) from_cache = from_en = still = 0 for key, de_val in de_flat.items(): if merged.get(key) != de_val: continue from_lang = "en" if en_flat.get(key) and en_flat[key] != de_val else "de" text = en_flat[key] if from_lang == "en" else de_val cache_key = f"{from_lang}|{target}|{text}" if cache_key in cache: merged[key] = cache[cache_key] from_cache += 1 elif from_lang == "en": merged[key] = text from_en += 1 else: still += 1 overrides = build_overrides(de_flat, merged) locale_path.write_text(json.dumps(overrides, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") print( f"[{code}] cache={from_cache} enFallback={from_en} stillDe={still} overrides={len(flatten(overrides))}", flush=True, ) def main(): codes = sys.argv[1:] or list(TARGETS.keys()) cache = json.loads(CACHE_FILE.read_text(encoding="utf-8")) de = json.loads((LOCALES_DIR / "de.json").read_text(encoding="utf-8")) en_us = json.loads((LOCALES_DIR / "en-US.json").read_text(encoding="utf-8")) de_flat = flatten(de) en_flat = flatten(deep_merge(de, en_us)) for code in codes: if code not in TARGETS: print(f"skip unknown: {code}", file=sys.stderr) continue apply_locale(code, cache, en_flat, de_flat) if __name__ == "__main__": main()