Files
trainingstagebuch/scripts/apply-i18n-cache.py
Torsten Schulz (local) eb54b4f7cf
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 45s
feat(i18n): add scripts for locale translation and patching
- Implemented `fill-de-extended-gaps.js` to fill missing billing/orders keys in de-extended from de.
- Created `fill-i18n-deep.py` for deep translation of locale JSONs using deep-translator with fallback options.
- Added `fill-i18n-locales.js` to translate locale JSONs and write overrides for untranslated keys.
- Introduced `fix-en-leaks.py` to translate keys that still match the en-US merge, addressing English leaks.
- Developed `patch-de-ch-swiss.js` to replace 'ß' with 'ss' in de-CH.json without deleting existing entries.
- Created `patch-en-gb-au.js` to apply UK/AU spelling corrections in en-GB and en-AU locales.
- Added shell scripts `run-fix-en-leaks.sh` and `run-i18n-deep-fill.sh` for sequential execution of translation tasks.
- Implemented `update-i18n-todo-stats.js` to update statistics in the I18N_TODO.md file based on translation completeness.
2026-05-15 15:52:54 +02:00

121 lines
3.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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()