fixed minor bug

This commit is contained in:
2026-05-22 17:14:20 +02:00
parent 2ded5b6aaf
commit 472e45d730
4 changed files with 38 additions and 152 deletions

View File

@ -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',

View File

@ -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!",

View File

@ -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);

View File

@ -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()