Files
trainingstagebuch/scripts/apply-i18n-cache.py
Torsten Schulz (local) 5357dac9e1
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 54s
chore: update file permissions for multiple files and add migration for club fee rules
- Changed file permissions from 644 to 755 for various files in the mobile-app and mobile-app_legacy_rn_expo directories, ensuring executable permissions where necessary.
- Added a new SQL migration script to the backend to introduce missing columns for club billing and invoice settings in the clubs table, maintaining synchronization with the current Sequelize model.
2026-07-17 11:51:24 +02:00

121 lines
3.6 KiB
Python
Executable File
Raw 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()