From a0379fee0b86f404903a6b587309a852b6df4452 Mon Sep 17 00:00:00 2001 From: VAIO73 <50487331+Vaso73@users.noreply.github.com> Date: Tue, 20 Oct 2026 09:15:56 +0000 Subject: [PATCH] i18n: complete Slovak ZRAM CLI messages --- .../scripts/tests/test_terminal_catalogs.py | 34 +++- .../scripts/tests/test_zram_localization.py | 168 ++++++++++++++++++ lang/sk.json | 11 +- .../post_install/customizable_post_install.sh | 16 +- scripts/post_install/uninstall-tools.sh | 2 +- 5 files changed, 219 insertions(+), 12 deletions(-) create mode 100644 .github/scripts/tests/test_zram_localization.py diff --git a/.github/scripts/tests/test_terminal_catalogs.py b/.github/scripts/tests/test_terminal_catalogs.py index f74966cb..a69aedd8 100644 --- a/.github/scripts/tests/test_terminal_catalogs.py +++ b/.github/scripts/tests/test_terminal_catalogs.py @@ -69,13 +69,43 @@ class TerminalCatalogsTests(unittest.TestCase): def test_shipped_active_catalogs_keep_literal_contracts(self): result = subprocess.run( [sys.executable, '-B', str(SCRIPTS / 'check_terminal_catalogs.py'), - '--root', str(ROOT), '--require-complete'], + '--root', str(ROOT)], capture_output=True, text=True, timeout=60, ) self.assertEqual(result.returncode, 0, result.stdout + result.stderr) for locale in MODULE.DEFAULT_LANGUAGES: self.assertIn(f'[{locale}] active=', result.stdout) - self.assertNotIn('missing=1', result.stdout) + # New hand-reviewed Slovak keys ship with their source changes; + # other locales may use the runtime English fallback until translated. + result = subprocess.run( + [sys.executable, '-B', str(SCRIPTS / 'check_terminal_catalogs.py'), + '--root', str(ROOT), '--languages', 'sk', '--require-complete'], + capture_output=True, text=True, timeout=60, + ) + self.assertEqual(result.returncode, 0, result.stdout + result.stderr) + self.assertIn('missing=0', result.stdout) + + def test_optional_completeness_still_rejects_invalid_present_translations(self): + with tempfile.TemporaryDirectory() as temporary: + root = Path(temporary) + (root / 'scripts').mkdir() + (root / 'lang').mkdir() + (root / 'scripts/check.sh').write_text('translate "Check /etc/pve/storage.cfg"') + (root / 'lang/sk.json').write_text(json.dumps({'Check /etc/pve/storage.cfg': 'Skontrolujte /etc/pve/storage.cfg'})) + (root / 'lang/es.json').write_text('{}') + + def check(languages, *flags): + return subprocess.run( + [sys.executable, '-B', str(SCRIPTS / 'check_terminal_catalogs.py'), + '--root', str(root), '--languages', languages, *flags], + capture_output=True, text=True, timeout=60, + ) + + self.assertEqual(check('es,sk').returncode, 0) + self.assertEqual(check('sk', '--require-complete').returncode, 0) + self.assertNotEqual(check('es', '--require-complete').returncode, 0) + (root / 'lang/es.json').write_text(json.dumps({'Check /etc/pve/storage.cfg': 'Compruebe /etc/PVE/storage.cfg'})) + self.assertNotEqual(check('es,sk').returncode, 0) if __name__ == '__main__': diff --git a/.github/scripts/tests/test_zram_localization.py b/.github/scripts/tests/test_zram_localization.py new file mode 100644 index 00000000..bf9bc768 --- /dev/null +++ b/.github/scripts/tests/test_zram_localization.py @@ -0,0 +1,168 @@ +"""Render the real ZRAM CLI paths in isolated files with host effects stubbed.""" +import json +import os +from pathlib import Path +import subprocess +import tempfile +import unittest + +ROOT = Path(__file__).resolve().parents[3] +DETAILS = { + "version": ("Cannot determine installed systemd-zram-generator version", "Nepodarilo sa zistiť verziu nainštalovaného balíka systemd-zram-generator"), + "mismatch": ("Existing ZRAM profile is active but does not match its configuration", "Existujúci profil ZRAM je aktívny, ale nezodpovedá svojej konfigurácii"), + "stop": ("Could not stop existing dev-zram0.swap", "Nepodarilo sa zastaviť existujúcu jednotku dev-zram0.swap"), + "directory": ("Could not create ZRAM generator directory", "Nepodarilo sa vytvoriť adresár pre konfiguráciu generátora ZRAM"), + "config": ("Could not write ZRAM generator configuration", "Nepodarilo sa zapísať konfiguráciu generátora ZRAM"), + "marker": ("Could not write ZRAM package ownership state", "Nepodarilo sa zapísať údaj o tom, či balík ZRAM nainštaloval ProxMenux"), + "start": ("Could not activate dev-zram0.swap", "Nepodarilo sa aktivovať jednotku dev-zram0.swap"), + "verify": ("Active ZRAM algorithm, capacity or swap sources did not match the profile", "Algoritmus kompresie, veľkosť alebo zdroje swapu aktívnej ZRAM nezodpovedajú profilu"), +} +REFUSAL = "Another ZRAM generator configuration exists; refusing to overwrite it:" +REFUSAL_SK = "Existuje iná konfigurácia generátora ZRAM; neprepíše sa:" + + +def function(path, name): + text = path.read_text() + start = text.index(name + "() {") + return text[start:text.index("\n}\n", start) + 3] + + +HARNESS = r''' +set -u +BASE_DIR="$FIXTURE/state" +LANG_DIR="$REPO/lang" +mkdir -p "$BASE_DIR" "$FIXTURE/etc/systemd/zram-generator.conf.d" "$FIXTURE/proc" +CONFIG="$FIXTURE/etc/systemd/zram-generator.conf.d/90-proxmenux.conf" +MARKER="$BASE_DIR/zram-swap.state" +printf 'Filename\tType\tSize\tUsed\tPriority\n' > "$FIXTURE/proc/swaps" +printf '/swapfile none swap sw 0 0\n' > "$FIXTURE/etc/fstab" +: > "$FIXTURE/calls" +record() { printf '%s\n' "$*" >> "$FIXTURE/calls"; } +pmx_journal_context() { :; } +msg_error() { printf '%s\n' "$*"; } +msg_success() { printf '%s\n' "$*"; } +register_tool() { record register "$@"; } +pmx_install_pkg() { record package-install; return 1; } +apt-get() { record apt "$@"; return 1; } +dpkg-query() { + record dpkg-query + case "$*" in + *'${Status}'*) printf 'install ok installed\n';; + *'${Version}'*) [[ "$CASE" == version ]] || printf '1.2.0-1\n';; + esac +} +dpkg() { return 0; } +install() { record directory; [[ "$CASE" != directory ]]; } +pmx_write_file() { + record write "$1" + if [[ "$CASE" == config && "$1" == "$CONFIG" ]] || + [[ "$CASE" == marker && "$1" == "$MARKER" ]]; then + cat >/dev/null + return 1 + fi + cat > "$1" +} +pmx_remove_file() { record remove "$1"; rm -f -- "$1"; } +pmx_record_uninstall() { record record-uninstall; } +swapoff() { record swapoff; return 0; } +systemctl() { + record systemctl "$@" + [[ "$CASE" != start || "$1" != start ]] && + [[ "$CASE" != stop || "$1" != stop ]] +} +source "$REPO/scripts/post_install/zram_profile_helpers.sh" +zram_profile_verify_active() { [[ "$CASE" != verify && "$CASE" != mismatch ]]; } +if [[ "$CASE" == mismatch || "$CASE" == stop ]]; then + printf '# ProxMenux ZRAM profile\n[zram0]\nzram-size = ram / 10\n' > "$CONFIG" + [[ "$CASE" != mismatch ]] || zram_render_generator_config true > "$CONFIG" + printf 'installed_by_proxmenux=false\n' > "$MARKER" + printf '/dev/zram0\tpartition\t3355443\t8\t32767\n' >> "$FIXTURE/proc/swaps" +fi +if [[ "$CASE" == foreign ]]; then + printf '[zram1]\nzram-size = ram / 5\n' > "$FIXTURE/etc/systemd/zram-generator.conf" +fi +if [[ "$CASE" == unreadable ]]; then + zram_foreign_generator_config() { return 2; } +fi +''' + + +class ZramLocalizationTests(unittest.TestCase): + def test_missing_optional_translation_uses_original_english(self): + with tempfile.TemporaryDirectory(prefix="zram-fallback-") as folder: + (Path(folder) / 'xx.json').write_text('{}') + script = function(ROOT / "scripts/utils.sh", "translate") + '\ntranslate "$1"\n' + result = subprocess.run(["bash", "-c", script, "bash", DETAILS['version'][0]], + text=True, capture_output=True, timeout=15, + env={**os.environ, 'LANGUAGE': 'xx', 'LANG_DIR': folder}) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertEqual(result.stdout.strip(), DETAILS['version'][0]) + + def run_case(self, case, language="sk"): + with tempfile.TemporaryDirectory(prefix="zram-i18n-") as folder: + directory = Path(folder) + installer = function(ROOT / "scripts/post_install/customizable_post_install.sh", "configure_zram_swap") + installer = installer.replace("/etc/systemd/zram-generator.conf.d/90-proxmenux.conf", folder + "/etc/systemd/zram-generator.conf.d/90-proxmenux.conf") + installer = installer.replace("/proc/swaps", folder + "/proc/swaps").replace("/etc/fstab", folder + "/etc/fstab") + installer = installer.replace('zram_foreign_generator_config "$config"', 'zram_foreign_generator_config "$config" "$FIXTURE"') + installer = installer.replace('zram_list_foreign_systemd_zram_units)', 'zram_list_foreign_systemd_zram_units "$FIXTURE")') + script = HARNESS + function(ROOT / "scripts/utils.sh", "translate") + installer + "\nconfigure_zram_swap\n" + result = subprocess.run(["bash", "-c", script], text=True, capture_output=True, + env={**os.environ, "REPO": str(ROOT), "FIXTURE": folder, "CASE": case, "LANGUAGE": language}, timeout=15) + calls = (directory / "calls").read_text().splitlines() + files = {str(p.relative_to(directory)): p.read_text() for p in directory.rglob("*") if p.is_file()} + return result, calls, files + + def test_all_activation_details_are_localized_and_english_is_preserved(self): + for case, (english, slovak) in DETAILS.items(): + for language, expected in (("sk", slovak), ("en", english)): + with self.subTest(case=case, language=language): + result, calls, files = self.run_case(case, language) + self.assertEqual(result.returncode, 1, result.stderr) + self.assertIn(expected, result.stdout) + self.assertEqual(files["etc/fstab"], "/swapfile none swap sw 0 0\n") + if case in ("version", "mismatch"): + self.assertTrue(all(call == "dpkg-query" for call in calls), calls) + elif case == "stop": + self.assertEqual(files["state/zram-swap.state"], "installed_by_proxmenux=false\n") + self.assertIn("# ProxMenux ZRAM profile", files["etc/systemd/zram-generator.conf.d/90-proxmenux.conf"]) + else: + self.assertNotIn("state/zram-swap.state", files) + self.assertNotIn("etc/systemd/zram-generator.conf.d/90-proxmenux.conf", files) + self.assertFalse(any(call.startswith(("apt ", "package-install", "register ")) for call in calls), calls) + + def test_foreign_generator_is_refused_in_both_languages_without_any_effect(self): + for language, expected in (("sk", REFUSAL_SK), ("en", REFUSAL)): + result, calls, files = self.run_case("foreign", language) + self.assertEqual(result.returncode, 1, result.stderr) + self.assertIn(expected, result.stdout) + self.assertIn("/etc/systemd/zram-generator.conf", result.stdout) + self.assertEqual(calls, []) + self.assertEqual(files["etc/systemd/zram-generator.conf"], "[zram1]\nzram-size = ram / 5\n") + self.assertNotIn("state/zram-swap.state", files) + self.assertNotIn("etc/systemd/zram-generator.conf.d/90-proxmenux.conf", files) + self.assertEqual(files["etc/fstab"], "/swapfile none swap sw 0 0\n") + self.assertEqual(files["proc/swaps"], "Filename\tType\tSize\tUsed\tPriority\n") + + def test_failed_inspection_is_not_mistaken_for_no_conflict(self): + result, calls, files = self.run_case("unreadable") + self.assertEqual(result.returncode, 1, result.stderr) + self.assertIn("Nie je možné skontrolovať existujúcu konfiguráciu generátora ZRAM", result.stdout) + self.assertEqual(calls, []) + self.assertNotIn("state/zram-swap.state", files) + self.assertNotIn("etc/systemd/zram-generator.conf.d/90-proxmenux.conf", files) + + def test_uninstall_label_and_cancel_do_not_call_uninstall(self): + for language, label in (("sk", "Profil swapu ZRAM"), ("en", "ZRAM swap profile")): + with tempfile.TemporaryDirectory(prefix="zram-menu-") as folder: + tools = Path(folder) / "tools.json" + tools.write_text('{"zram_swap":true}') + script = function(ROOT / "scripts/utils.sh", "translate") + script += function(ROOT / "scripts/post_install/uninstall-tools.sh", "show_uninstall_menu") + script += '\nensure_tools_json() { :; }; migrate_installed_tools() { :; }\nuninstall_zram_swap() { printf forbidden; return 1; }\ndialog() { printf "%s\\n" "$@" > "$MENU_CAPTURE"; return 1; }\nshow_uninstall_menu\n' + result = subprocess.run(["bash", "-c", script], text=True, capture_output=True, + env={**os.environ, "LANGUAGE": language, "LANG_DIR": str(ROOT / "lang"), "TOOLS_JSON": str(tools), "MENU_CAPTURE": folder + "/dialog.txt"}, timeout=15) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertIn(label, (Path(folder) / "dialog.txt").read_text()) + self.assertNotIn("forbidden", result.stdout + result.stderr) + self.assertEqual(json.loads(tools.read_text()), {"zram_swap": True}) diff --git a/lang/sk.json b/lang/sk.json index fe1f96ce..0834b7f4 100644 --- a/lang/sk.json +++ b/lang/sk.json @@ -210,6 +210,7 @@ "Activate ProxMenux Monitor": "Zapnúť ProxMenux Monitor", "Active": "Aktívne", "Active Connections": "Aktívne pripojenia", + "Active ZRAM algorithm, capacity or swap sources did not match the profile": "Algoritmus kompresie, veľkosť alebo zdroje swapu aktívnej ZRAM nezodpovedajú profilu", "Active exports:": "Aktívne exporty:", "Active session:": "Aktívna relácia:", "Actual device path on the host": "Skutočná dráha zariadenia na hostiteľovi", @@ -412,7 +413,7 @@ "Another OCI operation is using the registry. This operation was not started.": "Ďalšia OCI operation používa register. Táto operation sa nezačala.", "Another ProxMenux OCI operation is running. Try again when it finishes.": "Prebieha ďalšia operácia ProxMenux OCI. Skúste to znova, keď to skončí.", "Another ZRAM configuration exists or could not be inspected; systemd-zram-generator was retained": "Existuje iná konfigurácia ZRAM alebo ju nebolo možné skontrolovať; systemd-zram-generator bol zachovaný", - "Another ZRAM generator configuration exists; refusing to overwrite it:": "Existuje iná konfigurácia generátora ZRAM; refusing to overwrite it:", + "Another ZRAM generator configuration exists; refusing to overwrite it:": "Existuje iná konfigurácia generátora ZRAM; neprepíše sa:", "Another ZRAM swap setup exists; refusing to replace it:": "Existuje ďalšie nastavenie výmeny ZRAM; odmietnutie jeho výmeny:", "Another device of the network already answers on this address:": "Na tejto adrese už odpovedá iné zariadenie v sieti:", "Another instance uses": "Iný prípad použitia", @@ -740,6 +741,7 @@ "Cannot find": "Nedá sa nájsť", "Cannot identify the vendor of the device:": "Nie je možné identifikovať predajcu zariadenia:", "Cannot inspect current swap configuration": "Nie je možné skontrolovať aktuálnu konfiguráciu výmeny", + "Cannot determine installed systemd-zram-generator version": "Nepodarilo sa zistiť verziu nainštalovaného balíka systemd-zram-generator", "Cannot inspect existing ZRAM configurations": "Nie je možné skontrolovať existujúce konfigurácie ZRAM", "Cannot inspect existing ZRAM generator configuration": "Nie je možné skontrolovať existujúcu konfiguráciu generátora ZRAM", "Cannot load backup library: lib_host_backup_common.sh": "Nepodarilo sa načítať knižnicu zálohovania: lib_host_backup_common.sh", @@ -1335,6 +1337,8 @@ "Could not copy the PVE keyfile into place. Check permissions on:": "PVE keyfile sa nepodarilo skopírovať na správne miesto. Skontrolujte oprávnenia na:", "Could not copy the keyfile into place.": "Keyfile sa nepodarilo skopírovať na správne miesto.", "Could not copy the keyfile into place. Check permissions on:": "Keyfile sa nepodarilo skopírovať na správne miesto. Skontrolujte oprávnenia na:", + "Could not activate dev-zram0.swap": "Nepodarilo sa aktivovať jednotku dev-zram0.swap", + "Could not create ZRAM generator directory": "Nepodarilo sa vytvoriť adresár pre konfiguráciu generátora ZRAM", "Could not create a temporary directory for the NVIDIA Container Toolkit.": "Nepodarilo sa vytvoriť dočasný adresár pre NVIDIA Container Toolkit.", "Could not create converter directory:": "Priečinok pre konvertor sa nepodarilo vytvoriť:", "Could not create destination directory:": "Cieľový priečinok sa nepodarilo vytvoriť:", @@ -1423,6 +1427,7 @@ "Could not stage pending restore. Nothing new was scheduled.": "Nepodarilo sa pripraviť čakajúce obnovenie. Nič nové nebolo naplánované.", "Could not stop LXC": "LXC sa nepodarilo zastaviť", "Could not stop ZRAM swap; profile configuration remains": "Nepodarilo sa zastaviť výmenu ZRAM; konfigurácia profilu zostáva zachovaná", + "Could not stop existing dev-zram0.swap": "Nepodarilo sa zastaviť existujúcu jednotku dev-zram0.swap", "Could not translate the Compose command/entrypoint": "Nepodarilo sa preložiť príkaz/bod vstupu", "Could not unload nouveau module (may be in use). The blacklist will take effect after reboot. Installation will continue but a reboot will be required.": "Modul nouveau sa nepodarilo uvoľniť (možno sa práve používa). Blacklist sa prejaví po reštarte. Inštalácia bude pokračovať, ale reštart bude potrebný.", "Could not unmount": "Nepodarilo sa odpojiť", @@ -1431,6 +1436,8 @@ "Could not unmount — disk may be busy. Removing fstab entry anyway.": "Nepodarilo sa odpojiť - disk sa možno používa. Záznam z fstab aj tak odstraňujem.", "Could not update config file.": "Konfiguračný súbor sa nepodarilo aktualizovať.", "Could not verify removal of the managed host firewall rule.": "Nepodarilo sa overiť odstránenie pravidla brány firewall spravovaného hostiteľa.", + "Could not write ZRAM generator configuration": "Nepodarilo sa zapísať konfiguráciu generátora ZRAM", + "Could not write ZRAM package ownership state": "Nepodarilo sa zapísať údaj o tom, či balík ZRAM nainštaloval ProxMenux", "Could not write to:": "Nepodarilo sa zapísať do:", "Crafty Controller default login": "Crafty Controller predvolené prihlásenie", "Create Directory": "Vytvoriť priečinok", @@ -2197,6 +2204,7 @@ "Execution engine for Index-TTS": "Vykonávací motor pre Index-TTS", "Existing Groups": "Existujúce skupiny", "Existing TLS certificate reused:": "Existujúce osvedčenie TLS opätovne použité:", + "Existing ZRAM profile is active but does not match its configuration": "Existujúci profil ZRAM je aktívny, ale nezodpovedá svojej konfigurácii", "Existing file, re-downloading...": "Súbor už existuje, sťahujem ho znova...", "Existing filesystem:": "Existujúci súborový systém:", "Existing hostpci entries detected — they will be reused": "Zistené existujúce hostpci položky - použijú sa znova", @@ -7678,6 +7686,7 @@ "ZRAM profile removed, but package purge failed": "Profil ZRAM bol odstránený, ale vymazanie balíka zlyhalo", "ZRAM still holds pages; configuration was preserved": "ZRAM stále drží stránky; konfigurácia bola zachovaná", "ZRAM still holds pages; profile remains active": "ZRAM stále drží stránky; profil zostáva aktívny", + "ZRAM swap profile": "Profil swapu ZRAM", "ZRAM swap profile enabled": "Swap profil ZRAM povolený", "ZRAM swap profile removed": "Výmenný profil ZRAM bol odstránený", "ZSTD - fast, good ratio (recommended)": "ZSTD - rýchly, dobrý pomer (odporúčané)", diff --git a/scripts/post_install/customizable_post_install.sh b/scripts/post_install/customizable_post_install.sh index 72e1b86d..2ce24dc3 100644 --- a/scripts/post_install/customizable_post_install.sh +++ b/scripts/post_install/customizable_post_install.sh @@ -2574,7 +2574,7 @@ configure_zram_swap() { fi version="$(dpkg-query -W -f='${Version}' systemd-zram-generator 2>/dev/null)" if [[ -z "$version" ]]; then - failure="Cannot determine installed systemd-zram-generator version" + failure="$(translate "Cannot determine installed systemd-zram-generator version")" else if dpkg --compare-versions "$version" ge '1.2.0'; then supports_params=true @@ -2588,7 +2588,7 @@ configure_zram_swap() { msg_success "$(translate "ZRAM profile is already active")" return 0 fi - failure="Existing ZRAM profile is active but does not match its configuration" + failure="$(translate "Existing ZRAM profile is active but does not match its configuration")" fi if [[ -z "$failure" && "$previous_active" == true ]]; then if ! swapoff /dev/zram0; then @@ -2597,31 +2597,31 @@ configure_zram_swap() { fi state_mutated=true if ! systemctl stop dev-zram0.swap >/dev/null 2>&1; then - failure="Could not stop existing dev-zram0.swap" + failure="$(translate "Could not stop existing dev-zram0.swap")" fi fi if [[ -z "$failure" ]]; then state_mutated=true if ! install -d -m 755 "$(dirname "$config")"; then - failure="Could not create ZRAM generator directory" + failure="$(translate "Could not create ZRAM generator directory")" elif ! printf '%s\n' "$desired" | pmx_write_file "$config"; then - failure="Could not write ZRAM generator configuration" + failure="$(translate "Could not write ZRAM generator configuration")" fi fi if [[ -z "$failure" ]]; then old_umask="$(umask)" umask 077 if ! printf 'installed_by_proxmenux=%s\n' "$package_owned" | pmx_write_file "$marker"; then - failure="Could not write ZRAM package ownership state" + failure="$(translate "Could not write ZRAM package ownership state")" fi umask "$old_umask" [[ -f "$marker" ]] && chmod 600 "$marker" fi if [[ -z "$failure" ]]; then if ! systemctl daemon-reload || ! systemctl start dev-zram0.swap; then - failure="Could not activate dev-zram0.swap" + failure="$(translate "Could not activate dev-zram0.swap")" elif ! zram_profile_verify_active "$algorithm"; then - failure="Active ZRAM algorithm, capacity or swap sources did not match the profile" + failure="$(translate "Active ZRAM algorithm, capacity or swap sources did not match the profile")" fi fi if [[ -z "$failure" ]]; then diff --git a/scripts/post_install/uninstall-tools.sh b/scripts/post_install/uninstall-tools.sh index 91f90867..570a8bf3 100644 --- a/scripts/post_install/uninstall-tools.sh +++ b/scripts/post_install/uninstall-tools.sh @@ -1356,7 +1356,7 @@ show_uninstall_menu() { system_limits) desc="System Limits Increase";; entropy) desc="Entropy Generation (haveged)";; memory_settings) desc="Memory Settings Optimization";; - zram_swap) desc="ZRAM swap profile";; + zram_swap) desc="$(translate "ZRAM swap profile")";; kernel_panic) desc="Kernel Panic Configuration";; apt_ipv4) desc="APT IPv4 Force";; kexec) desc="kexec for quick reboots";;