From 89186753937824ab4e9d493b68b1002b76890f95 Mon Sep 17 00:00:00 2001 From: VAIO73 <50487331+Vaso73@users.noreply.github.com> Date: Sat, 12 Sep 2026 08:12:23 +0200 Subject: [PATCH] =?UTF-8?q?i18n:=20lokalizovan=C3=A9=20kateg=C3=B3rie=20ap?= =?UTF-8?q?lik=C3=A1ci=C3=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AppImage/components/apps-dashboard.tsx | 19 +++++----- AppImage/components/custom-link-editor.tsx | 3 +- AppImage/components/lxc-app-panel.tsx | 7 ++-- AppImage/lib/category-label.ts | 40 ++++++++++++++++++++++ AppImage/messages/de/common.json | 5 ++- AppImage/messages/en/common.json | 34 ++++++++++++++++-- AppImage/messages/es/common.json | 5 ++- AppImage/messages/fr/common.json | 5 ++- AppImage/messages/it/common.json | 5 ++- AppImage/messages/pt/common.json | 5 ++- AppImage/messages/sk/common.json | 32 ++++++++++++++++- AppImage/messages/sv/common.json | 7 ++-- 12 files changed, 145 insertions(+), 22 deletions(-) create mode 100644 AppImage/lib/category-label.ts diff --git a/AppImage/components/apps-dashboard.tsx b/AppImage/components/apps-dashboard.tsx index f52c95a6..f3846599 100644 --- a/AppImage/components/apps-dashboard.tsx +++ b/AppImage/components/apps-dashboard.tsx @@ -9,6 +9,7 @@ import { ThemeAwareLogo } from "./lxc-app-panel" import { CustomLinkEditor, type CustomLink, type GuestOption } from "./custom-link-editor" import { Button } from "./ui/button" import { categoryChipStyle, useIsLightTheme } from "../lib/category-color" +import { getCategoryLabel } from "../lib/category-label" // ─── Local subset of /api/vms shape ───────────────────────────── // Kept narrow on purpose — this component only needs what feeds a @@ -248,8 +249,8 @@ export function AppsDashboard() { return map }, [links, t]) const sortedCategoryEntries = useMemo( - () => Array.from(categoryCounts.entries()).sort((a, b) => a[0].localeCompare(b[0])), - [categoryCounts], + () => Array.from(categoryCounts.entries()).sort((a, b) => getCategoryLabel(t, a[0]).localeCompare(getCategoryLabel(t, b[0]))), + [categoryCounts, t], ) // ─── Controls state ──────────────────────────────────────────── @@ -327,7 +328,8 @@ export function AppsDashboard() { l.appName.toLowerCase().includes(q) || (l.ctName || "").toLowerCase().includes(q) || (l.vmid != null && String(l.vmid).includes(q)) || - (l.category || "").toLowerCase().includes(q) + (l.category || "").toLowerCase().includes(q) || + getCategoryLabel(t, l.category || "").toLowerCase().includes(q) ) } const sorted = [...filtered] @@ -344,7 +346,7 @@ export function AppsDashboard() { // category — grouped alphabetically, then by app name inside const catA = a.category || uncatKey const catB = b.category || uncatKey - const c = catA.localeCompare(catB) + const c = getCategoryLabel(t, catA).localeCompare(getCategoryLabel(t, catB)) return c !== 0 ? c : a.appName.localeCompare(b.appName) }) return sorted @@ -432,7 +434,7 @@ export function AppsDashboard() { > {sortedCategoryEntries.map(([cat, n]) => ( - + ))} @@ -532,6 +534,7 @@ function CardsGrid({ editMode: boolean onEditCustom: (customId: string) => void }) { + const t = useT() if (!links.length) { return (
@@ -572,7 +575,7 @@ function CardsGrid({ {groups.map(([cat, items]) => (

- {cat} + {getCategoryLabel(t, cat)} {items.length}

{items.map((link) => ( @@ -715,9 +718,9 @@ function AppCard({ - {link.category} + {getCategoryLabel(t, link.category)} )}
diff --git a/AppImage/components/custom-link-editor.tsx b/AppImage/components/custom-link-editor.tsx index f32cd455..18f391eb 100644 --- a/AppImage/components/custom-link-editor.tsx +++ b/AppImage/components/custom-link-editor.tsx @@ -4,6 +4,7 @@ import { useEffect, useState } from "react" import { Trash2 } from "lucide-react" import { fetchApi } from "../lib/api-config" import { useT } from "../lib/i18n/provider" +import { getCategoryLabel } from "../lib/category-label" import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "./ui/dialog" import { Button } from "./ui/button" import { Input } from "./ui/input" @@ -237,7 +238,7 @@ export function CustomLinkEditor({ {t("vmLxc.appEditor.portCategoryNone")} {categoryPresets.map((c) => ( - {c} + {getCategoryLabel(t, c)} ))} {t("vmLxc.appEditor.portCategoryAddNew")} diff --git a/AppImage/components/lxc-app-panel.tsx b/AppImage/components/lxc-app-panel.tsx index 3444fc93..3f40048c 100644 --- a/AppImage/components/lxc-app-panel.tsx +++ b/AppImage/components/lxc-app-panel.tsx @@ -35,6 +35,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from ". import { fetchApi } from "../lib/api-config" import { fetchLxcApps, getLxcAppsCached, setLxcAppsCached, subscribeLxcApps } from "../lib/lxc-apps-cache" import { categoryChipStyle, useIsLightTheme } from "../lib/category-color" +import { getCategoryLabel } from "../lib/category-label" import { useT } from "@/lib/i18n/provider" // installed_via is optional now — an empty value means "register only, @@ -1604,7 +1605,7 @@ export function LxcAppPanel({ vmid, ctIp, onChange, managed, initialData }: Prop {t("vmLxc.appEditor.portCategoryNone")} {categoryPresets.map((c) => ( - {c} + {getCategoryLabel(t, c)} ))} {t("vmLxc.appEditor.portCategoryAddNew")} @@ -2649,9 +2650,9 @@ export function LxcAppPanel({ vmid, ctIp, onChange, managed, initialData }: Prop - {p.category} + {getCategoryLabel(t, p.category)} )}
diff --git a/AppImage/lib/category-label.ts b/AppImage/lib/category-label.ts new file mode 100644 index 00000000..8b6b4ced --- /dev/null +++ b/AppImage/lib/category-label.ts @@ -0,0 +1,40 @@ +type Translate = (key: string) => string + +// Category values come from the community-scripts catalog and are also +// persisted with application links. Keep those raw values intact for +// filtering and storage; translate only what is displayed in the UI. +const CATEGORY_KEY_BY_VALUE: Record = { + "*Arr Suite": "arrSuite", + "AI / Coding & Dev-Tools": "aiCodingDevTools", + "Adblock & DNS": "adblockDns", + "Authentication & Security": "authenticationSecurity", + "Automation & Scheduling": "automationScheduling", + "Backup & Recovery": "backupRecovery", + "Business & ERP": "businessErp", + "Communication & Community": "communicationCommunity", + "Containers & Docker": "containersDocker", + "Dashboards & Frontends": "dashboardsFrontends", + "Databases": "databases", + "Documents & Notes": "documentsNotes", + "Files & Downloads": "filesDownloads", + "Finance & Budgeting": "financeBudgeting", + "Gaming & Leisure": "gamingLeisure", + "Host Management": "hostManagement", + "IoT & Smart Home": "iotSmartHome", + "Media & Streaming": "mediaStreaming", + "Messaging & Queues": "messagingQueues", + "Miscellaneous": "miscellaneous", + "Monitoring & Analytics": "monitoringAnalytics", + "NVR & Cameras": "nvrCameras", + "Network & Firewall": "networkFirewall", + "Operating Systems & Appliances": "operatingSystemsAppliances", + "Productivity & Workflows": "productivityWorkflows", + "Remote Access & VPN": "remoteAccessVpn", + "Webservers & Proxies": "webserversProxies", + "ZigBee, Z-Wave & Matter": "zigbeeZwaveMatter", +} + +export function getCategoryLabel(t: Translate, value: string): string { + const key = CATEGORY_KEY_BY_VALUE[value.trim()] + return key ? t(`apps.categoryLabels.${key}`) : value +} diff --git a/AppImage/messages/de/common.json b/AppImage/messages/de/common.json index cc57df24..86f6f5b8 100644 --- a/AppImage/messages/de/common.json +++ b/AppImage/messages/de/common.json @@ -4929,7 +4929,10 @@ "customLinkCancel": "Cancel", "customLinkDelete": "Delete", "customLinkSaveError": "Save failed", - "customLinkDeleteError": "Delete failed" + "customLinkDeleteError": "Delete failed", + "categoryLabels": { + "arrSuite": "*Arr Suite", "aiCodingDevTools": "AI / Coding & Dev-Tools", "adblockDns": "Adblock & DNS", "authenticationSecurity": "Authentication & Security", "automationScheduling": "Automation & Scheduling", "backupRecovery": "Backup & Recovery", "businessErp": "Business & ERP", "communicationCommunity": "Communication & Community", "containersDocker": "Containers & Docker", "dashboardsFrontends": "Dashboards & Frontends", "databases": "Databases", "documentsNotes": "Documents & Notes", "filesDownloads": "Files & Downloads", "financeBudgeting": "Finance & Budgeting", "gamingLeisure": "Gaming & Leisure", "hostManagement": "Host Management", "iotSmartHome": "IoT & Smart Home", "mediaStreaming": "Media & Streaming", "messagingQueues": "Messaging & Queues", "miscellaneous": "Miscellaneous", "monitoringAnalytics": "Monitoring & Analytics", "nvrCameras": "NVR & Cameras", "networkFirewall": "Network & Firewall", "operatingSystemsAppliances": "Operating Systems & Appliances", "productivityWorkflows": "Productivity & Workflows", "remoteAccessVpn": "Remote Access & VPN", "webserversProxies": "Webservers & Proxies", "zigbeeZwaveMatter": "ZigBee, Z-Wave & Matter" + } }, "audit": { "presentation": { diff --git a/AppImage/messages/en/common.json b/AppImage/messages/en/common.json index c6791134..51ca198d 100644 --- a/AppImage/messages/en/common.json +++ b/AppImage/messages/en/common.json @@ -4994,7 +4994,37 @@ "customLinkCancel": "Cancel", "customLinkDelete": "Delete", "customLinkSaveError": "Save failed", - "customLinkDeleteError": "Delete failed" + "customLinkDeleteError": "Delete failed", + "categoryLabels": { + "arrSuite": "*Arr Suite", + "aiCodingDevTools": "AI / Coding & Dev-Tools", + "adblockDns": "Adblock & DNS", + "authenticationSecurity": "Authentication & Security", + "automationScheduling": "Automation & Scheduling", + "backupRecovery": "Backup & Recovery", + "businessErp": "Business & ERP", + "communicationCommunity": "Communication & Community", + "containersDocker": "Containers & Docker", + "dashboardsFrontends": "Dashboards & Frontends", + "databases": "Databases", + "documentsNotes": "Documents & Notes", + "filesDownloads": "Files & Downloads", + "financeBudgeting": "Finance & Budgeting", + "gamingLeisure": "Gaming & Leisure", + "hostManagement": "Host Management", + "iotSmartHome": "IoT & Smart Home", + "mediaStreaming": "Media & Streaming", + "messagingQueues": "Messaging & Queues", + "miscellaneous": "Miscellaneous", + "monitoringAnalytics": "Monitoring & Analytics", + "nvrCameras": "NVR & Cameras", + "networkFirewall": "Network & Firewall", + "operatingSystemsAppliances": "Operating Systems & Appliances", + "productivityWorkflows": "Productivity & Workflows", + "remoteAccessVpn": "Remote Access & VPN", + "webserversProxies": "Webservers & Proxies", + "zigbeeZwaveMatter": "ZigBee, Z-Wave & Matter" + } }, "audit": { "presentation": { @@ -6054,4 +6084,4 @@ "cancel": "Cancel" } } -} \ No newline at end of file +} diff --git a/AppImage/messages/es/common.json b/AppImage/messages/es/common.json index fa8ffbc4..e2b1dee5 100644 --- a/AppImage/messages/es/common.json +++ b/AppImage/messages/es/common.json @@ -4929,7 +4929,10 @@ "customLinkCancel": "Cancelar", "customLinkDelete": "Eliminar", "customLinkSaveError": "Error al guardar", - "customLinkDeleteError": "Error al eliminar" + "customLinkDeleteError": "Error al eliminar", + "categoryLabels": { + "arrSuite": "*Arr Suite", "aiCodingDevTools": "AI / Coding & Dev-Tools", "adblockDns": "Adblock & DNS", "authenticationSecurity": "Authentication & Security", "automationScheduling": "Automation & Scheduling", "backupRecovery": "Backup & Recovery", "businessErp": "Business & ERP", "communicationCommunity": "Communication & Community", "containersDocker": "Containers & Docker", "dashboardsFrontends": "Dashboards & Frontends", "databases": "Databases", "documentsNotes": "Documents & Notes", "filesDownloads": "Files & Downloads", "financeBudgeting": "Finance & Budgeting", "gamingLeisure": "Gaming & Leisure", "hostManagement": "Host Management", "iotSmartHome": "IoT & Smart Home", "mediaStreaming": "Media & Streaming", "messagingQueues": "Messaging & Queues", "miscellaneous": "Miscellaneous", "monitoringAnalytics": "Monitoring & Analytics", "nvrCameras": "NVR & Cameras", "networkFirewall": "Network & Firewall", "operatingSystemsAppliances": "Operating Systems & Appliances", "productivityWorkflows": "Productivity & Workflows", "remoteAccessVpn": "Remote Access & VPN", "webserversProxies": "Webservers & Proxies", "zigbeeZwaveMatter": "ZigBee, Z-Wave & Matter" + } }, "audit": { "presentation": { diff --git a/AppImage/messages/fr/common.json b/AppImage/messages/fr/common.json index 351f3638..2bd92044 100644 --- a/AppImage/messages/fr/common.json +++ b/AppImage/messages/fr/common.json @@ -4929,7 +4929,10 @@ "customLinkCancel": "Cancel", "customLinkDelete": "Delete", "customLinkSaveError": "Save failed", - "customLinkDeleteError": "Delete failed" + "customLinkDeleteError": "Delete failed", + "categoryLabels": { + "arrSuite": "*Arr Suite", "aiCodingDevTools": "AI / Coding & Dev-Tools", "adblockDns": "Adblock & DNS", "authenticationSecurity": "Authentication & Security", "automationScheduling": "Automation & Scheduling", "backupRecovery": "Backup & Recovery", "businessErp": "Business & ERP", "communicationCommunity": "Communication & Community", "containersDocker": "Containers & Docker", "dashboardsFrontends": "Dashboards & Frontends", "databases": "Databases", "documentsNotes": "Documents & Notes", "filesDownloads": "Files & Downloads", "financeBudgeting": "Finance & Budgeting", "gamingLeisure": "Gaming & Leisure", "hostManagement": "Host Management", "iotSmartHome": "IoT & Smart Home", "mediaStreaming": "Media & Streaming", "messagingQueues": "Messaging & Queues", "miscellaneous": "Miscellaneous", "monitoringAnalytics": "Monitoring & Analytics", "nvrCameras": "NVR & Cameras", "networkFirewall": "Network & Firewall", "operatingSystemsAppliances": "Operating Systems & Appliances", "productivityWorkflows": "Productivity & Workflows", "remoteAccessVpn": "Remote Access & VPN", "webserversProxies": "Webservers & Proxies", "zigbeeZwaveMatter": "ZigBee, Z-Wave & Matter" + } }, "audit": { "presentation": { diff --git a/AppImage/messages/it/common.json b/AppImage/messages/it/common.json index 918e19bc..61114411 100644 --- a/AppImage/messages/it/common.json +++ b/AppImage/messages/it/common.json @@ -4929,7 +4929,10 @@ "customLinkCancel": "Cancel", "customLinkDelete": "Delete", "customLinkSaveError": "Save failed", - "customLinkDeleteError": "Delete failed" + "customLinkDeleteError": "Delete failed", + "categoryLabels": { + "arrSuite": "*Arr Suite", "aiCodingDevTools": "AI / Coding & Dev-Tools", "adblockDns": "Adblock & DNS", "authenticationSecurity": "Authentication & Security", "automationScheduling": "Automation & Scheduling", "backupRecovery": "Backup & Recovery", "businessErp": "Business & ERP", "communicationCommunity": "Communication & Community", "containersDocker": "Containers & Docker", "dashboardsFrontends": "Dashboards & Frontends", "databases": "Databases", "documentsNotes": "Documents & Notes", "filesDownloads": "Files & Downloads", "financeBudgeting": "Finance & Budgeting", "gamingLeisure": "Gaming & Leisure", "hostManagement": "Host Management", "iotSmartHome": "IoT & Smart Home", "mediaStreaming": "Media & Streaming", "messagingQueues": "Messaging & Queues", "miscellaneous": "Miscellaneous", "monitoringAnalytics": "Monitoring & Analytics", "nvrCameras": "NVR & Cameras", "networkFirewall": "Network & Firewall", "operatingSystemsAppliances": "Operating Systems & Appliances", "productivityWorkflows": "Productivity & Workflows", "remoteAccessVpn": "Remote Access & VPN", "webserversProxies": "Webservers & Proxies", "zigbeeZwaveMatter": "ZigBee, Z-Wave & Matter" + } }, "audit": { "presentation": { diff --git a/AppImage/messages/pt/common.json b/AppImage/messages/pt/common.json index c00319df..99f8572a 100644 --- a/AppImage/messages/pt/common.json +++ b/AppImage/messages/pt/common.json @@ -4930,7 +4930,10 @@ "customLinkCancel": "Cancel", "customLinkDelete": "Delete", "customLinkSaveError": "Save failed", - "customLinkDeleteError": "Delete failed" + "customLinkDeleteError": "Delete failed", + "categoryLabels": { + "arrSuite": "*Arr Suite", "aiCodingDevTools": "AI / Coding & Dev-Tools", "adblockDns": "Adblock & DNS", "authenticationSecurity": "Authentication & Security", "automationScheduling": "Automation & Scheduling", "backupRecovery": "Backup & Recovery", "businessErp": "Business & ERP", "communicationCommunity": "Communication & Community", "containersDocker": "Containers & Docker", "dashboardsFrontends": "Dashboards & Frontends", "databases": "Databases", "documentsNotes": "Documents & Notes", "filesDownloads": "Files & Downloads", "financeBudgeting": "Finance & Budgeting", "gamingLeisure": "Gaming & Leisure", "hostManagement": "Host Management", "iotSmartHome": "IoT & Smart Home", "mediaStreaming": "Media & Streaming", "messagingQueues": "Messaging & Queues", "miscellaneous": "Miscellaneous", "monitoringAnalytics": "Monitoring & Analytics", "nvrCameras": "NVR & Cameras", "networkFirewall": "Network & Firewall", "operatingSystemsAppliances": "Operating Systems & Appliances", "productivityWorkflows": "Productivity & Workflows", "remoteAccessVpn": "Remote Access & VPN", "webserversProxies": "Webservers & Proxies", "zigbeeZwaveMatter": "ZigBee, Z-Wave & Matter" + } }, "audit": { "presentation": { diff --git a/AppImage/messages/sk/common.json b/AppImage/messages/sk/common.json index dc7a6887..993f39f0 100644 --- a/AppImage/messages/sk/common.json +++ b/AppImage/messages/sk/common.json @@ -4994,7 +4994,37 @@ "customLinkCancel": "Zrušiť", "customLinkDelete": "Odstrániť", "customLinkSaveError": "Odkaz sa nepodarilo uložiť", - "customLinkDeleteError": "Odkaz sa nepodarilo odstrániť" + "customLinkDeleteError": "Odkaz sa nepodarilo odstrániť", + "categoryLabels": { + "arrSuite": "Sada *Arr", + "aiCodingDevTools": "AI, programovanie a vývojárske nástroje", + "adblockDns": "Blokovanie reklám a DNS", + "authenticationSecurity": "Overovanie a bezpečnosť", + "automationScheduling": "Automatizácia a plánovanie", + "backupRecovery": "Zálohovanie a obnova", + "businessErp": "Podnikové aplikácie a ERP", + "communicationCommunity": "Komunikácia a komunita", + "containersDocker": "Kontajnery a Docker", + "dashboardsFrontends": "Prehľady a webové rozhrania", + "databases": "Databázy", + "documentsNotes": "Dokumenty a poznámky", + "filesDownloads": "Súbory a sťahovanie", + "financeBudgeting": "Financie a rozpočet", + "gamingLeisure": "Hry a voľný čas", + "hostManagement": "Správa servera", + "iotSmartHome": "IoT a inteligentná domácnosť", + "mediaStreaming": "Médiá a streamovanie", + "messagingQueues": "Správy a fronty", + "miscellaneous": "Ostatné", + "monitoringAnalytics": "Monitorovanie a analýza", + "nvrCameras": "NVR a kamery", + "networkFirewall": "Sieť a firewall", + "operatingSystemsAppliances": "Operačné systémy a zariadenia", + "productivityWorkflows": "Produktivita a pracovné postupy", + "remoteAccessVpn": "Vzdialený prístup a VPN", + "webserversProxies": "Webové servery a proxy", + "zigbeeZwaveMatter": "Zigbee, Z-Wave a Matter" + } }, "audit": { "presentation": { diff --git a/AppImage/messages/sv/common.json b/AppImage/messages/sv/common.json index 4fbccd0c..4012c26c 100644 --- a/AppImage/messages/sv/common.json +++ b/AppImage/messages/sv/common.json @@ -4929,7 +4929,10 @@ "customLinkCancel": "Cancel", "customLinkDelete": "Delete", "customLinkSaveError": "Save failed", - "customLinkDeleteError": "Delete failed" + "customLinkDeleteError": "Delete failed", + "categoryLabels": { + "arrSuite": "*Arr Suite", "aiCodingDevTools": "AI / Coding & Dev-Tools", "adblockDns": "Adblock & DNS", "authenticationSecurity": "Authentication & Security", "automationScheduling": "Automation & Scheduling", "backupRecovery": "Backup & Recovery", "businessErp": "Business & ERP", "communicationCommunity": "Communication & Community", "containersDocker": "Containers & Docker", "dashboardsFrontends": "Dashboards & Frontends", "databases": "Databases", "documentsNotes": "Documents & Notes", "filesDownloads": "Files & Downloads", "financeBudgeting": "Finance & Budgeting", "gamingLeisure": "Gaming & Leisure", "hostManagement": "Host Management", "iotSmartHome": "IoT & Smart Home", "mediaStreaming": "Media & Streaming", "messagingQueues": "Messaging & Queues", "miscellaneous": "Miscellaneous", "monitoringAnalytics": "Monitoring & Analytics", "nvrCameras": "NVR & Cameras", "networkFirewall": "Network & Firewall", "operatingSystemsAppliances": "Operating Systems & Appliances", "productivityWorkflows": "Productivity & Workflows", "remoteAccessVpn": "Remote Access & VPN", "webserversProxies": "Webservers & Proxies", "zigbeeZwaveMatter": "ZigBee, Z-Wave & Matter" + } }, "audit": { "presentation": { @@ -5989,4 +5992,4 @@ "cancel": "Cancel" } } -} \ No newline at end of file +}