Intl.DisplayNames API

将语言、地区、货币和脚本代码转换为人类可读的名称

介绍

您的应用程序使用国家代码 US,但用户看到的文本是“United States”。您使用语言代码 fr,但语言切换器显示“French”。您使用货币代码 EUR,但结账页面显示“Euro”。

浏览器维护了广泛的本地化数据,用于以不同语言呈现其自身界面。Intl.DisplayNames API 将这些数据暴露给 JavaScript,将标准化代码转换为任何语言的本地化可读名称。

这消除了对需要维护和本地化的第三方库或自定义查找表的需求。浏览器同时处理数据和翻译。

将地区代码转换为国家名称

最常见的用例是将 ISO 国家代码转换为国家名称。创建一个带有区域设置和类型的 DisplayNames 实例,然后使用国家代码调用 of() 方法:

const regionNames = new Intl.DisplayNames(["en"], { type: "region" });

console.log(regionNames.of("US")); // "United States"
console.log(regionNames.of("GB")); // "United Kingdom"
console.log(regionNames.of("JP")); // "Japan"

第一个参数接受一个遵循 BCP 47 标准的区域代码数组。浏览器使用数组中第一个支持的区域设置。type 选项指定您想要转换的代码类型。

相同的代码在为不同语言本地化时会产生不同的输出:

const englishRegions = new Intl.DisplayNames(["en"], { type: "region" });
const japaneseRegions = new Intl.DisplayNames(["ja"], { type: "region" });
const spanishRegions = new Intl.DisplayNames(["es"], { type: "region" });

console.log(englishRegions.of("FR")); // "France"
console.log(japaneseRegions.of("FR")); // "フランス"
console.log(spanishRegions.of("FR")); // "Francia"

这种模式适用于构建国家选择器、位置显示以及任何将国家代码转换为可读名称的界面元素。

将语言代码转换为语言名称

语言代码的模式与区域代码相同。设置 type: "language" 来将语言代码转换为语言名称:

const languageNames = new Intl.DisplayNames(["en"], { type: "language" });

console.log(languageNames.of("en")); // "English"
console.log(languageNames.of("es")); // "Spanish"
console.log(languageNames.of("zh")); // "Chinese"
console.log(languageNames.of("ar")); // "Arabic"

语言代码可以包含区域子标签以表示区域变体:

const languageNames = new Intl.DisplayNames(["en"], { type: "language" });

console.log(languageNames.of("en-US")); // "American English"
console.log(languageNames.of("en-GB")); // "British English"
console.log(languageNames.of("fr-CA")); // "Canadian French"
console.log(languageNames.of("pt-BR")); // "Brazilian Portuguese"

这可以将语言代码转换为适用于语言切换器、翻译界面和语言偏好选择器的名称。

以语言自身的语言显示语言名称

语言切换器通常以每种语言的书写系统显示语言名称。为每种目标语言创建一个单独的 DisplayNames 实例:

const english = new Intl.DisplayNames(["en"], { type: "language" });
const french = new Intl.DisplayNames(["fr"], { type: "language" });
const japanese = new Intl.DisplayNames(["ja"], { type: "language" });
const arabic = new Intl.DisplayNames(["ar"], { type: "language" });

console.log(english.of("en")); // "English"
console.log(french.of("fr")); // "français"
console.log(japanese.of("ja")); // "日本語"
console.log(arabic.of("ar")); // "العربية"

当语言以其本地脚本显示时,用户可以更快地识别出他们的语言。

将货币代码转换为货币名称

货币代码遵循 ISO 4217 标准。设置 type: "currency" 来将三字母货币代码转换为货币名称:

const currencyNames = new Intl.DisplayNames(["en"], { type: "currency" });

console.log(currencyNames.of("USD")); // "US Dollar"
console.log(currencyNames.of("EUR")); // "Euro"
console.log(currencyNames.of("GBP")); // "British Pound"
console.log(currencyNames.of("JPY")); // "Japanese Yen"

货币名称会根据显示语言环境进行本地化:

const englishCurrency = new Intl.DisplayNames(["en"], { type: "currency" });
const germanCurrency = new Intl.DisplayNames(["de"], { type: "currency" });
const japaneseCurrency = new Intl.DisplayNames(["ja"], { type: "currency" });

console.log(englishCurrency.of("EUR")); // "Euro"
console.log(germanCurrency.of("EUR")); // "Euro"
console.log(japaneseCurrency.of("EUR")); // "ユーロ"

这种模式适用于结账流程中的货币选择器、金融仪表板和货币转换界面。

将脚本代码转换为脚本名称

脚本代码使用 ISO 15924 标准。设置 type: "script" 以将四字母脚本代码转换为脚本名称:

const scriptNames = new Intl.DisplayNames(["en"], { type: "script" });

console.log(scriptNames.of("Latn")); // "Latin"
console.log(scriptNames.of("Arab")); // "Arabic"
console.log(scriptNames.of("Cyrl")); // "Cyrillic"
console.log(scriptNames.of("Hans")); // "简体中文"
console.log(scriptNames.of("Hant")); // "繁体中文"

脚本名称在用户界面中较少出现,但在多语言内容管理系统和区分书写系统的语言选择界面中变得重要。

将日历代码转换为日历名称

日历系统因文化而异。设置 type: "calendar" 以将日历标识符转换为日历名称:

const calendarNames = new Intl.DisplayNames(["en"], { type: "calendar" });

console.log(calendarNames.of("gregory")); // "Gregorian Calendar"
console.log(calendarNames.of("japanese")); // "Japanese Calendar"
console.log(calendarNames.of("buddhist")); // "Buddhist Calendar"
console.log(calendarNames.of("hebrew")); // "Hebrew Calendar"
console.log(calendarNames.of("islamic")); // "Islamic Calendar"
console.log(calendarNames.of("chinese")); // "Chinese Calendar"

这在调度应用程序、带有日历系统选择的日期选择器和国际化日历界面中非常有用。

将日期和时间字段代码转换为字段名称

日期和时间界面包含诸如年份、月份和日期等标记字段。设置 type: "dateTimeField" 以将字段标识符转换为本地化字段名称:

const dateFields = new Intl.DisplayNames(["en"], { type: "dateTimeField" });

console.log(dateFields.of("year")); // "year"
console.log(dateFields.of("month")); // "month"
console.log(dateFields.of("day")); // "day"
console.log(dateFields.of("hour")); // "hour"
console.log(dateFields.of("minute")); // "minute"
console.log(dateFields.of("weekday")); // "day of the week"
console.log(dateFields.of("dayPeriod")); // "AM/PM"
console.log(dateFields.of("timeZoneName")); // "time zone"

这些字段名称会根据显示语言进行本地化:

const englishFields = new Intl.DisplayNames(["en"], { type: "dateTimeField" });
const spanishFields = new Intl.DisplayNames(["es"], { type: "dateTimeField" });
const japaneseFields = new Intl.DisplayNames(["ja"], { type: "dateTimeField" });

console.log(englishFields.of("month")); // "month"
console.log(spanishFields.of("month")); // "mes"
console.log(japaneseFields.of("month")); // "月"

有效的字段标识符包括 erayearquartermonthweekOfYearweekdaydaydayPeriodhourminutesecondtimeZoneName

此模式支持构建具有正确本地化标签的无障碍日期选择器、日历界面和时间选择组件。

使用样式选项控制显示长度

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 样式在可能的情况下会生成缩写形式,但并非所有代码都有更短的变体。

样式在语言名称中更为重要:

const longLanguages = new Intl.DisplayNames(["en"], {
  type: "language",
  style: "long",
});

const shortLanguages = new Intl.DisplayNames(["en"], {
  type: "language",
  style: "short",
});

console.log(longLanguages.of("en-US")); // "American English"
console.log(shortLanguages.of("en-US")); // "US English"

在表单和详细界面中使用 long 样式以显示完整标签。在移动导航或空间受限的 UI 元素中使用 shortnarrow 样式以实现紧凑显示。

使用 languageDisplay 处理区域语言变体

带有区域子标签的语言代码可以显示为方言或带有区域限定符的标准语言名称。languageDisplay 选项控制此行为,仅在 type: "language" 时适用:

const dialectNames = new Intl.DisplayNames(["en"], {
  type: "language",
  languageDisplay: "dialect",
});

const standardNames = new Intl.DisplayNames(["en"], {
  type: "language",
  languageDisplay: "standard",
});

console.log(dialectNames.of("nl-BE")); // "Flemish"
console.log(standardNames.of("nl-BE")); // "Dutch (Belgium)"

console.log(dialectNames.of("en-AU")); // "Australian English"
console.log(standardNames.of("en-AU")); // "English (Australia)"

dialect 值(默认值)使用常见名称显示区域变体。standard 值始终以括号中的区域限定符显示基础语言。

当区域变体有用户熟知的名称时,选择 dialect。当需要一致的格式或处理不太常见的语言-区域组合时,选择 standard

控制无效代码的回退行为

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("ZZ")); // "ZZ"
console.log(withNoneFallback.of("ZZ")); // undefined

code 值(默认值)在没有显示名称时返回输入代码。none 值对未映射的代码返回 undefined

当您始终需要一个字符串值用于显示时,即使它回退到代码本身,也请使用 code。当您需要检测无效代码并显式处理它们时,请使用 none

const regionNames = new Intl.DisplayNames(["en"], {
  type: "region",
  fallback: "none",
});

function getRegionName(code) {
  const name = regionNames.of(code);
  if (name === undefined) {
    return "未知地区";
  }
  return name;
}

console.log(getRegionName("US")); // "United States"
console.log(getRegionName("INVALID")); // "未知地区"

构建国家选择器组件

Intl.DisplayNames API 可直接集成到界面组件中。以下示例构建了一个国家选择器,它以用户的语言显示国家名称:

function CountrySelector({ locale, value, onChange }) {
  const regionNames = new Intl.DisplayNames([locale], { type: "region" });

  const countries = [
    "US",
    "GB",
    "CA",
    "AU",
    "FR",
    "DE",
    "JP",
    "CN",
    "BR",
    "IN",
  ];

  return (
    <select value={value} onChange={(e) => onChange(e.target.value)}>
      <option value="">选择一个国家</option>
      {countries.map((code) => (
        <option key={code} value={code}>
          {regionNames.of(code)}
        </option>
      ))}
    </select>
  );
}

该组件接收一个 locale 属性,用于控制显示语言。更改 locale 属性会重新渲染下拉菜单,并显示翻译后的国家名称。

构建语言切换器组件

语言切换器以各自的书写系统显示每种语言。为每种语言创建一个 DisplayNames 实例:

function LanguageSwitcher({ currentLocale, onLocaleChange }) {
  const languages = [
    { code: "en", name: "English" },
    { code: "es", name: "Español" },
    { code: "fr", name: "Français" },
    { code: "de", name: "Deutsch" },
    { code: "ja", name: "日本語" },
    { code: "zh", name: "中文" },
  ];

  return (
    <div>
      {languages.map((lang) => {
        const displayNames = new Intl.DisplayNames([lang.code], {
          type: "language",
        });
        const nativeName = displayNames.of(lang.code);

        return (
          <button
            key={lang.code}
            onClick={() => onLocaleChange(lang.code)}
            className={currentLocale === lang.code ? "active" : ""}
          >
            {nativeName}
          </button>
        );
      })}
    </div>
  );
}

每个按钮以其自身的脚本显示语言名称。无论当前界面语言如何,用户都能立即识别自己的语言。

构建货币选择器组件

货币选择器受益于本地化的货币名称。以下示例创建了一个适应显示语言的货币选择器:

function CurrencySelector({ locale, value, onChange }) {
  const currencyNames = new Intl.DisplayNames([locale], { type: "currency" });

  const currencies = ["USD", "EUR", "GBP", "JPY", "CNY", "CAD", "AUD"];

  return (
    <select value={value} onChange={(e) => onChange(e.target.value)}>
      <option value="">选择货币</option>
      {currencies.map((code) => (
        <option key={code} value={code}>
          {code} - {currencyNames.of(code)}
        </option>
      ))}
    </select>
  );
}

下拉菜单同时显示货币代码和本地化的货币名称。不同地区的用户会看到以其语言显示的货币名称。

获取所有支持的值

Intl.supportedValuesOf() 方法返回每种类型支持的所有值的数组。这消除了硬编码代码列表的需求:

const regions = Intl.supportedValuesOf("region");
console.log(regions); // ["AD", "AE", "AF", "AG", "AI", ...]

const languages = Intl.supportedValuesOf("language");
console.log(languages); // ["aa", "ab", "ae", "af", "ak", ...]

const currencies = Intl.supportedValuesOf("currency");
console.log(currencies); // ["AED", "AFN", "ALL", "AMD", ...]

const calendars = Intl.supportedValuesOf("calendar");
console.log(calendars); // ["buddhist", "chinese", "coptic", ...]

构建动态选择器,自动包含所有支持的值:

function UniversalCountrySelector({ locale, value, onChange }) {
  const regionNames = new Intl.DisplayNames([locale], { type: "region" });
  const allRegions = Intl.supportedValuesOf("region");

  return (
    <select value={value} onChange={(e) => onChange(e.target.value)}>
      <option value="">选择一个国家</option>
      {allRegions.map((code) => (
        <option key={code} value={code}>
          {regionNames.of(code)}
        </option>
      ))}
    </select>
  );
}

此组件包含浏览器支持的所有地区代码,而无需维护硬编码列表。

理解代码格式要求

每种类型都需要特定格式的代码。不正确的格式会导致回退行为,而不是显示名称。

区域代码遵循 ISO 3166-1 alpha-2(两个字母)或 UN M.49(三位数字):

const regionNames = new Intl.DisplayNames(["en"], { type: "region" });

console.log(regionNames.of("US")); // "United States"(ISO 3166-1)
console.log(regionNames.of("001")); // "world"(UN M.49)
console.log(regionNames.of("150")); // "Europe"(UN M.49)

语言代码遵循 BCP 47,它将 ISO 639 语言代码与可选的区域和脚本子标签结合起来:

const languageNames = new Intl.DisplayNames(["en"], { type: "language" });

console.log(languageNames.of("en")); // "English"
console.log(languageNames.of("en-US")); // "American English"
console.log(languageNames.of("zh-Hans")); // "Simplified Chinese"
console.log(languageNames.of("zh-Hans-CN")); // "Simplified Chinese (China)"

货币代码遵循 ISO 4217(三个字母):

const currencyNames = new Intl.DisplayNames(["en"], { type: "currency" });

console.log(currencyNames.of("USD")); // "US Dollar"
console.log(currencyNames.of("EUR")); // "Euro"

脚本代码遵循 ISO 15924(四个字母,首字母大写):

const scriptNames = new Intl.DisplayNames(["en"], { type: "script" });

console.log(scriptNames.of("Latn")); // "Latin"
console.log(scriptNames.of("Arab")); // "Arabic"

代码比较不区分大小写,但遵循标准的大小写格式可以提高可读性:

const regionNames = new Intl.DisplayNames(["en"], { type: "region" });

console.log(regionNames.of("US")); // "United States"
console.log(regionNames.of("us")); // "United States"
console.log(regionNames.of("Us")); // "United States"

浏览器支持与兼容性

Intl.DisplayNames API 自 2021 年起在所有主流浏览器中可用。现代应用程序可以无需 polyfill 直接使用。

带有 languageregionscriptcurrency 类型的基础 API 具有普遍支持。calendardateTimeField 类型出现在后续的浏览器版本中,但截至 2025 年已被广泛支持。

在必要时可以在运行时检查功能支持:

if (typeof Intl.DisplayNames !== "undefined") {
  const regionNames = new Intl.DisplayNames(["en"], { type: "region" });
  console.log(regionNames.of("US"));
} else {
  console.log("Intl.DisplayNames not supported");
}

对于支持旧版浏览器的应用程序,当 API 不可用时,可以回退到静态查找表或第三方库。

使用缓存优化性能

创建 DisplayNames 实例的开销很小,但对于需要转换大量代码的应用程序,应重用实例:

const cache = new Map();

function getDisplayNames(locale, type) {
  const key = `${locale}-${type}`;

  if (!cache.has(key)) {
    cache.set(key, new Intl.DisplayNames([locale], { type }));
  }

  return cache.get(key);
}

function getCountryName(locale, code) {
  const displayNames = getDisplayNames(locale, "region");
  return displayNames.of(code);
}

console.log(getCountryName("en", "US")); // "United States"
console.log(getCountryName("en", "FR")); // "France"
console.log(getCountryName("es", "US")); // "Estados Unidos"

缓存通过区域设置和类型作为键存储实例。后续调用会重用现有实例,而不是创建新实例。

这种模式在需要转换数百或数千个代码的热点代码路径中最为重要,例如渲染大型本地化数据表。

与替代方法的比较

Intl.DisplayNames API 出现之前,应用程序使用了几种方法将代码转换为名称。

硬编码查找表需要维护,并且仅支持预定的语言:

const countryNames = {
  US: "United States",
  GB: "United Kingdom",
  FR: "France",
};

function getCountryName(code) {
  return countryNames[code] || code;
}

这种方法在添加新语言时会失效,因为每种语言都需要单独的查找表。

第三方库提供了本地化数据,但增加了包的大小:

import countries from "i18n-iso-countries";
import countriesEN from "i18n-iso-countries/langs/en.json";
import countriesES from "i18n-iso-countries/langs/es.json";

countries.registerLocale(countriesEN);
countries.registerLocale(countriesES);

console.log(countries.getName("US", "en")); // "United States"
console.log(countries.getName("US", "es")); // "Estados Unidos"

库会向包中添加数千字节的数据,并且在出现新国家或名称更改时需要更新。

Intl.DisplayNames API 消除了这两个问题。浏览器维护数据,保持其最新状态,并消除了包大小的顾虑。数据支持浏览器支持的所有语言,无需额外下载。