136 lines
3.6 KiB
Python
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())
|