如何以不同语言显示国家名称?
使用 Intl.DisplayNames 将国家代码转换为国际用户本地化的国家名称。
简介
当你构建收货地址表单、用户资料页或地址选择器时,需要显示国家名称。用户在英文界面看到 "France",在西班牙语界面看到 "Francia",在德语界面看到 "Frankreich",在日语界面看到 "フランス"。每位用户都希望看到用自己语言书写的国家名称。
你的应用会在数据库和 API 中存储像 FR、US 或 JP 这样的国家代码。这些标准化代码可在所有系统中通用,但用户需要可读的国家名称。Intl.DisplayNames API 可以将国家代码转换为任意语言的本地化国家名称,无需维护翻译表或依赖外部库。
了解国家代码
各国通过 ISO 3166-1 alpha-2 标准定义的两位字母代码进行标识。每个国家都有唯一的代码,在所有语言和系统中都保持不变。
// Common country codes
// US = United States
// GB = Great Britain (United Kingdom)
// FR = France
// DE = Germany (Deutschland)
// JP = Japan
// CN = China
// BR = Brazil
// IN = India
这些代码会出现在表单、URL、数据库和 API 中。代码 US 无论在英文、西班牙文、日文或其他语言环境下,始终代表美国。代码为显示名称提供了稳定的标识符,而显示名称会根据用户的语言变化。
使用 Intl.DisplayNames 获取国家名称
Intl.DisplayNames 构造函数可创建格式化器,将国家代码转换为国家名称。你需要指定 locale,并将 type 设置为 "region",以获取国家名称。
const countryNames = new Intl.DisplayNames(["en"], { type: "region" });
console.log(countryNames.of("US"));
// "United States"
console.log(countryNames.of("FR"));
// "France"
console.log(countryNames.of("JP"));
// "Japan"
第一个参数是 locale 标识符数组。type: "region" 选项告诉格式化器你需要国家或地区名称。of() 方法接收国家代码并返回其本地化名称。
“地区”一词涵盖国家、领土和地理区域。这包括像法国这样的独立国家、像波多黎各这样的属地,以及像欧盟这样的特殊区域。
在不同语言中显示国家名称
相同的国家代码在不同语言中会显示不同的名称。为不同的本地化设置创建格式化器,可以看到国家名称的变化。
const englishNames = new Intl.DisplayNames(["en"], { type: "region" });
const spanishNames = new Intl.DisplayNames(["es"], { type: "region" });
const germanNames = new Intl.DisplayNames(["de"], { type: "region" });
const japaneseNames = new Intl.DisplayNames(["ja"], { type: "region" });
console.log(englishNames.of("FR"));
// "France"
console.log(spanishNames.of("FR"));
// "Francia"
console.log(germanNames.of("FR"));
// "Frankreich"
console.log(japaneseNames.of("FR"));
// "フランス"
每个格式化器会返回其显示语言下的国家名称。这简化了跨语言维护国家名称翻译的复杂性。
你可以创建一个函数,用于获取任意语言的国家名称。
function getCountryName(countryCode, locale) {
const names = new Intl.DisplayNames([locale], { type: "region" });
return names.of(countryCode);
}
console.log(getCountryName("US", "en"));
// "United States"
console.log(getCountryName("US", "fr"));
// "États-Unis"
console.log(getCountryName("US", "ar"));
// "الولايات المتحدة"
console.log(getCountryName("DE", "en"));
// "Germany"
console.log(getCountryName("DE", "de"));
// "Deutschland"
console.log(getCountryName("DE", "es"));
// "Alemania"
该函数适用于任意国家代码和本地化设置的组合。浏览器会自动提供相应的翻译。
构建国家选择器
一个常见的用例是构建一个下拉菜单,让用户选择自己的国家。国家名称应以用户的语言显示。
function createCountrySelector(locale) {
const countryNames = new Intl.DisplayNames([locale], { type: "region" });
const countries = [
"US", "GB", "CA", "AU", "FR", "DE", "ES", "IT",
"JP", "CN", "KR", "IN", "BR", "MX", "AR", "RU"
];
const select = document.createElement("select");
select.id = "country";
select.name = "country";
const placeholder = document.createElement("option");
placeholder.value = "";
placeholder.textContent = "Select a country";
select.appendChild(placeholder);
countries.forEach((code) => {
const option = document.createElement("option");
option.value = code;
option.textContent = countryNames.of(code);
select.appendChild(option);
});
return select;
}
const selector = createCountrySelector("en");
document.body.appendChild(selector);
这会创建一个以英文显示国家名称的下拉菜单。将本地化设置更改为 "es",同一个函数会生成以西班牙语显示国家名称的下拉菜单。更改为 "ja" 时,名称会以日语显示。
你可以让选择器根据用户的浏览器语言做出响应。
function createLocalizedCountrySelector() {
const userLocale = navigator.language;
return createCountrySelector(userLocale);
}
const selector = createLocalizedCountrySelector();
document.body.appendChild(selector);
选择器会根据用户的浏览器设置,自动以其首选语言显示国家名称。
获取所有可用国家
Intl.supportedValuesOf() 方法会返回所有支持的国家代码数组。这样就无需维护硬编码的列表。
const allCountries = Intl.supportedValuesOf("region");
console.log(allCountries.length);
// 249 (approximate count as of 2025)
console.log(allCountries.slice(0, 10));
// ["AC", "AD", "AE", "AF", "AG", "AI", "AL", "AM", "AO", "AQ"]
该方法返回的代码按代码字母顺序排列,而不是按国家名称。如果需要按特定语言的字母顺序排列,需要根据本地化名称进行排序。
function getSortedCountries(locale) {
const countryNames = new Intl.DisplayNames([locale], { type: "region" });
const allCountries = Intl.supportedValuesOf("region");
return allCountries
.map((code) => ({
code,
name: countryNames.of(code)
}))
.sort((a, b) => a.name.localeCompare(b.name, locale));
}
const sortedEnglish = getSortedCountries("en");
console.log(sortedEnglish.slice(0, 5));
// [
// { code: "AF", name: "Afghanistan" },
// { code: "AX", name: "Åland Islands" },
// { code: "AL", name: "Albania" },
// { code: "DZ", name: "Algeria" },
// { code: "AS", name: "American Samoa" }
// ]
const sortedSpanish = getSortedCountries("es");
console.log(sortedSpanish.slice(0, 5));
// [
// { code: "AF", name: "Afganistán" },
// { code: "AL", name: "Albania" },
// { code: "DE", name: "Alemania" },
// { code: "AD", name: "Andorra" },
// { code: "AO", name: "Angola" }
// ]
不同语言的排序顺序会有所不同,因为各国语名在不同的字母表和排序规则下排序方式不同。
构建全面的国家选择器
将 Intl.supportedValuesOf() 与 Intl.DisplayNames 结合,创建一个包含所有可用国家的选择器。
function createComprehensiveCountrySelector(locale) {
const countryNames = new Intl.DisplayNames([locale], { type: "region" });
const allCountries = Intl.supportedValuesOf("region");
const sortedCountries = allCountries
.map((code) => ({
code,
name: countryNames.of(code)
}))
.sort((a, b) => a.name.localeCompare(b.name, locale));
const select = document.createElement("select");
select.id = "country";
select.name = "country";
const placeholder = document.createElement("option");
placeholder.value = "";
placeholder.textContent = "Select a country";
select.appendChild(placeholder);
sortedCountries.forEach(({ code, name }) => {
const option = document.createElement("option");
option.value = code;
option.textContent = name;
select.appendChild(option);
});
return select;
}
const selector = createComprehensiveCountrySelector("en");
document.body.appendChild(selector);
该选择器包含浏览器支持的全部 249 个国家和地区,并按照用户语言的字母顺序排序。
处理无效的国家代码
并非所有的两位字符串都是有效的国家代码。of() 方法会根据 fallback 选项处理无效代码。
const withCodeFallback = new Intl.DisplayNames(["en"], {
type: "region",
fallback: "code"
});
const withNoneFallback = new Intl.DisplayNames(["en"], {
type: "region",
fallback: "none"
});
console.log(withCodeFallback.of("US"));
// "United States"
console.log(withCodeFallback.of("XX"));
// "XX"
console.log(withNoneFallback.of("US"));
// "United States"
console.log(withNoneFallback.of("XX"));
// undefined
fallback: "code" 选项在没有对应国家时返回输入的代码。fallback: "none" 选项在代码无效时返回 undefined。
当你需要检测无效代码并显式处理时,请使用 fallback: "none"。
function getValidatedCountryName(code, locale) {
const names = new Intl.DisplayNames([locale], {
type: "region",
fallback: "none"
});
const name = names.of(code);
if (name === undefined) {
return "Unknown country";
}
return name;
}
console.log(getValidatedCountryName("US", "en"));
// "United States"
console.log(getValidatedCountryName("INVALID", "en"));
// "Unknown country"
此模式有助于你校验用户输入或外部数据源的数据。
使用样式控制国家名称长度
style 选项用于控制国家名称的显示方式。三种取值会产生不同长度的输出。
const longNames = new Intl.DisplayNames(["en"], {
type: "region",
style: "long"
});
const shortNames = new Intl.DisplayNames(["en"], {
type: "region",
style: "short"
});
const narrowNames = new Intl.DisplayNames(["en"], {
type: "region",
style: "narrow"
});
console.log(longNames.of("US"));
// "United States"
console.log(shortNames.of("US"));
// "US"
console.log(narrowNames.of("US"));
// "US"
long 样式为默认值,显示完整国家名称。short 和 narrow 样式在可用时返回缩写形式。对于大多数国家,short 和 narrow 样式会直接返回国家代码。
部分国家有独特的简称。
const longNames = new Intl.DisplayNames(["en"], {
type: "region",
style: "long"
});
const shortNames = new Intl.DisplayNames(["en"], {
type: "region",
style: "short"
});
console.log(longNames.of("GB"));
// "United Kingdom"
console.log(shortNames.of("GB"));
// "UK"
console.log(longNames.of("BO"));
// "Bolivia"
console.log(shortNames.of("BO"));
// "Bolivia"
大多数界面建议使用默认的 long 样式。在移动端导航或紧凑表格等空间有限的场景下,可使用 short 或 narrow。
显示地区名称
ISO 3166-1 标准不仅包括独立国家,还涵盖了属地、附属地和特殊区域。Intl.DisplayNames API 同样支持这些地区。
const regionNames = new Intl.DisplayNames(["en"], { type: "region" });
console.log(regionNames.of("PR"));
// "Puerto Rico"
console.log(regionNames.of("GU"));
// "Guam"
console.log(regionNames.of("HK"));
// "Hong Kong"
console.log(regionNames.of("MQ"));
// "Martinique"
console.log(regionNames.of("GF"));
// "French Guiana"
这些代码的用法与国家代码相同。您的应用可以统一处理它们,浏览器会自动提供相应的本地化名称。
使用数字地区代码
ISO 3166-1 标准还定义了数字代码。Intl.DisplayNames API 除了支持两字母代码外,也接受联合国 M.49 数字地区代码。
const regionNames = new Intl.DisplayNames(["en"], { type: "region" });
console.log(regionNames.of("840"));
// "United States"
console.log(regionNames.of("250"));
// "France"
console.log(regionNames.of("392"));
// "Japan"
数字代码还可用于表示更大的地理区域。
const regionNames = new Intl.DisplayNames(["en"], { type: "region" });
console.log(regionNames.of("150"));
// "Europe"
console.log(regionNames.of("019"));
// "Americas"
console.log(regionNames.of("142"));
// "Asia"
console.log(regionNames.of("002"));
// "Africa"
console.log(regionNames.of("009"));
// "Oceania"
这些代码可跨语言使用。
const englishRegions = new Intl.DisplayNames(["en"], { type: "region" });
const spanishRegions = new Intl.DisplayNames(["es"], { type: "region" });
console.log(englishRegions.of("150"));
// "Europe"
console.log(spanishRegions.of("150"));
// "Europa"
当需要避免字符编码问题或与使用联合国 M.49 代码的系统对接时,可以使用数字代码。
缓存 DisplayNames 实例以提升性能
创建 Intl.DisplayNames 实例的开销很小,但如果应用需要转换大量国家代码,缓存格式化器会带来性能提升。
const displayNamesCache = new Map();
function getDisplayNames(locale, type) {
const key = `${locale}-${type}`;
if (!displayNamesCache.has(key)) {
displayNamesCache.set(
key,
new Intl.DisplayNames([locale], { type })
);
}
return displayNamesCache.get(key);
}
function getCountryName(code, locale) {
const formatter = getDisplayNames(locale, "region");
return formatter.of(code);
}
console.log(getCountryName("US", "en"));
// "United States"
console.log(getCountryName("FR", "en"));
// "France"
console.log(getCountryName("US", "es"));
// "Estados Unidos"
缓存会根据 locale 和 type 存储格式化器。后续调用会复用已有的格式化器,而不是每次都新建。
当需要渲染大量国家列表或在表格、数据网格中处理数百个国家代码时,这种优化尤为重要。
处理 locale 回退
Intl.DisplayNames 构造函数可以接受一个 locale 数组。如果第一个 locale 不被支持,浏览器会自动回退到数组中的下一个。
const names = new Intl.DisplayNames(["xx-XX", "en"], { type: "region" });
console.log(names.of("US"));
// "United States"
浏览器会先尝试 "xx-XX"(该 locale 不存在),然后回退到 "en"。这样可以确保即使请求的 locale 不可用,代码依然能正常工作。
你可以检查格式化器实际使用的是哪个 locale。
const names = new Intl.DisplayNames(["xx-XX", "en"], { type: "region" });
console.log(names.resolvedOptions().locale);
// "en"
resolvedOptions() 方法会返回格式化器在回退处理后最终确定的 locale。
跨语言对比国家名称
不同语言对国家名称的格式化方式各不相同。有些语言会将国家名称首字母大写,有些则不会。有些语言包含冠词,有些则不包含。
const english = new Intl.DisplayNames(["en"], { type: "region" });
const french = new Intl.DisplayNames(["fr"], { type: "region" });
const german = new Intl.DisplayNames(["de"], { type: "region" });
console.log(english.of("US"));
// "United States"
console.log(french.of("US"));
// "États-Unis"
console.log(german.of("US"));
// "Vereinigte Staaten"
console.log(english.of("NL"));
// "Netherlands"
console.log(french.of("NL"));
// "Pays-Bas"
console.log(german.of("NL"));
// "Niederlande"
格式化器会自动处理所有这些语言习惯。你无需了解每种语言的语法规则。
浏览器支持
Intl.DisplayNames API 及 type: "region" 在所有现代浏览器中均可用。从 2021 年起,主流浏览器(包括 Chrome、Firefox、Safari 和 Edge)都已支持。
现代应用可以直接使用该 API,无需 polyfill 或回退。浏览器会维护国家名称数据,并在国家和地区变化时保持更新。
你可以在使用前检查该 API 是否可用。
if (typeof Intl.DisplayNames !== "undefined") {
const names = new Intl.DisplayNames(["en"], { type: "region" });
console.log(names.of("US"));
} else {
console.log("Intl.DisplayNames is not supported");
}
对于需要支持旧版浏览器的应用,可以通过静态国家名称查找表提供回退方案。
function getCountryName(code, locale) {
if (typeof Intl.DisplayNames !== "undefined") {
const names = new Intl.DisplayNames([locale], { type: "region" });
return names.of(code);
}
const fallbackNames = {
US: "United States",
GB: "United Kingdom",
FR: "France",
DE: "Germany",
JP: "Japan"
};
return fallbackNames[code] || code;
}
console.log(getCountryName("US", "en"));
// "United States"
这样可以确保你的应用在所有浏览器中都能正常工作,但旧版浏览器将无法自动本地化。