From 9ffd154a2a5544de49cea1fcd3406b66f723a054 Mon Sep 17 00:00:00 2001 From: VAIO73 <50487331+Vaso73@users.noreply.github.com> Date: Tue, 20 Oct 2026 06:46:15 +0000 Subject: [PATCH] i18n: refine Slovak linked nodes and localize validation errors --- .github/scripts/run_offline_qualified.py | 3 + AppImage/components/monitor-switcher.tsx | 22 +-- AppImage/lib/monitor-link-errors.ts | 29 ++++ AppImage/messages/en/common.json | 13 +- AppImage/messages/sk/common.json | 35 +++-- .../scripts/flask_monitor_links_routes.py | 19 ++- AppImage/scripts/monitor_links.py | 27 ++-- .../scripts/tests/test_monitor_links_i18n.py | 138 ++++++++++++++++++ tests/test_monitor_links_i18n.cjs | 133 +++++++++++++++++ 9 files changed, 379 insertions(+), 40 deletions(-) create mode 100644 AppImage/lib/monitor-link-errors.ts create mode 100644 AppImage/scripts/tests/test_monitor_links_i18n.py create mode 100644 tests/test_monitor_links_i18n.cjs diff --git a/.github/scripts/run_offline_qualified.py b/.github/scripts/run_offline_qualified.py index 8a9548cd..4ee4eb95 100644 --- a/.github/scripts/run_offline_qualified.py +++ b/.github/scripts/run_offline_qualified.py @@ -13,6 +13,8 @@ import sys import tempfile PYTHON_FILES = ( + "AppImage/scripts/tests/test_monitor_links_i18n.py", + "AppImage/scripts/tests/test_monitor_links.py", "AppImage/scripts/tests/test_local_app_icon_isolation.py", "AppImage/scripts/tests/test_local_app_icons.py", "AppImage/scripts/tests/test_docker_app_discovery.py", @@ -28,6 +30,7 @@ PYTHON_FILES = ( "AppImage/scripts/tests/test_health_persistence_recurrence.py", ) NODE_FILES = ( + "tests/test_monitor_links_i18n.cjs", "tests/lxc_updates/test_local_app_icons_ui.cjs", "tests/lxc_updates/test_docker_app_discovery_ui.cjs", "tests/lxc_updates/test_native_app_discovery_ui.cjs", diff --git a/AppImage/components/monitor-switcher.tsx b/AppImage/components/monitor-switcher.tsx index 89f8d249..7fb88eb9 100644 --- a/AppImage/components/monitor-switcher.tsx +++ b/AppImage/components/monitor-switcher.tsx @@ -14,6 +14,7 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "./ui/dropdown-menu" import { fetchApi } from "../lib/api-config" +import { monitorLinkError } from "../lib/monitor-link-errors" import { useT } from "../lib/i18n/provider" interface MonitorLink { @@ -185,8 +186,9 @@ export function MonitorSwitcher({ nodeName, compact = false }: { nodeName: strin await refreshCache("/api/monitor-links") setOfferOrigin(false) } catch (err) { - await refreshCache("/api/monitor-links") - setAddError(err instanceof Error ? err.message : t("monitorLinks.saveFailed")) + setAddError(monitorLinkError(err, t)) + try { await refreshCache("/api/monitor-links") } + catch { /* SWR shows the load error; keep the localized mutation error. */ } } finally { setAdding(false) } } const notNow = () => { @@ -260,7 +262,7 @@ export function MonitorSwitcher({ nodeName, compact = false }: { nodeName: strin {manageOpen && } {origin && { if (!open) notNow() }}> - event.stopPropagation()}> + event.stopPropagation()}> {t("monitorLinks.knownTitle")} {t("monitorLinks.knownBody", { name: origin.name })} @@ -290,7 +292,7 @@ export function MonitorSwitcher({ nodeName, compact = false }: { nodeName: strin function ManageLinksDialog({ open, onOpenChange }: { open: boolean; onOpenChange: (open: boolean) => void }) { const t = useT() - const { data, mutate } = useSWR("/api/monitor-links?all=1", fetcher, { revalidateOnFocus: false }) + const { data, mutate, error: loadError, isLoading } = useSWR("/api/monitor-links?all=1", fetcher, { revalidateOnFocus: false }) const [form, setForm] = useState({ name: "", url: "", product: "pve" }) const [addresses, setAddresses] = useState>({}) const [editing, setEditing] = useState(null) @@ -304,14 +306,14 @@ function ManageLinksDialog({ open, onOpenChange }: { open: boolean; onOpenChange await mutate() await refreshCache("/api/monitor-links") } catch (err) { - setError(err instanceof Error ? err.message : t("monitorLinks.saveFailed")) + setError(monitorLinkError(err, t)) } finally { setBusy(false) } } const send = (path: string, method: string, body?: unknown) => fetchApi(path, { method, ...(body === undefined ? {} : { body: JSON.stringify(body) }) }) return - event.stopPropagation()}> {t("monitorLinks.dialogTitle")} @@ -320,7 +322,7 @@ function ManageLinksDialog({ open, onOpenChange }: { open: boolean; onOpenChange

{t("monitorLinks.addTitle")}

-
+
setForm({ ...form, name: event.target.value })} /> @@ -350,6 +352,8 @@ function ManageLinksDialog({ open, onOpenChange }: { open: boolean; onOpenChange {error &&

{error}

}
+ {isLoading &&

{t("monitorLinks.checking")}

} + {loadError &&

{t("monitorLinks.loadFailed")}

} {data?.links.length === 0 &&

{t("monitorLinks.empty")}

} {data?.links.map(link => { const own = link.manual || link.custom_url @@ -378,8 +382,8 @@ function ManageLinksDialog({ open, onOpenChange }: { open: boolean; onOpenChange {t("monitorLinks.thisNode")}
: isEditing - ?
- + setAddresses({ ...addresses, [link.key]: event.target.value })} />