gateway/scripts/_archive/i18n_rekey_plaintext_keys.py
2026-04-29 21:27:08 +02:00

136 lines
3.6 KiB
Python

"""
Rekey frontend t('dot.notation') -> t('Deutscher Klartext') using locales/de.ts mapping.
Usage (from repo root):
python gateway/scripts/i18n_rekey_plaintext_keys.py
Excludes: src/locales/, this script's output is in-place file edits.
"""
from __future__ import annotations
import re
import sys
from pathlib import Path
_REPO = Path(__file__).resolve().parents[2]
_SRC = _REPO / "frontend_nyla" / "src"
_DE_FILE = _SRC / "locales" / "de.ts"
def _unescape_ts_single_quoted(raw: str) -> str:
out: list[str] = []
i = 0
while i < len(raw):
c = raw[i]
if c == "\\" and i + 1 < len(raw):
n = raw[i + 1]
if n == "n":
out.append("\n")
i += 2
continue
if n == "r":
out.append("\r")
i += 2
continue
if n == "t":
out.append("\t")
i += 2
continue
out.append(n)
i += 2
continue
out.append(c)
i += 1
return "".join(out)
def _escape_for_ts_single_quoted(s: str) -> str:
return (
s.replace("\\", "\\\\")
.replace("'", "\\'")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t")
)
def _parse_de_ts(path: Path) -> dict[str, str]:
text = path.read_text(encoding="utf-8")
mapping: dict[str, str] = {}
line_re = re.compile(
r"^\s*'((?:\\.|[^'])*)':\s*'((?:\\.|[^'])*)'\s*,?\s*(//.*)?$"
)
for line in text.splitlines():
m = line_re.match(line.strip())
if not m:
continue
key = _unescape_ts_single_quoted(m.group(1))
val = _unescape_ts_single_quoted(m.group(2))
mapping[key] = val
return mapping
def _iter_source_files():
for ext in ("*.tsx", "*.ts"):
for p in _SRC.rglob(ext):
rel = p.relative_to(_SRC).as_posix()
if rel.startswith("locales/"):
continue
yield p
def _rekey_content(content: str, mapping: dict[str, str]) -> tuple[str, int]:
changes = 0
keys = sorted(mapping.keys(), key=len, reverse=True)
for key in keys:
if f"'{key}'" not in content:
continue
german = mapping[key]
escaped = _escape_for_ts_single_quoted(german)
repl_single = f"t('{escaped}')"
key_re = re.escape(key)
# t('key', "..." )
content, c = re.subn(
rf"t\(\s*'{key_re}'\s*,\s*\"(?:\\.|[^\"])*\"\s*\)",
repl_single,
content,
)
changes += c
# t('key', '...' )
content, c = re.subn(
rf"t\(\s*'{key_re}'\s*,\s*'(?:\\.|[^'])*'\s*\)",
repl_single,
content,
)
changes += c
# t('key')
content, c = re.subn(rf"t\(\s*'{key_re}'\s*\)", repl_single, content)
changes += c
return content, changes
def main() -> int:
if not _DE_FILE.is_file():
print("Missing", _DE_FILE, file=sys.stderr)
return 1
mapping = _parse_de_ts(_DE_FILE)
print("Loaded", len(mapping), "entries from de.ts")
total = 0
for path in _iter_source_files():
raw = path.read_text(encoding="utf-8")
new_raw, n = _rekey_content(raw, mapping)
if n and new_raw != raw:
path.write_text(new_raw, encoding="utf-8", newline="\n")
print(path.relative_to(_REPO), n, "replacements")
total += n
print("Done. Total replacements:", total)
return 0
if __name__ == "__main__":
raise SystemExit(main())