如何显示拉丁文、西里尔文、阿拉伯文等脚本名称?
使用 Intl.DisplayNames 将脚本代码转换为任何语言中可读的书写系统名称。
简介
一种书写系统被称为文字系统。拉丁文字是英语、法语和西班牙语使用的文字系统。西里尔文字是俄语、保加利亚语和乌克兰语使用的文字系统。阿拉伯文字是阿拉伯语、波斯语和乌尔都语使用的文字系统。文字系统与语言不同,因为同一种语言可以用多种文字系统书写。例如,塞尔维亚语同时使用西里尔文字和拉丁文字。塞尔维亚的用户可以选择他们偏好的文字系统。
当您构建语言选择器、字体选择器或文本输入控件时,您需要显示文字系统的名称,以便用户能够识别书写系统。Intl.DisplayNames API 可以将文字代码转换为本地化的、易于理解的名称,而无需您维护翻译表。
理解文字系统与语言
文字系统与语言并不是同一回事。语言是人们说的内容,而文字系统是人们书写的方式。
英语是一种语言,拉丁文字是一种文字系统。英语使用拉丁文字,但还有许多其他语言也使用拉丁文字,包括西班牙语、法语、德语、越南语和土耳其语。
塞尔维亚语是一种可以用两种文字系统书写的语言。用西里尔文字书写的塞尔维亚语看起来像“Српски”。用拉丁文字书写的塞尔维亚语看起来像“Srpski”。两者都代表相同的语言,具有相同的单词和语法。不同之处仅在于书写系统。
中文有两种常见的文字变体。简体中文使用简化的汉字,繁体中文使用传统的汉字。同一句话根据使用的文字系统不同会有不同的表现形式。
在构建界面时,这种区别非常重要。塞尔维亚用户可能更喜欢西里尔文字而不是拉丁文字。中文用户需要在简体和繁体字符之间进行选择。您的界面需要显示文字系统的名称,以便用户做出这些选择。
硬编码脚本名称的问题
您可以创建一个查找表,将脚本代码映射到脚本名称。
const scriptNames = {
Latn: "拉丁文",
Cyrl: "西里尔文",
Arab: "阿拉伯文",
Hans: "简体中文",
Hant: "繁体中文"
};
console.log(scriptNames.Latn);
// "拉丁文"
这种方法仅适用于英语使用者。讲其他语言的用户会看到他们可能无法理解的英文脚本名称。您需要为支持的每种语言提供翻译。
const scriptNames = {
en: {
Latn: "Latin",
Cyrl: "Cyrillic",
Arab: "Arabic"
},
es: {
Latn: "latino",
Cyrl: "cirílico",
Arab: "árabe"
},
fr: {
Latn: "latin",
Cyrl: "cyrillique",
Arab: "arabe"
}
};
这种方法很快就会变得难以维护。每增加一种新语言,都需要一整套翻译。每增加一种新脚本,都需要在每种语言中添加条目。您需要一个更好的解决方案。
使用 Intl.DisplayNames 获取脚本名称
Intl.DisplayNames 构造函数创建一个格式化器,将脚本代码转换为人类可读的名称。您需要指定一个区域设置,并将类型设置为 "script"。
const names = new Intl.DisplayNames(["en"], { type: "script" });
console.log(names.of("Latn"));
// "Latin"
第一个参数是一个区域标识符数组。第二个参数是一个选项对象,其中 type: "script" 告诉格式化器您需要脚本名称。of() 方法接受一个脚本代码并返回其名称。
脚本代码遵循 ISO 15924 标准。每种脚本都有一个四个字母的代码,第一个字母大写,其余三个字母小写。例如,拉丁文是 Latn,西里尔文是 Cyrl,阿拉伯文是 Arab。
const names = new Intl.DisplayNames(["en"], { type: "script" });
console.log(names.of("Latn"));
// "Latin"
console.log(names.of("Cyrl"));
// "Cyrillic"
console.log(names.of("Arab"));
// "Arabic"
console.log(names.of("Hani"));
// "Han"
console.log(names.of("Hira"));
// "Hiragana"
console.log(names.of("Kana"));
// "Katakana"
格式化器处理了维护脚本名称翻译的所有复杂性。您只需要提供脚本代码即可。
常见的脚本代码
ISO 15924 标准定义了超过 160 种脚本的代码。以下是最常用的代码。
const names = new Intl.DisplayNames(["en"], { type: "script" });
console.log(names.of("Latn"));
// "Latin"
console.log(names.of("Cyrl"));
// "Cyrillic"
console.log(names.of("Arab"));
// "Arabic"
console.log(names.of("Hebr"));
// "Hebrew"
console.log(names.of("Deva"));
// "Devanagari"
console.log(names.of("Thai"));
// "Thai"
console.log(names.of("Hani"));
// "Han"
console.log(names.of("Hans"));
// "Simplified Han"
console.log(names.of("Hant"));
// "Traditional Han"
console.log(names.of("Hang"));
// "Hangul"
console.log(names.of("Hira"));
// "Hiragana"
console.log(names.of("Kana"));
// "Katakana"
console.log(names.of("Beng"));
// "Bengali"
console.log(names.of("Grek"));
// "Greek"
拉丁文覆盖了大多数西欧语言。西里尔文覆盖了俄语、保加利亚语、乌克兰语和其他斯拉夫语言。阿拉伯文覆盖了阿拉伯语、波斯语和乌尔都语。汉字覆盖了中文,其中 Hans 表示简体中文,Hant 表示繁体中文。韩文覆盖了韩语。平假名和片假名是日语的脚本。
在不同语言环境中显示脚本名称
脚本名称会根据显示语言环境进行本地化。通过创建不同语言环境的格式化器,可以查看不同语言中的名称。
const enNames = new Intl.DisplayNames(["en"], { type: "script" });
const esNames = new Intl.DisplayNames(["es"], { type: "script" });
const frNames = new Intl.DisplayNames(["fr"], { type: "script" });
const jaNames = new Intl.DisplayNames(["ja"], { type: "script" });
console.log(enNames.of("Latn"));
// "Latin"
console.log(esNames.of("Latn"));
// "latino"
console.log(frNames.of("Latn"));
// "latin"
console.log(jaNames.of("Latn"));
// "ラテン文字"
每个格式化器都会返回其显示语言环境中的脚本名称。这自动处理了脚本名称翻译的所有复杂性。
相同的模式适用于任何脚本代码。
const enNames = new Intl.DisplayNames(["en"], { type: "script" });
const deNames = new Intl.DisplayNames(["de"], { type: "script" });
const zhNames = new Intl.DisplayNames(["zh"], { type: "script" });
console.log(enNames.of("Cyrl"));
// "Cyrillic"
console.log(deNames.of("Cyrl"));
// "Kyrillisch"
console.log(zhNames.of("Cyrl"));
// "西里尔文"
console.log(enNames.of("Arab"));
// "Arabic"
console.log(deNames.of("Arab"));
// "Arabisch"
console.log(zhNames.of("Arab"));
// "阿拉伯文"
格式化器会自动为每种语言应用正确的语言学惯例。
为语言变体构建脚本选择器
某些语言为用户提供了脚本选择的选项。例如,塞尔维亚语可以用西里尔字母或拉丁字母书写。中文可以用简体或繁体字符书写。您需要显示这些选项,以便用户可以进行选择。
function getScriptOptions(language, userLocale) {
const names = new Intl.DisplayNames([userLocale], { type: "script" });
if (language === "sr") {
return [
{ code: "Cyrl", name: names.of("Cyrl") },
{ code: "Latn", name: names.of("Latn") }
];
}
if (language === "zh") {
return [
{ code: "Hans", name: names.of("Hans") },
{ code: "Hant", name: names.of("Hant") }
];
}
return [];
}
console.log(getScriptOptions("sr", "en"));
// [
// { code: "Cyrl", name: "Cyrillic" },
// { code: "Latn", name: "Latin" }
// ]
console.log(getScriptOptions("zh", "en"));
// [
// { code: "Hans", name: "Simplified Han" },
// { code: "Hant", name: "Traditional Han" }
// ]
console.log(getScriptOptions("zh", "es"));
// [
// { code: "Hans", name: "han simplificado" },
// { code: "Hant", name: "han tradicional" }
// ]
此函数以用户界面语言返回脚本选项。塞尔维亚语用户会看到西里尔字母和拉丁字母的选项。中文用户会看到简体和繁体的选项。名称以用户理解的语言显示。
显示包含脚本信息的完整区域标识符
区域标识符可以包含脚本代码以区分书写系统。格式为 language-script-region,例如 sr-Cyrl-RS 表示在塞尔维亚用西里尔字母书写的塞尔维亚语,或 zh-Hans-CN 表示在中国用简体中文书写的中文。
当您显示这些区域标识符时,提取脚本代码并将其转换为可读名称。
function parseLocaleWithScript(locale) {
const parts = locale.split("-");
if (parts.length < 2) {
return null;
}
const [language, script] = parts;
if (script.length === 4) {
return {
language,
script: script.charAt(0).toUpperCase() + script.slice(1).toLowerCase()
};
}
return null;
}
function formatLocaleWithScriptName(locale, displayLocale) {
const parsed = parseLocaleWithScript(locale);
if (!parsed) {
return locale;
}
const languageNames = new Intl.DisplayNames([displayLocale], {
type: "language"
});
const scriptNames = new Intl.DisplayNames([displayLocale], { type: "script" });
const languageName = languageNames.of(parsed.language);
const scriptName = scriptNames.of(parsed.script);
return `${languageName} (${scriptName})`;
}
console.log(formatLocaleWithScriptName("sr-Cyrl", "en"));
// "Serbian (Cyrillic)"
console.log(formatLocaleWithScriptName("sr-Latn", "en"));
// "Serbian (Latin)"
console.log(formatLocaleWithScriptName("zh-Hans", "en"));
// "Chinese (Simplified Han)"
console.log(formatLocaleWithScriptName("zh-Hant", "en"));
// "Chinese (Traditional Han)"
console.log(formatLocaleWithScriptName("sr-Cyrl", "es"));
// "serbio (cirílico)"
此模式通过将语言名称与脚本名称结合,使区域标识符更易于理解。用户会看到 "Serbian (Cyrillic)" 而不是 "sr-Cyrl"。
使用脚本名称创建字体选择器
字体选择界面通常按支持的脚本对字体进行分组。您需要显示脚本名称,以便用户了解每种字体支持哪些脚本。
function createFontOptions() {
const fonts = [
{
name: "Arial",
scripts: ["Latn", "Cyrl", "Grek", "Hebr", "Arab"]
},
{
name: "Noto Sans CJK",
scripts: ["Hans", "Hant", "Hira", "Kana", "Hang"]
},
{
name: "Noto Sans Devanagari",
scripts: ["Deva"]
}
];
const names = new Intl.DisplayNames(["en"], { type: "script" });
return fonts.map((font) => ({
name: font.name,
scripts: font.scripts.map((code) => names.of(code))
}));
}
console.log(createFontOptions());
// [
// {
// name: "Arial",
// scripts: ["Latin", "Cyrillic", "Greek", "Hebrew", "Arabic"]
// },
// {
// name: "Noto Sans CJK",
// scripts: ["简体汉字", "繁体汉字", "平假名", "片假名", "韩文"]
// },
// {
// name: "Noto Sans Devanagari",
// scripts: ["天城文"]
// }
// ]
这将创建一个包含字体及其支持脚本的列表,以人类可读的形式显示。用户可以根据所需的书写系统选择字体。
按脚本显示可用的输入法
操作系统和浏览器为不同的脚本提供输入法。例如,日语输入法将拉丁字符转换为平假名、片假名或汉字;中文输入法将拼音转换为简体或繁体汉字。您可以显示可用的输入法及其脚本名称。
function getInputMethods(userLocale) {
const inputMethods = [
{ id: "latin-ime", script: "Latn" },
{ id: "japanese-ime", script: "Hira" },
{ id: "chinese-pinyin-simplified", script: "Hans" },
{ id: "chinese-pinyin-traditional", script: "Hant" },
{ id: "korean-ime", script: "Hang" },
{ id: "arabic-ime", script: "Arab" },
{ id: "hebrew-ime", script: "Hebr" }
];
const names = new Intl.DisplayNames([userLocale], { type: "script" });
return inputMethods.map((method) => ({
id: method.id,
name: names.of(method.script)
}));
}
console.log(getInputMethods("en"));
// [
// { id: "latin-ime", name: "Latin" },
// { id: "japanese-ime", name: "Hiragana" },
// { id: "chinese-pinyin-simplified", name: "Simplified Han" },
// { id: "chinese-pinyin-traditional", name: "Traditional Han" },
// { id: "korean-ime", name: "Hangul" },
// { id: "arabic-ime", name: "Arabic" },
// { id: "hebrew-ime", name: "Hebrew" }
// ]
console.log(getInputMethods("ja"));
// [
// { id: "latin-ime", name: "ラテン文字" },
// { id: "japanese-ime", name: "ひらがな" },
// { id: "chinese-pinyin-simplified", name: "簡体字" },
// { id: "chinese-pinyin-traditional", name: "繁体字" },
// { id: "korean-ime", name: "ハングル" },
// { id: "arabic-ime", name: "アラビア文字" },
// { id: "hebrew-ime", name: "ヘブライ文字" }
// ]
这将以用户的语言显示输入法名称。例如,当界面为英文时,用户会看到“Hiragana”;当界面为日文时,用户会看到“ひらがな”。
理解脚本代码的大小写规则
脚本代码遵循特定的大小写模式。第一个字母大写,其余三个字母小写。例如,Latn 是正确的,而 LATN、latn 和 LaTn 都不是标准格式。
of() 方法接受任何大小写形式的脚本代码。
const names = new Intl.DisplayNames(["en"], { type: "script" });
console.log(names.of("Latn"));
// "Latin"
console.log(names.of("LATN"));
// "Latin"
console.log(names.of("latn"));
// "Latin"
console.log(names.of("LaTn"));
// "Latin"
格式化器能够正确处理所有形式。然而,使用标准的大小写模式可以使代码更具可读性,并与 ISO 15924 标准保持一致。
处理回退语言环境
Intl.DisplayNames 构造函数接受一个语言环境数组。如果第一个语言环境不可用,格式化器会回退到数组中的下一个语言环境。
const names = new Intl.DisplayNames(["xx-XX", "en"], { type: "script" });
console.log(names.of("Latn"));
// "Latin"
格式化器首先尝试 "xx-XX",但由于不存在该语言环境,它会回退到 "en"。这确保了即使请求的语言环境不可用,代码仍然可以正常工作。
您可以使用 resolvedOptions() 方法检查格式化器实际使用的语言环境。
const names = new Intl.DisplayNames(["xx-XX", "en"], { type: "script" });
console.log(names.resolvedOptions().locale);
// "en"
这表明格式化器在回退后解析为英语。
构建多语言内容管理系统
支持多种脚本的内容管理系统需要显示每段内容可用的脚本。您可以显示脚本名称,帮助内容编辑者选择正确的版本。
function getContentVersions(contentId, userLocale) {
const versions = [
{ script: "Latn", url: `/content/${contentId}/latn` },
{ script: "Cyrl", url: `/content/${contentId}/cyrl` },
{ script: "Arab", url: `/content/${contentId}/arab` }
];
const names = new Intl.DisplayNames([userLocale], { type: "script" });
return versions.map((version) => ({
script: version.script,
name: names.of(version.script),
url: version.url
}));
}
console.log(getContentVersions("article-123", "en"));
// [
// { script: "Latn", name: "Latin", url: "/content/article-123/latn" },
// { script: "Cyrl", name: "Cyrillic", url: "/content/article-123/cyrl" },
// { script: "Arab", name: "Arabic", url: "/content/article-123/arab" }
// ]
这种模式可以帮助内容编辑者查看哪些脚本版本存在,并在它们之间导航。
浏览器支持
Intl.DisplayNames API 支持脚本类型功能,可在所有现代浏览器中使用。自 2021 年 3 月起,包括 Chrome、Firefox、Safari 和 Edge 在内的主流浏览器均已支持该功能。
在使用之前,您可以检查该 API 是否可用。
if (typeof Intl.DisplayNames !== "undefined") {
const names = new Intl.DisplayNames(["en"], { type: "script" });
console.log(names.of("Latn"));
} else {
console.log("Intl.DisplayNames 不受支持");
}
对于较旧的浏览器,您需要提供一个回退方案或使用 polyfill。一个简单的回退方案是使用脚本代码到名称的硬编码映射。
function getScriptName(code, locale) {
if (typeof Intl.DisplayNames !== "undefined") {
const names = new Intl.DisplayNames([locale], { type: "script" });
return names.of(code);
}
const fallbackNames = {
Latn: "拉丁文",
Cyrl: "西里尔文",
Arab: "阿拉伯文",
Hans: "简体汉字",
Hant: "繁体汉字"
};
return fallbackNames[code] || code;
}
console.log(getScriptName("Latn", "en"));
// "拉丁文"
这可以确保您的代码即使在不支持 Intl.DisplayNames 的浏览器中也能正常工作,但您将失去自动本地化功能。