diff --git a/apps/console/src/components/form/CountriesField.tsx b/apps/console/src/components/form/CountriesField.tsx
index bc071d11e..2f1c2c7f8 100644
--- a/apps/console/src/components/form/CountriesField.tsx
+++ b/apps/console/src/components/form/CountriesField.tsx
@@ -63,9 +63,17 @@ type CountriesFieldInputProps = {
};
function CountriesFieldInput(props: CountriesFieldInputProps) {
- const { i18n } = useTranslation();
+ const { t, i18n } = useTranslation();
const [animateBadge, setAnimateBadge] = useState(false);
+ const countryLabel = (code: CountryCode) => {
+ // GLOBAL is not a valid Intl region code; use the translated label.
+ if (code === "GLOBAL") {
+ return t("country.GLOBAL");
+ }
+ return getCountryName(i18n.language, code);
+ };
+
const addCountry = (code: string) => {
setAnimateBadge(true);
props.onValueChange([...props.value, code]);
@@ -94,7 +102,7 @@ function CountriesFieldInput(props: CountriesFieldInputProps) {
&& "starting:opacity-0 starting:w-0 w-max transition-all duration-500 starting:bg-accent",
)}
>
- {getCountryName(i18n.language, countryCode as CountryCode)}
+ {countryLabel(countryCode as CountryCode)}
@@ -110,6 +118,7 @@ function CountriesFieldInput(props: CountriesFieldInputProps) {
(c: CountryCode) => !props.value.includes(c),
)}
onAdd={addCountry}
+ countryLabel={countryLabel}
/>
)}
@@ -119,15 +128,16 @@ function CountriesFieldInput(props: CountriesFieldInputProps) {
type CountryInputProps = {
availableCountries: readonly CountryCode[];
onAdd: (code: string) => void;
+ countryLabel: (code: CountryCode) => string;
};
-function CountryInput({ availableCountries, onAdd }: CountryInputProps) {
- const { t, i18n } = useTranslation();
+function CountryInput({ availableCountries, onAdd, countryLabel }: CountryInputProps) {
+ const { t } = useTranslation();
const [search, setSearch] = useState("");
const [isOpen, setIsOpen] = useState(false);
const countryOptions = availableCountries.map(code => ({
value: code,
- label: getCountryName(i18n.language, code),
+ label: countryLabel(code),
}));
useEffect(() => {
diff --git a/packages/helpers/src/countries.test.ts b/packages/helpers/src/countries.test.ts
new file mode 100644
index 000000000..5fc2eab3b
--- /dev/null
+++ b/packages/helpers/src/countries.test.ts
@@ -0,0 +1,43 @@
+// Copyright (c) 2025-2026 Probo Inc .
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+import { describe, it, expect } from "vitest";
+import { getCountryName, getCountryOptions } from "./countries";
+
+describe("getCountryName", () => {
+ it("returns a label for the GLOBAL pseudo-region", () => {
+ expect(getCountryName("en", "GLOBAL")).toBe("Global");
+ });
+
+ it("returns localized names for ISO country codes", () => {
+ expect(getCountryName("en", "US")).toBe("United States");
+ expect(getCountryName("en", "EU")).toBe("European Union");
+ });
+});
+
+describe("getCountryOptions", () => {
+ it("includes GLOBAL without throwing", () => {
+ const options = getCountryOptions("en");
+ expect(options.find(option => option.value === "GLOBAL")).toEqual({
+ value: "GLOBAL",
+ label: "Global",
+ });
+ });
+});
diff --git a/packages/helpers/src/countries.ts b/packages/helpers/src/countries.ts
index ef2599490..351d149ec 100644
--- a/packages/helpers/src/countries.ts
+++ b/packages/helpers/src/countries.ts
@@ -50,8 +50,22 @@ export const countries = [
export type CountryCode = typeof countries[number];
+// Pseudo-regions accepted by our CountryCode enum but not by Intl.DisplayNames.
+const pseudoRegionNames: Partial> = {
+ GLOBAL: "Global",
+};
+
export function getCountryName(language: string, code: CountryCode): string {
- return new Intl.DisplayNames(language, { type: "region" }).of(code) ?? code;
+ const pseudoName = pseudoRegionNames[code];
+ if (pseudoName) {
+ return pseudoName;
+ }
+
+ try {
+ return new Intl.DisplayNames(language, { type: "region" }).of(code) ?? code;
+ } catch {
+ return code;
+ }
}
export function getCountryOptions(lang: string) {