如何以不同语言显示国家名称?

使用 Intl.DisplayNames 将国家代码转换为国际用户的本地化国家名称。

介绍

当您构建一个运输表单、用户个人资料页面或地址选择器时,您需要显示国家名称。用户会看到英文的 "France",西班牙语的 "Francia",德语的 "Frankreich",以及日语的 "フランス"。每个用户都希望看到以他们自己的语言书写的国家名称。

您的应用程序在数据库和 API 中存储国家代码,例如 FRUSJP。这些标准化代码可以在所有系统中使用,但用户需要可读的国家名称。Intl.DisplayNames API 可以将国家代码转换为任何语言的本地化国家名称,而无需维护翻译表或依赖外部库。

了解国家代码

国家通过 ISO 3166-1 alpha-2 标准定义的两位字母代码进行标识。每个国家都有一个唯一的代码,该代码在所有语言和系统中保持不变。

// 常见的国家代码
// US = 美国
// GB = 英国(联合王国)
// FR = 法国
// DE = 德国(Deutschland)
// JP = 日本
// CN = 中国
// BR = 巴西
// IN = 印度

这些代码出现在表单、URL、数据库和 API 中。代码 US 始终表示美国,无论您的应用程序是以英语、西班牙语、日语还是其他任何语言运行。代码提供了一个稳定的标识符,而显示名称会根据用户的语言而变化。

使用 Intl.DisplayNames 获取国家名称

Intl.DisplayNames 构造函数创建一个格式化器,用于将国家代码转换为国家名称。您需要指定一个语言环境,并将类型设置为 "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"

第一个参数是一个语言环境标识符数组。type: "region" 选项告诉格式化器您需要国家或地区名称。of() 方法接受一个国家代码并返回其本地化名称。

术语 "region" 包括国家、地区和地理区域。这包括像法国这样的独立国家、像波多黎各这样的地区,以及像欧盟这样的特殊区域。

在不同语言中显示国家名称

相同的国家代码在不同语言中会生成不同的名称。为不同的语言环境创建格式化器,查看国家名称如何变化。

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.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(截至 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.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 "未知国家";
  }

  return name;
}

console.log(getValidatedCountryName("US", "en"));
// "United States"

console.log(getValidatedCountryName("INVALID", "en"));
// "未知国家"

这种模式有助于验证用户输入或外部数据。

使用样式控制国家名称长度

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 样式是默认值,生成完整的国家名称。shortnarrow 样式在可用时返回缩写形式。对于大多数国家,shortnarrow 样式返回国家代码本身。

某些国家有独特的短形式。

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 样式。在空间有限的情况下,例如移动导航或紧凑表格中,使用 shortnarrow 样式。

显示地区的区域名称

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"

缓存以区域和类型为键存储格式化器。后续调用会重用现有的格式化器,而不是创建新的。

当渲染大量国家列表或在表格或数据网格中处理数百个国家代码时,这种优化尤为重要。

处理语言环境回退

Intl.DisplayNames 构造函数接受一个语言环境数组。如果第一个语言环境不受支持,浏览器会回退到数组中的下一个语言环境。

const names = new Intl.DisplayNames(["xx-XX", "en"], { type: "region" });

console.log(names.of("US"));
// "United States"

浏览器首先尝试 "xx-XX",但该语言环境不存在,因此回退到 "en"。这确保了即使请求的语言环境不可用,代码也能正常运行。

您可以检查格式化器实际使用的语言环境。

const names = new Intl.DisplayNames(["xx-XX", "en"], { type: "region" });

console.log(names.resolvedOptions().locale);
// "en"

resolvedOptions() 方法返回格式化器在回退处理后解析到的语言环境。

比较不同语言中的国家名称

不同语言对国家名称的格式化方式不同。有些语言将国家名称大写,而有些则不会。有些语言包含冠词,而有些则没有。

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"

这确保了您的应用程序可以在所有浏览器中运行,尽管旧版浏览器会失去自动本地化功能。