Files
nat-as-server/scripts/build_app_ui_strings.py

141 lines
3.9 KiB
Python

#!/usr/bin/env python3
"""Rebuild data/app_ui_strings.json from coach-visible Android code only."""
from __future__ import annotations
import json
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
APP_JAVA = ROOT / "Questionnaire-App" / "app" / "src" / "main"
LM_FILE = APP_JAVA / "java" / "com" / "dano" / "test1" / "utils" / "LanguageManager.kt"
OUT = Path(__file__).resolve().parents[1] / "data" / "app_ui_strings.json"
DEV_KT = {
"DevSettingsActivity.kt",
"DatabaseButtonHandler.kt",
"SaveButtonHandler.kt",
"HeaderOrderRepository.kt",
"ExcelExportService.kt",
}
DEV_ONLY_KEYS = {
"database",
"database_clients_title",
"download_header",
"export_success_downloads",
"export_failed",
"headers",
"view_missing",
"no_header_template_found",
"saved_pdf_csv",
"no_pdf_viewer",
"save_error",
"no_clients_available",
"questionnaire_id",
"questionnaires",
"status",
"data",
"data_final_warning",
"open_client_via_load",
"ask_before_upload",
"You have completed questionnaires that have not been uploaded yet.",
"You have completed questionnaires that have not been uploaded yet. Tap to open the app and upload.",
}
EXTRA_COACH_KEYS = {
"save",
"please_client_code",
"choose_more_elements",
"previous",
"client",
"question",
"answer",
"no_questionnaires",
"no_questions_available",
"error",
"client_code",
"cancel",
"ok",
"not_done",
"none",
}
def parse_german_defaults(text: str) -> dict[str, str]:
out: dict[str, str] = {}
in_german = False
for line in text.splitlines():
if '"GERMAN" to mapOf(' in line:
in_german = True
continue
if not in_german:
continue
m = re.match(r'\s*"([^"]+)"\s+to\s+"(.*)",?\s*$', line)
if m:
key = m.group(1)
val = m.group(2).replace("\\n", "\n").replace('\\"', '"')
out[key] = val
elif line.strip().startswith("),") or ('"ENGLISH"' in line and "mapOf" in line):
break
return out
def extract_keys(text: str) -> set[str]:
keys: set[str] = set()
patterns = [
r'LanguageManager\.getText(?:Formatted)?\(\s*[^,]+,\s*"([^"]+)"',
r'LanguageManager\.getText(?:Formatted)?\(\s*"([^"]+)"\s*,\s*"([^"]+)"',
r'\bt\(\s*"([^"]+)"\s*\)',
r'\bt\(\s*lang\s*,\s*"([^"]+)"',
]
for pat in patterns:
for m in re.finditer(pat, text):
keys.add(m.group(m.lastindex))
return keys
def main() -> None:
de_defaults = parse_german_defaults(LM_FILE.read_text(encoding="utf-8"))
old = json.loads(OUT.read_text(encoding="utf-8")) if OUT.exists() else {}
old_def = old.get("germanDefaults", {})
coach: set[str] = set(EXTRA_COACH_KEYS)
dev: set[str] = set()
for kt in (APP_JAVA / "java").rglob("*.kt"):
keys = extract_keys(kt.read_text(encoding="utf-8", errors="ignore"))
if kt.name in DEV_KT:
dev |= keys
else:
coach |= keys
for xml in (APP_JAVA / "res" / "layout").rglob("*.xml"):
for m in re.finditer(r'android:tag="([^"]+)"', xml.read_text(encoding="utf-8", errors="ignore")):
coach.add(m.group(1))
for month in (
"january", "february", "march", "april", "may", "june",
"july", "august", "september", "october", "november", "december",
):
coach.add(month)
keys = sorted(coach - dev - DEV_ONLY_KEYS)
german_defaults = {
k: de_defaults.get(k) or old_def.get(k) or k for k in keys
}
payload = {
"version": 2,
"description": "Coach-visible app UI strings only (excludes dev settings / database tools).",
"keys": keys,
"germanDefaults": german_defaults,
}
OUT.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
print(f"Wrote {len(keys)} keys to {OUT}")
if __name__ == "__main__":
main()