From 472e45d730ae85bddf0ad37cbf2698bda8c31c52 Mon Sep 17 00:00:00 2001 From: Tom Hempel Date: Fri, 22 May 2026 17:14:20 +0200 Subject: [PATCH] fixed minor bug --- common.php | 14 +++- data/app_ui_strings.json | 34 ++++++-- handlers/translations.php | 2 +- scripts/build_app_ui_strings.py | 140 -------------------------------- 4 files changed, 38 insertions(+), 152 deletions(-) delete mode 100644 scripts/build_app_ui_strings.py diff --git a/common.php b/common.php index eea7cc5..d539292 100644 --- a/common.php +++ b/common.php @@ -339,13 +339,15 @@ function qdb_all_questionnaire_translation_key_set(PDO $pdo): array { return $cache; } -/** App UI catalog entries for coaches (excludes dev-only and questionnaire-scoped keys). */ -function qdb_app_ui_string_entries_global_only(PDO $pdo): array { - $used = qdb_all_questionnaire_translation_key_set($pdo); +/** + * App UI catalog for the website Translations page (coach-visible, no dev-only keys). + * Catalog keys always appear here even when also used inside a questionnaire (e.g. "save"). + */ +function qdb_app_ui_string_entries_for_website(): array { $dev = qdb_dev_only_app_string_key_set(); $entries = []; foreach (qdb_app_ui_string_entries() as $e) { - if (!isset($used[$e['key']]) && !isset($dev[$e['key']])) { + if (!isset($dev[$e['key']])) { $entries[] = $e; } } @@ -438,10 +440,14 @@ function qdb_translation_entry_lists(PDO $pdo, string $qnID): array { } } + $appKeySet = qdb_app_string_key_set(); $stringOrder = 0; $skList = array_keys($stringKeys); sort($skList, SORT_STRING); foreach ($skList as $sk) { + if (isset($appKeySet[$sk])) { + continue; + } $stringEntries[] = [ 'key' => $sk, 'type' => 'string', diff --git a/data/app_ui_strings.json b/data/app_ui_strings.json index 073e185..2ef79a6 100644 --- a/data/app_ui_strings.json +++ b/data/app_ui_strings.json @@ -3,6 +3,7 @@ "description": "Coach-visible app UI strings only (excludes dev settings / database tools).", "keys": [ "all_clients", + "answer", "april", "august", "auth_footer_accounts", @@ -12,6 +13,8 @@ "cancel", "choose_answer", "choose_more_elements", + "client", + "client_code", "client_code_exists", "coach_code", "confirm_password_hint", @@ -23,6 +26,7 @@ "download", "download_failed_use_offline", "enter_coach_code", + "error", "error_invalid_data", "error_not_found", "example_text", @@ -46,6 +50,8 @@ "new_password_hint", "no_clients_assigned", "no_profile", + "no_questionnaires", + "no_questions_available", "none", "not_done", "november", @@ -56,10 +62,14 @@ "password_hint", "password_too_short", "passwords_dont_match", + "please_client_code", "please_username_password", "points", + "previous", + "question", "questions_filled", "refresh", + "save", "save_password_btn", "select_one_answer", "select_one_answer_per_row", @@ -73,16 +83,19 @@ "year" ], "germanDefaults": { - "all_clients": "all_clients", + "all_clients": "Alle Klienten", + "answer": "Antwort", "april": "April", "august": "August", "auth_footer_accounts": "Konten werden von Ihrer Organisation vergeben.", "auth_subtitle_change_password": "Bitte legen Sie jetzt ein eigenes Passwort fest.", "auth_subtitle_login": "Melden Sie sich mit Ihrem Coach-Konto an.", "auth_title": "BW Schützt", - "cancel": "Cancel", + "cancel": "Abbrechen", "choose_answer": "Antwort wählen", "choose_more_elements": "Es müssen mehr Elemenete ausgewählt werden.", + "client": "Klient", + "client_code": "Klientencode", "client_code_exists": "Dieser Client-Code existiert bereits.", "coach_code": "Code Coach", "confirm_password_hint": "Passwort bestätigen", @@ -94,19 +107,20 @@ "download": "Herunterladen", "download_failed_use_offline": "Download fehlgeschlagen – arbeite offline mit vorhandener Datenbank", "enter_coach_code": "Bitte geben Sie Ihren Coach Code ein, um fortzufahren!", - "error_invalid_data": "error_invalid_data", - "error_not_found": "error_not_found", + "error": "Fehler", + "error_invalid_data": "Ungültige Daten", + "error_not_found": "Nicht gefunden", "example_text": "Beispieltext", "exit_btn": "Beenden", "february": "Februar", - "fill_all_fields": "fill_all_fields", + "fill_all_fields": "Bitte alle Felder ausfüllen!", "fill_both_fields": "Bitte beide Felder ausfüllen!", "hours_short": "h", "january": "Januar", "july": "Juli", "june": "Juni", "lay": "liegen.", - "locked": "Locked", + "locked": "Gesperrt", "login_btn": "Login", "login_failed_with_reason": "Login fehlgeschlagen: {reason}", "login_required": "Bitte zuerst einloggen", @@ -117,6 +131,8 @@ "new_password_hint": "Neues Passwort", "no_clients_assigned": "Ihr Supervisor hat Ihnen noch keine Klienten zugewiesen.", "no_profile": "Dieser Klient ist noch nicht Teil der Datenbank", + "no_questionnaires": "Keine Fragebögen vorhanden.", + "no_questions_available": "Keine Fragen vorhanden.", "none": "Keine", "not_done": "Nicht erledigt", "november": "November", @@ -127,10 +143,14 @@ "password_hint": "Passwort", "password_too_short": "Mindestens 6 Zeichen", "passwords_dont_match": "Passwörter stimmen nicht überein", + "please_client_code": "Bitte Klienten Code eingeben", "please_username_password": "Bitte Benutzername und Passwort eingeben.", "points": "Punkte", - "questions_filled": "questions_filled", + "previous": "Zurück", + "question": "Frage", + "questions_filled": "Antworten", "refresh": "Aktualisieren", + "save": "Speichern", "save_password_btn": "Passwort speichern", "select_one_answer": "Bitte wählen Sie eine Antwort aus!", "select_one_answer_per_row": "Bitte wählen Sie eine Antwort pro Reihe aus!", diff --git a/handlers/translations.php b/handlers/translations.php index 4e396f5..ce8f14a 100644 --- a/handlers/translations.php +++ b/handlers/translations.php @@ -26,7 +26,7 @@ case 'GET': SELECT questionnaireID, name, orderIndex FROM questionnaire ORDER BY orderIndex ")->fetchAll(PDO::FETCH_ASSOC); - $appEntries = qdb_app_ui_string_entries_global_only($pdo); + $appEntries = qdb_app_ui_string_entries_for_website(); $appTranslations = qdb_load_translations_for_entries($pdo, $appEntries); qdb_attach_translation_texts($appEntries, $appTranslations); diff --git a/scripts/build_app_ui_strings.py b/scripts/build_app_ui_strings.py deleted file mode 100644 index 374cd05..0000000 --- a/scripts/build_app_ui_strings.py +++ /dev/null @@ -1,140 +0,0 @@ -#!/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()