Nothing open on GitHub. Fix merged in #29997 on 21 May 2026. Check it covers your case.
The short answer
- Known?
- Yes. 3 related items grouped here, 1 issue already closed.
- Fix event
- A fix was merged to main in PR #29997. Check it covers your case. No release data is tracked.
- Tracker
- The maintainers' tracker marks this
resolved, deciding PR #29997. That is separate from the fix event. - Still open
- Nothing open on GitHub.
These items concern a bug where Traditional Chinese showed an incorrect flag, an attempted fix assigning a PRC flag, and a subsequent change to remove country flags from the language picker entirely. The members reflect an ongoing discussion about how to represent language options without implying national identity.
Open issues0
Open PRs0
Fixes on record
-
#29997 fix(dashboard): remove country flags from language picker
files:
web/package.json,web/src/components/LanguageSwitcher.tsx,web/src/i18n/context.tsx,web/src/main.tsxShow the diff
-
web/package-lock.json@@ -19,7 +19,6 @@ "@xterm/xterm": "^6.0.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "flag-icons": "^7.5.0", "gsap": "^3.15.0", "leva": "^0.10.1", "lucide-react": "^0.577.0", @@ -78,7 +77,6 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -1129,7 +1127,6 @@ "resolved": "https://registry.npmjs.org/@observablehq/plot/-/plot-0.6.17.tgz", "integrity": "sha512-/qaXP/7mc4MUS0s4cPPFASDRjtsWp85/TbfsciqDgU1HwYixbSbbytNuInD8AcTYC3xaxACgVX06agdfQy9W+g==", "license": "ISC", - "peer": true, "dependencies": { "d3": "^7.9.0", "interval-tree-1d": "^1.0.0", @@ -1868,7 +1865,6 @@ "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-9.6.0.tgz", "integrity": "sha512-90abYK2q5/qDM+GACs9zRvc5KhEEpEWqWlHSd64zTPNxg+9wCJvTfyD9x2so7hlQhjRYO1Fa6flR3BC/kpTFkA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.17.8", "@types/webxr": "*", @@ -2574,7 +2570,6 @@ "integrity": "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -2584,7 +2579,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -2595,7 +2589,6 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "devOptional": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -2660,7 +2653,6 @@ "integrity": "sha512-HDQH9O/47Dxi1ceDhBXdaldtf/WV9yRYMjbjCuNk3qnaTD564qwv61Y7+gTxwxRKzSrgO5uhtw584igXVuuZkA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.59.1", "@typescript-eslint/types": "8.59.1", @@ -2989,7 +2981,6 @@ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3142,7 +3133,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", @@ -3650,7 +3640,6 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -3970,7 +3959,6 @@ "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -4250,12 +4238,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/flag-icons": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/flag-icons/-/flag-icons-7.5.0.tgz", - "integrity": "sha512-kd+MNXviFIg5hijH766tt+3x76ele1AXlo4zDdCxIvqWZhKt4T83bOtxUOOMlTx/EcFdUMH5yvQgYlFh1EqqFg==", - "license": "MIT" - }, "node_modules/flat-cache": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", @@ -4382,8 +4364,7 @@ "version": "3.15.0", "resolved": "https://registry.npmjs.org/gsap/-/gsap-3.15.0.tgz", "integrity": "sha512-dMW4CWBTUK1AEEDeZc1g4xpPGIrSf9fJF960qbTZmN/QwZIWY5wgliS6JWl9/25fpTGJrMRtSjGtOmPnfjZB+A==", - "license": "Standard 'no charge' license: https://gsap.com/standard-license.", - "peer": true + "license": "Standard 'no charge' license: https://gsap.com/standard-license." }, "node_modules/has-flag": { "version": "4.0.0", @@ -4698,7 +4679,6 @@ "resolved": "https://registry.npmjs.org/leva/-/leva-0.10.1.tgz", "integrity": "sha512-BcjnfUX8jpmwZUz2L7AfBtF9vn4ggTH33hmeufDULbP3YgNZ/C+ss/oO3stbrqRQyaOmRwy70y7BGTGO81S3rA==", "license": "MIT", - "peer": true, "dependencies": { "@radix-ui/react-portal": "^1.1.4", "@radix-ui/react-tooltip": "^1.1.8", @@ -5106,7 +5086,6 @@ "resolved": "https://registry.npmjs.org/motion/-/motion-12.39.0.tgz", "integrity": "sha512-H4a+Ze+a9j+/NTla5ezfb/g9vmIOxC+viDj++NGDZyTZkdRKjiOz3kSv6TalRWM8ZmD2y/CfC6TkQc97ybyqSA==", "license": "MIT", - "peer": true, "dependencies": { "framer-motion": "^12.39.0", "tslib": "^2.4.0" @@ -5179,7 +5158,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": "^20.0.0 || >=22.0.0" } @@ -5307,7 +5285,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -5379,7 +5356,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.5.tgz", "integrity": "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -5399,7 +5375,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.5.tgz", "integrity": "sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -5760,8 +5735,7 @@ "version": "0.180.0", "resolved": "https://registry.npmjs.org/three/-/three-0.180.0.tgz", "integrity": "sha512-o+qycAMZrh+TsE01GqWUxUIKR1AL0S8pq7zDkYOQw8GqfX8b8VoCKYUoHbhiX5j+7hr8XsuHDVU6+gkQJQKg9w==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/tinyglobby": { "version": "0.2.16", @@ -5826,7 +5800,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -5925,7 +5898,6 @@ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", "license": "MIT", - "peer": true, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } @@ -5941,7 +5913,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==", "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -6063,7 +6034,6 @@ "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } -
web/package.json@@ -21,7 +21,6 @@ "@xterm/xterm": "^6.0.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "flag-icons": "^7.5.0", "gsap": "^3.15.0", "leva": "^0.10.1", "lucide-react": "^0.577.0", -
web/src/components/LanguageSwitcher.tsx@@ -9,15 +9,16 @@ import type { Locale } from "@/i18n"; import { cn } from "@/lib/utils"; /** - * Language picker — shows the current language's flag + endonym, opens a - * dropdown of all supported locales when clicked. Persists choice to - * localStorage via the I18n context. + * Language picker — shows the current language's endonym, opens a dropdown + * of all supported locales when clicked. Persists choice to localStorage via + * the I18n context. * * Replaces the older two-state EN↔ZH toggle now that we ship 16 locales * (en, zh, zh-hant, ja, de, es, fr, tr, uk, af, ko, it, ga, pt, ru, hu). * - * Locale markers use lipis/flag-icons (SVG sprites) instead of emoji so flags - * render consistently across platforms. + * No country flags by design — languages aren't countries, and flag pairings + * inevitably create political mismappings (e.g. Mandarin variants ≠ any single + * jurisdiction, English ≠ GB, Portuguese ≠ PT). Endonyms are unambiguous. * * When placed at the bottom of the sidebar (next to ThemeSwitcher), pass * `dropUp` so the list opens above the trigger and avoids clipping below the @@ -71,7 +72,6 @@ export function LanguageSwitcher({ dropUp = false }: LanguageSwitcherProps) { className="px-2 py-1 normal-case tracking-normal font-normal text-xs text-muted-foreground hover:text-foreground" > <span className="inline-flex items-center gap-1.5"> - <LocaleFlagIcon countryCode={current.flagCountryCode} /> <Typography mondwest className="hidden sm:inline tracking-wide uppercase text-[0.65rem]" @@ -146,8 +146,6 @@ function LanguageSwitcherOptions({ role="option" type="button" > - <LocaleFlagIcon countryCode={meta.flagCountryCode} /> - <span className="truncate">{meta.name}</span> {selected && <span className="ml-auto text-xs">✓</span>} @@ -158,15 +156,6 @@ function LanguageSwitcherOptions({ ); } -function LocaleFlagIcon({ countryCode }: LocaleFlagIconProps) { - return ( - <span - aria-hidden - className={cn("fi fis shrink-0 text-base leading-none", `fi-${countryCode}`)} - /> - ); -} - interface LanguageSwitcherOptionsProps { allLocales: Array<[Locale, (typeof LOCALE_META)[Locale]]>; locale: Locale; @@ -177,7 +166,3 @@ interface LanguageSwitcherOptionsProps { interface LanguageSwitcherProps { dropUp?: boolean; } - -interface LocaleFlagIconProps { - countryCode: string; -} -
web/src/i18n/context.tsx@@ -37,27 +37,31 @@ const TRANSLATIONS: Record<Locale, Translations> = { }; // Display metadata for the language picker — endonym (native name) so users -// recognize their language even if they don't speak the current UI language, -// plus a flag-icons sprite (ISO 3166-1 alpha-2) for visual scanning. +// recognize their language even if they don't speak the current UI language. // Exposed as a constant so the LanguageSwitcher and any future settings page // can share the same list. -export const LOCALE_META: Record<Locale, { name: string; flagCountryCode: string }> = { - en: { name: "English", flagCountryCode: "gb" }, - zh: { name: "简体中文", flagCountryCode: "cn" }, - "zh-hant": { name: "繁體中文", flagCountryCode: "tw" }, - ja: { name: "日本語", flagCountryCode: "jp" }, - de: { name: "Deutsch", flagCountryCode: "de" }, - es: { name: "Español", flagCountryCode: "es" }, - fr: { name: "Français", flagCountryCode: "fr" }, - tr: { name: "Türkçe", flagCountryCode: "tr" }, - uk: { name: "Українська", flagCountryCode: "ua" }, - af: { name: "Afrikaans", flagCountryCode: "za" }, - ko: { name: "한국어", flagCountryCode: "kr" }, - it: { name: "Italiano", flagCountryCode: "it" }, - ga: { name: "Gaeilge", flagCountryCode: "ie" }, - pt: { name: "Português", flagCountryCode: "pt" }, - ru: { name: "Русский", flagCountryCode: "ru" }, - hu: { name: "Magyar", flagCountryCode: "hu" }, +// +// We intentionally do NOT pair locales with country flags. Languages are not +// countries (English ≠ GB, Portuguese ≠ PT, Spanish ≠ ES, Chinese variants ≠ +// any single jurisdiction). Endonyms are unambiguous and avoid the political +// mismapping that flag pairings inevitably create. +export const LOCALE_META: Record<Locale, { name: string }> = { + en: { name: "English" }, + zh: { name: "简体中文" }, + "zh-hant": { name: "繁體中文" }, + ja: { name: "日本語" }, + de: { name: "Deutsch" }, + es: { name: "Español" }, + fr: { name: "Français" }, + tr: { name: "Türkçe" }, + uk: { name: "Українська" }, + af: { name: "Afrikaans" }, + ko: { name: "한국어" }, + it: { name: "Italiano" }, + ga: { name: "Gaeilge" }, + pt: { name: "Português" }, + ru: { name: "Русский" }, + hu: { name: "Magyar" }, }; const SUPPORTED_LOCALES = Object.keys(TRANSLATIONS) as Locale[]; -
web/src/main.tsx@@ -1,6 +1,5 @@ import { createRoot } from "react-dom/client"; import { BrowserRouter } from "react-router-dom"; -import "flag-icons/css/flag-icons.min.css"; import "./index.css"; import App from "./App"; import { SystemActionsProvider } from "./contexts/SystemActions";
-
1 PR closed without merging
From the close comments: superseded by another PR 1
-
#29765 fix(web): show PRC flag for Traditional Chinese (繁體中文) · superseded by another PR →
#29997
Closed issues · 1
- Closed#29750[Bug]: Traditional Chinese (繁體中文) shows incorrect flag in language selector
How this cluster was grouped
-
Link evidence (
structural links throughout): every member is connected by structural evidence: shared changed files, or a closing/superseded reference. -
Pairwise link density
0.67: the share of item pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36.1.00means every pair is linked.
Pick up a Lab task
Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.
Open the LabAt a glance
- Merged PRs
- #29997
- Closed issues
- 1
- Attempts
- 1 PR closed without merging
- Fix link checked
- 21 May 2026