From c3a0c1beeb5ad3f0ab1ff7d49fab783c5559e3f5 Mon Sep 17 00:00:00 2001 From: Eduard Gert Date: Tue, 2 Jun 2026 12:36:29 +0200 Subject: [PATCH] update language switcher, remove flags --- .../ui/frontend/src/assets/flags/1x1/de.svg | 5 -- .../ui/frontend/src/assets/flags/1x1/en.svg | 7 --- .../ui/frontend/src/assets/flags/1x1/hu.svg | 7 --- .../src/components/LanguagePicker.tsx | 60 +++++-------------- client/ui/frontend/src/lib/i18n.ts | 16 +++-- client/ui/i18n/locales/_index.json | 2 +- client/ui/i18n/locales/en/common.json | 4 +- 7 files changed, 28 insertions(+), 73 deletions(-) delete mode 100644 client/ui/frontend/src/assets/flags/1x1/de.svg delete mode 100644 client/ui/frontend/src/assets/flags/1x1/en.svg delete mode 100644 client/ui/frontend/src/assets/flags/1x1/hu.svg diff --git a/client/ui/frontend/src/assets/flags/1x1/de.svg b/client/ui/frontend/src/assets/flags/1x1/de.svg deleted file mode 100644 index 0019e560d..000000000 --- a/client/ui/frontend/src/assets/flags/1x1/de.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/client/ui/frontend/src/assets/flags/1x1/en.svg b/client/ui/frontend/src/assets/flags/1x1/en.svg deleted file mode 100644 index ce4d1e000..000000000 --- a/client/ui/frontend/src/assets/flags/1x1/en.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/client/ui/frontend/src/assets/flags/1x1/hu.svg b/client/ui/frontend/src/assets/flags/1x1/hu.svg deleted file mode 100644 index 088242d93..000000000 --- a/client/ui/frontend/src/assets/flags/1x1/hu.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/client/ui/frontend/src/components/LanguagePicker.tsx b/client/ui/frontend/src/components/LanguagePicker.tsx index ea0b650d8..3d44bdda4 100644 --- a/client/ui/frontend/src/components/LanguagePicker.tsx +++ b/client/ui/frontend/src/components/LanguagePicker.tsx @@ -4,7 +4,7 @@ import * as Popover from "@radix-ui/react-popover"; import * as ScrollArea from "@radix-ui/react-scroll-area"; import { Command } from "cmdk"; import { errorDialog } from "@/lib/dialogs.ts"; -import { CheckIcon, ChevronDown, Search } from "lucide-react"; +import { CheckIcon, ChevronDown, LanguagesIcon, Search } from "lucide-react"; import { Preferences } from "@bindings/services"; import { LanguageCode, type Language } from "@bindings/i18n/models.js"; import { HelpText } from "@/components/typography/HelpText"; @@ -13,43 +13,17 @@ import { loadLanguages } from "@/lib/i18n"; import { cn } from "@/lib/cn"; import { formatErrorMessage } from "@/lib/errors"; -// Flags live alongside the rest of the SVG flag library under -// assets/flags/1x1 and are filename-matched to the language code -// (de → de.svg, en → en.svg, hu → hu.svg). Vite eager-globs them at -// build time; the JS bundle only holds URL refs, not the SVG bytes. -const FLAG_URLS = import.meta.glob("@/assets/flags/1x1/*.svg", { - eager: true, - import: "default", - query: "?url", -}); +// Intentionally no flag icons here: flags represent countries, not +// languages (German is spoken across DE/AT/CH; English across US/UK/AU/ +// etc.). Each label shows the endonym followed by the englishName in +// parentheses when the two differ (e.g. "Deutsch (German)"), in both +// the trigger and the dropdown rows. +// See: https://www.flagsarenotlanguages.com/blog/ -const flagByCode: Record = {}; -for (const path in FLAG_URLS) { - const match = path.match(/1x1\/([^/]+)\.svg$/); - if (match) flagByCode[match[1]] = FLAG_URLS[path]; -} - -const flagFor = (code: string): string | undefined => flagByCode[code.toLowerCase().split("-")[0]]; - -function Flag({ code, label }: { code: string; label: string }) { - const src = flagFor(code); - if (!src) { - return ( - - ); - } - return ( - {label} - ); -} +const labelFor = (lang: Language): string => + lang.englishName && lang.englishName !== lang.displayName + ? `${lang.displayName} (${lang.englishName})` + : lang.displayName; export function LanguagePicker() { const { t, i18n } = useTranslation(); @@ -121,9 +95,9 @@ export function LanguagePicker() { "disabled:opacity-50", )} > - {current && } + - {current?.displayName ?? "—"} + {current ? labelFor(current) : "—"} @@ -193,12 +167,8 @@ export function LanguagePicker() { "data-[selected=true]:bg-nb-gray-850 data-[selected=true]:text-nb-gray-50", )} > - - - {lang.displayName} + + {labelFor(lang)} typeof tag === "string" && tag.length > 0, ); + const byLower = new Map(available.map((code) => [code.toLowerCase(), code])); for (const tag of tags) { - const base = tag.toLowerCase().split("-")[0]; - if (available.includes(base)) return base; + const lower = tag.toLowerCase(); + const exact = byLower.get(lower); + if (exact) return exact; + const base = byLower.get(lower.split("-")[0]); + if (base) return base; } return null; } diff --git a/client/ui/i18n/locales/_index.json b/client/ui/i18n/locales/_index.json index 67dded15b..4fa5369a5 100644 --- a/client/ui/i18n/locales/_index.json +++ b/client/ui/i18n/locales/_index.json @@ -1,6 +1,6 @@ { "languages": [ - {"code": "en", "displayName": "English", "englishName": "English"}, + {"code": "en", "displayName": "English (US)", "englishName": "English (US)"}, {"code": "de", "displayName": "Deutsch", "englishName": "German"}, {"code": "hu", "displayName": "Magyar", "englishName": "Hungarian"} ] diff --git a/client/ui/i18n/locales/en/common.json b/client/ui/i18n/locales/en/common.json index de59e33b1..6cf54572f 100644 --- a/client/ui/i18n/locales/en/common.json +++ b/client/ui/i18n/locales/en/common.json @@ -245,7 +245,7 @@ "settings.troubleshooting.duration.suffix": "Minute(s)", "settings.troubleshooting.create": "Create Bundle", "settings.troubleshooting.progress.description": "Collecting logs, system details, and connection state. This usually takes a moment — keep this window open until it completes.", - "settings.troubleshooting.cancelling": "Cancelling…", + "settings.troubleshooting.cancelling": "Canceling…", "settings.troubleshooting.done.uploadedTitle": "Debug bundle successfully uploaded!", "settings.troubleshooting.done.savedTitle": "Bundle saved", "settings.troubleshooting.done.uploadedDescription": "Share the upload key below with NetBird support. A local copy was also saved on your device.", @@ -261,7 +261,7 @@ "settings.troubleshooting.stage.restoring": "Restoring previous log level…", "settings.troubleshooting.stage.bundling": "Generating debug bundle…", "settings.troubleshooting.stage.uploading": "Uploading to NetBird…", - "settings.troubleshooting.stage.cancelling": "Cancelling…", + "settings.troubleshooting.stage.cancelling": "Canceling…", "settings.about.client": "NetBird Client v{version}", "settings.about.clientName": "NetBird Client",