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 (
-
- );
-}
+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",