如何显示语言名称,例如 English、Español、日本語?

使用 Intl.DisplayNames 在语言选择器和国际化界面中以本地脚本显示语言名称。

介绍

当您构建语言选择器或显示可用语言列表时,需要以用户能够识别的方式显示每种语言的名称。法语使用者会寻找“Français”,西班牙语使用者会寻找“Español”,而日语使用者会寻找“日本語”。用户通过其母语的文字和拼写来识别语言。

硬编码这些翻译无法扩展。您需要维护每种语言名称到其他所有语言的翻译。Intl.DisplayNames API 通过提供标准化的、符合语言环境的语言、国家/地区、脚本和货币名称,解决了这个问题。

硬编码语言名称的问题

您可以通过在对象中硬编码语言名称来创建语言选择器。

const languageNames = {
  en: "English",
  es: "Spanish",
  fr: "French",
  de: "German",
  ja: "Japanese"
};

console.log(languageNames.en);
// "English"

这种方法有三个问题。首先,这些名称仅适用于英语使用者。其次,用户无法在以英语显示的情况下识别其语言。一位日语用户在扫描其语言时会寻找日语字符,而不是单词“Japanese”。第三,您需要手动维护每种语言到其他所有语言的翻译。

const languageNames = {
  en: {
    en: "English",
    es: "Spanish",
    fr: "French",
    de: "German",
    ja: "Japanese"
  },
  es: {
    en: "Inglés",
    es: "Español",
    fr: "Francés",
    de: "Alemán",
    ja: "Japonés"
  }
  // ... 更多语言
};

这很快就会变得难以维护。您需要一个更好的解决方案。

使用 Intl.DisplayNames 获取语言名称

Intl.DisplayNames 构造函数创建一个格式化器,将语言代码转换为人类可读的名称。您需要指定一个语言环境和您想要显示的名称类型。

const names = new Intl.DisplayNames(["en"], { type: "language" });
console.log(names.of("en"));
// "English"

第一个参数是一个语言环境标识符数组。第二个参数是一个选项对象,其中 type: "language" 告诉格式化器您需要语言名称。of() 方法接受一个语言代码并返回其名称。

通过更改语言环境,您可以以任何语言获取名称。

const enNames = new Intl.DisplayNames(["en"], { type: "language" });
const esNames = new Intl.DisplayNames(["es"], { type: "language" });
const frNames = new Intl.DisplayNames(["fr"], { type: "language" });

console.log(enNames.of("es"));
// "Spanish"

console.log(esNames.of("es"));
// "español"

console.log(frNames.of("es"));
// "espagnol"

每个格式化器都会返回其显示语言环境中的语言名称。这处理了维护语言名称翻译的所有复杂性。

以母语形式显示语言名称

语言选择器的最佳实践是以每种语言的脚本显示语言名称。当用户看到熟悉的字符时,他们能更快地识别自己的语言。

const names = new Intl.DisplayNames(["ja"], { type: "language" });
console.log(names.of("ja"));
// "日本語"

要获取每种语言的母语名称,可以使用目标语言作为显示区域来创建格式化器。

function getNativeName(languageCode) {
  const names = new Intl.DisplayNames([languageCode], { type: "language" });
  return names.of(languageCode);
}

console.log(getNativeName("en"));
// "English"

console.log(getNativeName("es"));
// "español"

console.log(getNativeName("fr"));
// "français"

console.log(getNativeName("de"));
// "Deutsch"

console.log(getNativeName("ja"));
// "日本語"

console.log(getNativeName("ar"));
// "العربية"

console.log(getNativeName("zh"));
// "中文"

这种模式适用于任何语言代码。格式化器会返回母语使用者使用的脚本和形式中的名称。

理解语言代码格式

of() 方法接受多种格式的语言代码。您可以使用基本的语言代码(如 "en")或完整的区域标识符(如 "en-US")。

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

console.log(names.of("en"));
// "English"

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

console.log(names.of("en-GB"));
// "British English"

console.log(names.of("zh"));
// "Chinese"

console.log(names.of("zh-Hans"));
// "Simplified Chinese"

console.log(names.of("zh-Hant"));
// "Traditional Chinese"

格式化器可以识别短代码和带有区域或脚本子标签的扩展标识符。这使您能够区分语言变体。

控制语言名称的显示方式

languageDisplay 选项控制返回名称的详细程度。它接受两个值。

"standard" 值返回包含方言信息的完整名称。这是默认值。

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

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

console.log(names.of("en-GB"));
// "British English"

console.log(names.of("pt-BR"));
// "Brazilian Portuguese"

console.log(names.of("pt-PT"));
// "European Portuguese"

"dialect" 值也返回包含方言信息的完整名称。在大多数情况下,它的输出与 "standard" 相同。

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

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

console.log(names.of("pt-BR"));
// "Brazilian Portuguese"

对于语言选择器,标准格式有助于用户在多种方言可用时选择正确的变体。

为用户界面获取本地化的语言名称

当您构建设置页面或语言选择器时,需要以用户当前的界面语言显示语言名称。使用用户的语言环境创建一个格式化器。

function getLocalizedLanguageName(languageCode, userLocale) {
  const names = new Intl.DisplayNames([userLocale], { type: "language" });
  return names.of(languageCode);
}

// 用户界面为英文
console.log(getLocalizedLanguageName("ja", "en"));
// "Japanese"

// 用户界面为法文
console.log(getLocalizedLanguageName("ja", "fr"));
// "japonais"

// 用户界面为西班牙文
console.log(getLocalizedLanguageName("ja", "es"));
// "japonés"

这种方法以用户理解的语言显示描述性名称。将此方法与本地名称结合使用,可以创建像 "日本語 (Japanese)" 这样的混合标签,既适合母语使用者,也适合其他用户。

使用本地名称构建语言选择器

一个常见的用例是构建一个下拉菜单或列表,让用户选择他们的首选语言。以本地形式显示每种语言,使用户可以快速找到他们的选项。

const supportedLanguages = ["en", "es", "fr", "de", "ja", "ar", "zh"];

function createLanguageOptions() {
  return supportedLanguages.map((code) => {
    const names = new Intl.DisplayNames([code], { type: "language" });
    const nativeName = names.of(code);
    return { code, name: nativeName };
  });
}

const options = createLanguageOptions();
console.log(options);

这将生成一个包含本地名称的语言选项数组。

[
  { code: "en", name: "English" },
  { code: "es", name: "español" },
  { code: "fr", name: "français" },
  { code: "de", name: "Deutsch" },
  { code: "ja", name: "日本語" },
  { code: "ar", name: "العربية" },
  { code: "zh", name: "中文" }
]

您可以将这些选项渲染为 HTML,以创建一个语言选择器。

function renderLanguageSelector() {
  const options = createLanguageOptions();
  const select = document.createElement("select");
  select.id = "language-selector";

  options.forEach((option) => {
    const optionElement = document.createElement("option");
    optionElement.value = option.code;
    optionElement.textContent = option.name;
    select.appendChild(optionElement);
  });

  return select;
}

const selector = renderLanguageSelector();
document.body.appendChild(selector);

这将创建一个下拉菜单,其中每种语言以其本地脚本显示,使用户可以轻松识别他们的语言。

创建混合语言标签

某些界面同时显示本地名称和用户语言的翻译。这有助于用户识别不熟悉的文字,同时也使界面更加易于访问。

function createHybridLabel(languageCode, userLocale) {
  const nativeNames = new Intl.DisplayNames([languageCode], {
    type: "language"
  });
  const localizedNames = new Intl.DisplayNames([userLocale], {
    type: "language"
  });

  const nativeName = nativeNames.of(languageCode);
  const localizedName = localizedNames.of(languageCode);

  if (nativeName === localizedName) {
    return nativeName;
  }

  return `${nativeName} (${localizedName})`;
}

// 用户界面为英文
console.log(createHybridLabel("ja", "en"));
// "日本語 (Japanese)"

console.log(createHybridLabel("ar", "en"));
// "العربية (Arabic)"

console.log(createHybridLabel("en", "en"));
// "English"

// 用户界面为西班牙语
console.log(createHybridLabel("ja", "es"));
// "日本語 (japonés)"

这种模式结合了本地名称的识别优势和翻译的清晰性。

处理回退语言环境

Intl.DisplayNames 构造函数接受一个语言环境数组。如果第一个语言环境不可用,格式化器会回退到数组中的下一个语言环境。

const names = new Intl.DisplayNames(["xx-XX", "en"], { type: "language" });
console.log(names.of("fr"));
// "French"

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

您可以使用 resolvedOptions() 方法检查格式化器实际使用的语言环境。

const names = new Intl.DisplayNames(["xx-XX", "en"], { type: "language" });
console.log(names.resolvedOptions().locale);
// "en"

这表明格式化器在回退后解析为英语。

不同语言环境如何格式化语言名称

每种语言环境都有其自己的语言名称约定。格式化器会自动应用这些约定。

const supportedLanguages = ["en", "es", "fr", "de", "ja"];

function showLanguageNamesInLocale(locale) {
  const names = new Intl.DisplayNames([locale], { type: "language" });
  return supportedLanguages.map((code) => ({
    code,
    name: names.of(code)
  }));
}

console.log(showLanguageNamesInLocale("en"));
// [
//   { code: "en", name: "English" },
//   { code: "es", name: "Spanish" },
//   { code: "fr", name: "French" },
//   { code: "de", name: "German" },
//   { code: "ja", name: "Japanese" }
// ]

console.log(showLanguageNamesInLocale("es"));
// [
//   { code: "en", name: "inglés" },
//   { code: "es", name: "español" },
//   { code: "fr", name: "francés" },
//   { code: "de", name: "alemán" },
//   { code: "ja", name: "japonés" }
// ]

console.log(showLanguageNamesInLocale("ja"));
// [
//   { code: "en", name: "英語" },
//   { code: "es", name: "スペイン語" },
//   { code: "fr", name: "フランス語" },
//   { code: "de", name: "ドイツ語" },
//   { code: "ja", name: "日本語" }
// ]

格式化器会自动处理每种语言的大小写、文字和语言习惯。

浏览器支持

Intl.DisplayNames API 可在所有现代浏览器中使用。从 2021 年 3 月起,主流浏览器(包括 Chrome、Firefox、Safari 和 Edge)已支持该功能。

在使用之前,您可以检查该 API 是否可用。

if (typeof Intl.DisplayNames !== "undefined") {
  const names = new Intl.DisplayNames(["en"], { type: "language" });
  console.log(names.of("fr"));
} else {
  console.log("Intl.DisplayNames 不受支持");
}

对于较旧的浏览器,您需要提供一个回退方案或使用 polyfill。一个简单的回退方案是使用硬编码的语言代码到名称的映射。

function getLanguageName(code, locale) {
  if (typeof Intl.DisplayNames !== "undefined") {
    const names = new Intl.DisplayNames([locale], { type: "language" });
    return names.of(code);
  }

  // 较旧浏览器的回退方案
  const fallbackNames = {
    en: "English",
    es: "español",
    fr: "français",
    de: "Deutsch",
    ja: "日本語"
  };

  return fallbackNames[code] || code;
}

console.log(getLanguageName("es", "en"));
// "español"(如果您调整了回退方案以进行本地化,则可能显示为 "Spanish")

这可以确保您的代码即使在不支持 Intl.DisplayNames 的浏览器中也能正常工作,但您将失去自动本地化功能。