如何显示语言名称,如 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"
}
// ... more languages
};
这种方式很快就变得难以维护。你需要更好的解决方案。
使用 Intl.DisplayNames 获取语言名称
Intl.DisplayNames 构造函数可以创建一个格式化器,将语言代码转换为可读的名称。你可以指定本地化和要显示的名称类型。
const names = new Intl.DisplayNames(["en"], { type: "language" });
console.log(names.of("en"));
// "English"
第一个参数是本地标识符数组。第二个参数是选项对象,其中 type: "language" 指定格式化器返回语言名称。of() 方法接收语言代码并返回其名称。
只需更改 locale,即可获取任意语言的名称。
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"
每个 formatter 都会根据显示 locale 返回对应的语言名称,无需手动维护语言名称的翻译。
以本地形式显示语言名称
语言选择器的最佳实践是用各自的文字脚本显示每种语言。用户在看到熟悉的字符时能更快识别自己的语言。
const names = new Intl.DisplayNames(["ja"], { type: "language" });
console.log(names.of("ja"));
// "日本語"
要获取每种语言的本地名称,请使用目标语言作为显示 locale 创建 formatter。
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"));
// "中文"
这种模式适用于任意语言代码。formatter 会以母语者常用的脚本和形式返回名称。
了解语言代码格式
of() 方法支持多种语言代码格式。你可以使用基础语言代码(如 "en"),也可以用完整的 locale 标识符(如 "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"
formatter 能识别简短代码和带有地区或脚本子标签的扩展标识符,从而区分不同的语言变体。
控制语言名称的显示方式
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"
对于语言选择器,标准格式有助于用户在存在多种方言时选择正确的变体。
获取用于用户界面的本地化语言名称
在构建设置页面或语言选择器时,需要以用户当前界面语言显示语言名称。请使用用户的 locale 创建格式化器。
function getLocalizedLanguageName(languageCode, userLocale) {
const names = new Intl.DisplayNames([userLocale], { type: "language" });
return names.of(languageCode);
}
// User interface is in English
console.log(getLocalizedLanguageName("ja", "en"));
// "Japanese"
// User interface is in French
console.log(getLocalizedLanguageName("ja", "fr"));
// "japonais"
// User interface is in Spanish
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})`;
}
// User interface is in English
console.log(createHybridLabel("ja", "en"));
// "日本語 (Japanese)"
console.log(createHybridLabel("ar", "en"));
// "العربية (Arabic)"
console.log(createHybridLabel("en", "en"));
// "English"
// User interface is in Spanish
console.log(createHybridLabel("ja", "es"));
// "日本語 (japonés)"
这种模式结合了本地名称的识别优势和本地化翻译的清晰性。
处理回退语言环境
Intl.DisplayNames 构造函数接受一个 locale 数组。如果第一个 locale 不可用,格式化器会回退到数组中的下一个 locale。
const names = new Intl.DisplayNames(["xx-XX", "en"], { type: "language" });
console.log(names.of("fr"));
// "French"
格式化器会先尝试 "xx-XX"(该项不存在),然后回退到 "en"。这样可以确保即使请求的 locale 不可用,代码也能正常工作。
你可以使用 resolvedOptions() 方法来检查格式化器实际使用的是哪个 locale。
const names = new Intl.DisplayNames(["xx-XX", "en"], { type: "language" });
console.log(names.resolvedOptions().locale);
// "en"
这表明在回退后,格式化器解析为英文。
不同 locale 如何格式化语言名称
每个 locale 都有自己的语言名称规范。格式化器会自动应用这些规范。
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 is not supported");
}
对于旧版浏览器,你需要提供回退方案或使用 polyfill。一个简单的回退方式是使用硬编码的语言代码到名称的映射。
function getLanguageName(code, locale) {
if (typeof Intl.DisplayNames !== "undefined") {
const names = new Intl.DisplayNames([locale], { type: "language" });
return names.of(code);
}
// Fallback for older browsers
const fallbackNames = {
en: "English",
es: "español",
fr: "français",
de: "Deutsch",
ja: "日本語"
};
return fallbackNames[code] || code;
}
console.log(getLanguageName("es", "en"));
// "español" (or "Spanish" if you adjust the fallback for localization)
这样可以确保你的代码即使在不支持 Intl.DisplayNames 的浏览器中也能运行,但会失去自动本地化功能。