diff --git a/.github/scripts/tests/test_documentation_markdown.py b/.github/scripts/tests/test_documentation_markdown.py new file mode 100644 index 00000000..98255351 --- /dev/null +++ b/.github/scripts/tests/test_documentation_markdown.py @@ -0,0 +1,16 @@ +"""Keep the canonical conduct policy and its English website source in sync.""" +import json +from pathlib import Path +import unittest + +ROOT = Path(__file__).resolve().parents[3] + + +class DocumentationMarkdownTests(unittest.TestCase): + def test_english_conduct_body_matches_canonical_policy(self): + source = json.loads((ROOT / 'web/messages/en/docs/about/code-of-conduct.json').read_text(encoding='utf-8')) + self.assertEqual(source['contentMarkdown'], (ROOT / 'CODE_OF_CONDUCT.md').read_text(encoding='utf-8')) + + +if __name__ == '__main__': + unittest.main() diff --git a/web/app/[locale]/docs/about/code-of-conduct/page.tsx b/web/app/[locale]/docs/about/code-of-conduct/page.tsx index de18716b..53365824 100644 --- a/web/app/[locale]/docs/about/code-of-conduct/page.tsx +++ b/web/app/[locale]/docs/about/code-of-conduct/page.tsx @@ -24,23 +24,27 @@ export async function generateMetadata({ params }: { params: Promise<{ locale: s } } -async function getCodeOfConductContent(notFoundMsg: string, loadFailedMsg: string) { +async function getCodeOfConductContent(notFoundMsg: string, loadFailedMsg: string, translatedMarkdown?: string) { try { const codeOfConductPath = path.join(process.cwd(), "..", "CODE_OF_CONDUCT.md") - if (!fs.existsSync(codeOfConductPath)) { + if (!translatedMarkdown && !fs.existsSync(codeOfConductPath)) { console.error("CODE_OF_CONDUCT.md file not found.") return `
${notFoundMsg}
` } - const fileContents = fs.readFileSync(codeOfConductPath, "utf8") + const fileContents = translatedMarkdown || fs.readFileSync(codeOfConductPath, "utf8") const result = await remark() .use(gfm.default || gfm) .use(html) .process(fileContents) - return result.toString() + // Repository-relative policy links otherwise resolve under the docs URL. + return result.toString().replaceAll( + 'href="./SECURITY.md"', + 'href="https://github.com/MacRimi/ProxMenux/blob/main/SECURITY.md"', + ) } catch (error) { console.error("Error reading the CODE_OF_CONDUCT.md file", error) return `${loadFailedMsg}
` @@ -71,7 +75,11 @@ export default async function CodeOfConductPage({ params }: { params: Promise<{ const { locale } = await params setRequestLocale(locale) const t = await getTranslations({ locale, namespace: "docs.about.codeOfConduct" }) - const codeOfConductContent = await getCodeOfConductContent(t("errors.notFound"), t("errors.loadFailed")) + const translatedMarkdown = t.has("contentMarkdown") ? t.raw("contentMarkdown") : undefined + const codeOfConductContent = await getCodeOfConductContent( + t("errors.notFound"), t("errors.loadFailed"), + typeof translatedMarkdown === "string" ? translatedMarkdown : undefined, + ) const cleanedInlineCode = cleanInlineCode(codeOfConductContent) const parsedContent = wrapCodeBlocksWithCopyable(cleanedInlineCode) diff --git a/web/messages/de/docs/about/code-of-conduct.json b/web/messages/de/docs/about/code-of-conduct.json new file mode 100644 index 00000000..4e79d0fe --- /dev/null +++ b/web/messages/de/docs/about/code-of-conduct.json @@ -0,0 +1,13 @@ +{ + "meta": { + "title": "Verhaltenskodex | ProxMenux-Dokumentation", + "description": "ProxMenux Verhaltenskodex und Best Practices für Mitwirkende, Tester und Nutzer.", + "ogTitle": "Verhaltenskodex | ProxMenux-Dokumentation", + "ogDescription": "Erwartungen an die Verantwortung für eingereichten Code, die Meldung von Sicherheitslücken und den Umfang von Pull Requests im ProxMenux-Projekt." + }, + "errors": { + "notFound": "Fehler: Die Datei CODE_OF_CONDUCT.md wurde nicht gefunden.", + "loadFailed": "Fehler: Der Inhalt des Verhaltenskodex kann nicht geladen werden." + }, + "contentMarkdown": "# 📝 Verhaltenskodex und bewährte Vorgehensweisen\n\nDieses Dokument legt die **Grundsätze und Richtlinien** für die Nutzung von **ProxMenux** fest. Es soll **Respekt, Zusammenarbeit und Sicherheit** bei der Entwicklung fördern.\n\n## 📌 1. Urheberangaben und Anerkennung\n\n- Werden **Skripte, Codeausschnitte oder Ideen** anderer Repositorys oder Entwickler verwendet, wird der ursprüngliche Urheber immer genannt.\n- Ein Kommentar im Code oder in der Dokumentation nennt die Quelle und verlinkt möglichst auf das ursprüngliche Repository.\n- Bei Code mit einer bestimmten **Lizenz** müssen deren Bedingungen eingehalten werden.\n\n### ✅ Beispiel für eine korrekte Quellenangabe im Code:\n\n```bash\n# Skript auf Grundlage der Arbeit von [Autor] unter [Repository-Link]\n```\n\n## 🔒 2. Sicherheit und Verantwortung für den Code\n\n- Der gesamte Code in diesem Repository folgt bewährten Vorgehensweisen für sichere Entwicklung.\n- Beiträge mit absichtlich eingebauten Schwachstellen oder unsicheren Vorgehensweisen sind nicht erlaubt.\n- Skripte dürfen niemals die Systemsicherheit oder Benutzerdaten gefährden.\n- Beiträge sollen vor der Implementierung auf Sicherheit und Stabilität geprüft werden.\n\n### ⚠️ Verantwortungsvolle Meldung von Sicherheitslücken\n\nEntdecken Sie eine Sicherheitslücke, melden Sie diese NICHT in öffentlichen Issues oder Foren.\n\nMelden Sie sie stattdessen vertraulich per E-Mail:\n\n📧 proxmenux@macrimi.pro\n\nWeitere Informationen zu Sicherheitslücken und deren Meldung finden Sie in unserer [Sicherheitsrichtlinie](./SECURITY.md).\n\n## 🤝 3. Regeln für die Community\n\nFür ein respektvolles und professionelles Umfeld müssen alle Benutzer diese Regeln beachten:\n\n- ✅ Bleiben Sie in Diskussionen respektvoll und konstruktiv.\n- ❌ Belästigung, Hassrede und beleidigendes Verhalten werden nicht toleriert.\n- ✅ Geben Sie Rückmeldungen sachlich und ohne persönliche Angriffe.\n- ❌ Verstöße können je nach Schwere zu Verwarnungen oder Ausschlüssen führen.\n\n##\n\nDieses Dokument fördert den ethischen Umgang mit Code, Sicherheitsbewusstsein und eine respektvolle Community.\n\n📢 Lassen Sie uns gemeinsam etwas Großartiges schaffen!\n" +} diff --git a/web/messages/de/docs/about/contributing.json b/web/messages/de/docs/about/contributing.json new file mode 100644 index 00000000..7827e51f --- /dev/null +++ b/web/messages/de/docs/about/contributing.json @@ -0,0 +1,293 @@ +{ + "meta": { + "title": "Zu ProxMenux beitragen | ProxMenux-Dokumentation", + "description": "Zu ProxMenux beitragen: Branch-Modell (main / develop / feature/*), Pull-Request-Ablauf, Skript-Header mit Autorenangabe und optionalem Sponsoring-Link, zweiphasige UI-Richtlinie, Nachrichtenfunktionen und der Weg vom Feature-Branch zur stabilen Version.", + "ogTitle": "Zu ProxMenux beitragen", + "ogDescription": "Branch-Modell, Arbeitsablauf, Autorenangabe im Skript-Header und zweiphasige UI-Richtlinie für Mitwirkende." + }, + "header": { + "title": "Zu ProxMenux beitragen", + "description": "ProxMenux ist offen für Community-Beiträge - neue Skripte, Fixes für bestehende, Dialogverbesserungen, Übersetzungen, Integrationen. Diese Seite ist die formale Tür: wie das Repository strukturiert ist, das Verzweigungsmodell und der Pull-Request-Workflow, der Skript-Header mit Autorzuweisung und optionalem Sponsor-Link und die Design-Konventionen, denen jeder Beitrag folgen muss.", + "section": "Über" + }, + "twoPagesCallout": { + "title": "Zwei verwandte Seiten, ein Projekt", + "body": "Verwechseln Sie diese Seite nicht mitmain übernommen."
+ },
+ {
+ "branch": "feature/*",
+ "purposeRich": "Kurzlebige Branchs pro Feature, Fix oder Verbesserung. Erstellt aus develop, nach Überprüfung über einen Pull Request wieder in develop zusammengeführt."
+ }
+ ],
+ "calloutTitle": "Was das für die Nutzer bedeutet",
+ "calloutBody": "Endbenutzer, die main verfolgen, erhalten getestete Releases. Benutzer, die die neuesten Funktionen frühzeitig wünschen - und gelegentliche raue Kanten nicht stören - können develop folgen. Neue Funktionen passieren immer zuerst develop; nichts erreicht main, ohne diesen Zyklus zu durchlaufen."
+ },
+ "workflow": {
+ "heading": "Pull Request Workflow",
+ "intro": "Von der Idee zum fusionierten Release in fünf Schritten:",
+ "step1Lead": "Erstellen Sie einen Feature Branch aus develop:",
+ "step1Code": "git clone https://github.com/MacRimi/ProxMenux.git\ncd ProxMenux\ngit checkout develop\ngit pull origin develop\ngit checkout -b feature/your-feature-name",
+ "step1Trail": "Verwenden Sie einen beschreibenden Zweignamen: feature/zfs-arc-tuning, feature/fix-iommu-detection, feature/add-tailscale-script.",
+ "step2Lead": "Arbeiten Sie an Ihren Änderungen und schieben Sie den Branch: ",
+ "step2Code": "# Make your changes, then:\ngit add scripts/...\ngit commit -m \"Add ZFS ARC tuning script\"\ngit push -u origin feature/your-feature-name",
+ "step3": "Öffnen Sie einen Pull Request für develop, nicht für main. Prüfen Sie auf GitHub, dass der Basisbranch auf develop steht. Beschreiben Sie, was das Skript tut und ändert und auf welchen Proxmox-VE-Versionen es getestet wurde.",
+ "step4": "Nach der Prüfung werden Änderungen in develop zusammengeführt. Ein Maintainer prüft Codequalität, Header-Konventionen und die zweiphasige UI-Richtlinie. Falls Änderungen nötig sind, pushen Sie weitere Commits in denselben Branch; der PR aktualisiert sich automatisch.",
+ "step5": "Stabile Versionen werden von develop nach main übernommen. Bei der Veröffentlichung wird main per Fast-Forward auf develop gebracht und mit einem Tag versehen. Ihr Beitrag wird Teil der nächsten stabilen Version."
+ },
+ "scriptHeader": {
+ "heading": "Skript-Header — Metadaten und Beschreibung",
+ "intro": "Jedes Skript in ProxMenux wird mit zwei benachbarten Kommentarblöcken geöffnet, die zusammen den Header bilden. Sie sind beide erforderlich - zusammen lassen sie jeden Leser wissen, wer das Skript geschrieben hat und was es tut, alles ohne den Code selbst zu öffnen.",
+ "bullets": [
+ "Oberer Block: Metadaten. Autor, optionale GitHub-/Sponsoring-Links, Maintainer, Copyright, Lizenz, Version und Aktualisierungsdatum. Hier erfolgt auch die Würdigung der Mitwirkenden: Bei einem neuen Skript tragen Sie Ihren Namen und optional Links zur persönlichen GitHub-Seite und einem Unterstützungsprofil ein, etwa Ko-fi, GitHub Sponsors oder Buy Me a Coffee.",
+ "Unterer Block: Beschreibung. Ein kurzer Absatz in einfachem Englisch erklärt die Funktion. Nutzer lesen ihn vor dem Code. Er muss für sich allein Zweck, Hauptaktionen, betroffene Ressourcen und Voraussetzungen verständlich machen."
+ ],
+ "licenseCalloutTitle": "Die Lizenzlinie ist festgelegt — GPL-3.0",
+ "licenseCalloutBody": "ProxMenux wird unter der GNU General Public License v3.0 veröffentlicht. Jedes Skript im Projekt wird unter derselben Lizenz ausgeliefert; die License-Zeile im Header ist immer die GPL-3.0-Referenz, die im folgenden Beispiel gezeigt wird - es ist keine Per-Script-Wahl. Indem Sie ein Skript beisteuern, erklären Sie sich damit einverstanden, es unter GPL-3.0 zu veröffentlichen, was bedeutet, dass jeder es lesen, ändern und weiterverteilen kann (einschließlich Änderungen), solange er es unter der gleichen Lizenz behält. Der vollständige Text befindet sich unter GitHub und Sponsor sind optional - lassen Sie sie aus, wenn Sie sie nicht veröffentlichen möchten. Alles andere ist erforderlich.",
+ "whyCalloutTitle": "Warum das wichtig ist",
+ "whyCalloutBody": "Open-Source-Beiträge sind freiwillige Arbeit. Name und optionaler Sponsoring-Link im Quellcode machen die Urheberschaft bei jedem Lesen sichtbar, statt sie hinter dem Projektnamen zu verbergen. Der Beschreibungsblock ist aus einem anderen Grund wichtig: Er ist der erste Anlaufpunkt künftiger Maintainer und neugieriger Nutzer. Eine klare Erklärung entscheidet oft darüber, ob sie einem Skript vertrauen oder es meiden."
+ },
+ "structure": {
+ "heading": "Projektstruktur",
+ "intro": "Wo jede Art von Skript im Repository lebt:",
+ "treeCode": "scripts/\n├── menus/ # Top-level menu scripts (entry points)\n├── storage/ # Disk, storage and passthrough scripts\n├── share/ # NFS, Samba, local share scripts\n├── vm/ # VM creation and configuration scripts\n├── gpu_tpu/ # GPU / TPU passthrough scripts\n├── post_install/ # Post-install automation scripts\n├── backup_restore/ # Backup and restore scripts\n├── utilities/ # System utility scripts\n├── global/ # Shared helper libraries (sourced by other scripts)\n├── utils.sh # Shared utility functions and message helpers\n└── help_info_menu.sh # Interactive help and command reference",
+ "outro": "Jedes Skript lädt utils.sh beim Start per source, um Nachrichtenfunktionen, Spinner, Farbvariablen und Übersetzungssystem einzubinden. Gemeinsame Hilfsbibliotheken in scripts/global/ werden ausdrücklich von den Skripten geladen, die sie benötigen."
+ },
+ "twoPhase": {
+ "heading": "Die zweiphasige UI Design Policy",
+ "intro": "Dies ist die wichtigste Konvention in ProxMenux und die PRs werden am häufigsten gebeten, sie zu beheben. Jedes Skript ist in genau zwei Phasen unterteilt:",
+ "headerPhase": "Phase",
+ "headerPurpose": "Zweck",
+ "headerScreen": "Bildschirmzustand",
+ "rows": [
+ {
+ "phaseRich": "Phase 1 — Auswahl",
+ "purposeRich": "Sammeln Sie jede Benutzerentscheidung. Führen Sie alle erforderlichen Vorbereitungsarbeiten durch (Sonden, Scans, Überprüfungen).",
+ "screenRich": "dialog-Overlays. Wenn eine Suche zwischen zwei Menüs länger als ein oder zwei Sekunden dauert, zeigen Sie einen msg_info-Spinner an, damit der Benutzer weiß, dass das Skript nicht eingefroren ist, und rufen Sie dann stop_spinner direkt vor dem nächsten Dialog auf."
+ },
+ {
+ "phaseRich": "Phase 2 — Ausführung",
+ "purposeRich": "Führen Sie jede Operation aus. Zeigen Sie den gesamten Fortschrittsverlauf an, der sich auf dem Bildschirm ansammelt.",
+ "screenRich": "Sichtbare msg_info / msg_ok Nachrichten; niemals dialog."
+ }
+ ],
+ "principle": "Das Prinzip: Sammeln Sie zuerst alles und führen Sie dann alles aus. Der Benutzer sieht ein sauberes dialoggesteuertes Menü (Phase 1), dann eine saubere Ausführungsansicht im Protokollstil (Phase 2). Kein Mischen — kein Dialog erscheint mitten in der Ausführung, kein Fortschrittsrauschen während der Auswahl.",
+ "phase1Heading": "Phase 1 — typisches Muster",
+ "phase1Code": "# Silent preparatory work between dialogs\nmsg_info \"$(translate \"Checking disk assignments...\")\"\nASSIGNED_TO=$(check_assignments \"$DISK\")\nstop_spinner # ← clears line silently, result saved in variable\n\n# Next dialog can now use ASSIGNED_TO\nif [ -n \"$ASSIGNED_TO\" ]; then\n dialog --yesno \"$(translate \"Disk already assigned. Continue?\")\" $UI_YESNO_H $UI_YESNO_W\nfi\n\n# Collect multiple decisions per item with parallel arrays\ndeclare -a DISK_LIST=()\ndeclare -a DISK_FORMAT_TYPES=()\ndeclare -a DISK_MOUNT_POINTS=()\nfor DISK in $SELECTED; do\n msg_info \"$(translate \"Analyzing disk...\")\"\n CURRENT_FS=$(lsblk -no FSTYPE \"$DISK\" | xargs)\n stop_spinner\n\n FORMAT=$(dialog --backtitle \"$BACKTITLE\" \\\n --title \"$(translate \"Select Filesystem\")\" \\\n --menu \"...\" $UI_SHORT_MENU_H $UI_SHORT_MENU_W $UI_SHORT_MENU_LIST_H \\\n \"ext4\" \"...\" \"xfs\" \"...\" \"btrfs\" \"...\" \\\n 2>&1 >/dev/tty)\n [ -z \"$FORMAT\" ] && continue\n\n DISK_LIST+=(\"$DISK\")\n DISK_FORMAT_TYPES+=(\"$FORMAT\")\ndone",
+ "phase1RulesIntro": "Regeln für Phase 1:",
+ "phase1Rules": [
+ "Läuft gerade ein msg_info-Spinner und soll ein Menü mit dialog oder whiptail geöffnet werden, rufen Sie zuerst stop_spinner auf. Der Spinner verträgt sich nicht mit deren Bildschirmüberlagerung. Ohne aktiven Spinner ist der Aufruf nicht nötig.",
+ "Verwenden Sie show_proxmenux_logo + msg_title + msg_info, um in Phase 1 einen längeren Vorgang sichtbar einzuordnen, etwa eine Prüfung ab fünf Sekunden. Die Funktion leert bereits den Bildschirm; rufen Sie davor nicht clear auf.",
+ "Rufen Sie show_proxmenux_logo nicht zwischen Dialogmenüs auf, in denen nichts angezeigt werden kann - das Löschen des Bildschirms für ein leeres Terminal ist nur visuelles Rauschen.",
+ "Speichern Sie alle Entscheidungen und Sondenergebnisse in Variablen oder parallelen Arrays. Die sichtbare Zusammenfassung erfolgt zu Beginn der Phase 2, nicht in Phase 1."
+ ],
+ "phase2Heading": "Phase 2 — typisches Muster",
+ "phase2Code": "# ── PHASE 2 — EXECUTION ─────────────────────────────\nshow_proxmenux_logo\nmsg_title \"$(translate \"My Script Title\")\"\n\n# Recap Phase 1 preparatory results — show what was already done\nmsg_ok \"$(translate \"CT $CTID selected.\")\"\nmsg_ok \"$(translate \"Repositories verified.\")\"\nmsg_ok \"$(translate \"Disks to process: ${#DISK_LIST[@]}\")\"\n\n# Now execute operations\nfor i in \"${!DISK_LIST[@]}\"; do\n DISK=\"${DISK_LIST[$i]}\"\n FORMAT=\"${DISK_FORMAT_TYPES[$i]}\"\n\n msg_info \"$(translate \"Formatting\") $DISK $(translate \"as\") $FORMAT...\"\n mkfs.\"$FORMAT\" \"$DISK\" >/dev/null 2>&1\n msg_ok \"$(translate \"Formatted.\")\"\ndone\n\nmsg_ok \"$(translate \"Completed. ${#DISK_LIST[@]} disk(s) processed.\")\"\nmsg_success \"$(translate \"Press Enter to return to menu...\")\"\nread -r",
+ "phase2Rules": "Regeln für Phase 2: Beginnen Sie mit show_proxmenux_logo + msg_title und fassen Sie Phase 1 sofort in msg_ok-Zeilen zusammen. Rufen Sie show_proxmenux_logo nicht erneut auf, da dies den bisherigen Verlauf löscht. Verwenden Sie kein dialog; ist eine Entscheidung zur Laufzeit unvermeidbar, nutzen Sie whiptail wie im nächsten Abschnitt."
+ },
+ "dialogVsWhiptail": {
+ "headingRich": "Wann dialog vs whiptail zu verwenden",
+ "intro": "Beide Tools zeichnen Benutzeroberflächen im Textmodus, aber sie verhalten sich auf dem Bildschirm sehr unterschiedlich - und ProxMenux verwendet sie aus einem bestimmten Grund in zwei verschiedenen Phasen.",
+ "headerTool": "Werkzeug",
+ "headerWhen": "Wann man es benutzt",
+ "headerEffect": "Wirkung auf den Bildschirm",
+ "rows": [
+ {
+ "toolRich": "dialog",
+ "whenRich": "Immer in Phase 1. Jede interaktive Auswahl – Auswahl einer VM, einer Festplatte, eines Dateisystems, das eine Aktion bestätigt – verwendet dialog. Dies ist das Standard-UI-Tool von ProxMenux.",
+ "effectRich": "Übernimmt das Terminal: löscht den Bildschirm, zieht sein Overlay und bringt das Terminal beim Schließen in seinen vorherigen Zustand zurück. Fein in Phase 1, weil sich noch nichts Nützliches zeigt."
+ },
+ {
+ "toolRich": "whiptail",
+ "whenRich": "Nur in Phase 2, nur wenn unvermeidlich. Der typische Fall ist eine Neustartaufforderung am Ende der Ausführung. Greifen Sie nicht zu whiptail, um \"Weiter?\" mitten in der Ausführung zu fragen - diese Entscheidung hätte in Phase 1 getroffen werden sollen.",
+ "effectRich": "Leichteres Overlay, das den Terminalkontext nicht löscht. Der akkumulierte msg_ok / msg_info-Verlauf der Phase 2 bleibt hinter dem Dialogfeld sichtbar. Deshalb ist es die richtige Wahl, wenn der Fortschritt bereits auf dem Bildschirm zu sehen ist."
+ }
+ ],
+ "calloutTitle": "Warum die Trennung wichtig ist",
+ "calloutBody": "Wenn Sie dialog in der Mitte der Phase 2 anrufen, verschwindet jede msg_ok-Zeile, die der Benutzer beobachtet hat. Sie wischen den Audit-Trail. whiptail vermeidet das. Die Regel ist also nicht willkürlich - es geht darum, die Sicht des Benutzers auf das, was das Skript bisher getan hat, zu bewahren.",
+ "rebootHeading": "Neustartabfrage: das typische whiptail in Phase 2",
+ "rebootIntro": "Wenn ein Skript endet und ein Neustart erforderlich ist (z.B.) IOMMU aktiviert, Kernelparameter geändert), die Aufforderung am Ende der Phase 2 verwendet whiptail. Fügen Sie immer einen \"Nein\"-Zweig hinzu, der den Benutzer warnt, die betroffene Ressource nicht zu verwenden, bis er neu startet:",
+ "rebootCode": "if [[ \"$HOST_REBOOT_REQUIRED\" == \"yes\" ]]; then\n echo \"\"\n if whiptail --title \"$(translate \"Reboot Required\")\" --yesno \\\n \"\\n$(translate \"A host reboot is required before starting the VM. Reboot now?\")\" \\\n 13 78; then\n msg_warn \"$(translate \"Rebooting the system...\")\"\n reboot\n else\n echo \"\"\n msg_info2 \"$(translate \"Do not start the VM until the system has been rebooted.\")\"\n fi\nfi\n\nmsg_success \"$(translate \"Press Enter to return to menu...\")\"\nread -r"
+ },
+ "messageFunctions": {
+ "heading": "Referenz der Nachrichtenfunktionen",
+ "intro": "Alle definiert in utils.sh. Verwenden Sie sie als Standard für jede benutzersichtliche Ausgabe - konsistente Visuals über Skripte hinweg ist der springende Punkt. Wenn Ihr Skript eine neue Funktion benötigt, die nicht zum vorhandenen Set passt (ein neuer Schweregrad, ein neuer Layout-Helfer usw.), schlagen Sie es in Ihrem Pull Request vor - es wird überprüft und zu utils.sh hinzugefügt, wenn es allgemein nützlich ist.",
+ "headerFunction": "Funktion",
+ "headerWhen": "Wann zu verwenden",
+ "headerSpinner": "Fortschrittsanzeige",
+ "rows": [
+ {
+ "function": "msg_info \"text\"",
+ "whenRich": "Operation in Arbeit.",
+ "spinner": "Startet"
+ },
+ {
+ "function": "stop_spinner",
+ "whenRich": "Ende der stillen Vorbereitungsarbeiten in Phase 1 — tötet Spinner, löscht die Linie.",
+ "spinner": "Stoppt"
+ },
+ {
+ "function": "msg_ok \"text\"",
+ "whenRich": "Vorgang erfolgreich. Auch für „Funktion aktiviert“ verwenden, wenn noch ein Neustart erforderlich ist.",
+ "spinner": "Stoppt"
+ },
+ {
+ "function": "msg_warn \"text\"",
+ "whenRich": "Tatsächliche Warnung oder gestörter Zustand.",
+ "spinner": "Stoppt"
+ },
+ {
+ "function": "msg_error \"text\"",
+ "whenRich": "Schwerwiegender Fehler.",
+ "spinner": "Stoppt"
+ },
+ {
+ "function": "msg_info2 \"text\"",
+ "whenRich": "Nicht blockierender Hinweis (türkisfarbene Infozeile).",
+ "spinner": "Stoppt"
+ },
+ {
+ "function": "msg_success \"text\"",
+ "whenRich": "Abschließende Aufforderung „Enter zum Zurückkehren“ am Ende von Phase 2.",
+ "spinner": "Stoppt"
+ },
+ {
+ "function": "msg_title \"text\"",
+ "whenRich": "Fetter Titel mit eingebautem Abstand. Wird zu Beginn der Phase 2 verwendet.",
+ "spinner": "—"
+ },
+ {
+ "function": "show_proxmenux_logo",
+ "whenRich": "Leert den Bildschirm und zeigt das Logo. Zu Beginn von Phase 2 einmal aufrufen.",
+ "spinner": "—"
+ }
+ ]
+ },
+ "dialogConventions": {
+ "heading": "Dialogkonventionen",
+ "bullets": [
+ "Geben Sie --backtitle \"$BACKTITLE\" immer an jeden dialog- und whiptail-Aufruf weiter. $BACKTITLE ist immer \"ProxMenux\" - einmal im Skript-Header gesetzt und nie außer Kraft gesetzt. Der Benutzer muss den Projektnamen immer als Framing-Kontext sehen, niemals den eigenen Titel des Skripts.",
+ "Verpacken Sie Titel und Nachrichten immer mit $(translate \"...\").",
+ "Immer dialog Ausgabe mit 2>&1 >/dev/tty umleiten — die erfasste stdout wird die Auswahl des Benutzers, während der Dialog selbst auf das Terminal zieht.",
+ "Verwenden Sie die Standard-UI-Dimensionsvariablen ($UI_MENU_H, $UI_MSG_W, usw.) für eine konsistente Dimensionierung über Skripte hinweg.",
+ "Prüfen Sie immer auf leere oder abgebrochene Auswahlen und behandeln Sie diese sauber."
+ ],
+ "exampleIntro": "Vollständiges Beispiel — Erstellung eines VM-Auswahlmenüs und Bearbeitung der Stornierung:",
+ "exampleCode": "# 1) Build the list of VMs as alternating \"ID NAME\" pairs.\n# dialog --menu expects this exact shape: tag1 description1 tag2 description2 ...\nVM_LIST=\"\"\nfor vmid in $(qm list | awk 'NR>1 {print $1}'); do\n vm_name=$(qm config \"$vmid\" | awk -F': ' '/^name:/ {print $2}')\n VM_LIST=\"$VM_LIST $vmid \\\"$vm_name\\\"\"\ndone\n\n# 2) Show the dialog. Captured stdout is the user's selection (the VMID).\nVMID=$(eval \"dialog --backtitle \\\"\\$BACKTITLE\\\" \\\n --title \\\"\\$(translate \\\"Select VM\\\")\\\" \\\n --menu \\\"\\$(translate \\\"Choose a VM from the list:\\\")\\\" \\\n \\$UI_MENU_H \\$UI_MENU_W \\$UI_MENU_LIST_H \\\n $VM_LIST \\\n 2>&1 >/dev/tty\")\n\n# 3) Empty result means the user pressed Cancel or Esc — exit silently.\nif [ -z \"$VMID\" ]; then\n exit 0\nfi\n\n# 4) Continue with the rest of Phase 1, knowing VMID is now set.\necho \"User selected VMID=$VMID\""
+ },
+ "translation": {
+ "heading": "Übersetzungspolitik",
+ "intro": "Alle vom Benutzer sichtbaren Zeichenfolgen müssen mit der translate-Funktion gewickelt sein. ProxMenux übersetzt sie automatisch in alle unterstützten Sprachen - Sie schreiben Englisch, der Benutzer liest seine Muttersprache.",
+ "code": "msg_ok \"$(translate \"Operation completed successfully.\")\"\nmsg_error \"$(translate \"Failed to start container\") $CTID.\"\ndialog --title \"$(translate \"Select Storage\")\" ...",
+ "bullets": [
+ "Schreibe Strings in Englisch – die Übersetzung wird automatisch vom Build bearbeitet.",
+ "Halten Sie Strings kurz. Vermeiden Sie das Einbetten von Variablen in lange Sätze, wenn möglich.",
+ "Variablennamen, Pfade oder technische Bezeichner nichtübersetzen."
+ ]
+ },
+ "variableStyle": {
+ "heading": "Variable und Stilkonventionen",
+ "bullets": [
+ "Verwenden Sie UPPER_CASE für Variablen auf Skriptebene.",
+ "Verwenden Sie lower_case für lokale Funktionsvariablen (mit local deklarieren).",
+ "Setzen Sie alle Variablenexpansionen in Anführungszeichen: \"$VAR\" statt $VAR.",
+ "Verwenden Sie [[ ]] für Konditionale, nicht [ ] (außer wenn POSIX erforderlich ist).",
+ "show_proxmenux_logo ist der geeignete Weg, um den Bildschirm zu löschen - er enthält das Clear und zeigt das Projektlogo, so dass der Benutzer immer einen visuellen Kontext hat. Rufen Sie es einmal zu Beginn der Phase 2 (und optional vor einem langen Phase 1-Spinnerblock) auf."
+ ],
+ "standardNamesIntro": "Standardvariablennamen im gesamten Projekt:",
+ "standardNamesCode": "CTID # container ID\nVMID # virtual machine ID\nDISK # device path (e.g. /dev/sdb)\nPARTITION # partition path (e.g. /dev/sdb1)\nSTORAGE # Proxmox storage name\nMOUNT_POINT # filesystem mount path",
+ "redirectHeading": "Umleitung der Werkzeugausgabe während der Phase 2",
+ "redirectIntro": "Phase 2 zeigt ein sauberes Protokoll der msg_info → msg_ok-Zeilen an, die sich auf dem Bildschirm ansammeln. Wenn ein Tool, das Sie aufrufen (apt, mkfs, qm, pct, dd, etc.), seine eigene Ausgabe in stdout/stderr schreibt, scrollt es an Ihren Nachrichten vorbei und unterbricht den visuellen Fluss - Sie haben ein chaotisches Terminal, in dem der Benutzer die eigenen Fortschrittslinien des Skripts nicht vom Rauschen des zugrunde liegenden Tools unterscheiden kann.",
+ "withoutRedirectIntro": "Ohne Umleitung: die Ausgabe für Nutzer, wenn zusätzliche Werkzeugausgaben nicht abgefangen werden.",
+ "withoutRedirectCode": "ℹ Installing kernel package...\nReading package lists... Done\nBuilding dependency tree... Done\nReading state information... Done\nThe following NEW packages will be installed:\n proxmox-kernel-6.5\n0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.\nNeed to get 12.5 MB of archives.\nAfter this operation, 47.2 MB of additional disk space will be used.\nGet:1 http://download.proxmox.com/debian/pve trixie/pve-no-subscription amd64 ...\n... [200+ more lines of dpkg output] ...\n✓ Kernel installed.",
+ "withRedirectIntro": "Mit Umleitung: dieselbe Aktion, wenn zusätzliche Ausgaben an anderer Stelle landen.",
+ "withRedirectCode": "ℹ Installing kernel package...\n✓ Kernel installed.\nℹ Configuring kernel command line...\n✓ Configured.\nℹ Refreshing boot loader...\n✓ Boot loader updated.",
+ "twoPatternsIntro": "Zwei Muster zur Auswahl:",
+ "discardLead": "Ausgabe verwerfen, wenn sie nicht benötigt wird: die einfachste und schnellste Variante.",
+ "discardCode": "DEBIAN_FRONTEND=noninteractive apt-get install -y \"$package\" >/dev/null 2>&1",
+ "logLead": "Ausgabe in eine Protokolldatei schreiben, wenn Sie sie später prüfen möchten, etwa zur Fehlersuche bei einer Installation oder um dpkg-Aktionen nachzuvollziehen. Dies ist das bevorzugte Muster für apt-Aufrufe:",
+ "logCode": "apt-get install -y \"$package\" >> \"$log_file\" 2>&1",
+ "referenceOutro": "scripts/global/update-pve9_2.sh dient als Referenz: Jeder apt-get-Aufruf schreibt in eine Protokolldatei. Nutzer sehen nur den Ablauf msg_info → msg_ok, während die Datei bei Fehlern genau zeigt, was apt getan hat."
+ },
+ "dosAndDonts": {
+ "heading": "Do's und Don'ts",
+ "doHeading": "✅ Empfohlen",
+ "doBullets": [
+ "stop_spinner vor einem dialog in Phase 1 nur dann, wenn ein msg_info Spinner gerade läuft.",
+ "Phase 2 beginnt mit show_proxmenux_logo + msg_title + msg_ok als Zusammenfassung der Ergebnisse von Phase 1.",
+ "Verwenden Sie msg_ok für erfolgreich aktivierte Funktionen – auch wenn ein Neustart erforderlich ist.",
+ "Verwenden Sie whiptail (nicht dialog) für jede Aufforderung nach der Ausführung, die in Phase 2 erscheinen muss.",
+ "Fügen Sie immer einen \"Nein\" -Zweig in Reboot-Dialoge ein, der den Benutzer warnt, die betroffene Ressource bis zum Neustart nicht zu starten.",
+ "Schützen Sie die reine VM-Logik, indem Sie [[ -f \"/etc/pve/qemu-server/$'{'vmid'}'.conf\" ]] überprüfen - Controller und NVMe PCIe können nicht zu LXC-Containern hinzugefügt werden.",
+ "Verwenden Sie ensure_repositories von utils-install-functions.sh anstelle von bedingungslosem apt-get update.",
+ "Verwenden Sie parallele Arrays in Phase 1, wenn jedes Element mehrere Dialoge benötigt."
+ ],
+ "dontHeading": "❌ Vermeiden",
+ "dontBullets": [
+ "Rufen Sie dialog an, während ein Spinner aktiv ist.",
+ "Überspringen Sie die Phase 1 Zusammenfassung zu Beginn der Phase 2.",
+ "Rufen Sie show_proxmenux_logo ein zweites Mal an - es löscht alles, was Phase 2 gedruckt hat.",
+ "Verwenden Sie dialog in Phase 2 (verwenden Sie whiptail für den seltenen unvermeidlichen Fall).",
+ "Verwenden Sie reine clear.",
+ "msg_title mit Leerzeilen aus echo \"\" umgeben; die Abstände sind bereits enthalten.",
+ "Verwenden Sie msg_warn, um eine erfolgreich aktivierte Funktion zu melden - das ist ein msg_ok.",
+ "Führen Sie bedingungslos apt-get update aus - verwenden Sie ensure_repositories."
+ ]
+ },
+ "submitting": {
+ "heading": "Einreichen Ihres Beitrags",
+ "steps": [
+ "Fork MacRimi/ProxMenux auf GitHub und klonen Sie Ihre Fork.",
+ "Erstellen Sie einen feature/*-Zweig aus develop (siehe Branching-Modell oben).",
+ "Befolgen Sie diese Anleitung für neue oder geänderte Skripte. Schreiben Sie den Header mit Ihrem Namen; fügen Sie die optionale Sponsorenzeile hinzu, wenn Sie möchten.",
+ "Testen Sie Ihr Skript auf einer echten Proxmox VE-Instanz - sowohl Phase 1 (jeder Dialogzweig) als auch Phase 2 (jede Operation ist erfolgreich und wird bei Fehlern sauber zurückgesetzt).",
+ "Öffnen Sie eine Pull Request gegen develop mit einer klaren Beschreibung: was das Skript macht, was sich geändert hat, auf welcher Proxmox VE-Version es getestet wurde.",
+ "Stellen Sie sicher, dass Ihr Beitrag den menu und bietet ein Update an. Stimmen Sie zu, werden die Dateien und die Konfiguration des Werkzeugs in der bestehenden Installation ersetzt. Ein manueller Download ist nicht nötig.",
+ "p2Rich": "Benutzer der stabilen Version erhalten stabile Updates, Beta-Benutzer die Beta-Updates. Sobald eine stabile Version erscheint, informiert die Beta beim nächsten Menüstart darüber und bietet den automatischen Wechsel an. Weitere Informationen finden Sie im journalctl -u proxmenux-monitor -n 50.",
+ "p2Rich": "Bei Sicherheitsproblemen: Veröffentlichen Sie keine Details. Folgen Sie dem Verfahren zur verantwortungsvollen Meldung im dialog, curl, jq und git. Die Übersetzungen verwenden vorgefertigte JSON-Kataloge. Der Installer legt auf dem Host keine virtuelle Python-Umgebung für Übersetzungen an.",
+ "item2Rich": "Der Skriptbaum bei /usr/local/share/proxmenux/.",
+ "item3Rich": "Das Startskript unter /usr/local/bin/menu.",
+ "item4Rich": "Optional: der systemd-Dienst von Monitor unter proxmenux-monitor.service.",
+ "p2Rich": "ProxMenux verändert die zentrale Proxmox-Konfiguration nicht, es sei denn, Sie fordern dies ausdrücklich über ein entsprechendes Menü an. Die Netzwerkreparatur bearbeitet beispielsweise /etc/network/interfaces, jedoch erst nach Ihrer Bestätigung und dem Anlegen einer Sicherung."
+ },
+ "q9": {
+ "question": "Ist es sicher, ProxMenux in der Produktion zu verwenden?",
+ "bodyRich": "Ja. Da ProxMenux die zentralen Proxmox-Dateien nur auf ausdrücklichen Wunsch verändert, kann es in Produktionsumgebungen eingesetzt werden. Testen Sie automatisierte Abläufe zunächst in einer kontrollierten Umgebung und erstellen Sie Sicherungen, bevor Sie destruktive Vorgänge ausführen, etwa das Upgrade von PVE 8 auf 9, das Formatieren eines Datenträgers oder das Löschen einer VM."
+ },
+ "q10": {
+ "question": "Wie deinstalliere ich ProxMenux?",
+ "p1Rich": "In ProxMenux: Einstellungen → ProxMenux deinstallieren. Die Deinstallation entfernt den Skriptbaum, das Startskript und den Monitor-Dienst sowie auf Wunsch ausgewählte Abhängigkeiten. /root/.bashrc und /etc/motd werden aus den bei der Installation angelegten Sicherungen wiederhergestellt, sofern diese vorhanden sind.",
+ "p2Rich": "Die vollständige Anleitung finden Sie unter curl | bash und kann jq aus dessen offizieller GitHub-Veröffentlichung herunterladen. Dieses Verhalten kann heuristische Scanner auslösen. Der damalige Bericht ist keine Bewertung aller künftigen Downloads.",
+ "p2Rich": "ProxMenux ist vollständig quelloffen. Sie können das Installationsskript Zeile für Zeile prüfen: dialog, curl, jq, git (and python3 + googletrans on the Translation install).",
+ "p1Rich": "Installing ProxMenux adds the following components.",
+ "item1Rich": "Dependencies via apt: dialog, curl, jq and git. Translations use pre-built JSON catalogs; the installer does not add a translation virtualenv to the host.",
"item2Rich": "The script tree at /usr/local/share/proxmenux/.",
"item3Rich": "The launcher at /usr/local/bin/menu.",
"item4Rich": "Optional: the Monitor systemd service at proxmenux-monitor.service.",
@@ -83,12 +83,12 @@
},
"q10": {
"question": "How do I uninstall ProxMenux?",
- "p1Rich": "From inside ProxMenux: Settings → Uninstall ProxMenux. The uninstaller removes the script tree, the launcher and the Monitor service, optionally removes selected dependencies, and restores /root/.bashrc and /etc/motd backups taken at install time.",
+ "p1Rich": "From inside ProxMenux: Settings → Uninstall ProxMenux. The uninstaller removes the script tree, the launcher and the Monitor service, optionally removes selected dependencies, and restores /root/.bashrc and /etc/motd from install-time backups if those backups exist.",
"p2Rich": "Full step-by-step: curl | bash pattern and downloads legitimate binaries (like jq from its official GitHub release), which aggressive scanners flag based on behaviour rather than actual malicious code.",
+ "p1Rich": "The 1/95 result reported in Issue #162, from Chong Lua Dao, was identified by the maintainer as a false positive. The installer uses the curl | bash pattern and can download jq from its official GitHub release. Such behaviour can trigger heuristic scanners; the historical report is not a verdict on every future download.",
"p2Rich": "ProxMenux is 100% open source and the install script is reviewable line by line: utils.sh. Úsalas como el valor por defecto para cualquier salida visible para el usuario — visuales coherentes entre scripts es la idea. Si tu script necesita una función nueva que no encaja en el conjunto existente (un nuevo nivel de severidad, un nuevo helper de layout, etc.), propónla en tu Pull Request — se revisará y se añadirá a utils.sh si es útil de forma amplia.",
"headerFunction": "Función",
"headerWhen": "Cuándo usar",
- "headerSpinner": "Spinner",
+ "headerSpinner": "Indicador de progreso",
"rows": [
{
"function": "msg_info \"text\"",
@@ -163,7 +163,7 @@
},
{
"function": "msg_success \"text\"",
- "whenRich": "Prompt final \"Press Enter to return\" al final de la fase 2.",
+ "whenRich": "Mensaje final «Press Enter to return» al terminar la fase 2.",
"spinner": "Para"
},
{
diff --git a/web/messages/es/docs/about/contributors.json b/web/messages/es/docs/about/contributors.json
index 6cf0ca0f..bba0ff22 100644
--- a/web/messages/es/docs/about/contributors.json
+++ b/web/messages/es/docs/about/contributors.json
@@ -1,32 +1,32 @@
{
"meta": {
- "title": "Colaboradores | ProxMenux Documentation",
- "description": "Reconocimiento a las personas que hacen posible ProxMenux — testers, revisores y desarrolladores que dan forma a cada release.",
- "ogTitle": "Colaboradores | ProxMenux Documentation",
+ "title": "Colaboradores | Documentación de ProxMenux",
+ "description": "Reconocimiento a las personas que hacen posible ProxMenux: quienes prueban, revisan y desarrollan cada versión.",
+ "ogTitle": "Colaboradores | Documentación de ProxMenux",
"ogDescription": "Conoce a los colaboradores detrás de ProxMenux."
},
"header": {
"title": "Colaboradores",
- "description": "El proyecto ProxMenux crece y prospera gracias a la contribución de sus colaboradores. Este es el merecido reconocimiento a su trabajo — probando builds antes del release, cazando regresiones, revisando PRs y dando forma a la dirección de las nuevas funciones.",
+ "description": "ProxMenux crece gracias a sus colaboradores. Esta página reconoce su trabajo: probar versiones antes de publicarlas, detectar regresiones, revisar PR y ayudar a orientar las nuevas funciones.",
"section": "Acerca de"
},
"beyond": {
"title": "Más allá de esta lista",
- "body": "Mucha más gente contribuye vía reportes de bugs, ideas de funciones en Discussions, pruebas beta y traducciones. La lista completa de colaboradores de código vive en el menu y te pide actualizar. Aceptar reemplaza los archivos de utilidad y las configuraciones en sitio. No hace falta descarga manual.",
- "p2Rich": "Los usuarios estables reciben releases estables; los usuarios beta reciben releases beta. Cuando se publica una versión estable, ProxMenux notifica a los usuarios beta en el siguiente lanzamiento y ofrece cambiar automáticamente — mira la página del menu y te propone actualizar. Si aceptas, sustituye los archivos de la herramienta y su configuración en la instalación existente; no necesitas descargar nada a mano.",
+ "p2Rich": "Los usuarios de la versión estable reciben las actualizaciones estables y los de la beta, las actualizaciones beta. Cuando se publica una versión estable, la beta avisa al volver a abrir el menú y ofrece cambiar automáticamente a la estable. Consulta el dialog, curl, jq, git (y python3 + googletrans en la instalación con traducción).",
+ "p1Rich": "La instalación de ProxMenux añade los siguientes componentes.",
+ "item1Rich": "Dependencias mediante apt: dialog, curl, jq y git. Las traducciones usan catálogos JSON pregenerados; el instalador no añade al host un entorno virtual de traducción.",
"item2Rich": "El árbol de scripts en /usr/local/share/proxmenux/.",
"item3Rich": "El lanzador en /usr/local/bin/menu.",
"item4Rich": "Opcional: el servicio systemd del Monitor en proxmenux-monitor.service.",
- "p2Rich": "ProxMenux no toca la configuración del núcleo de Proxmox a menos que se lo pidas explícitamente vía un menú dedicado (p. ej. el flujo de reparación de red edita /etc/network/interfaces — pero solo después de que confirmes y se haga un backup)."
+ "p2Rich": "ProxMenux no modifica la configuración principal de Proxmox salvo que lo solicites expresamente desde un menú específico. Por ejemplo, la reparación de red edita /etc/network/interfaces, pero solo después de tu confirmación y de hacer un backup."
},
"q9": {
"question": "¿Es seguro usar ProxMenux en producción?",
@@ -83,12 +83,12 @@
},
"q10": {
"question": "¿Cómo desinstalo ProxMenux?",
- "p1Rich": "Desde dentro de ProxMenux: Settings → Desinstalar ProxMenux. El desinstalador elimina el árbol de scripts, el lanzador y el servicio del Monitor, opcionalmente elimina las dependencias seleccionadas y restaura los backups de /root/.bashrc y /etc/motd tomados en el momento de la instalación.",
+ "p1Rich": "Desde ProxMenux: Ajustes → Desinstalar ProxMenux. El desinstalador elimina el árbol de scripts, el lanzador y el servicio Monitor, permite eliminar dependencias seleccionadas y restaura /root/.bashrc y /etc/motd desde los backups hechos al instalar, si existen.",
"p2Rich": "Paso a paso completo: curl | bash y descarga binarios legítimos (como jq desde su release oficial en GitHub), que los escáneres agresivos marcan basándose en el comportamiento y no en código realmente malicioso.",
+ "p1Rich": "El resultado de 1/95 notificado en el issue #162, de Chong Lua Dao, fue identificado por el mantenedor como un falso positivo. El instalador usa el patrón curl | bash y puede descargar jq desde su versión oficial de GitHub. Este comportamiento puede activar análisis heurísticos; aquel informe histórico no determina la seguridad de futuras descargas.",
"p2Rich": "ProxMenux es 100% código abierto y el script de instalación es revisable línea por línea: main à partir de cette branche."
+ },
+ {
+ "branch": "feature/*",
+ "purposeRich": "Branches temporaires pour une fonctionnalité, une correction ou une amélioration. Créées à partir de develop, puis fusionnées dans develop par pull request après relecture."
+ }
+ ],
+ "calloutTitle": "Ce que cela signifie pour les utilisateurs",
+ "calloutBody": "Les utilisateurs qui suivent main reçoivent des versions testées. Ceux qui souhaitent les nouveautés plus tôt et acceptent quelques imperfections peuvent suivre develop. Les nouvelles fonctions passent toujours d’abord par develop ; rien n’arrive dans main sans ce cycle."
+ },
+ "workflow": {
+ "heading": "Processus de pull request",
+ "intro": "De l'idée à la version fusionnée en cinq étapes:",
+ "step1Lead": "Créer une branche de fonction à partir de develop:",
+ "step1Code": "git clone https://github.com/MacRimi/ProxMenux.git\ncd ProxMenux\ngit checkout develop\ngit pull origin develop\ngit checkout -b feature/your-feature-name",
+ "step1Trail": "Utilisez un nom descriptif de branche : feature/zfs-arc-tuning, feature/fix-iommu-detection, feature/add-tailscale-script.",
+ "step2Lead": "Travailler sur vos changements et pousser la branche:",
+ "step2Code": "# Make your changes, then:\ngit add scripts/...\ngit commit -m \"Add ZFS ARC tuning script\"\ngit push -u origin feature/your-feature-name",
+ "step3": "Ouvrez une pull request vers develop, pas vers main. Vérifiez sur GitHub que la branche de base est develop. Décrivez le rôle du script, ses modifications et les versions de Proxmox VE utilisées pour les tests.",
+ "step4": "Après relecture, les modifications sont fusionnées dans develop. Un responsable vérifie le code, les conventions d’en-tête et la règle d’interface en deux phases. S’il demande des corrections, envoyez de nouveaux commits dans la même branche : la PR se met à jour automatiquement.",
+ "step5": "Les versions stables passent de develop à main. Lors d’une publication, main est avancée jusqu’à develop par fast-forward, puis étiquetée. Votre contribution entre dans la prochaine version stable."
+ },
+ "scriptHeader": {
+ "heading": "En-tête de script — métadonnées et description",
+ "intro": "Chaque script de ProxMenux s'ouvre avec deux blocs de commentaires adjacents qui forment ensemble l'en-tête. Ils sont tous les deux requis — ensemble, ils font savoir à tout lecteur qui a écrit le script et ce qu'il fait, le tout sans ouvrir le code lui-même.",
+ "bullets": [
+ "Bloc supérieur : métadonnées. Auteur, liens GitHub/de soutien facultatifs, responsable, copyright, licence, version et date de mise à jour. C’est aussi la reconnaissance des contributeurs : pour un nouveau script, ajoutez votre nom et, si vous le souhaitez, votre page GitHub et un profil de soutien tel que Ko-fi, GitHub Sponsors ou Buy Me a Coffee.",
+ "Bloc inférieur : description. Un court paragraphe en anglais simple explique le rôle du script. Il se lit avant le code et doit se suffire à lui-même : objectif, actions principales, ressources concernées et prérequis."
+ ],
+ "licenseCalloutTitle": "La ligne de licence est fixe — GPL-3.0",
+ "licenseCalloutBody": "ProxMenux est publié sous la licence publique générale GNU v3.0. Chaque script du projet est livré sous cette même licence; la ligne License dans l'en-tête est toujours la référence GPL-3.0 montrée dans l'exemple ci-dessous — ce n'est pas un choix par script. En contribuant un script, vous acceptez de le publier sous GPL-3.0, ce qui signifie que n'importe qui peut le lire, le modifier et le redistribuer (y compris les modifications) tant qu'ils le conservent sous la même licence. Le texte entier vit à GitHub et Sponsor sont optionnelles — laissez-les dehors si vous ne voulez pas les publier. Tout le reste est nécessaire.",
+ "whyCalloutTitle": "Pourquoi cela est important",
+ "whyCalloutBody": "Contribuer à l’open source est un travail bénévole. Le nom et le lien de soutien éventuel dans le code rendent l’auteur visible à chaque lecture, au lieu de le cacher derrière le projet. La description a un autre rôle : c’est la première chose qu’un futur responsable ou utilisateur curieux lit. Sa clarté détermine souvent si le script inspire confiance ou est évité."
+ },
+ "structure": {
+ "heading": "Structure du projet",
+ "intro": "Où chaque type de script vit dans le dépôt :",
+ "treeCode": "scripts/\n├── menus/ # Top-level menu scripts (entry points)\n├── storage/ # Disk, storage and passthrough scripts\n├── share/ # NFS, Samba, local share scripts\n├── vm/ # VM creation and configuration scripts\n├── gpu_tpu/ # GPU / TPU passthrough scripts\n├── post_install/ # Post-install automation scripts\n├── backup_restore/ # Backup and restore scripts\n├── utilities/ # System utility scripts\n├── global/ # Shared helper libraries (sourced by other scripts)\n├── utils.sh # Shared utility functions and message helpers\n└── help_info_menu.sh # Interactive help and command reference",
+ "outro": "Chaque script charge utils.sh au démarrage avec source pour obtenir les fonctions de message, l’indicateur d’attente, les couleurs et le système de traduction. Les bibliothèques communes dans scripts/global/ sont chargées explicitement par les scripts qui les utilisent."
+ },
+ "twoPhase": {
+ "heading": "La règle de conception de l’interface en deux phases",
+ "intro": "C’est la convention la plus importante de ProxMenux et celle qui entraîne le plus souvent des demandes de correction dans les PR. Chaque script est divisé en exactement deux phases :",
+ "headerPhase": "Phase",
+ "headerPurpose": "Objet",
+ "headerScreen": "État de l'écran",
+ "rows": [
+ {
+ "phaseRich": "Phase 1 — Sélection",
+ "purposeRich": "Recueillir chaque décision de l'utilisateur. Effectuer tout travail préparatoire nécessaire (sondes, scans, vérifications).",
+ "screenRich": "dialog superpositions. Si une sonde entre deux menus prend plus d'une seconde ou deux, montrez un spinner msg_info afin que l'utilisateur sache que le script n'a pas gelé, puis appelez stop_spinner juste avant la boîte de dialogue suivante."
+ },
+ {
+ "phaseRich": "Phase 2 — Exécution",
+ "purposeRich": "Exécutez toutes les opérations. Affichez l'historique complet des progrès accumulés à l'écran.",
+ "screenRich": "Messages visibles msg_info / msg_ok; jamais dialog."
+ }
+ ],
+ "principle": "Le principe: collecte tout d'abord, puis exécute tout. L'utilisateur voit un menu de dialogue propre (phase 1), puis une vue d'exécution propre (phase 2). Pas de mélange — pas de dialogue apparaissant au milieu de l'exécution, pas de bruit de progression pendant la sélection.",
+ "phase1Heading": "Phase 1 — modèle typique",
+ "phase1Code": "# Silent preparatory work between dialogs\nmsg_info \"$(translate \"Checking disk assignments...\")\"\nASSIGNED_TO=$(check_assignments \"$DISK\")\nstop_spinner # ← clears line silently, result saved in variable\n\n# Next dialog can now use ASSIGNED_TO\nif [ -n \"$ASSIGNED_TO\" ]; then\n dialog --yesno \"$(translate \"Disk already assigned. Continue?\")\" $UI_YESNO_H $UI_YESNO_W\nfi\n\n# Collect multiple decisions per item with parallel arrays\ndeclare -a DISK_LIST=()\ndeclare -a DISK_FORMAT_TYPES=()\ndeclare -a DISK_MOUNT_POINTS=()\nfor DISK in $SELECTED; do\n msg_info \"$(translate \"Analyzing disk...\")\"\n CURRENT_FS=$(lsblk -no FSTYPE \"$DISK\" | xargs)\n stop_spinner\n\n FORMAT=$(dialog --backtitle \"$BACKTITLE\" \\\n --title \"$(translate \"Select Filesystem\")\" \\\n --menu \"...\" $UI_SHORT_MENU_H $UI_SHORT_MENU_W $UI_SHORT_MENU_LIST_H \\\n \"ext4\" \"...\" \"xfs\" \"...\" \"btrfs\" \"...\" \\\n 2>&1 >/dev/tty)\n [ -z \"$FORMAT\" ] && continue\n\n DISK_LIST+=(\"$DISK\")\n DISK_FORMAT_TYPES+=(\"$FORMAT\")\ndone",
+ "phase1RulesIntro": "Règles pour la phase 1:",
+ "phase1Rules": [
+ "Si un spinner msg_info est en cours d'exécution et que vous devez ouvrir un menu dialog ou whiptail, appelez d'abord stop_spinner — le spinner ne peut pas coexister avec la superposition dessinée par l'un ou l'autre des outils. Si aucun spinner n'est actif, vous n'avez pas besoin de l'appeler.",
+ "Utilisez show_proxmenux_logo + msg_title + msg_info pour donner un contexte visuel à une opération longue en phase 1, par exemple une vérification de plus de cinq secondes. La fonction efface déjà l’écran : n’appelez pas clear avant.",
+ "N'appelez pas show_proxmenux_logo entre les menus de dialogue où il n'y a rien à afficher — le nettoyage de l'écran pour un terminal vide n'est que du bruit visuel.",
+ "Conservez toutes les décisions et les résultats de la sonde dans des variables ou des tableaux parallèles. La récapitulation visible se produit au début de la phase 2, pas dans la phase 1."
+ ],
+ "phase2Heading": "Phase 2 — modèle typique",
+ "phase2Code": "# ── PHASE 2 — EXECUTION ─────────────────────────────\nshow_proxmenux_logo\nmsg_title \"$(translate \"My Script Title\")\"\n\n# Recap Phase 1 preparatory results — show what was already done\nmsg_ok \"$(translate \"CT $CTID selected.\")\"\nmsg_ok \"$(translate \"Repositories verified.\")\"\nmsg_ok \"$(translate \"Disks to process: ${#DISK_LIST[@]}\")\"\n\n# Now execute operations\nfor i in \"${!DISK_LIST[@]}\"; do\n DISK=\"${DISK_LIST[$i]}\"\n FORMAT=\"${DISK_FORMAT_TYPES[$i]}\"\n\n msg_info \"$(translate \"Formatting\") $DISK $(translate \"as\") $FORMAT...\"\n mkfs.\"$FORMAT\" \"$DISK\" >/dev/null 2>&1\n msg_ok \"$(translate \"Formatted.\")\"\ndone\n\nmsg_ok \"$(translate \"Completed. ${#DISK_LIST[@]} disk(s) processed.\")\"\nmsg_success \"$(translate \"Press Enter to return to menu...\")\"\nread -r",
+ "phase2Rules": "Règles pour la phase 2: toujours commencer avec show_proxmenux_logo + msg_title; récapituler immédiatement les résultats de la phase 1 sous la forme de lignes msg_ok; n'appelez plus jamais show_proxmenux_logo (il effacerait les progrès accumulés); n'appelez jamais dialog dans la phase 2 — si une décision d'exécution est vraiment inévitable, utilisez whiptail (voir la section suivante)."
+ },
+ "dialogVsWhiptail": {
+ "headingRich": "Quand utiliser dialog vs whiptail",
+ "intro": "Les deux outils dessinent des interfaces utilisateur en mode texte, mais ils se comportent très différemment à l'écran — et ProxMenux les utilise en deux phases distinctes pour une raison.",
+ "headerTool": "Outil",
+ "headerWhen": "Quand l'utiliser",
+ "headerEffect": "Effet sur l'écran",
+ "rows": [
+ {
+ "toolRich": "dialog",
+ "whenRich": "Toujours dans la phase 1. Chaque sélection interactive — choisir un VM, un disque, un système de fichiers, confirmer une action — utilise dialog. C'est l'outil d'interface utilisateur par défaut de ProxMenux.",
+ "effectRich": "Prend le contrôle du terminal : efface l’écran, dessine son interface et rétablit l’état précédent à la fermeture. Cela convient à la phase 1, où aucun résultat utile n’est encore affiché."
+ },
+ {
+ "toolRich": "whiptail",
+ "whenRich": "Seulement en phase 2, en cas de nécessité. Le cas typique est la proposition de redémarrage en fin d’exécution. N’utilisez pas whiptail pour demander « continuer ? » en cours d’exécution : cette décision devait être prise en phase 1.",
+ "effectRich": "Interface plus légère qui n’efface pas le contexte du terminal. L’historique msg_ok/msg_info de la phase 2 reste visible derrière la boîte de dialogue. Elle convient donc lorsque la progression est déjà affichée."
+ }
+ ],
+ "calloutTitle": "Pourquoi la scission est importante",
+ "calloutBody": "Si vous appelez dialog au milieu de la phase 2, chaque ligne msg_ok que l'utilisateur regarde disparaît. Vous effacez la piste de vérification. whiptail évite cela. Donc la règle n'est pas arbitraire — il s'agit de préserver la vision de l'utilisateur de ce que le script a fait jusqu'ici.",
+ "rebootHeading": "Proposition de redémarrage : le cas type de whiptail en phase 2",
+ "rebootIntro": "Si un script peut nécessiter un redémarrage après l’activation d’IOMMU ou la modification du noyau, la question de fin de phase 2 utilise whiptail. Prévoyez toujours une branche « Non » avertissant de ne pas utiliser la ressource concernée avant le redémarrage :",
+ "rebootCode": "if [[ \"$HOST_REBOOT_REQUIRED\" == \"yes\" ]]; then\n echo \"\"\n if whiptail --title \"$(translate \"Reboot Required\")\" --yesno \\\n \"\\n$(translate \"A host reboot is required before starting the VM. Reboot now?\")\" \\\n 13 78; then\n msg_warn \"$(translate \"Rebooting the system...\")\"\n reboot\n else\n echo \"\"\n msg_info2 \"$(translate \"Do not start the VM until the system has been rebooted.\")\"\n fi\nfi\n\nmsg_success \"$(translate \"Press Enter to return to menu...\")\"\nread -r"
+ },
+ "messageFunctions": {
+ "heading": "Référence des fonctions du message",
+ "intro": "Toutes sont définies dans utils.sh. Utilisez-les par défaut pour les sorties visibles afin de garder une présentation cohérente entre scripts. Si une fonction manque, par exemple un niveau de sévérité ou un outil de mise en page, proposez-la dans votre pull request. Elle sera examinée et ajoutée à utils.sh si elle est utile à plusieurs scripts.",
+ "headerFunction": "Fonction",
+ "headerWhen": "Quand utiliser",
+ "headerSpinner": "Indicateur de progression",
+ "rows": [
+ {
+ "function": "msg_info \"text\"",
+ "whenRich": "Opération en cours.",
+ "spinner": "Démarre"
+ },
+ {
+ "function": "stop_spinner",
+ "whenRich": "Fin des travaux préparatoires silencieux dans la phase 1 — tue spinner, efface la ligne.",
+ "spinner": "Arrête"
+ },
+ {
+ "function": "msg_ok \"text\"",
+ "whenRich": "Opération réussie. À utiliser aussi pour une fonction activée, même si un redémarrage reste nécessaire.",
+ "spinner": "Arrête"
+ },
+ {
+ "function": "msg_warn \"text\"",
+ "whenRich": "Avertissement réel ou état dégradé.",
+ "spinner": "Arrête"
+ },
+ {
+ "function": "msg_error \"text\"",
+ "whenRich": "Erreur fatale.",
+ "spinner": "Arrête"
+ },
+ {
+ "function": "msg_info2 \"text\"",
+ "whenRich": "Conseil sans blocage, dans une ligne d’information cyan.",
+ "spinner": "Arrête"
+ },
+ {
+ "function": "msg_success \"text\"",
+ "whenRich": "Message final « Appuyez sur Entrée pour revenir » en fin de phase 2.",
+ "spinner": "Arrête"
+ },
+ {
+ "function": "msg_title \"text\"",
+ "whenRich": "Titre gras avec espacement intégré. Utilisé au début de la phase 2.",
+ "spinner": "—"
+ },
+ {
+ "function": "show_proxmenux_logo",
+ "whenRich": "Efface l’écran et affiche le logo. À appeler une seule fois au début de la phase 2.",
+ "spinner": "—"
+ }
+ ]
+ },
+ "dialogConventions": {
+ "heading": "conventions de dialogue",
+ "bullets": [
+ "Passez toujours --backtitle \"$BACKTITLE\" à chaque appel dialog et whiptail. $BACKTITLE est toujours \"ProxMenux\" — réglé une fois à l'en-tête du script et jamais dépassé. L'utilisateur doit toujours voir le nom du projet comme le contexte de cadrage, jamais le propre titre du script.",
+ "Enveloppez toujours les titres et les messages avec $(translate \"...\").",
+ "Redirige toujours la sortie dialog avec 2>&1 >/dev/tty — le stdout capturé devient la sélection de l'utilisateur, tandis que la boîte de dialogue elle-même s'appuie sur le terminal.",
+ "Utilisez les variables standard de dimension UI ($UI_MENU_H, $UI_MSG_W, etc.) pour un calibrage cohérent entre les scripts.",
+ "Vérifiez toujours les choix vides ou annulés et gérez-les proprement."
+ ],
+ "exampleIntro": "Exemple complet — construire un menu de sélection VM et gérer l'annulation:",
+ "exampleCode": "# 1) Build the list of VMs as alternating \"ID NAME\" pairs.\n# dialog --menu expects this exact shape: tag1 description1 tag2 description2 ...\nVM_LIST=\"\"\nfor vmid in $(qm list | awk 'NR>1 {print $1}'); do\n vm_name=$(qm config \"$vmid\" | awk -F': ' '/^name:/ {print $2}')\n VM_LIST=\"$VM_LIST $vmid \\\"$vm_name\\\"\"\ndone\n\n# 2) Show the dialog. Captured stdout is the user's selection (the VMID).\nVMID=$(eval \"dialog --backtitle \\\"\\$BACKTITLE\\\" \\\n --title \\\"\\$(translate \\\"Select VM\\\")\\\" \\\n --menu \\\"\\$(translate \\\"Choose a VM from the list:\\\")\\\" \\\n \\$UI_MENU_H \\$UI_MENU_W \\$UI_MENU_LIST_H \\\n $VM_LIST \\\n 2>&1 >/dev/tty\")\n\n# 3) Empty result means the user pressed Cancel or Esc — exit silently.\nif [ -z \"$VMID\" ]; then\n exit 0\nfi\n\n# 4) Continue with the rest of Phase 1, knowing VMID is now set.\necho \"User selected VMID=$VMID\""
+ },
+ "translation": {
+ "heading": "Politique de traduction",
+ "intro": "Toutes les chaînes visibles par l'utilisateur doivent être enveloppées avec la fonction translate. ProxMenux les traduit automatiquement dans toutes les langues prises en charge — vous écrivez l'anglais, l'utilisateur lit leur langue maternelle.",
+ "code": "msg_ok \"$(translate \"Operation completed successfully.\")\"\nmsg_error \"$(translate \"Failed to start container\") $CTID.\"\ndialog --title \"$(translate \"Select Storage\")\" ...",
+ "bullets": [
+ "Écrivez les chaînes en anglais : la traduction est gérée automatiquement lors du build.",
+ "Rédigez des chaînes concises. Évitez si possible les variables dans de longues phrases.",
+ "Ne traduisez pas les noms de variables, chemins ou identifiants techniques."
+ ]
+ },
+ "variableStyle": {
+ "heading": "Conventions de variables et de style",
+ "bullets": [
+ "Utilisez UPPER_CASE pour les variables de niveau script.",
+ "Utiliser lower_case pour les variables de fonction locales (déclarer avec local).",
+ "Entourez les expansions de variables de guillemets : \"$VAR\", pas $VAR.",
+ "Utiliser [[ ]] pour les conditions, et non [ ] (sauf lorsque POSIX est nécessaire).",
+ "show_proxmenux_logo est le moyen prévu pour effacer l’écran : il le nettoie et affiche le logo du projet pour conserver un contexte visuel. Appelez-le une fois au début de la phase 2, et éventuellement avant une longue attente en phase 1."
+ ],
+ "standardNamesIntro": "Noms de variables standard dans l'ensemble du projet :",
+ "standardNamesCode": "CTID # container ID\nVMID # virtual machine ID\nDISK # device path (e.g. /dev/sdb)\nPARTITION # partition path (e.g. /dev/sdb1)\nSTORAGE # Proxmox storage name\nMOUNT_POINT # filesystem mount path",
+ "redirectHeading": "Réorienter la sortie de l'outil pendant la phase 2",
+ "redirectIntro": "La phase 2 affiche un journal de lignes msg_info → msg_ok. Si un outil appelé, comme apt, mkfs, qm, pct ou dd, écrit sur stdout/stderr, sa sortie fait défiler les messages et brouille la présentation. L’utilisateur ne distingue plus la progression du script des détails produits par l’outil.",
+ "withoutRedirectIntro": "Sans redirection — ce que l'utilisateur voit si vous ne manipulez pas le bruit:",
+ "withoutRedirectCode": "ℹ Installing kernel package...\nReading package lists... Done\nBuilding dependency tree... Done\nReading state information... Done\nThe following NEW packages will be installed:\n proxmox-kernel-6.5\n0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.\nNeed to get 12.5 MB of archives.\nAfter this operation, 47.2 MB of additional disk space will be used.\nGet:1 http://download.proxmox.com/debian/pve trixie/pve-no-subscription amd64 ...\n... [200+ more lines of dpkg output] ...\n✓ Kernel installed.",
+ "withRedirectIntro": "Avec redirection — à quoi ressemble la même opération lorsque le bruit est envoyé ailleurs:",
+ "withRedirectCode": "ℹ Installing kernel package...\n✓ Kernel installed.\nℹ Configuring kernel command line...\n✓ Configured.\nℹ Refreshing boot loader...\n✓ Boot loader updated.",
+ "twoPatternsIntro": "Deux modèles à choisir :",
+ "discardLead": "Éliminez la sortie lorsque vous n'en avez pas besoin — plus rapide et plus simple:",
+ "discardCode": "DEBIAN_FRONTEND=noninteractive apt-get install -y \"$package\" >/dev/null 2>&1",
+ "logLead": "Envoyez la sortie à un fichier journal lorsque vous voudrez peut-être l'inspecter plus tard (débogage d'une installation échouée, vérification de ce que dpkg a fait réellement). C'est le modèle préféré pour toute opération apt:",
+ "logCode": "apt-get install -y \"$package\" >> \"$log_file\" 2>&1",
+ "referenceOutro": "Le script scripts/global/update-pve9_2.sh est une implémentation de référence — chaque appel apt-get envoie une sortie vers un fichier journal de sorte que l'utilisateur ne voit que le flux propre msg_info → msg_ok, tandis que le journal sur le disque vous permet de reconstruire exactement ce qu'apt a fait si quelque chose tourne mal."
+ },
+ "dosAndDonts": {
+ "heading": "Faites et ne faites pas",
+ "doHeading": "✅ À faire",
+ "doBullets": [
+ "stop_spinner avant un dialog dans la phase 1 seulement quand un spinner msg_info est en cours d'exécution.",
+ "La phase 2 commence par show_proxmenux_logo + msg_title + msg_ok pour récapituler les résultats de la phase 1.",
+ "Utilisez msg_ok pour des fonctionnalités activées avec succès, même si un redémarrage est nécessaire.",
+ "Utilisez le whiptail (et non le dialog) pour toute invitation après exécution qui doit apparaître dans la phase 2.",
+ "Prévoyez toujours une branche « Non » dans les dialogues de redémarrage pour avertir de ne pas démarrer la ressource concernée avant le redémarrage.",
+ "Protégez la logique VM uniquement en vérifiant [[ -f \"/etc/pve/qemu-server/$'{'vmid'}'.conf\" ]] — les contrôleurs et NVMe PCIe ne peuvent pas être ajoutés aux conteneurs LXC.",
+ "Utiliser ensure_repositories de utils-install-functions.sh au lieu de apt-get update inconditionnel.",
+ "Utiliser des tableaux parallèles dans la phase 1 lorsque chaque élément nécessite plusieurs dialogues."
+ ],
+ "dontHeading": "❌ À éviter",
+ "dontBullets": [
+ "Appelez dialog alors qu'un spinner est actif.",
+ "Passez la récapitulation de la phase 1 au début de la phase 2.",
+ "Appelez show_proxmenux_logo une deuxième fois — il efface tout ce que la phase 2 a imprimé.",
+ "Utiliser dialog dans la phase 2 (utiliser whiptail pour le cas inévitable rare).",
+ "Utiliser clear seul.",
+ "Enveloppez msg_title dans des lignes vierges echo \"\" — il inclut déjà l'espacement.",
+ "Utilisez msg_warn pour signaler une fonctionnalité activée avec succès — c'est un msg_ok.",
+ "Exécuter sans condition apt-get update — utiliser ensure_repositories."
+ ]
+ },
+ "submitting": {
+ "heading": "Soumettre votre contribution",
+ "steps": [
+ "Créez un fork de MacRimi/ProxMenux sur GitHub, puis clonez votre fork.",
+ "Créer une branche feature/* à partir de develop (voir Modèle de branchage ci-dessus).",
+ "Suivez ce guide pour tout script nouveau ou modifié. Écrivez l'en-tête avec votre nom; ajoutez la ligne de sponsor optionnelle si vous voulez.",
+ "Testez le script sur une véritable instance Proxmox VE : phase 1 avec toutes les branches de dialogue, et phase 2 avec chaque opération et son retour arrière propre en cas d’erreur.",
+ "Ouvrez une pull request vers develop avec une description claire : rôle du script, changements et version Proxmox VE utilisée pour les tests.",
+ "Assurez-vous que votre contribution respecte le menu et propose la mise à jour. Si vous acceptez, les fichiers et la configuration de l’outil sont remplacés dans l’installation existante ; aucun téléchargement manuel n’est nécessaire.",
+ "p2Rich": "Les utilisateurs de la version stable reçoivent les mises à jour stables, et ceux de la bêta, les mises à jour bêta. Lorsqu’une version stable est publiée, la bêta le signale à la prochaine ouverture du menu et propose de basculer automatiquement. Consultez le journalctl -u proxmenux-monitor -n 50.",
+ "p2Rich": "Pour les problèmes de sécurité, ne les divulguez pas publiquement. Suivez la procédure de signalement responsable du dialog, curl, jq et git. Les traductions utilisent des catalogues JSON préconstruits ; l’installateur n’ajoute aucun environnement virtuel de traduction à l’hôte.",
+ "item2Rich": "L'arborescence des scripts à /usr/local/share/proxmenux/.",
+ "item3Rich": "Le lanceur situé dans /usr/local/bin/menu.",
+ "item4Rich": "En option : le service systemd de Monitor, proxmenux-monitor.service.",
+ "p2Rich": "ProxMenux ne modifie pas la configuration principale de Proxmox, sauf si vous le demandez explicitement depuis un menu dédié. Par exemple, la réparation du réseau modifie /etc/network/interfaces, mais seulement après votre confirmation et la création d’une sauvegarde."
+ },
+ "q9": {
+ "question": "Est-il sûr d'utiliser ProxMenux en production?",
+ "bodyRich": "Oui. ProxMenux ne modifie les fichiers principaux de Proxmox que sur demande explicite et peut donc être utilisé en production. Comme pour toute automatisation, testez d’abord dans un environnement contrôlé et prévoyez des sauvegardes avant les opérations destructives : mise à niveau de PVE 8 vers 9, formatage d’un disque, suppression d’une VM, etc."
+ },
+ "q10": {
+ "question": "Comment désinstaller ProxMenux ?",
+ "p1Rich": "Dans ProxMenux : Paramètres → Désinstaller ProxMenux. La désinstallation supprime l’arborescence des scripts, le lanceur et le service Monitor, ainsi que les dépendances sélectionnées si vous le souhaitez. Elle restaure /root/.bashrc et /etc/motd depuis les sauvegardes de l’installation, si elles existent.",
+ "p2Rich": "Étape par étape : curl | bash et peut télécharger jq depuis sa version officielle sur GitHub. Ce comportement peut déclencher des analyses heuristiques ; ce rapport historique ne préjuge pas de tous les téléchargements futurs.",
+ "p2Rich": "ProxMenux est entièrement open source. Vous pouvez examiner le script d’installation ligne par ligne : main."
+ },
+ {
+ "branch": "feature/*",
+ "purposeRich": "Rami temporanei per una funzionalità, una correzione o un miglioramento. Creati da develop e reintegrati in develop tramite pull request dopo la revisione."
+ }
+ ],
+ "calloutTitle": "Ciò significa per gli utenti",
+ "calloutBody": "Chi segue main riceve versioni testate. Chi vuole prima le novità e accetta qualche imperfezione può seguire develop. Le nuove funzioni passano sempre prima da develop; nulla arriva in main senza questo ciclo."
+ },
+ "workflow": {
+ "heading": "Procedura delle pull request",
+ "intro": "Dall'idea alla fusione del rilascio in cinque fasi:",
+ "step1Lead": "Crea un ramo per la funzionalità da develop:",
+ "step1Code": "git clone https://github.com/MacRimi/ProxMenux.git\ncd ProxMenux\ngit checkout develop\ngit pull origin develop\ngit checkout -b feature/your-feature-name",
+ "step1Trail": "Utilizzare un nome di ramo descrittivo: feature/zfs-arc-tuning, feature/fix-iommu-detection, feature/add-tailscale-script.",
+ "step2Lead": "Lavora alle modifiche e pubblica il ramo:",
+ "step2Code": "# Make your changes, then:\ngit add scripts/...\ngit commit -m \"Add ZFS ARC tuning script\"\ngit push -u origin feature/your-feature-name",
+ "step3": "Apri una pull request verso develop, non verso main. Su GitHub verifica che il ramo di base sia develop. Descrivi cosa fa e modifica lo script e su quali versioni di Proxmox VE è stato testato.",
+ "step4": "Dopo la revisione le modifiche vengono integrate in develop. Un manutentore verifica codice, intestazione e interfaccia in due fasi. Se richiede modifiche, aggiungi commit allo stesso ramo: la PR si aggiorna automaticamente.",
+ "step5": "Le versioni stabili passano da develop a main. Al rilascio, main viene portato a develop con un fast-forward e riceve un tag. Il tuo contributo entra nella prossima versione stabile."
+ },
+ "scriptHeader": {
+ "heading": "Intestazione script — metadati & descrizione",
+ "intro": "Ogni script ProxMenux inizia con due blocchi di commenti adiacenti che formano l’intestazione. Sono entrambi obbligatori: indicano autore e scopo senza dover leggere il corpo del codice.",
+ "bullets": [
+ "Blocco superiore: metadati. Autore, link GitHub/di sostegno facoltativi, manutentore, copyright, licenza, versione e data di aggiornamento. Qui avviene il riconoscimento dei collaboratori: per un nuovo script inserisci il tuo nome e, facoltativamente, la pagina GitHub e un profilo come Ko-fi, GitHub Sponsors o Buy Me a Coffee.",
+ "Blocco inferiore: descrizione. Un breve paragrafo in inglese semplice spiega il compito dello script. Si legge prima del codice e deve chiarire da solo scopo, azioni principali, risorse coinvolte e prerequisiti."
+ ],
+ "licenseCalloutTitle": "La linea di licenza è fissa — GPL-3.0",
+ "licenseCalloutBody": "ProxMenux è pubblicato sotto GNU General Public License v3.0. Tutti gli script usano la stessa licenza: la riga License nell’intestazione deve essere il riferimento GPL-3.0 dell’esempio seguente, non una scelta per singolo script. Contribuendo accetti il rilascio sotto GPL-3.0: chiunque può leggere, modificare e ridistribuire lo script e le modifiche mantenendo la stessa licenza. Testo completo: GitHub e Sponsor sono facoltative: lasciatele fuori se non volete pubblicarle. Tutto il resto è richiesto.",
+ "whyCalloutTitle": "Perché questo è importante",
+ "whyCalloutBody": "Contribuire all’open source è un lavoro volontario. Il nome e l’eventuale link di sostegno nel codice rendono visibile l’autore a ogni lettura, senza nasconderlo dietro il progetto. La descrizione ha un altro scopo: è la prima cosa letta da un futuro manutentore o utente curioso. La sua chiarezza spesso determina se ci si fida dello script o lo si evita."
+ },
+ "structure": {
+ "heading": "Struttura del progetto",
+ "intro": "Dove ogni tipo di script vive nel repository:",
+ "treeCode": "scripts/\n├── menus/ # Top-level menu scripts (entry points)\n├── storage/ # Disk, storage and passthrough scripts\n├── share/ # NFS, Samba, local share scripts\n├── vm/ # VM creation and configuration scripts\n├── gpu_tpu/ # GPU / TPU passthrough scripts\n├── post_install/ # Post-install automation scripts\n├── backup_restore/ # Backup and restore scripts\n├── utilities/ # System utility scripts\n├── global/ # Shared helper libraries (sourced by other scripts)\n├── utils.sh # Shared utility functions and message helpers\n└── help_info_menu.sh # Interactive help and command reference",
+ "outro": "Ogni script carica utils.sh all’avvio tramite source per avere funzioni dei messaggi, indicatore di attesa, colori e sistema di traduzione. Le librerie condivise in scripts/global/ vengono caricate esplicitamente dagli script che ne hanno bisogno."
+ },
+ "twoPhase": {
+ "heading": "La politica di progettazione dell'interfaccia utente bifase",
+ "intro": "È la convenzione più importante di ProxMenux e quella per cui vengono richieste più spesso correzioni alle PR. Ogni script è diviso in esattamente due fasi:",
+ "headerPhase": "Fase",
+ "headerPurpose": "Scopo",
+ "headerScreen": "Stato dello schermo",
+ "rows": [
+ {
+ "phaseRich": "Phase 1 — Selezione",
+ "purposeRich": "Raccogliere ogni decisione dell'utente. Eseguire qualsiasi lavoro preparatorio necessario (sonde, scansioni, controlli).",
+ "screenRich": "Finestre dialog. Se una verifica tra due menu richiede più di uno o due secondi, mostra l’indicatore di attesa msg_info perché l’utente sappia che lo script non è bloccato, poi chiama stop_spinner subito prima del prossimo dialogo."
+ },
+ {
+ "phaseRich": "Phase 2 — Esecuzione",
+ "purposeRich": "Eseguire ogni operazione. Visualizza la storia del progresso completo che si accumula sullo schermo.",
+ "screenRich": "Messaggi msg_info / msg_ok visibili; mai dialog."
+ }
+ ],
+ "principle": "Il principio è raccogliere prima tutte le scelte, poi eseguire tutto. L’utente vede prima menu ordinati con dialoghi (fase 1), poi una vista di esecuzione come un log (fase 2). Le fasi non si mescolano: niente dialoghi durante l’esecuzione né messaggi di avanzamento durante la selezione.",
+ "phase1Heading": "Fase 1 — modello tipico",
+ "phase1Code": "# Silent preparatory work between dialogs\nmsg_info \"$(translate \"Checking disk assignments...\")\"\nASSIGNED_TO=$(check_assignments \"$DISK\")\nstop_spinner # ← clears line silently, result saved in variable\n\n# Next dialog can now use ASSIGNED_TO\nif [ -n \"$ASSIGNED_TO\" ]; then\n dialog --yesno \"$(translate \"Disk already assigned. Continue?\")\" $UI_YESNO_H $UI_YESNO_W\nfi\n\n# Collect multiple decisions per item with parallel arrays\ndeclare -a DISK_LIST=()\ndeclare -a DISK_FORMAT_TYPES=()\ndeclare -a DISK_MOUNT_POINTS=()\nfor DISK in $SELECTED; do\n msg_info \"$(translate \"Analyzing disk...\")\"\n CURRENT_FS=$(lsblk -no FSTYPE \"$DISK\" | xargs)\n stop_spinner\n\n FORMAT=$(dialog --backtitle \"$BACKTITLE\" \\\n --title \"$(translate \"Select Filesystem\")\" \\\n --menu \"...\" $UI_SHORT_MENU_H $UI_SHORT_MENU_W $UI_SHORT_MENU_LIST_H \\\n \"ext4\" \"...\" \"xfs\" \"...\" \"btrfs\" \"...\" \\\n 2>&1 >/dev/tty)\n [ -z \"$FORMAT\" ] && continue\n\n DISK_LIST+=(\"$DISK\")\n DISK_FORMAT_TYPES+=(\"$FORMAT\")\ndone",
+ "phase1RulesIntro": "Regole per la fase 1:",
+ "phase1Rules": [
+ "Se è attivo un indicatore msg_info e devi aprire un menu dialog o whiptail, chiama prima stop_spinner: l’indicatore non può convivere con l’overlay dei due strumenti. Se nessun indicatore è attivo, la chiamata non serve.",
+ "Usa show_proxmenux_logo + msg_title + msg_info per dare un contesto visivo a un’operazione lunga nella fase 1, ad esempio una verifica di oltre cinque secondi. La funzione pulisce già lo schermo: non chiamare prima clear.",
+ "Non chiamare show_proxmenux_logo tra i menu di dialogo in cui non c'è nulla da mostrare — cancellare lo schermo per un terminale vuoto è solo rumore visivo.",
+ "Conservare tutte le decisioni e i risultati della sonda in variabili o array paralleli. Il recap visibile avviene all'inizio della fase 2, non in fase 1."
+ ],
+ "phase2Heading": "Fase 2 — modello tipico",
+ "phase2Code": "# ── PHASE 2 — EXECUTION ─────────────────────────────\nshow_proxmenux_logo\nmsg_title \"$(translate \"My Script Title\")\"\n\n# Recap Phase 1 preparatory results — show what was already done\nmsg_ok \"$(translate \"CT $CTID selected.\")\"\nmsg_ok \"$(translate \"Repositories verified.\")\"\nmsg_ok \"$(translate \"Disks to process: ${#DISK_LIST[@]}\")\"\n\n# Now execute operations\nfor i in \"${!DISK_LIST[@]}\"; do\n DISK=\"${DISK_LIST[$i]}\"\n FORMAT=\"${DISK_FORMAT_TYPES[$i]}\"\n\n msg_info \"$(translate \"Formatting\") $DISK $(translate \"as\") $FORMAT...\"\n mkfs.\"$FORMAT\" \"$DISK\" >/dev/null 2>&1\n msg_ok \"$(translate \"Formatted.\")\"\ndone\n\nmsg_ok \"$(translate \"Completed. ${#DISK_LIST[@]} disk(s) processed.\")\"\nmsg_success \"$(translate \"Press Enter to return to menu...\")\"\nread -r",
+ "phase2Rules": "Regole per la fase 2: inizia con show_proxmenux_logo + msg_title e riepiloga subito la fase 1 con righe msg_ok. Non richiamare show_proxmenux_logo, perché cancellerebbe il progresso accumulato. Non usare dialog; se una scelta durante l’esecuzione è inevitabile, usa whiptail come spiegato nella sezione seguente."
+ },
+ "dialogVsWhiptail": {
+ "headingRich": "Quando utilizzare dialog vs whiptail",
+ "intro": "Entrambi gli strumenti disegnano interfacce utente in modalità testo, ma si comportano molto diversamente sullo schermo — e ProxMenux li utilizza in due fasi distinte per un motivo.",
+ "headerTool": "Strumento",
+ "headerWhen": "Quando usarlo",
+ "headerEffect": "Effetti sullo schermo",
+ "rows": [
+ {
+ "toolRich": "dialog",
+ "whenRich": " Sempre in Fase 1. Ogni selezione interattiva — raccogliendo un VM, un disco, un filesystem, confermando un'azione — utilizza dialog. Questo è lo strumento UI predefinito di ProxMenux.",
+ "effectRich": "Prende il controllo del terminale: pulisce lo schermo, disegna l’interfaccia e alla chiusura ripristina lo stato precedente. Va bene nella fase 1, quando non ci sono ancora risultati utili da mostrare."
+ },
+ {
+ "toolRich": "whiptail",
+ "whenRich": "Solo in Fase 2, solo quando inevitabile. Il caso tipico è un prompt di riavvio alla fine dell'esecuzione. Non raggiungere whiptail per chiedere “continua?” mid-execution — tale decisione dovrebbe essere presa in fase 1.",
+ "effectRich": "Overlay più leggero che non cancella il contesto del terminale. La cronologia msg_ok/msg_info della fase 2 resta visibile dietro il dialogo. È quindi adatto quando l’avanzamento è già sullo schermo."
+ }
+ ],
+ "calloutTitle": "Perché la divisione conta",
+ "calloutBody": "Se si chiama dialog nel mezzo della fase 2, ogni linea msg_ok l'utente sta guardando scompare. Tu pulisci la pista di controllo. whiptail lo evita. Quindi la regola non è arbitraria — si tratta di preservare la vista dell'utente di ciò che lo script ha fatto finora.",
+ "rebootHeading": "Richiesta di riavvio: il caso tipico di whiptail nella fase 2",
+ "rebootIntro": "Quando uno script termina e un riavvio può essere richiesto (ad es. IOMMU abilitato, parametri del kernel modificati), il prompt alla fine della fase 2 utilizza whiptail. Sempre includere un ramo “No” che avverte l’utente di non utilizzare la risorsa interessata fino al riavvio:",
+ "rebootCode": "if [[ \"$HOST_REBOOT_REQUIRED\" == \"yes\" ]]; then\n echo \"\"\n if whiptail --title \"$(translate \"Reboot Required\")\" --yesno \\\n \"\\n$(translate \"A host reboot is required before starting the VM. Reboot now?\")\" \\\n 13 78; then\n msg_warn \"$(translate \"Rebooting the system...\")\"\n reboot\n else\n echo \"\"\n msg_info2 \"$(translate \"Do not start the VM until the system has been rebooted.\")\"\n fi\nfi\n\nmsg_success \"$(translate \"Press Enter to return to menu...\")\"\nread -r"
+ },
+ "messageFunctions": {
+ "heading": "Funzioni di messaggio",
+ "intro": "Tutti definiti in utils.sh. Utilizzarli come predefinito per qualsiasi output visibile dall'utente — visuali coerenti tra gli script è l'intero punto. Se il tuo script ha bisogno di una nuova funzione che non si adatta al set esistente (un nuovo livello di gravità, un nuovo aiutante di layout, ecc.), proporlo nella tua richiesta di pull — sarà rivisto e aggiunto a utils.sh se è ampiamente utile.",
+ "headerFunction": "Funzione",
+ "headerWhen": "Quando usare",
+ "headerSpinner": "Indicatore di avanzamento",
+ "rows": [
+ {
+ "function": "msg_info \"text\"",
+ "whenRich": "Operazione in corso.",
+ "spinner": "Inizia"
+ },
+ {
+ "function": "stop_spinner",
+ "whenRich": "Fine del lavoro preparatorio silenzioso in Fase 1 — uccide spinner, cancella la linea.",
+ "spinner": "Arresta"
+ },
+ {
+ "function": "msg_ok \"text\"",
+ "whenRich": "L'operazione è riuscita. Utilizzare anche per “funzione abilitata” anche quando è richiesto un riavvio.",
+ "spinner": "Arresta"
+ },
+ {
+ "function": "msg_warn \"text\"",
+ "whenRich": "Avvertenza effettiva o stato degradato.",
+ "spinner": "Arresta"
+ },
+ {
+ "function": "msg_error \"text\"",
+ "whenRich": "Errore fatale.",
+ "spinner": "Arresta"
+ },
+ {
+ "function": "msg_info2 \"text\"",
+ "whenRich": "Avviso non bloccante, su una riga informativa ciano.",
+ "spinner": "Arresta"
+ },
+ {
+ "function": "msg_success \"text\"",
+ "whenRich": "Messaggio finale «Premi Invio per tornare» alla fine della fase 2.",
+ "spinner": "Arresta"
+ },
+ {
+ "function": "msg_title \"text\"",
+ "whenRich": "Titolo in grassetto con spaziatura integrata. Usato all’inizio della fase 2.",
+ "spinner": "—"
+ },
+ {
+ "function": "show_proxmenux_logo",
+ "whenRich": "Pulisce lo schermo e mostra il logo. Da chiamare una sola volta all’inizio della fase 2.",
+ "spinner": "—"
+ }
+ ]
+ },
+ "dialogConventions": {
+ "heading": "convenzioni di dialogo",
+ "bullets": [
+ "Passa sempre --backtitle \"$BACKTITLE\" ad ogni chiamata dialog e whiptail. $BACKTITLE è sempre \"ProxMenux\" — impostato una volta all'intestazione dello script e mai sovrascritto. L'utente deve sempre vedere il nome del progetto come il contesto di inquadramento, mai il titolo dello script.",
+ "Avvolgi sempre titoli e messaggi con $(translate \"...\").",
+ "Reindirizza sempre l'output dialog con 2>&1 >/dev/tty — lo stdout catturato diventa la selezione dell'utente, mentre la finestra di dialogo si disegna sul terminale.",
+ "Utilizzare le variabili standard di dimensione dell'interfaccia utente ($UI_MENU_H, $UI_MSG_W, ecc.) per un dimensionamento coerente tra gli script.",
+ "Controlla sempre le selezioni vuote o annullate e gestiscile correttamente."
+ ],
+ "exampleIntro": "Esempio completo: creare un menu di selezione della VM e gestire l’annullamento.",
+ "exampleCode": "# 1) Build the list of VMs as alternating \"ID NAME\" pairs.\n# dialog --menu expects this exact shape: tag1 description1 tag2 description2 ...\nVM_LIST=\"\"\nfor vmid in $(qm list | awk 'NR>1 {print $1}'); do\n vm_name=$(qm config \"$vmid\" | awk -F': ' '/^name:/ {print $2}')\n VM_LIST=\"$VM_LIST $vmid \\\"$vm_name\\\"\"\ndone\n\n# 2) Show the dialog. Captured stdout is the user's selection (the VMID).\nVMID=$(eval \"dialog --backtitle \\\"\\$BACKTITLE\\\" \\\n --title \\\"\\$(translate \\\"Select VM\\\")\\\" \\\n --menu \\\"\\$(translate \\\"Choose a VM from the list:\\\")\\\" \\\n \\$UI_MENU_H \\$UI_MENU_W \\$UI_MENU_LIST_H \\\n $VM_LIST \\\n 2>&1 >/dev/tty\")\n\n# 3) Empty result means the user pressed Cancel or Esc — exit silently.\nif [ -z \"$VMID\" ]; then\n exit 0\nfi\n\n# 4) Continue with the rest of Phase 1, knowing VMID is now set.\necho \"User selected VMID=$VMID\""
+ },
+ "translation": {
+ "heading": "Politica di traduzione",
+ "intro": "Tutte le stringhe visualizzabili dall'utente devono essere avvolte con la funzione translate. ProxMenux li traduce automaticamente in tutte le lingue supportate — scrivi inglese, l'utente legge la loro lingua madre.",
+ "code": "msg_ok \"$(translate \"Operation completed successfully.\")\"\nmsg_error \"$(translate \"Failed to start container\") $CTID.\"\ndialog --title \"$(translate \"Select Storage\")\" ...",
+ "bullets": [
+ "Scrivere stringhe in inglese — la traduzione viene gestita automaticamente dalla build.",
+ "Mantieni concise le stringhe. Evita, se possibile, variabili all’interno di frasi lunghe.",
+ "non tradurre nomi di variabili, percorsi o identificatori tecnici."
+ ]
+ },
+ "variableStyle": {
+ "heading": "Convenzioni variabili e di stile",
+ "bullets": [
+ "Utilizzare UPPER_CASE per le variabili a livello di script.",
+ "Utilizzare lower_case per le variabili di funzione locali (dichiarazione con local).",
+ "Quotare tutte le espansioni variabili: \"$VAR\" — non $VAR.",
+ "Utilizzare [[ ]] per condizionali, non [ ] (eccetto dove è richiesto il POSIX).",
+ "show_proxmenux_logo è il modo previsto per pulire lo schermo: lo cancella e mostra il logo del progetto per dare un contesto visivo. Chiamalo una volta all’inizio della fase 2, e facoltativamente prima di una lunga attesa nella fase 1."
+ ],
+ "standardNamesIntro": "Nomi variabili standard nel progetto:",
+ "standardNamesCode": "CTID # container ID\nVMID # virtual machine ID\nDISK # device path (e.g. /dev/sdb)\nPARTITION # partition path (e.g. /dev/sdb1)\nSTORAGE # Proxmox storage name\nMOUNT_POINT # filesystem mount path",
+ "redirectHeading": "Reindirizza l'output dello strumento durante la fase 2",
+ "redirectIntro": "La fase 2 mostra un log di righe msg_info → msg_ok. Se uno strumento chiamato, come apt, mkfs, qm, pct o dd, scrive su stdout/stderr, il suo output fa scorrere i messaggi e confonde la vista. L’utente non distingue più l’avanzamento dello script dai dettagli dello strumento.",
+ "withoutRedirectIntro": "Senza reindirizzare — ciò che l'utente vede se non si gestisce il rumore:",
+ "withoutRedirectCode": "ℹ Installing kernel package...\nReading package lists... Done\nBuilding dependency tree... Done\nReading state information... Done\nThe following NEW packages will be installed:\n proxmox-kernel-6.5\n0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.\nNeed to get 12.5 MB of archives.\nAfter this operation, 47.2 MB of additional disk space will be used.\nGet:1 http://download.proxmox.com/debian/pve trixie/pve-no-subscription amd64 ...\n... [200+ more lines of dpkg output] ...\n✓ Kernel installed.",
+ "withRedirectIntro": "Con redirect — quale sia la stessa operazione quando il rumore viene inviato altrove:",
+ "withRedirectCode": "ℹ Installing kernel package...\n✓ Kernel installed.\nℹ Configuring kernel command line...\n✓ Configured.\nℹ Refreshing boot loader...\n✓ Boot loader updated.",
+ "twoPatternsIntro": "Due modelli tra cui scegliere:",
+ "discardLead": "Scarta l’output quando non serve: è la soluzione più semplice e rapida.",
+ "discardCode": "DEBIAN_FRONTEND=noninteractive apt-get install -y \"$package\" >/dev/null 2>&1",
+ "logLead": "Inviare l'output a un file di registro quando si può desiderare di ispezionare in seguito (debugging un'installazione fallita, controllando ciò che dpkg effettivamente fatto). Questo è il modello preferito per qualsiasi operazione apt:",
+ "logCode": "apt-get install -y \"$package\" >> \"$log_file\" 2>&1",
+ "referenceOutro": "Lo script scripts/global/update-pve9_2.sh è un'implementazione di riferimento — ogni chiamata apt-get invia l'output a un file di registro in modo che l'utente vede solo il flusso msg_info → msg_ok pulito, mentre il log su disco consente di ricostruire esattamente ciò che ha fatto apt se qualcosa va storto."
+ },
+ "dosAndDonts": {
+ "heading": "Cosa fare e cosa non fare",
+ "doHeading": "✅ Da fare",
+ "doBullets": [
+ "stop_spinner prima di un dialog in Fase 1 solo quando un girante msg_info è in esecuzione.",
+ "La fase 2 inizia con show_proxmenux_logo + msg_title + msg_ok per riepilogare i risultati della fase 1.",
+ "Utilizzare msg_ok per funzioni abilitate con successo, anche se è necessario un riavvio.",
+ "Utilizzare whiptail (non dialog) per qualsiasi prompt post-esecuzione che deve apparire in Fase 2.",
+ "Sempre includere un ramo “No” nelle finestre di dialogo di riavvio che avverte l’utente di non avviare la risorsa interessata fino al riavvio.",
+ "Limita la logica riservata alle VM verificando [[ -f \"/etc/pve/qemu-server/$'{'vmid'}'.conf\" ]]: controller e NVMe PCIe non possono essere assegnati a LXC con passthrough PCI.",
+ "Utilizzare ensure_repositories da utils-install-functions.sh invece di apt-get update incondizionato.",
+ "Utilizzare array paralleli in Fase 1 quando ogni elemento ha bisogno di finestre di dialogo multiple."
+ ],
+ "dontHeading": "❌ Da evitare",
+ "dontBullets": [
+ "Chiama dialog mentre uno spinner è attivo.",
+ "Saltare la fase 1 recap all'inizio della fase 2.",
+ "Chiama show_proxmenux_logo una seconda volta — cancella tutto Fase 2 ha stampato.",
+ "Utilizzare dialog in Fase 2 (usare whiptail per il raro caso inevitabile).",
+ "Usare il solo clear.",
+ "Avvolgere msg_title in linee vuote echo \"\" — include già spaziatura.",
+ "Utilizzare msg_warn per segnalare una funzione abilitata con successo: è un msg_ok.",
+ "Eseguire apt-get update incondizionato — utilizzare ensure_repositories."
+ ]
+ },
+ "submitting": {
+ "heading": "Inviare il tuo contributo",
+ "steps": [
+ "Crea un fork di MacRimi/ProxMenux su GitHub e clonalo.",
+ "Crea un ramo feature/* da develop (vedi Modello dei rami sopra).",
+ "Segui questa guida per qualsiasi script nuovo o modificato. Scrivi l'intestazione con il tuo nome; aggiungi la linea di sponsor opzionale se vuoi.",
+ "Prova lo script su una vera istanza Proxmox VE: fase 1 con tutti i rami dei dialoghi e fase 2 con ogni operazione e il ripristino pulito in caso di errore.",
+ "Apri una pull request verso develop con una descrizione chiara: cosa fa lo script, cosa è cambiato e su quale versione di Proxmox VE è stato testato.",
+ "Assicurati che il contributo rispetti il menu e propone l’aggiornamento. Se accetti, sostituisce i file e la configurazione dello strumento nell’installazione esistente, senza richiedere download manuali.",
+ "p2Rich": "Chi usa la versione stabile riceve aggiornamenti stabili; chi usa la beta riceve quelli beta. Quando viene pubblicata una versione stabile, la beta lo segnala alla successiva apertura del menu e propone il passaggio automatico. Consulta il journalctl -u proxmenux-monitor -n 50.",
+ "p2Rich": "Per i problemi di sicurezza, non pubblicare i dettagli. Segui la procedura di segnalazione responsabile nel dialog, curl, jq e git. Le traduzioni usano cataloghi JSON già generati; l’installazione non aggiunge all’host un ambiente virtuale per la traduzione.",
+ "item2Rich": "L'albero di script a /usr/local/share/proxmenux/.",
+ "item3Rich": "Il comando di avvio in /usr/local/bin/menu.",
+ "item4Rich": "Facoltativo: il servizio systemd di Monitor, proxmenux-monitor.service.",
+ "p2Rich": "ProxMenux non modifica la configurazione principale di Proxmox, a meno che tu non lo richieda esplicitamente da un menu dedicato. Per esempio, la riparazione della rete modifica /etc/network/interfaces, ma solo dopo la tua conferma e la creazione di un backup."
+ },
+ "q9": {
+ "question": "È sicuro usare ProxMenux in produzione?",
+ "bodyRich": "Sì. Poiché ProxMenux modifica i file principali di Proxmox solo su richiesta esplicita, può essere usato in produzione. Come per ogni automazione, provalo prima in un ambiente controllato e prepara i backup prima delle operazioni distruttive: aggiornamento da PVE 8 a 9, formattazione di dischi, eliminazione di VM e simili."
+ },
+ "q10": {
+ "question": "Come posso disinstallare ProxMenux?",
+ "p1Rich": "Da ProxMenux: Impostazioni → Disinstalla ProxMenux. La disinstallazione rimuove gli script, il comando di avvio e il servizio Monitor, oltre alle dipendenze selezionate se richiesto. Ripristina /root/.bashrc e /etc/motd dalle copie create all’installazione, se presenti.",
+ "p2Rich": "Procedura completa: curl | bash e può scaricare jq dalla sua release ufficiale su GitHub. Questo comportamento può attivare gli scanner euristici; il rapporto storico non costituisce una valutazione di ogni download futuro.",
+ "p2Rich": "ProxMenux è completamente open source e puoi esaminare lo script di installazione riga per riga: main."
+ },
+ {
+ "branch": "feature/*",
+ "purposeRich": "Ramos de curta duração por recurso, correção ou melhoria. Criado a partir de develop, fundiu-se novamente em develop através de um Pull Request após revisão."
+ }
+ ],
+ "calloutTitle": "O que isto significa para os utilizadores",
+ "calloutBody": "Usuários finais rastreando main recebem versões testadas. Usuários que querem os recursos mais recentes cedo — e não se importem com as bordas ásperas ocasionais — podem seguir o develop. Novos recursos sempre passam por develop primeiro; nada atinge main sem passar por esse ciclo."
+ },
+ "workflow": {
+ "heading": "Processo de pull request",
+ "intro": "Da ideia ao lançamento mesclado em cinco etapas:",
+ "step1Lead": "Criar um ramo de recursos de develop:",
+ "step1Code": "git clone https://github.com/MacRimi/ProxMenux.git\ncd ProxMenux\ngit checkout develop\ngit pull origin develop\ngit checkout -b feature/your-feature-name",
+ "step1Trail": "Use um nome de ramo descritivo: feature/zfs-arc-tuning, feature/fix-iommu-detection, feature/add-tailscale-script.",
+ "step2Lead": "Trabalhe nas suas alterações e empurre o branch:",
+ "step2Code": "# Make your changes, then:\ngit add scripts/...\ngit commit -m \"Add ZFS ARC tuning script\"\ngit push -u origin feature/your-feature-name",
+ "step3": "Abra um pedido de pull contra develop (não contra main). Na página de criação de GitHub PR, verifique novamente se o ramo base está definido como develop. Incluir na descrição: o que o script faz, o que ele muda, e em quais versões Proxmox VE você testou.",
+ "step4": "Após a revisão, as alterações são integradas em develop. Um responsável verifica o código, o cabeçalho e a interface em duas fases. Se pedir alterações, envie novos commits para o mesmo ramo: a PR atualiza-se automaticamente.",
+ "step5": "As versões estáveis passam de develop para main. No lançamento, main avança até develop por fast-forward e recebe uma etiqueta. A contribuição passa a integrar a próxima versão estável."
+ },
+ "scriptHeader": {
+ "heading": "Cabeçalho do programa — metadados e descrição",
+ "intro": "Cada script em ProxMenux abre com dois blocos de comentários adjacentes que juntos formam o cabeçalho. Eles são ambos necessários — juntos eles deixam qualquer leitor saber quem escreveu o script e o que ele faz, tudo sem abrir o próprio código.",
+ "bullets": [
+ "Bloco superior: metadados. Autor, ligações GitHub/de apoio opcionais, responsável, copyright, licença, versão e data de atualização. É também o reconhecimento dos colaboradores: num script novo, inclua o seu nome e, se quiser, a página GitHub e um perfil como Ko-fi, GitHub Sponsors ou Buy Me a Coffee.",
+ "Bloco inferior: descrição. Um parágrafo curto em inglês simples explica o script. É lido antes do código e deve bastar para compreender o objetivo, ações principais, recursos afetados e requisitos."
+ ],
+ "licenseCalloutTitle": "A linha de licença é fixa — GPL-3.0",
+ "licenseCalloutBody": "ProxMenux é publicado sob a Licença Pública Geral GNU v3.0. Cada script no projeto envia sob essa mesma licença; a linha License no cabeçalho é sempre a referência GPL-3.0 mostrada no exemplo abaixo — não é uma escolha por script. Ao contribuir com um script, você concorda em lançá-lo sob GPL-3.0, o que significa que qualquer um pode lê-lo, modificá-lo e redistribuí-lo (incluindo modificações), desde que o mantenha sob a mesma licença. O texto completo vive em GitHub e Sponsor são opcionais — deixe-as de fora se não quiser publicá-las. Tudo o resto é necessário.",
+ "whyCalloutTitle": "Por que isso importa?",
+ "whyCalloutBody": "A contribuição de código aberto é trabalho voluntário. Colocar o nome do contribuinte e (quando fornecido) o link do patrocinador diretamente na fonte dá às pessoas que constroem os scripts reconhecimento visível cada vez que alguém lê o código — sua autoria é preservada, não escondida sob “o projeto”. O bloco de descrição importa por uma razão diferente: é a primeira coisa que um futuro mantenedor ou usuário curioso lê, e uma descrição clara é muitas vezes a diferença entre um script que as pessoas confiam e uma que elas evitam."
+ },
+ "structure": {
+ "heading": "Estrutura do projecto",
+ "intro": "Onde cada tipo de script vive no repositório:",
+ "treeCode": "scripts/\n├── menus/ # Top-level menu scripts (entry points)\n├── storage/ # Disk, storage and passthrough scripts\n├── share/ # NFS, Samba, local share scripts\n├── vm/ # VM creation and configuration scripts\n├── gpu_tpu/ # GPU / TPU passthrough scripts\n├── post_install/ # Post-install automation scripts\n├── backup_restore/ # Backup and restore scripts\n├── utilities/ # System utility scripts\n├── global/ # Shared helper libraries (sourced by other scripts)\n├── utils.sh # Shared utility functions and message helpers\n└── help_info_menu.sh # Interactive help and command reference",
+ "outro": "Cada script carrega utils.sh no arranque através de source para obter funções de mensagens, indicador de espera, cores e sistema de tradução. As bibliotecas partilhadas em scripts/global/ são carregadas explicitamente pelos scripts que delas precisam."
+ },
+ "twoPhase": {
+ "heading": "A política de design de IU em duas fases",
+ "intro": "É a convenção mais importante do ProxMenux e a que mais frequentemente leva a pedidos de correção nas PR. Cada script divide-se em exatamente duas fases:",
+ "headerPhase": "Fase",
+ "headerPurpose": "Finalidade",
+ "headerScreen": "Estado da tela",
+ "rows": [
+ {
+ "phaseRich": "Fase 1 — Selecção",
+ "purposeRich": "Recolha todas as decisões do utilizador. Executar todos os trabalhos preparatórios necessários (sondas, sondagens, verificações).",
+ "screenRich": "Janelas dialog. Se uma verificação entre dois menus demorar mais de um ou dois segundos, mostre um indicador msg_info para sinalizar que o script não bloqueou, e chame stop_spinner imediatamente antes do próximo diálogo."
+ },
+ {
+ "phaseRich": "Fase 2 — Execução",
+ "purposeRich": "Executar todas as operações. Mostra o histórico de progresso completo acumulado na tela.",
+ "screenRich": "Mensagens visíveis msg_info / msg_ok; nunca dialog."
+ }
+ ],
+ "principle": "O princípio: colha tudo primeiro, depois executa tudo. O usuário vê um menu de diálogo limpo (Fase 1), em seguida, uma visão de execução de log-style limpo (Fase 2). Nenhuma mistura — nenhuma janela que apareça no meio da execução, nenhum ruído de progresso durante a selecção.",
+ "phase1Heading": "Fase 1 — padrão típico",
+ "phase1Code": "# Silent preparatory work between dialogs\nmsg_info \"$(translate \"Checking disk assignments...\")\"\nASSIGNED_TO=$(check_assignments \"$DISK\")\nstop_spinner # ← clears line silently, result saved in variable\n\n# Next dialog can now use ASSIGNED_TO\nif [ -n \"$ASSIGNED_TO\" ]; then\n dialog --yesno \"$(translate \"Disk already assigned. Continue?\")\" $UI_YESNO_H $UI_YESNO_W\nfi\n\n# Collect multiple decisions per item with parallel arrays\ndeclare -a DISK_LIST=()\ndeclare -a DISK_FORMAT_TYPES=()\ndeclare -a DISK_MOUNT_POINTS=()\nfor DISK in $SELECTED; do\n msg_info \"$(translate \"Analyzing disk...\")\"\n CURRENT_FS=$(lsblk -no FSTYPE \"$DISK\" | xargs)\n stop_spinner\n\n FORMAT=$(dialog --backtitle \"$BACKTITLE\" \\\n --title \"$(translate \"Select Filesystem\")\" \\\n --menu \"...\" $UI_SHORT_MENU_H $UI_SHORT_MENU_W $UI_SHORT_MENU_LIST_H \\\n \"ext4\" \"...\" \"xfs\" \"...\" \"btrfs\" \"...\" \\\n 2>&1 >/dev/tty)\n [ -z \"$FORMAT\" ] && continue\n\n DISK_LIST+=(\"$DISK\")\n DISK_FORMAT_TYPES+=(\"$FORMAT\")\ndone",
+ "phase1RulesIntro": "Regras para fase 1:",
+ "phase1Rules": [
+ "Se estiver ativo um indicador msg_info e precisar de abrir um menu dialog ou whiptail, chame primeiro stop_spinner: o indicador não pode coexistir com a sobreposição das ferramentas. Se nenhum estiver ativo, a chamada não é necessária.",
+ "Use show_proxmenux_logo + msg_title + msg_info quando você precisa dar ao usuário contexto visual para uma operação de longa duração em fase 1 (por exemplo, uma sonda que leva 5+ segundos). A função inclui uma tela limpa, então não chame clear antes.",
+ "Não chame o show_proxmenux_logo entre menus de diálogo onde não há nada para exibir — limpar a tela para um terminal vazio é apenas ruído visual.",
+ "Armazene todas as decisões e resultados de sonda em variáveis ou arrays paralelos. A recapitulação visível ocorre no início da Fase 2, não na Fase 1."
+ ],
+ "phase2Heading": "Fase 2 — padrão típico",
+ "phase2Code": "# ── PHASE 2 — EXECUTION ─────────────────────────────\nshow_proxmenux_logo\nmsg_title \"$(translate \"My Script Title\")\"\n\n# Recap Phase 1 preparatory results — show what was already done\nmsg_ok \"$(translate \"CT $CTID selected.\")\"\nmsg_ok \"$(translate \"Repositories verified.\")\"\nmsg_ok \"$(translate \"Disks to process: ${#DISK_LIST[@]}\")\"\n\n# Now execute operations\nfor i in \"${!DISK_LIST[@]}\"; do\n DISK=\"${DISK_LIST[$i]}\"\n FORMAT=\"${DISK_FORMAT_TYPES[$i]}\"\n\n msg_info \"$(translate \"Formatting\") $DISK $(translate \"as\") $FORMAT...\"\n mkfs.\"$FORMAT\" \"$DISK\" >/dev/null 2>&1\n msg_ok \"$(translate \"Formatted.\")\"\ndone\n\nmsg_ok \"$(translate \"Completed. ${#DISK_LIST[@]} disk(s) processed.\")\"\nmsg_success \"$(translate \"Press Enter to return to menu...\")\"\nread -r",
+ "phase2Rules": "Regras para a fase 2: comece com show_proxmenux_logo + msg_title e resuma de imediato a fase 1 em linhas msg_ok. Não volte a chamar show_proxmenux_logo, pois apagaria o progresso acumulado. Não utilize dialog; se uma decisão durante a execução for inevitável, utilize whiptail como na secção seguinte."
+ },
+ "dialogVsWhiptail": {
+ "headingRich": "Quando usar dialog vs whiptail",
+ "intro": "Ambas as ferramentas desenham interfaces de usuário de modo texto, mas elas se comportam de forma muito diferente na tela — e ProxMenux as usa em duas fases distintas por uma razão.",
+ "headerTool": "Ferramenta",
+ "headerWhen": "Quando usá-lo",
+ "headerEffect": "Efeito no ecrã",
+ "rows": [
+ {
+ "toolRich": "dialog",
+ "whenRich": "Sempre em fase 1. Cada seleção interativa — escolhendo um VM, um disco, um sistema de arquivos, confirmando uma ação — usa dialog. Esta é a ferramenta padrão de UI do ProxMenux.",
+ "effectRich": "Assume o terminal: limpa a tela, desenha sua sobreposição, e ao fechar retorna o terminal ao seu estado anterior. Tudo bem na fase 1 porque nada de útil está mostrando ainda."
+ },
+ {
+ "toolRich": "whiptail",
+ "whenRich": "Apenas na Fase 2, somente quando inevitável. O caso típico é um prompt de reinicialização no final da execução. Não procure o whiptail para pedir “continuar?” no meio da execução — essa decisão deveria ter sido tomada na Fase 1.",
+ "effectRich": "Sobreposição mais leve que não limpa o contexto do terminal. O histórico msg_ok/msg_info da fase 2 permanece visível atrás do diálogo. É por isso a escolha indicada quando o progresso já está no ecrã."
+ }
+ ],
+ "calloutTitle": "Por que a divisão importa",
+ "calloutBody": "Se você chamar dialog no meio da fase 2, cada linha msg_ok que o usuário tem assistido desaparece. Limpas o rasto da auditoria. whiptail evita isso. Então a regra não é arbitrária — é sobre preservar a visão do usuário sobre o que o script tem feito até agora.",
+ "rebootHeading": "Pedido de reinício: o caso típico de whiptail na fase 2",
+ "rebootIntro": "Quando um script termina e uma reinicialização pode ser necessária (por exemplo: IOMMU habilitado, parâmetros do kernel alterados), o prompt no final da Fase 2 usa whiptail. Sempre inclua um branch “Não” que avisa o usuário para não usar o recurso afetado até que ele reinicie:",
+ "rebootCode": "if [[ \"$HOST_REBOOT_REQUIRED\" == \"yes\" ]]; then\n echo \"\"\n if whiptail --title \"$(translate \"Reboot Required\")\" --yesno \\\n \"\\n$(translate \"A host reboot is required before starting the VM. Reboot now?\")\" \\\n 13 78; then\n msg_warn \"$(translate \"Rebooting the system...\")\"\n reboot\n else\n echo \"\"\n msg_info2 \"$(translate \"Do not start the VM until the system has been rebooted.\")\"\n fi\nfi\n\nmsg_success \"$(translate \"Press Enter to return to menu...\")\"\nread -r"
+ },
+ "messageFunctions": {
+ "heading": "Referência das funções da mensagem",
+ "intro": "Todos definidos em utils.sh. Use-os como padrão para qualquer saída visível pelo usuário — visual consistente entre scripts é o ponto principal. Se seu script precisar de uma nova função que não se encaixe no conjunto existente (um novo nível de gravidade, um novo auxiliar de layout, etc.), proponha-o em seu pedido de pull — ele será revisado e adicionado ao utils.sh se for amplamente útil.",
+ "headerFunction": "Função",
+ "headerWhen": "Quando utilizar",
+ "headerSpinner": "Indicador de progresso",
+ "rows": [
+ {
+ "function": "msg_info \"text\"",
+ "whenRich": "Operação em curso.",
+ "spinner": "Inicia"
+ },
+ {
+ "function": "stop_spinner",
+ "whenRich": "Fim dos trabalhos preparatórios silenciosos na fase 1 — mata spinner, limpa a linha.",
+ "spinner": "Para"
+ },
+ {
+ "function": "msg_ok \"text\"",
+ "whenRich": "Operação concluída. Utilize também para uma funcionalidade ativada, mesmo que ainda seja necessário reiniciar.",
+ "spinner": "Para"
+ },
+ {
+ "function": "msg_warn \"text\"",
+ "whenRich": "Aviso real ou estado degradado.",
+ "spinner": "Para"
+ },
+ {
+ "function": "msg_error \"text\"",
+ "whenRich": "Erro fatal.",
+ "spinner": "Para"
+ },
+ {
+ "function": "msg_info2 \"text\"",
+ "whenRich": "Informação sem bloqueio, numa linha ciano.",
+ "spinner": "Para"
+ },
+ {
+ "function": "msg_success \"text\"",
+ "whenRich": "Final “Pressione Enter para retornar” no final da fase 2.",
+ "spinner": "Para"
+ },
+ {
+ "function": "msg_title \"text\"",
+ "whenRich": "Título negrito com espaçamento embutido. Utilizado no início da fase 2.",
+ "spinner": "—"
+ },
+ {
+ "function": "show_proxmenux_logo",
+ "whenRich": "Limpa o ecrã, mostra o logótipo. Chamado uma vez apenas no início da Fase 2.",
+ "spinner": "—"
+ }
+ ]
+ },
+ "dialogConventions": {
+ "heading": "convenções de diálogo",
+ "bullets": [
+ "Passe sempre --backtitle \"$BACKTITLE\" para cada chamada dialog e whiptail. $BACKTITLE é sempre \"ProxMenux\" — definido uma vez no cabeçalho do script e nunca substituído. O usuário deve sempre ver o nome do projeto como o contexto de enquadramento, nunca o próprio título do script.",
+ "Enrole sempre títulos e mensagens com $(translate \"...\").",
+ "Sempre redirecionar saída dialog com 2>&1 >/dev/tty - o stdout capturado torna-se a seleção do usuário, enquanto o diálogo em si desenha no terminal.",
+ "Use as variáveis de dimensão padrão de UI ($UI_MENU_H, $UI_MSG_W, etc.) para dimensionamento consistente entre scripts.",
+ "Verifique sempre escolhas vazias ou canceladas e trate-as corretamente."
+ ],
+ "exampleIntro": "Exemplo completo: criar um menu de seleção de VM e tratar o cancelamento.",
+ "exampleCode": "# 1) Build the list of VMs as alternating \"ID NAME\" pairs.\n# dialog --menu expects this exact shape: tag1 description1 tag2 description2 ...\nVM_LIST=\"\"\nfor vmid in $(qm list | awk 'NR>1 {print $1}'); do\n vm_name=$(qm config \"$vmid\" | awk -F': ' '/^name:/ {print $2}')\n VM_LIST=\"$VM_LIST $vmid \\\"$vm_name\\\"\"\ndone\n\n# 2) Show the dialog. Captured stdout is the user's selection (the VMID).\nVMID=$(eval \"dialog --backtitle \\\"\\$BACKTITLE\\\" \\\n --title \\\"\\$(translate \\\"Select VM\\\")\\\" \\\n --menu \\\"\\$(translate \\\"Choose a VM from the list:\\\")\\\" \\\n \\$UI_MENU_H \\$UI_MENU_W \\$UI_MENU_LIST_H \\\n $VM_LIST \\\n 2>&1 >/dev/tty\")\n\n# 3) Empty result means the user pressed Cancel or Esc — exit silently.\nif [ -z \"$VMID\" ]; then\n exit 0\nfi\n\n# 4) Continue with the rest of Phase 1, knowing VMID is now set.\necho \"User selected VMID=$VMID\""
+ },
+ "translation": {
+ "heading": "Política de tradução",
+ "intro": "Todas as strings visíveis ao usuário devem ser enroladas com a função translate. ProxMenux traduz-os automaticamente em todas as línguas suportadas — você escreve inglês, o usuário lê sua língua nativa.",
+ "code": "msg_ok \"$(translate \"Operation completed successfully.\")\"\nmsg_error \"$(translate \"Failed to start container\") $CTID.\"\ndialog --title \"$(translate \"Select Storage\")\" ...",
+ "bullets": [
+ "Escreva strings em inglês — a tradução é tratada automaticamente pela compilação.",
+ "Mantenha as cadeias de texto concisas. Evite, se possível, variáveis dentro de frases longas.",
+ "Não traduza nomes de variáveis, caminhos ou identificadores técnicos."
+ ]
+ },
+ "variableStyle": {
+ "heading": "Convenções de variáveis e estilo",
+ "bullets": [
+ "Usar UPPER_CASE para variáveis de nível de script.",
+ "Use lower_case para variáveis de função local (declare com local).",
+ "Coloque todas as expansões de variáveis entre aspas: \"$VAR\", não $VAR.",
+ "Usar [[ ]] para condicionantes, não [ ] (exceto onde POSIX é necessário).",
+ "show_proxmenux_logo é a forma prevista de limpar o ecrã: limpa-o e mostra o logótipo do projeto para manter o contexto visual. Chame-o uma vez no início da fase 2, e opcionalmente antes de uma espera longa na fase 1."
+ ],
+ "standardNamesIntro": "Nomes de variáveis padrão em todo o projeto:",
+ "standardNamesCode": "CTID # container ID\nVMID # virtual machine ID\nDISK # device path (e.g. /dev/sdb)\nPARTITION # partition path (e.g. /dev/sdb1)\nSTORAGE # Proxmox storage name\nMOUNT_POINT # filesystem mount path",
+ "redirectHeading": "Redirecionando a saída da ferramenta durante a fase 2",
+ "redirectIntro": "A fase 2 mostra um registo de linhas msg_info → msg_ok. Se uma ferramenta chamada, como apt, mkfs, qm, pct ou dd, escrever em stdout/stderr, a sua saída desloca as mensagens e confunde o ecrã. O utilizador deixa de distinguir o progresso do script dos detalhes da ferramenta.",
+ "withoutRedirectIntro": "Sem redirecionar — o que o usuário vê se você não lidar com o ruído:",
+ "withoutRedirectCode": "ℹ Installing kernel package...\nReading package lists... Done\nBuilding dependency tree... Done\nReading state information... Done\nThe following NEW packages will be installed:\n proxmox-kernel-6.5\n0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.\nNeed to get 12.5 MB of archives.\nAfter this operation, 47.2 MB of additional disk space will be used.\nGet:1 http://download.proxmox.com/debian/pve trixie/pve-no-subscription amd64 ...\n... [200+ more lines of dpkg output] ...\n✓ Kernel installed.",
+ "withRedirectIntro": "Com redirecionamento — como é a mesma operação quando o ruído é enviado para outro lugar:",
+ "withRedirectCode": "ℹ Installing kernel package...\n✓ Kernel installed.\nℹ Configuring kernel command line...\n✓ Configured.\nℹ Refreshing boot loader...\n✓ Boot loader updated.",
+ "twoPatternsIntro": "Dois padrões para escolher:",
+ "discardLead": "Descarte a saída quando você não precisar — mais rápido, mais simples:",
+ "discardCode": "DEBIAN_FRONTEND=noninteractive apt-get install -y \"$package\" >/dev/null 2>&1",
+ "logLead": "Envie a saída para um arquivo de log quando você quiser inspeccioná-lo mais tarde (depurando uma instalação falhada, verificando o que o dpkg realmente fez). Este é o padrão preferido para qualquer operação apt:",
+ "logCode": "apt-get install -y \"$package\" >> \"$log_file\" 2>&1",
+ "referenceOutro": "O script scripts/global/update-pve9_2.sh é uma implementação de referência — cada chamada apt-get envia saída para um arquivo de log para que o usuário apenas veja o fluxo limpo msg_info → msg_ok, enquanto o log no disco permite reconstruir exatamente o que o apt fez se algo der errado."
+ },
+ "dosAndDonts": {
+ "heading": "Fazer e Não Fazer",
+ "doHeading": "✅ Fazer",
+ "doBullets": [
+ "stop_spinner antes de um dialog em fase 1 somente quando um spinner msg_info está em execução atualmente.",
+ "Fase 2 começa com show_proxmenux_logo + msg_title + msg_ok recap dos resultados da Fase 1.",
+ "Use msg_ok para recursos habilitados com sucesso — mesmo que seja necessário reiniciar.",
+ "Use whiptail (não dialog) para qualquer prompt pós-execução que deve aparecer na Fase 2.",
+ "Sempre inclua um branch \"Não\" nas janelas de reinicialização que alerta o usuário para não iniciar o recurso afetado até reiniciar.",
+ "Limite a lógica exclusiva de VM verificando [[ -f \"/etc/pve/qemu-server/$'{'vmid'}'.conf\" ]]: controladores e NVMe PCIe não podem ser atribuídos a LXC por passthrough PCI.",
+ "Utilizar ensure_repositories de utils-install-functions.sh em vez de apt-get update incondicional.",
+ "Use arrays paralelos na Fase 1 quando cada item precisar de múltiplas janelas."
+ ],
+ "dontHeading": "❌ Não fazer",
+ "dontBullets": [
+ "Chame dialog enquanto um spinner está ativo.",
+ "Pular a fase 1 recap no início da fase 2.",
+ "Chame o show_proxmenux_logo pela segunda vez — ele apaga tudo que a Fase 2 imprimiu.",
+ "Utilizar dialog na Fase 2 (utilizar whiptail para o caso raro inevitável).",
+ "Utilizar apenas clear.",
+ "Enrole msg_title em linhas em branco echo \"\" — já inclui espaçamento.",
+ "Use o msg_warn para relatar um recurso habilitado com sucesso — que é um msg_ok.",
+ "Executar apt-get update incondicional — utilizar ensure_repositories."
+ ]
+ },
+ "submitting": {
+ "heading": "Submissão da sua contribuição",
+ "steps": [
+ "Crie um fork de MacRimi/ProxMenux no GitHub e clone esse fork.",
+ "Crie um ramo feature/* a partir de develop (veja Modelo de ramos acima).",
+ "Siga este guia para quaisquer scripts novos ou modificados. Escreva o cabeçalho com o seu nome; adicione a linha de patrocinador opcional se quiser.",
+ "Teste o script numa instância real do Proxmox VE: fase 1 com todos os ramos dos diálogos e fase 2 com cada operação e a reversão correta em caso de erro.",
+ "Abra um Pull Request contra develop com uma descrição clara: o que o script faz, o que mudou, em que versão Proxmox VE foi testado.",
+ "Certifique-se de que sua contribuição respeite o menu e propõe a atualização. Se aceitar, os ficheiros e a configuração da ferramenta são substituídos na instalação existente, sem downloads manuais.",
+ "p2Rich": "Os utilizadores da versão estável recebem atualizações estáveis; os da beta recebem atualizações beta. Quando é publicada uma versão estável, a beta avisa na próxima abertura do menu e propõe a mudança automática. Consulte o journalctl -u proxmenux-monitor -n 50.",
+ "p2Rich": "No caso de problemas de segurança, não publique os detalhes. Siga o procedimento de divulgação responsável no dialog, curl, jq e git. As traduções usam catálogos JSON pré-gerados; o instalador não adiciona ao anfitrião um ambiente virtual de tradução.",
+ "item2Rich": "A árvore de scripts em /usr/local/share/proxmenux/.",
+ "item3Rich": "O comando de arranque em /usr/local/bin/menu.",
+ "item4Rich": "Opcional: o serviço systemd do Monitor, proxmenux-monitor.service.",
+ "p2Rich": "O ProxMenux não altera a configuração principal do Proxmox, salvo se o pedir explicitamente num menu específico. Por exemplo, a reparação de rede edita /etc/network/interfaces, mas apenas após a sua confirmação e a criação de uma cópia de segurança."
+ },
+ "q9": {
+ "question": "É seguro usar ProxMenux na produção?",
+ "bodyRich": "Sim. Como o ProxMenux só altera os ficheiros principais do Proxmox quando solicitado explicitamente, pode ser usado em ambientes de produção. Como em qualquer automação, teste primeiro num ambiente controlado e tenha cópias de segurança antes de operações destrutivas: atualização do PVE 8 para 9, formatação de discos, eliminação de VM, entre outras."
+ },
+ "q10": {
+ "question": "Como faço para desinstalar ProxMenux?",
+ "p1Rich": "No ProxMenux: Definições → Desinstalar ProxMenux. A desinstalação remove os scripts, o comando de arranque e o serviço Monitor, além das dependências selecionadas, se assim escolher. Restaura /root/.bashrc e /etc/motd a partir das cópias criadas na instalação, caso existam.",
+ "p2Rich": "Passo a passo completo: curl | bash e pode descarregar jq da sua versão oficial no GitHub. Este comportamento pode ativar análises heurísticas; esse relatório histórico não avalia todos os downloads futuros.",
+ "p2Rich": "O ProxMenux é totalmente de código aberto e pode analisar o script de instalação linha a linha: main."
+ },
+ {
+ "branch": "feature/*",
+ "purposeRich": "Krátkodobé vetvy pre funkciu, opravu alebo vylepšenie. Vzniknú z develop a po kontrole sa cez pull request zlúčia späť do develop."
+ }
+ ],
+ "calloutTitle": "Čo to znamená pre užívateľov",
+ "calloutBody": "Používatelia vetvy main dostávajú otestované vydania. Kto chce nové funkcie skôr a znesie občasné nedostatky, môže sledovať develop. Nové funkcie vždy najprv prejdú cez develop; bez tohto cyklu sa do main nedostanú."
+ },
+ "workflow": {
+ "heading": "Postup pull requestu",
+ "intro": "Od nápadu po začlenenie do vydania v piatich krokoch:",
+ "step1Lead": "Vytvorte vetvu pre funkciu z develop:",
+ "step1Code": "git clone https://github.com/MacRimi/ProxMenux.git\ncd ProxMenux\ngit checkout develop\ngit pull origin develop\ngit checkout -b feature/your-feature-name",
+ "step1Trail": "Použite výstižný názov vetvy: feature/zfs-arc-tuning, feature/fix-iommu-detection, feature/add-tailscale-script.",
+ "step2Lead": "Pracujte na svojich zmenách a posuňte vetvu:",
+ "step2Code": "# Make your changes, then:\ngit add scripts/...\ngit commit -m \"Add ZFS ARC tuning script\"\ngit push -u origin feature/your-feature-name",
+ "step3": "Otvorte pull request do develop, nie do main. Na GitHube overte, že základná vetva je develop. Opíšte účel skriptu, jeho zmeny a verzie Proxmox VE, na ktorých ste ho testovali.",
+ "step4": "Po kontrole sa zmeny zlúčia do develop. Správca skontroluje kvalitu kódu, hlavičky a dvojfázové rozhranie. Ak vyžiada úpravy, odošlite ďalšie commity do rovnakej vetvy; PR sa aktualizuje automaticky.",
+ "step5": "Stabilné vydania sa prenášajú z develop do main. Pri vydaní sa main posunie na develop pomocou fast-forward a označí sa tagom. Váš príspevok sa stane súčasťou ďalšej stabilnej verzie."
+ },
+ "scriptHeader": {
+ "heading": "Hlavička skriptu: metadáta a popis",
+ "intro": "Každý skript ProxMenux začína dvoma susednými blokmi komentárov, ktoré tvoria hlavičku. Oba sú povinné: prezradia autora a účel bez potreby čítať samotný kód.",
+ "bullets": [
+ "Horný blok: metadáta. Autor, voliteľné odkazy na GitHub a podporu, správca, autorské práva, licencia, verzia a dátum aktualizácie. Tu prebieha aj uznanie prispievateľov: pri novom skripte uveďte svoje meno a voliteľne stránku GitHub a profil podpory, napríklad Ko-fi, GitHub Sponsors alebo Buy Me a Coffee.",
+ "Dolný blok: popis. Krátky odsek v jednoduchej angličtine vysvetľuje skript. Číta sa pred kódom a musí sám objasniť účel, hlavné akcie, dotknuté zdroje a predpoklady."
+ ],
+ "licenseCalloutTitle": "Licenčná linka je pevne stanovená GPL-3.0",
+ "licenseCalloutBody": "ProxMenux je vydaný pod GNU General Public License v3.0. Všetky skripty používajú rovnakú licenciu; riadok License v hlavičke musí obsahovať odkaz GPL-3.0 z príkladu nižšie. Nie je to voľba pre jednotlivý skript. Prispením súhlasíte s vydaním pod GPL-3.0: každý môže skript čítať, upraviť a ďalej šíriť vrátane zmien pri zachovaní rovnakej licencie. Úplné znenie: GitHub a Sponsor sú voliteľné – vynechajte ich, ak ich nechcete zverejniť. Všetko ostatné sa vyžaduje.",
+ "whyCalloutTitle": "Prečo na tom záleží",
+ "whyCalloutBody": "Prispievanie do otvoreného softvéru je dobrovoľná práca. Meno a prípadný odkaz na podporu priamo v zdrojovom kóde zviditeľňujú autorstvo pri každom čítaní; nestratí sa za názvom projektu. Popis má iný význam: je prvou vecou, ktorú číta budúci správca alebo zvedavý používateľ. Jasný popis často rozhoduje, či skriptu dôverujú alebo sa mu vyhnú."
+ },
+ "structure": {
+ "heading": "Štruktúra projektu",
+ "intro": "Kde sa v repozitári nachádzajú jednotlivé druhy skriptov:",
+ "treeCode": "scripts/\n├── menus/ # Top-level menu scripts (entry points)\n├── storage/ # Disk, storage and passthrough scripts\n├── share/ # NFS, Samba, local share scripts\n├── vm/ # VM creation and configuration scripts\n├── gpu_tpu/ # GPU / TPU passthrough scripts\n├── post_install/ # Post-install automation scripts\n├── backup_restore/ # Backup and restore scripts\n├── utilities/ # System utility scripts\n├── global/ # Shared helper libraries (sourced by other scripts)\n├── utils.sh # Shared utility functions and message helpers\n└── help_info_menu.sh # Interactive help and command reference",
+ "outro": "Každý skript pri štarte načíta utils.sh pomocou source, aby získal funkcie správ, indikátor priebehu, farby a prekladový systém. Zdieľané pomocné knižnice v scripts/global/ výslovne načítavajú skripty, ktoré ich potrebujú."
+ },
+ "twoPhase": {
+ "heading": "Dvojfázová politika návrhu UI",
+ "intro": "Ide o najdôležitejšie pravidlo ProxMenux a najčastejší dôvod požiadaviek na úpravu PR. Každý skript je rozdelený na presne dve fázy:",
+ "headerPhase": "Fáza",
+ "headerPurpose": "Účel",
+ "headerScreen": "Stav obrazovky",
+ "rows": [
+ {
+ "phaseRich": "Fáza 1: výber",
+ "purposeRich": "Zbierajte každé rozhodnutie užívateľa. Spustite všetky potrebné prípravné práce (sondy, skeny, kontroly).",
+ "screenRich": "Prekrytia dialog. Ak kontrola medzi ponukami trvá viac ako sekundu či dve, zobrazte indikátor msg_info, aby používateľ vedel, že skript nezamrzol. Tesne pred ďalším dialógom zavolajte stop_spinner."
+ },
+ {
+ "phaseRich": "Fáza 2: vykonanie",
+ "purposeRich": "Vykonajte všetky operácie. Na obrazovke postupne zobrazujte úplnú históriu priebehu.",
+ "screenRich": "Viditeľné hlásenia msg_info / msg_ok; nikdy nie dialog."
+ }
+ ],
+ "principle": "Zásada: najprv zhromaždiť všetky voľby, potom všetko vykonať. Používateľ najprv pracuje s prehľadným dialógovým menu (fáza 1) a potom sleduje vykonávanie vo forme záznamu (fáza 2). Fázy sa nemiešajú: počas vykonávania sa neotvárajú dialógy a počas výberu sa nevypisuje priebeh.",
+ "phase1Heading": "Fáza 1: typický vzor",
+ "phase1Code": "# Silent preparatory work between dialogs\nmsg_info \"$(translate \"Checking disk assignments...\")\"\nASSIGNED_TO=$(check_assignments \"$DISK\")\nstop_spinner # ← clears line silently, result saved in variable\n\n# Next dialog can now use ASSIGNED_TO\nif [ -n \"$ASSIGNED_TO\" ]; then\n dialog --yesno \"$(translate \"Disk already assigned. Continue?\")\" $UI_YESNO_H $UI_YESNO_W\nfi\n\n# Collect multiple decisions per item with parallel arrays\ndeclare -a DISK_LIST=()\ndeclare -a DISK_FORMAT_TYPES=()\ndeclare -a DISK_MOUNT_POINTS=()\nfor DISK in $SELECTED; do\n msg_info \"$(translate \"Analyzing disk...\")\"\n CURRENT_FS=$(lsblk -no FSTYPE \"$DISK\" | xargs)\n stop_spinner\n\n FORMAT=$(dialog --backtitle \"$BACKTITLE\" \\\n --title \"$(translate \"Select Filesystem\")\" \\\n --menu \"...\" $UI_SHORT_MENU_H $UI_SHORT_MENU_W $UI_SHORT_MENU_LIST_H \\\n \"ext4\" \"...\" \"xfs\" \"...\" \"btrfs\" \"...\" \\\n 2>&1 >/dev/tty)\n [ -z \"$FORMAT\" ] && continue\n\n DISK_LIST+=(\"$DISK\")\n DISK_FORMAT_TYPES+=(\"$FORMAT\")\ndone",
+ "phase1RulesIntro": "Pravidlá pre fázu 1:",
+ "phase1Rules": [
+ "Ak beží indikátor msg_info a potrebujete otvoriť ponuku dialog alebo whiptail, najprv zavolajte stop_spinner. Indikátor nemôže bežať súčasne s prekrytím týchto nástrojov. Ak indikátor nebeží, volanie nie je potrebné.",
+ "Použite show_proxmenux_logo + msg_title + msg_info na vizuálny kontext dlhej operácie vo fáze 1, napríklad kontroly trvajúcej päť sekúnd či viac. Funkcia už vyčistí obrazovku, preto pred ňou nevolajte clear.",
+ "Nevolajte show_proxmenux_logo medzi dialógovými menumi, kde nie je čo zobraziť, a vyčistenie obrazovky prázdneho terminálu je len vizuálny hluk.",
+ "Uložte všetky rozhodnutia a výsledky sondy v premenných alebo paralelných poliach. Viditeľné zhrnutie sa uskutoční na začiatku fázy 2, nie vo fáze 1."
+ ],
+ "phase2Heading": "Fáza 2: typický vzor",
+ "phase2Code": "# ── PHASE 2 — EXECUTION ─────────────────────────────\nshow_proxmenux_logo\nmsg_title \"$(translate \"My Script Title\")\"\n\n# Recap Phase 1 preparatory results — show what was already done\nmsg_ok \"$(translate \"CT $CTID selected.\")\"\nmsg_ok \"$(translate \"Repositories verified.\")\"\nmsg_ok \"$(translate \"Disks to process: ${#DISK_LIST[@]}\")\"\n\n# Now execute operations\nfor i in \"${!DISK_LIST[@]}\"; do\n DISK=\"${DISK_LIST[$i]}\"\n FORMAT=\"${DISK_FORMAT_TYPES[$i]}\"\n\n msg_info \"$(translate \"Formatting\") $DISK $(translate \"as\") $FORMAT...\"\n mkfs.\"$FORMAT\" \"$DISK\" >/dev/null 2>&1\n msg_ok \"$(translate \"Formatted.\")\"\ndone\n\nmsg_ok \"$(translate \"Completed. ${#DISK_LIST[@]} disk(s) processed.\")\"\nmsg_success \"$(translate \"Press Enter to return to menu...\")\"\nread -r",
+ "phase2Rules": "Pravidlá fázy 2: začnite s show_proxmenux_logo + msg_title a hneď zhrňte výsledky fázy 1 riadkami msg_ok. Už nevolajte show_proxmenux_logo, pretože by vymazalo nahromadený priebeh. Nevolajte dialog; pri nevyhnutnom rozhodnutí za behu použite whiptail podľa nasledujúcej časti."
+ },
+ "dialogVsWhiptail": {
+ "headingRich": "Kedy používať dialog vs whiptail",
+ "intro": "Oba nástroje vykresľujú textové používateľské rozhranie, ale na obrazovke sa správajú odlišne. ProxMenux ich preto používa v dvoch samostatných fázach.",
+ "headerTool": "Nástroj",
+ "headerWhen": "Kedy ju použiť",
+ "headerEffect": "Účinok na obrazovku",
+ "rows": [
+ {
+ "toolRich": "dialog",
+ "whenRich": "Vždy vo fáze 1. Každý interaktívny výber, napríklad VM, disk, súborový systém alebo potvrdenie akcie, používa dialog. Ide o predvolený nástroj rozhrania ProxMenux.",
+ "effectRich": "Preberá terminál: vyčistí obrazovku, kreslí jej prekrývanie a pri zatvorení vráti terminál do svojho predchádzajúceho stavu. Fáza 1, pretože zatiaľ nič užitočné neukazuje."
+ },
+ {
+ "toolRich": "whiptail",
+ "whenRich": "Iba vo fáze 2, iba ak je to nevyhnutné. Typickým prípadom je výzva na reštartovanie na konci vykonávania. Nesiahajte po whiptail, aby ste sa spýtali „pokračovať?“ uprostred vykonávania — toto rozhodnutie malo byť urobené vo fáze 1.",
+ "effectRich": "Ľahšie prekrytie, ktoré nevymaže kontext terminálu. Nahromadená história msg_ok/msg_info z fázy 2 zostane viditeľná za dialógom. Preto je vhodné, keď už obrazovka zobrazuje priebeh."
+ }
+ ],
+ "calloutTitle": "Prečo je rozdelenie dôležité",
+ "calloutBody": "Ak zavoláte dialog uprostred fázy 2, zmiznú všetky riadky msg_ok, ktoré používateľ dovtedy sledoval. Vymažete tým viditeľný záznam vykonaných krokov. whiptail tomu zabráni. Pravidlo teda nie je svojvoľné: zachováva používateľovi prehľad o tom, čo skript doteraz urobil.",
+ "rebootHeading": "Výzva na reštart: typické použitie whiptail vo fáze 2",
+ "rebootIntro": "Ak môže byť po skončení skriptu potrebný reštart, napríklad po zapnutí IOMMU alebo zmene parametrov jadra, výzva na konci fázy 2 používa whiptail. Vždy pridajte vetvu Nie, ktorá upozorní, aby používateľ nepoužíval dotknutý zdroj pred reštartom:",
+ "rebootCode": "if [[ \"$HOST_REBOOT_REQUIRED\" == \"yes\" ]]; then\n echo \"\"\n if whiptail --title \"$(translate \"Reboot Required\")\" --yesno \\\n \"\\n$(translate \"A host reboot is required before starting the VM. Reboot now?\")\" \\\n 13 78; then\n msg_warn \"$(translate \"Rebooting the system...\")\"\n reboot\n else\n echo \"\"\n msg_info2 \"$(translate \"Do not start the VM until the system has been rebooted.\")\"\n fi\nfi\n\nmsg_success \"$(translate \"Press Enter to return to menu...\")\"\nread -r"
+ },
+ "messageFunctions": {
+ "heading": "Prehľad funkcií správ",
+ "intro": "Všetky sú definované v utils.sh. Používajte ich pre výstup viditeľný používateľovi, aby skripty mali jednotný vzhľad. Ak potrebujete novú funkciu, napríklad úroveň závažnosti alebo pomocníka rozloženia, navrhnite ju v pull requeste. Po kontrole sa pridá do utils.sh, ak má širšie využitie.",
+ "headerFunction": "Funkcia",
+ "headerWhen": "Kedy používať",
+ "headerSpinner": "Indikátor priebehu",
+ "rows": [
+ {
+ "function": "msg_info \"text\"",
+ "whenRich": "Prebieha operácia.",
+ "spinner": "Spustí"
+ },
+ {
+ "function": "stop_spinner",
+ "whenRich": "Koniec tichej prípravnej práce vo fáze 1: zastaví indikátor a vyčistí riadok.",
+ "spinner": "Zastaví"
+ },
+ {
+ "function": "msg_ok \"text\"",
+ "whenRich": "Operácia bola úspešná. Použite aj pre zapnutú funkciu, hoci je ešte potrebný reštart.",
+ "spinner": "Zastaví"
+ },
+ {
+ "function": "msg_warn \"text\"",
+ "whenRich": "Skutočné varovanie alebo zhoršený stav.",
+ "spinner": "Zastaví"
+ },
+ {
+ "function": "msg_error \"text\"",
+ "whenRich": "Závažná chyba.",
+ "spinner": "Zastaví"
+ },
+ {
+ "function": "msg_info2 \"text\"",
+ "whenRich": "Neblokujúce odporúčanie, tyrkysový informačný riadok.",
+ "spinner": "Zastaví"
+ },
+ {
+ "function": "msg_success \"text\"",
+ "whenRich": "Záverečná výzva „Stlačte Enter pre návrat“ na konci fázy 2.",
+ "spinner": "Zastaví"
+ },
+ {
+ "function": "msg_title \"text\"",
+ "whenRich": "Tučný nadpis so zabudovanými rozostupmi. Používa sa na začiatku fázy 2.",
+ "spinner": "—"
+ },
+ {
+ "function": "show_proxmenux_logo",
+ "whenRich": "Vyčistí obrazovku a zobrazí logo. Na začiatku fázy 2 sa volá raz.",
+ "spinner": "—"
+ }
+ ]
+ },
+ "dialogConventions": {
+ "heading": "Pravidlá používania dialog",
+ "bullets": [
+ "Každému volaniu dialog a whiptail vždy odovzdajte --backtitle \"$BACKTITLE\". $BACKTITLE je vždy \"ProxMenux\", nastavené raz v hlavičke skriptu a nikdy neprepísané. Rámec rozhrania musí používateľovi ukazovať názov projektu, nie vlastný nadpis skriptu.",
+ "Vždy zabaľte titulky a správy s $(translate \"...\").",
+ "Vždy presmerujte dialog výstup pomocou 2>&1 >/dev/tty — zachytený stdout sa stane výberom používateľa, zatiaľ čo samotné dialógové okno sa kreslí na terminál.",
+ "Použite štandardné premenné rozmerov UI ($UI_MENU_H, $UI_MSG_W, atď.) pre konzistentnú veľkosť medzi skriptmi.",
+ "Vždy skontrolujte prázdne / zrušené výbery a zaobchádzajte s nimi elegantne."
+ ],
+ "exampleIntro": "Úplný príklad: vytvorenie ponuky na výber VM a spracovanie zrušenia.",
+ "exampleCode": "# 1) Build the list of VMs as alternating \"ID NAME\" pairs.\n# dialog --menu expects this exact shape: tag1 description1 tag2 description2 ...\nVM_LIST=\"\"\nfor vmid in $(qm list | awk 'NR>1 {print $1}'); do\n vm_name=$(qm config \"$vmid\" | awk -F': ' '/^name:/ {print $2}')\n VM_LIST=\"$VM_LIST $vmid \\\"$vm_name\\\"\"\ndone\n\n# 2) Show the dialog. Captured stdout is the user's selection (the VMID).\nVMID=$(eval \"dialog --backtitle \\\"\\$BACKTITLE\\\" \\\n --title \\\"\\$(translate \\\"Select VM\\\")\\\" \\\n --menu \\\"\\$(translate \\\"Choose a VM from the list:\\\")\\\" \\\n \\$UI_MENU_H \\$UI_MENU_W \\$UI_MENU_LIST_H \\\n $VM_LIST \\\n 2>&1 >/dev/tty\")\n\n# 3) Empty result means the user pressed Cancel or Esc — exit silently.\nif [ -z \"$VMID\" ]; then\n exit 0\nfi\n\n# 4) Continue with the rest of Phase 1, knowing VMID is now set.\necho \"User selected VMID=$VMID\""
+ },
+ "translation": {
+ "heading": "Politika prekladu",
+ "intro": "Všetky užívateľsky viditeľné reťazce musia byť zabalené s funkciou translate. ProxMenux ich automaticky prekladá do všetkých podporovaných jazykov, ktoré píšete anglicky, užívateľ číta ich rodný jazyk.",
+ "code": "msg_ok \"$(translate \"Operation completed successfully.\")\"\nmsg_error \"$(translate \"Failed to start container\") $CTID.\"\ndialog --title \"$(translate \"Select Storage\")\" ...",
+ "bullets": [
+ "Reťazce píšte po anglicky; preklad sa spracuje automaticky pri zostavení.",
+ "Udržujte stručnosť. Ak je to možné, nepoužívajte premenné vo vnútri dlhých viet.",
+ "Neprekladajte názvy premenných, cesty ani technické identifikátory."
+ ]
+ },
+ "variableStyle": {
+ "heading": "Pravidlá premenných a štýlu",
+ "bullets": [
+ "Pre premenné úrovne skriptov použite UPPER_CASE.",
+ "Pre lokálne funkčné premenné (vyhlásiť s local) použite lower_case.",
+ "Všetky rozvinutia premenných uzavrite do úvodzoviek: \"$VAR\", nie $VAR.",
+ "Použite [[ ]] pre podmienky, nie [ ] (s výnimkou prípadov, keď sa POSIX vyžaduje).",
+ "show_proxmenux_logo je správny spôsob vyčistenia obrazovky: vyčistí ju a zobrazí logo projektu pre vizuálny kontext. Zavolajte ho raz na začiatku fázy 2 a voliteľne pred dlhou prípravnou kontrolou s indikátorom vo fáze 1."
+ ],
+ "standardNamesIntro": "Štandardné názvy premenných v rámci projektu:",
+ "standardNamesCode": "CTID # container ID\nVMID # virtual machine ID\nDISK # device path (e.g. /dev/sdb)\nPARTITION # partition path (e.g. /dev/sdb1)\nSTORAGE # Proxmox storage name\nMOUNT_POINT # filesystem mount path",
+ "redirectHeading": "Presmerovanie výstupu nástroja počas fázy 2",
+ "redirectIntro": "Fáza 2 zobrazuje prehľadný záznam riadkov msg_info → msg_ok. Ak volaný nástroj, napríklad apt, mkfs, qm, pct alebo dd, zapisuje na stdout/stderr, posúva správy a naruší prehľad. Používateľ potom nerozozná priebeh skriptu od podrobného výstupu nástroja.",
+ "withoutRedirectIntro": "Bez presmerovania: čo používateľ vidí, ak neošetríte rušivý výstup.",
+ "withoutRedirectCode": "ℹ Installing kernel package...\nReading package lists... Done\nBuilding dependency tree... Done\nReading state information... Done\nThe following NEW packages will be installed:\n proxmox-kernel-6.5\n0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.\nNeed to get 12.5 MB of archives.\nAfter this operation, 47.2 MB of additional disk space will be used.\nGet:1 http://download.proxmox.com/debian/pve trixie/pve-no-subscription amd64 ...\n... [200+ more lines of dpkg output] ...\n✓ Kernel installed.",
+ "withRedirectIntro": "S presmerovaním — ako vyzerá tá istá operácia, keď je šum odoslaný inam:",
+ "withRedirectCode": "ℹ Installing kernel package...\n✓ Kernel installed.\nℹ Configuring kernel command line...\n✓ Configured.\nℹ Refreshing boot loader...\n✓ Boot loader updated.",
+ "twoPatternsIntro": "Dva vzory na výber:",
+ "discardLead": "Zahodiť výstup, ak ho nepotrebujete: najjednoduchšia a najrýchlejšia možnosť.",
+ "discardCode": "DEBIAN_FRONTEND=noninteractive apt-get install -y \"$package\" >/dev/null 2>&1",
+ "logLead": "Pošlite výstup do súboru denníka, keď ho budete chcieť neskôr skontrolovať (ladenie neúspešnej inštalácie, kontrola toho, čo dpkg skutočne urobil). Toto je preferovaný vzor pre akúkoľvek operáciu apt:",
+ "logCode": "apt-get install -y \"$package\" >> \"$log_file\" 2>&1",
+ "referenceOutro": "scripts/global/update-pve9_2.sh je referenčná implementácia: každé volanie apt-get zapisuje do súboru záznamu. Používateľ vidí iba prehľadný tok msg_info → msg_ok, no pri probléme možno zo súboru presne zistiť, čo apt vykonal."
+ },
+ "dosAndDonts": {
+ "heading": "Čo robiť a čomu sa vyhnúť",
+ "doHeading": "✅ Robiť",
+ "doBullets": [
+ "stop_spinner pred dialog vo fáze 1 iba vtedy, keď msg_info spinner beží.",
+ "Fáza 2 začína s show_proxmenux_logo + msg_title + msg_ok zhrnutie výsledkov fázy 1.",
+ "Pre úspešne zapnuté funkcie použite msg_ok, aj keď je potrebný reštart.",
+ "Používajte whiptail (nie dialog) pre akýkoľvek postup po vykonaní, ktorý sa musí objaviť vo fáze 2.",
+ "V dialógových oknách reštartu vždy zahrňte vetvu „Nie“, ktorá varuje používateľa, aby nespúšťal dotknutý zdroj, kým nebude reštartovaný.",
+ "Logiku určenú iba pre VM chráňte kontrolou [[ -f \"/etc/pve/qemu-server/$'{'vmid'}'.conf\" ]]: radiče a NVMe PCIe nemožno priradiť LXC cez PCI passthrough.",
+ "Použite ensure_repositories z utils-install-functions.sh namiesto bezpodmienečného apt-get update.",
+ "Používajte paralelné polia vo fáze 1, ak každá položka potrebuje viac dialógov."
+ ],
+ "dontHeading": "❌ Nerobiť",
+ "dontBullets": [
+ "Zavolajte dialog, kým je spinner aktívny.",
+ "Preskočiť zhrnutie fázy 1 na začiatku fázy 2.",
+ "Zavolať show_proxmenux_logo druhýkrát; vymaže všetko, čo fáza 2 vypísala.",
+ "Použite dialog vo fáze 2 (použite whiptail pre zriedkavý nevyhnutný prípad).",
+ "Použite holý clear.",
+ "Obaľovať msg_title prázdnymi riadkami echo \"\" — potrebné medzery už obsahuje.",
+ "Použiť msg_warn pre hlásenie úspešne zapnutej funkcie, ktorá je msg_ok.",
+ "Spustiť bezpodmienečné apt-get update; namiesto toho použite ensure_repositories."
+ ]
+ },
+ "submitting": {
+ "heading": "Predloženie príspevku",
+ "steps": [
+ "Vytvorte fork repozitára MacRimi/ProxMenux na GitHube a potom svoj fork naklonujte.",
+ "Vytvorte vetvu feature/* z develop (pozrite Model vetiev vyššie).",
+ "Postupujte podľa tejto príručky pre akékoľvek nové alebo zmenené skripty. Napíšte hlavičku s Vaším menom; pridajte voliteľný riadok sponzora, ak chcete.",
+ "Otestujte skript na skutočnej inštancii Proxmox VE: fázu 1 so všetkými vetvami dialógov a fázu 2 so všetkými operáciami aj čistým návratom pri chybe.",
+ "Otvorte pull request do vetvy develop s jasným opisom: čo skript robí, čo sa zmenilo a na ktorej verzii Proxmox VE bol otestovaný.",
+ "Uistite sa, že váš príspevok rešpektuje menu a ponúkne aktualizáciu. Ak ju prijmete, nahradí súbory a konfiguráciu nástroja v existujúcej inštalácii. Nemusíte nič sťahovať ručne.",
+ "p2Rich": "Používatelia stabilnej verzie dostávajú stabilné aktualizácie a používatelia beta verzie beta aktualizácie. Po vydaní stabilnej verzie na to beta upozorní pri ďalšom otvorení ponuky a ponúkne automatický prechod. Pozrite si journalctl -u proxmenux-monitor -n 50.",
+ "p2Rich": "V prípade problémov s bezpečnosťou ich prosím nezverejňujte. Prečítajte si dialog, curl, jq a git. Preklady používajú vopred vytvorené katalógy JSON; inštalátor na hostiteľa nepridáva virtuálne prostredie na preklad.",
+ "item2Rich": "Adresárový strom skriptov v /usr/local/share/proxmenux/.",
+ "item3Rich": "Spúšťač v /usr/local/bin/menu.",
+ "item4Rich": "Voliteľne: služba systemd pre Monitor, proxmenux-monitor.service.",
+ "p2Rich": "ProxMenux nemení základnú konfiguráciu Proxmoxu, pokiaľ o to výslovne nepožiadate v príslušnej ponuke. Oprava siete napríklad upravuje /etc/network/interfaces, ale až po vašom potvrdení a vytvorení zálohy."
+ },
+ "q9": {
+ "question": "Je bezpečné používať ProxMenux v produkčnom prostredí?",
+ "bodyRich": "Áno. Keďže ProxMenux mení základné súbory Proxmoxu iba na výslovnú žiadosť, možno ho používať aj v produkčnom prostredí. Ako pri každej automatizácii ho najprv otestujte v kontrolovanom prostredí a pred deštruktívnymi operáciami majte zálohy. Týka sa to napríklad prechodu z PVE 8 na 9, formátovania diskov či odstránenia VM."
+ },
+ "q10": {
+ "question": "Ako odinštalujem ProxMenux?",
+ "p1Rich": "V ProxMenuxe: Nastavenia → Odinštalovať ProxMenux. Odinštalovanie odstráni skripty, spúšťač a službu Monitor a voliteľne aj vybrané závislosti. Súbory /root/.bashrc a /etc/motd obnoví zo záloh vytvorených pri inštalácii, ak sú dostupné.",
+ "p2Rich": "Celý postup nájdete na stránke curl | bash a môže stiahnuť jq z jeho oficiálneho vydania na GitHube. Takéto správanie môže spustiť heuristickú detekciu; historické hlásenie nie je hodnotením všetkých budúcich stiahnutí.",
+ "p2Rich": "ProxMenux má úplne otvorený zdrojový kód a inštalačný skript si môžete skontrolovať riadok po riadku: main."
+ },
+ {
+ "branch": "feature/*",
+ "purposeRich": "Kortlivade grenar per funktion, fix eller förbättring. Skapad från develop, fusioneras tillbaka till develop via en Pull begäran efter granskning."
+ }
+ ],
+ "calloutTitle": "Vad detta innebär för användare",
+ "calloutBody": "Slutanvändare som spårar main får testade releaser. Användare som vill ha de senaste funktionerna tidigt - och inte har något emot enstaka grova kanter - kan följa develop. Nya funktioner passerar alltid genom develop först; ingenting når main utan att gå igenom den cykeln."
+ },
+ "workflow": {
+ "heading": "Arbetsflöde för pull requests",
+ "intro": "Från idé till fusion i fem steg:",
+ "step1Lead": "Skapa en funktionsgren från develop:",
+ "step1Code": "git clone https://github.com/MacRimi/ProxMenux.git\ncd ProxMenux\ngit checkout develop\ngit pull origin develop\ngit checkout -b feature/your-feature-name",
+ "step1Trail": "Använd ett beskrivande grennamn: feature/zfs-arc-tuning, feature/fix-iommu-detection, feature/add-tailscale-script.",
+ "step2Lead": "Arbeta med ändringarna och skicka upp grenen:",
+ "step2Code": "# Make your changes, then:\ngit add scripts/...\ngit commit -m \"Add ZFS ARC tuning script\"\ngit push -u origin feature/your-feature-name",
+ "step3": "Öppna en pull request mot develop, inte mot main. Kontrollera på GitHub att basgrenen är develop. Beskriv vad skriptet gör och ändrar och vilka Proxmox VE-versioner det testats på.",
+ "step4": "Efter granskning slås ändringarna samman i develop. En underhållare granskar kodkvalitet, skripthuvud och gränssnittets två faser. Om ändringar begärs skickar du fler incheckningar till samma gren; PR:n uppdateras automatiskt.",
+ "step5": "Stabila utgåvor förs från develop till main. Vid utgivning flyttas main fram till develop med fast-forward och taggas. Ditt bidrag ingår i nästa stabila version."
+ },
+ "scriptHeader": {
+ "heading": "Skripthuvud: metadata och beskrivning",
+ "intro": "Varje ProxMenux-skript börjar med två intilliggande kommentarsblock som bildar skripthuvudet. Båda krävs: de anger författare och syfte utan att läsaren behöver gå igenom själva koden.",
+ "bullets": [
+ "Övre blocket: metadata. Författare, valfria GitHub-/stödlänkar, underhållare, upphovsrätt, licens, version och uppdateringsdatum. Här ges också erkännande åt bidragsgivare: för ett nytt skript anger du ditt namn och valfritt GitHub-sida och stödprofil, till exempel Ko-fi, GitHub Sponsors eller Buy Me a Coffee.",
+ "Nedre blocket: beskrivning. Ett kort stycke på enkel engelska förklarar skriptet. Det läses före koden och ska på egen hand klargöra syfte, huvudåtgärder, berörda resurser och förutsättningar."
+ ],
+ "licenseCalloutTitle": "Licenslinjen är fast - GPL-3.0",
+ "licenseCalloutBody": "ProxMenux ges ut under GNU General Public License v3.0. Alla skript har samma licens. Raden License i skripthuvudet ska alltid ha GPL-3.0-hänvisningen i exemplet nedan; den väljs inte per skript. Genom att bidra godkänner du GPL-3.0: alla får läsa, ändra och sprida skriptet och ändringarna med samma licens. Fullständig text: GitHub och Sponsor är valfria. Utelämna dem om du inte vill publicera dem. Allt annat krävs.",
+ "whyCalloutTitle": "Varför detta är viktigt",
+ "whyCalloutBody": "Bidrag till öppen källkod är frivilligt arbete. Namn och eventuell stödlänk direkt i källkoden ger författaren synligt erkännande vid varje läsning, i stället för att döljas bakom projektet. Beskrivningen har ett annat syfte: den är det första en framtida underhållare eller nyfiken användare läser. En tydlig beskrivning avgör ofta om skriptet inger förtroende eller undviks."
+ },
+ "structure": {
+ "heading": "Projektstruktur",
+ "intro": "Var olika typer av skript finns i arkivet:",
+ "treeCode": "scripts/\n├── menus/ # Top-level menu scripts (entry points)\n├── storage/ # Disk, storage and passthrough scripts\n├── share/ # NFS, Samba, local share scripts\n├── vm/ # VM creation and configuration scripts\n├── gpu_tpu/ # GPU / TPU passthrough scripts\n├── post_install/ # Post-install automation scripts\n├── backup_restore/ # Backup and restore scripts\n├── utilities/ # System utility scripts\n├── global/ # Shared helper libraries (sourced by other scripts)\n├── utils.sh # Shared utility functions and message helpers\n└── help_info_menu.sh # Interactive help and command reference",
+ "outro": "Varje skript läser in utils.sh vid start med source för att få meddelandefunktioner, väntindikator, färgvariabler och översättningssystem. Gemensamma hjälpbibliotek i scripts/global/ läses uttryckligen in av de skript som behöver dem."
+ },
+ "twoPhase": {
+ "heading": "Regler för gränssnitt i två faser",
+ "intro": "Detta är den viktigaste regeln i ProxMenux och den som oftast leder till ändringskrav i PR:er. Varje skript delas in i exakt två faser:",
+ "headerPhase": "Fas",
+ "headerPurpose": "syfte",
+ "headerScreen": "Skärmtillstånd",
+ "rows": [
+ {
+ "phaseRich": "Fas 1 — Urval",
+ "purposeRich": "Samla varje användarbeslut. Kör något förberedande arbete som behövs (sonder, skanningar, kontroller).",
+ "screenRich": "dialog-överlägg. Om en kontroll mellan två menyer tar mer än någon sekund, visa en msg_info-väntindikator så att användaren ser att skriptet inte hängt sig. Anropa sedan stop_spinner direkt före nästa dialogruta."
+ },
+ {
+ "phaseRich": "Fas 2 - Utförande",
+ "purposeRich": "Utför varje operation. Visa hela framstegshistorien som ackumuleras på skärmen.",
+ "screenRich": "Synliga msg_info/msg_ok-meddelanden; aldrig dialog."
+ }
+ ],
+ "principle": "Principen är samla alla val först och kör sedan allt. Användaren ser först ordnade dialogmenyer (fas 1), sedan en loggliknande körningsvy (fas 2). Faserna blandas inte: inga dialogrutor mitt i körningen och inga förloppsmeddelanden under valet.",
+ "phase1Heading": "Fas 1 - typiskt mönster",
+ "phase1Code": "# Silent preparatory work between dialogs\nmsg_info \"$(translate \"Checking disk assignments...\")\"\nASSIGNED_TO=$(check_assignments \"$DISK\")\nstop_spinner # ← clears line silently, result saved in variable\n\n# Next dialog can now use ASSIGNED_TO\nif [ -n \"$ASSIGNED_TO\" ]; then\n dialog --yesno \"$(translate \"Disk already assigned. Continue?\")\" $UI_YESNO_H $UI_YESNO_W\nfi\n\n# Collect multiple decisions per item with parallel arrays\ndeclare -a DISK_LIST=()\ndeclare -a DISK_FORMAT_TYPES=()\ndeclare -a DISK_MOUNT_POINTS=()\nfor DISK in $SELECTED; do\n msg_info \"$(translate \"Analyzing disk...\")\"\n CURRENT_FS=$(lsblk -no FSTYPE \"$DISK\" | xargs)\n stop_spinner\n\n FORMAT=$(dialog --backtitle \"$BACKTITLE\" \\\n --title \"$(translate \"Select Filesystem\")\" \\\n --menu \"...\" $UI_SHORT_MENU_H $UI_SHORT_MENU_W $UI_SHORT_MENU_LIST_H \\\n \"ext4\" \"...\" \"xfs\" \"...\" \"btrfs\" \"...\" \\\n 2>&1 >/dev/tty)\n [ -z \"$FORMAT\" ] && continue\n\n DISK_LIST+=(\"$DISK\")\n DISK_FORMAT_TYPES+=(\"$FORMAT\")\ndone",
+ "phase1RulesIntro": "Regler för fas 1:",
+ "phase1Rules": [
+ "Om en msg_info-väntindikator körs och du ska öppna en dialog- eller whiptail-meny, anropa först stop_spinner. Indikatorn kan inte samexistera med verktygens överlägg. Om ingen indikator är aktiv behövs inget anrop.",
+ "Använd show_proxmenux_logo + msg_title + msg_info för att ge visuellt sammanhang åt längre åtgärder i fas 1, exempelvis en kontroll som tar minst fem sekunder. Funktionen rensar redan skärmen; anropa inte clear före den.",
+ "Anropa inte show_proxmenux_logo mellan dialogmenyer när det saknas något att visa. Att rensa skärmen för en tom terminal ger bara visuellt brus.",
+ "Lagra alla val och kontrollresultat i variabler eller parallella arrayer. Sammanfattningen visas i början av fas 2, inte i fas 1."
+ ],
+ "phase2Heading": "Fas 2 - typiskt mönster",
+ "phase2Code": "# ── PHASE 2 — EXECUTION ─────────────────────────────\nshow_proxmenux_logo\nmsg_title \"$(translate \"My Script Title\")\"\n\n# Recap Phase 1 preparatory results — show what was already done\nmsg_ok \"$(translate \"CT $CTID selected.\")\"\nmsg_ok \"$(translate \"Repositories verified.\")\"\nmsg_ok \"$(translate \"Disks to process: ${#DISK_LIST[@]}\")\"\n\n# Now execute operations\nfor i in \"${!DISK_LIST[@]}\"; do\n DISK=\"${DISK_LIST[$i]}\"\n FORMAT=\"${DISK_FORMAT_TYPES[$i]}\"\n\n msg_info \"$(translate \"Formatting\") $DISK $(translate \"as\") $FORMAT...\"\n mkfs.\"$FORMAT\" \"$DISK\" >/dev/null 2>&1\n msg_ok \"$(translate \"Formatted.\")\"\ndone\n\nmsg_ok \"$(translate \"Completed. ${#DISK_LIST[@]} disk(s) processed.\")\"\nmsg_success \"$(translate \"Press Enter to return to menu...\")\"\nread -r",
+ "phase2Rules": "Regler för fas 2: börja med show_proxmenux_logo + msg_title och sammanfatta genast fas 1 som msg_ok-rader. Anropa aldrig show_proxmenux_logo igen, eftersom det raderar förloppshistoriken. Använd inte dialog; om ett val under körningen är oundvikligt, använd whiptail enligt nästa avsnitt."
+ },
+ "dialogVsWhiptail": {
+ "headingRich": "När du ska använda dialog vs whiptail",
+ "intro": "Båda verktygen ritar textbaserade gränssnitt men beter sig olika på skärmen. ProxMenux använder dem därför i två skilda faser.",
+ "headerTool": "Verktyg",
+ "headerWhen": "När du ska använda den",
+ "headerEffect": "Effekt på skärmen",
+ "rows": [
+ {
+ "toolRich": "dialog",
+ "whenRich": "Alltid i fas 1. Alla interaktiva val, som VM, disk, filsystem eller bekräftelse av en åtgärd, använder dialog. Det är ProxMenux standardverktyg för gränssnitt.",
+ "effectRich": "Tar över terminalen, rensar skärmen, ritar sitt överlägg och återställer föregående tillstånd när den stängs. Det fungerar i fas 1 eftersom inga användbara resultat visas ännu."
+ },
+ {
+ "toolRich": "whiptail",
+ "whenRich": "Bara i fas 2, när det är oundvikligt. Ett typiskt fall är en omstartsfråga när körningen är klar. Använd inte whiptail för att fråga ”fortsätt?” mitt i körningen; det beslutet skulle ha fattats i fas 1.",
+ "effectRich": "Ett lättare överlägg som inte rensar terminalens innehåll. Historiken från msg_ok/msg_info i fas 2 syns bakom dialogrutan. Därför passar det när förlopp redan visas på skärmen."
+ }
+ ],
+ "calloutTitle": "Varför uppdelningen är viktig",
+ "calloutBody": "Om du anropar dialog mitt i fas 2 försvinner alla msg_ok-rader användaren har följt. Det synliga händelseförloppet raderas. whiptail undviker det. Regeln bevarar alltså användarens bild av vad skriptet hittills har gjort.",
+ "rebootHeading": "Omstartsfråga: det typiska whiptail-fallet i fas 2",
+ "rebootIntro": "Om ett skript kan kräva omstart efter exempelvis aktivering av IOMMU eller ändrade kärnparametrar använder slutfrågan i fas 2 whiptail. Ha alltid en Nej-gren som säger att den berörda resursen inte ska användas före omstart:",
+ "rebootCode": "if [[ \"$HOST_REBOOT_REQUIRED\" == \"yes\" ]]; then\n echo \"\"\n if whiptail --title \"$(translate \"Reboot Required\")\" --yesno \\\n \"\\n$(translate \"A host reboot is required before starting the VM. Reboot now?\")\" \\\n 13 78; then\n msg_warn \"$(translate \"Rebooting the system...\")\"\n reboot\n else\n echo \"\"\n msg_info2 \"$(translate \"Do not start the VM until the system has been rebooted.\")\"\n fi\nfi\n\nmsg_success \"$(translate \"Press Enter to return to menu...\")\"\nread -r"
+ },
+ "messageFunctions": {
+ "heading": "Referens för meddelandefunktioner",
+ "intro": "Alla finns i utils.sh. Använd dem som standard för synlig utdata så att skripten får ett enhetligt utseende. Om en ny funktion behövs, till exempel en allvarlighetsnivå eller layouthjälpare, föreslå den i din pull request. Den granskas och läggs till i utils.sh om den är användbar för fler skript.",
+ "headerFunction": "Funktion",
+ "headerWhen": "När man ska använda",
+ "headerSpinner": "Förloppsindikator",
+ "rows": [
+ {
+ "function": "msg_info \"text\"",
+ "whenRich": "Operation pågår.",
+ "spinner": "Börjar"
+ },
+ {
+ "function": "stop_spinner",
+ "whenRich": "Slutet av tyst förberedande arbete i fas 1 - dödar spinner, rensar linjen.",
+ "spinner": "Stopp"
+ },
+ {
+ "function": "msg_ok \"text\"",
+ "whenRich": "Operationen lyckades. Använd också för \"funktion aktiverad\" även när en omstart krävs.",
+ "spinner": "Stopp"
+ },
+ {
+ "function": "msg_warn \"text\"",
+ "whenRich": "Faktisk varning eller nedbrutet tillstånd.",
+ "spinner": "Stopp"
+ },
+ {
+ "function": "msg_error \"text\"",
+ "whenRich": "Allvarligt fel.",
+ "spinner": "Stopp"
+ },
+ {
+ "function": "msg_info2 \"text\"",
+ "whenRich": "Icke blockerande upplysning på en cyan informationsrad.",
+ "spinner": "Stopp"
+ },
+ {
+ "function": "msg_success \"text\"",
+ "whenRich": "Avslutande frågan ”Tryck Enter för att återgå” i slutet av fas 2.",
+ "spinner": "Stopp"
+ },
+ {
+ "function": "msg_title \"text\"",
+ "whenRich": "Fet rubrik med inbyggda mellanrum. Används i början av fas 2.",
+ "spinner": "—"
+ },
+ {
+ "function": "show_proxmenux_logo",
+ "whenRich": "Rensar skärmen och visar logotypen. Anropas en gång i början av fas 2.",
+ "spinner": "—"
+ }
+ ]
+ },
+ "dialogConventions": {
+ "heading": "dialogkonventioner",
+ "bullets": [
+ "Skicka alltid --backtitle \"$BACKTITLE\" till varje dialog- och whiptail-anrop. $BACKTITLE är alltid \"ProxMenux\", satt en gång i skripthuvudet och aldrig överskrivet. Användaren ska alltid se projektnamnet som ram, inte skriptets egen titel.",
+ "Omslut alltid rubriker och meddelanden med $(translate \"...\").",
+ "Omdirigera alltid dialog-utgången med 2>&1 >/dev/tty - den fångade stdouten blir användarens val, medan dialogrutan själv drar på terminalen.",
+ "Använd standard UI dimension variabler ($UI_MENU_H, $UI_MSG_W, etc.) för konsekvent storlek över skript.",
+ "Kontrollera alltid tomma eller avbrutna val och hantera dem korrekt."
+ ],
+ "exampleIntro": "Fullständigt exempel: skapa en VM-valmeny och hantera avbrott.",
+ "exampleCode": "# 1) Build the list of VMs as alternating \"ID NAME\" pairs.\n# dialog --menu expects this exact shape: tag1 description1 tag2 description2 ...\nVM_LIST=\"\"\nfor vmid in $(qm list | awk 'NR>1 {print $1}'); do\n vm_name=$(qm config \"$vmid\" | awk -F': ' '/^name:/ {print $2}')\n VM_LIST=\"$VM_LIST $vmid \\\"$vm_name\\\"\"\ndone\n\n# 2) Show the dialog. Captured stdout is the user's selection (the VMID).\nVMID=$(eval \"dialog --backtitle \\\"\\$BACKTITLE\\\" \\\n --title \\\"\\$(translate \\\"Select VM\\\")\\\" \\\n --menu \\\"\\$(translate \\\"Choose a VM from the list:\\\")\\\" \\\n \\$UI_MENU_H \\$UI_MENU_W \\$UI_MENU_LIST_H \\\n $VM_LIST \\\n 2>&1 >/dev/tty\")\n\n# 3) Empty result means the user pressed Cancel or Esc — exit silently.\nif [ -z \"$VMID\" ]; then\n exit 0\nfi\n\n# 4) Continue with the rest of Phase 1, knowing VMID is now set.\necho \"User selected VMID=$VMID\""
+ },
+ "translation": {
+ "heading": "Översättningspolicy",
+ "intro": "Alla användarsynliga strängar måste inslagas med funktionen translate. ProxMenux översätter dem automatiskt till alla språk - du skriver engelska, användaren läser sitt modersmål.",
+ "code": "msg_ok \"$(translate \"Operation completed successfully.\")\"\nmsg_error \"$(translate \"Failed to start container\") $CTID.\"\ndialog --title \"$(translate \"Select Storage\")\" ...",
+ "bullets": [
+ "Skriv strängar på engelska - översättning hanteras automatiskt av bygget.",
+ "Håll strängar koncis. Undvik inbäddningsvariabler inom långa meningar där det är möjligt.",
+ "Översätt inte variabelnamn, sökvägar eller tekniska identifierare."
+ ]
+ },
+ "variableStyle": {
+ "heading": "Regler för variabler och stil",
+ "bullets": [
+ "Använd UPPER_CASE för script-nivå variabler.",
+ "Använd lower_case för lokala funktionsvariabler (deklarera med local).",
+ "Sätt alla variabelexpansioner inom citattecken: \"$VAR\", inte $VAR.",
+ "Använd [[ ]] för villkor, inte [ ] (förutom där POSIX krävs).",
+ "show_proxmenux_logo är det avsedda sättet att rensa skärmen: den rensar och visar projektlogotypen för att ge visuellt sammanhang. Anropa den en gång i början av fas 2, och valfritt före ett längre block med väntindikator i fas 1."
+ ],
+ "standardNamesIntro": "Standardvariabla namn över hela projektet:",
+ "standardNamesCode": "CTID # container ID\nVMID # virtual machine ID\nDISK # device path (e.g. /dev/sdb)\nPARTITION # partition path (e.g. /dev/sdb1)\nSTORAGE # Proxmox storage name\nMOUNT_POINT # filesystem mount path",
+ "redirectHeading": "Omdirigera verktygsutgång under fas 2",
+ "redirectIntro": "Fas 2 visar en logg med msg_info → msg_ok-rader. Om ett anropat verktyg, som apt, mkfs, qm, pct eller dd, skriver till stdout/stderr rullar dess utdata förbi meddelandena och stör överblicken. Användaren kan inte längre skilja skriptets förlopp från verktygets detaljer.",
+ "withoutRedirectIntro": " Utan omdirigering - vad användaren ser om du inte hanterar ljudet:",
+ "withoutRedirectCode": "ℹ Installing kernel package...\nReading package lists... Done\nBuilding dependency tree... Done\nReading state information... Done\nThe following NEW packages will be installed:\n proxmox-kernel-6.5\n0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.\nNeed to get 12.5 MB of archives.\nAfter this operation, 47.2 MB of additional disk space will be used.\nGet:1 http://download.proxmox.com/debian/pve trixie/pve-no-subscription amd64 ...\n... [200+ more lines of dpkg output] ...\n✓ Kernel installed.",
+ "withRedirectIntro": " Med omdirigering - hur samma operation ser ut när buller skickas någon annanstans:",
+ "withRedirectCode": "ℹ Installing kernel package...\n✓ Kernel installed.\nℹ Configuring kernel command line...\n✓ Configured.\nℹ Refreshing boot loader...\n✓ Boot loader updated.",
+ "twoPatternsIntro": "Två mönster att välja mellan:",
+ "discardLead": "Kasta utdata när de inte behövs: snabbast och enklast.",
+ "discardCode": "DEBIAN_FRONTEND=noninteractive apt-get install -y \"$package\" >/dev/null 2>&1",
+ "logLead": "Skicka utdata till en loggfil när de kan behöva granskas senare, exempelvis vid en misslyckad installation eller för att se vad dpkg gjorde. Det är det föredragna mönstret för apt-åtgärder:",
+ "logCode": "apt-get install -y \"$package\" >> \"$log_file\" 2>&1",
+ "referenceOutro": "Skriptet scripts/global/update-pve9_2.sh är ett referensimplementering - varje apt-get-samtal skickar ut till en loggfil så att användaren bara ser det rena msg_info → msg_ok-flödet, medan loggen på disken låter dig rekonstruera exakt vad apt gjorde om något går fel."
+ },
+ "dosAndDonts": {
+ "heading": "Do's och Don'ts",
+ "doHeading": "✅ Gör",
+ "doBullets": [
+ "stop_spinner före en dialog i fas 1 endast när en msg_info spinner körs för närvarande.",
+ "Fas 2 börjar med show_proxmenux_logo + msg_title + msg_ok för att sammanfatta resultaten från fas 1.",
+ "Använd msg_ok för framgångsrikt aktiverade funktioner - även om en omstart krävs.",
+ "Använd whiptail (inte dialog) för någon post-exekveringsprompt som måste visas i Fas 2.",
+ "Ha alltid en Nej-gren i omstartsfrågor som säger att den berörda resursen inte ska startas före omstart.",
+ "Bevakning VM-bara logik genom att kontrollera [[ -f \"/etc/pve/qemu-server/$'{'vmid'}'.conf\" ]] - controllers och NVMe PCIe kan inte läggas till LXC containrar.",
+ "Använd ensure_repositories från utils-install-functions.sh istället för ovillkorlig apt-get update.",
+ "Använd parallella arrayer i Fas 1 när varje objekt behöver flera dialoger."
+ ],
+ "dontHeading": "❌ Gör inte",
+ "dontBullets": [
+ "Anropa dialog medan en väntindikator är aktiv.",
+ "Hoppa över fas 1 recap i början av fas 2.",
+ "Anropa show_proxmenux_logo en andra gång; det raderar allt fas 2 har visat.",
+ "Använd dialog i Fas 2 (använd whiptail för det sällsynta oundvikliga fallet).",
+ "Använda enbart clear.",
+ "Omge msg_title med tomma echo \"\"-rader; mellanrum ingår redan.",
+ "Använd msg_warn för att rapportera en framgångsrikt aktiverad funktion - det är en msg_ok.",
+ "Kör ovillkorlig apt-get update - använd ensure_repositories."
+ ]
+ },
+ "submitting": {
+ "heading": "Skicka in ditt bidrag",
+ "steps": [
+ "Skapa en fork av MacRimi/ProxMenux på GitHub och klona din fork.",
+ "Skapa en feature/*-gren från develop (se Grenmodell ovan).",
+ "Följ denna guide för nya eller modifierade skript. Skriv rubriken med ditt namn; lägg till den valfria sponsorlinjen om du vill.",
+ "Testa ditt manus på en riktig Proxmox VE-instans - både Fas 1 (varje dialogruta) och Fas 2 (varje operation lyckas och rullar tillbaka rent på fel).",
+ "Öppna en pull request mot develop med en tydlig beskrivning: skriptets syfte, ändringar och den Proxmox VE-version som användes för tester.",
+ "Se till att ditt bidrag respekterar menu och erbjuder en uppdatering. Om du accepterar ersätts verktygets filer och konfiguration i den befintliga installationen. Du behöver inte ladda ned något manuellt.",
+ "p2Rich": "Användare av den stabila versionen får stabila uppdateringar, och betaanvändare får betauppdateringar. När en stabil version släpps meddelar betan det nästa gång menyn öppnas och erbjuder automatiskt byte. Läs mer om journalctl -u proxmenux-monitor -n 50.",
+ "p2Rich": "För säkerhetsproblem: publicera inte detaljerna. Följ rutinen för ansvarsfull rapportering i dialog, curl, jq och git. Översättningarna använder färdiga JSON-kataloger. Installationsprogrammet lägger inte till någon virtuell översättningsmiljö på värden.",
+ "item2Rich": "Skriptträdet på /usr/local/share/proxmenux/.",
+ "item3Rich": "Startkommandot i /usr/local/bin/menu.",
+ "item4Rich": "Valfritt: Monitors systemd-tjänst proxmenux-monitor.service.",
+ "p2Rich": "ProxMenux ändrar inte Proxmox centrala konfiguration om du inte uttryckligen begär det via en särskild meny. Nätverksreparationen redigerar till exempel /etc/network/interfaces, men först efter din bekräftelse och efter att en säkerhetskopia har skapats."
+ },
+ "q9": {
+ "question": "Är det säkert att använda ProxMenux i produktion?",
+ "bodyRich": "Ja. Eftersom ProxMenux bara ändrar Proxmox centrala filer på uttrycklig begäran kan det användas i produktionsmiljöer. Som med all automatisering bör du först testa i en kontrollerad miljö och ha säkerhetskopior innan du kör destruktiva åtgärder, till exempel uppgradering från PVE 8 till 9, diskformatering eller borttagning av en VM."
+ },
+ "q10": {
+ "question": "Hur avinstallerar jag ProxMenux?",
+ "p1Rich": "I ProxMenux: Inställningar → Avinstallera ProxMenux. Avinstallationen tar bort skriptträdet, startkommandot och Monitor-tjänsten samt, om du väljer det, utvalda beroenden. Den återställer /root/.bashrc och /etc/motd från säkerhetskopiorna som skapades vid installationen, om de finns.",
+ "p2Rich": "Fullständiga instruktioner: curl | bash och kan ladda ned jq från dess officiella GitHub-utgåva. Detta beteende kan utlösa heuristiska skannrar. Den historiska rapporten säger inget avgörande om alla framtida nedladdningar.",
+ "p2Rich": "ProxMenux har helt öppen källkod och du kan granska installationsskriptet rad för rad: