如何通过组件构建本地化标识符
在 JavaScript 中通过组合语言、书写系统和地区代码来构建本地化标识符
简介
像 en-US 或 zh-Hans-CN 这样的本地化标识符编码了语言、书写系统和地区等信息。有时你需要以编程方式构建这些标识符,而不是使用固定字符串。例如,你可能让用户分别选择语言和地区,然后将它们组合成一个有效的本地化标识符。
JavaScript 的 Intl.Locale 构造函数允许你从各个组件构建本地化标识符。你可以分别指定语言、书写系统和地区,构造函数会将它们组装成格式正确的标识符。
本指南将解释如何通过组件构建本地化标识符、何时使用这种方法,以及如何处理特殊情况。
了解本地化标识符的组成部分
本地化标识符由连字符分隔的各个组件组成。每个组件代表文化偏好的不同方面。
语言代码指定要使用的语言。它采用 ISO 639 的两个或三个小写字母:
en表示英语es表示西班牙语fr表示法语zh表示中文ar表示阿拉伯语
书写系统代码指定书写体系。它采用 ISO 15924 的四个字母,首字母大写:
Hans表示简体中文字符Hant表示繁体中文字符Cyrl表示西里尔字母Latn表示拉丁字母
地区代码指定地理区域。它采用 ISO 3166-1 的两个大写字母或 UN M.49 的三位数字:
US表示美国GB表示英国CN表示中国MX表示墨西哥
这些组件按照特定顺序组合:先语言,再脚本,最后地区。例如,zh-Hans-CN 表示中文语言、简体脚本、中国地区。
仅使用语言和地区构建 locale
最常见的场景是组合语言代码和地区代码。大多数应用无需指定脚本,因为每种语言都有默认脚本。
你可以通过将语言代码作为第一个参数,并传递包含地区的 options 对象来构建 locale:
const locale = new Intl.Locale("en", {
region: "US"
});
console.log(locale.toString());
// Output: "en-US"
这将创建一个美式英语的 locale 标识符。
你可以构建同一语言的不同地区变体:
const usEnglish = new Intl.Locale("en", { region: "US" });
const britishEnglish = new Intl.Locale("en", { region: "GB" });
const canadianEnglish = new Intl.Locale("en", { region: "CA" });
console.log(usEnglish.toString()); // "en-US"
console.log(britishEnglish.toString()); // "en-GB"
console.log(canadianEnglish.toString()); // "en-CA"
每个变体使用相同的语言,但采用不同的地区格式规范。
使用语言、脚本和地区构建 locale
有些语言需要显式指定脚本代码。中文、塞尔维亚语等少数语言使用多种书写系统。你必须指定脚本以避免歧义。
你可以在 options 对象中添加脚本组件:
const simplifiedChinese = new Intl.Locale("zh", {
script: "Hans",
region: "CN"
});
console.log(simplifiedChinese.toString());
// Output: "zh-Hans-CN"
这将创建一个在中国使用的简体中文 locale。
繁体中文使用不同的脚本和地区:
const traditionalChinese = new Intl.Locale("zh", {
script: "Hant",
region: "TW"
});
console.log(traditionalChinese.toString());
// Output: "zh-Hant-TW"
脚本代码用于区分两种书写系统。
塞尔维亚语同时使用西里尔字母和拉丁字母。你需要指定使用哪种脚本:
const serbianCyrillic = new Intl.Locale("sr", {
script: "Cyrl",
region: "RS"
});
const serbianLatin = new Intl.Locale("sr", {
script: "Latn",
region: "RS"
});
console.log(serbianCyrillic.toString()); // "sr-Cyrl-RS"
console.log(serbianLatin.toString()); // "sr-Latn-RS"
这两个 locale 都表示塞尔维亚语(地区为塞尔维亚),但书写系统不同。
根据用户选择构建 locale
用户界面通常允许用户分别选择语言和地区。你可以将这些选择组合成一个 locale 标识符。
考虑一个包含两个下拉菜单的设置表单:
function buildLocaleFromSelections(languageCode, regionCode) {
const locale = new Intl.Locale(languageCode, {
region: regionCode
});
return locale.toString();
}
const userLocale = buildLocaleFromSelections("es", "MX");
console.log(userLocale);
// Output: "es-MX"
这样可以通过独立的选择创建一个 locale 标识符。
你可以通过捕获构造函数抛出的错误来校验这些选择:
function buildLocaleFromSelections(languageCode, regionCode) {
try {
const locale = new Intl.Locale(languageCode, {
region: regionCode
});
return {
success: true,
locale: locale.toString()
};
} catch (error) {
return {
success: false,
error: error.message
};
}
}
const valid = buildLocaleFromSelections("fr", "CA");
console.log(valid);
// Output: { success: true, locale: "fr-CA" }
const invalid = buildLocaleFromSelections("invalid", "XX");
console.log(invalid);
// Output: { success: false, error: "..." }
如果某个组件无效,构造函数会抛出 RangeError。
使用可选组件构建 locale
并非每个 locale 都需要所有组件。你可以省略不需要的部分。
仅包含语言的 locale 会省略地区和书写系统:
const locale = new Intl.Locale("fr");
console.log(locale.toString());
// Output: "fr"
这表示法语,但没有指定具体的地区或书写系统。
你可以根据用户输入有条件地包含组件:
function buildLocale(language, options = {}) {
const localeOptions = {};
if (options.region) {
localeOptions.region = options.region;
}
if (options.script) {
localeOptions.script = options.script;
}
const locale = new Intl.Locale(language, localeOptions);
return locale.toString();
}
console.log(buildLocale("en"));
// Output: "en"
console.log(buildLocale("en", { region: "US" }));
// Output: "en-US"
console.log(buildLocale("zh", { script: "Hans", region: "CN" }));
// Output: "zh-Hans-CN"
该函数会根据可用信息构建最简有效的 locale 标识符。
覆盖已有 locale 的组件
你可以基于现有的 locale 标识符覆盖特定组件。当你只需更改某一部分而保留其他部分时,这非常有用。
构造函数的第二个参数会覆盖第一个参数中的组件:
const baseLocale = new Intl.Locale("en-US");
const withDifferentRegion = new Intl.Locale(baseLocale, {
region: "GB"
});
console.log(withDifferentRegion.toString());
// Output: "en-GB"
新 locale 保留了语言,但更改了地区。
你可以同时覆盖多个组件:
const original = new Intl.Locale("zh-Hans-CN");
const modified = new Intl.Locale(original, {
script: "Hant",
region: "TW"
});
console.log(modified.toString());
// Output: "zh-Hant-TW"
这会同时更改书写系统和地区,同时保留语言。
为构建的 locale 添加格式化偏好
除了语言、书写系统和地区,locale 还可以包含格式化偏好。这些偏好控制日期、数字等值的显示方式。
在构建 locale 时,可以添加日历偏好设置:
const locale = new Intl.Locale("ar", {
region: "SA",
calendar: "islamic"
});
console.log(locale.toString());
// Output: "ar-SA-u-ca-islamic"
console.log(locale.calendar);
// Output: "islamic"
日历偏好会作为 Unicode 扩展出现在标识符字符串中。
你可以指定多个格式化偏好:
const locale = new Intl.Locale("en", {
region: "US",
calendar: "gregory",
numberingSystem: "latn",
hourCycle: "h12"
});
console.log(locale.toString());
// Output: "en-US-u-ca-gregory-hc-h12-nu-latn"
构造函数会按字母顺序排列扩展键。
这些偏好会影响格式化器的数据展示方式:
const locale = new Intl.Locale("ar", {
region: "EG",
numberingSystem: "arab"
});
const formatter = new Intl.NumberFormat(locale);
console.log(formatter.format(12345));
// Output: "١٢٬٣٤٥" (Arabic-Indic numerals)
数字系统偏好控制显示的数字样式。
验证组件组合
并非所有语言、书写系统和地区的组合都是有意义的。构造函数接受任何语法上有效的组件,但有些组合可能并不代表真实的 locale。
构造函数只验证语法正确性,不验证语义正确性:
// Syntactically valid but semantically questionable
const locale = new Intl.Locale("en", {
script: "Arab",
region: "JP"
});
console.log(locale.toString());
// Output: "en-Arab-JP"
这会构建一个在日本使用阿拉伯文书写的英语 locale。该标识符符合 BCP 47 标准,但并不代表真实世界中的 locale。
你可以使用 maximize() 方法检查 locale 是否符合常见模式:
const locale = new Intl.Locale("en", { region: "JP" });
const maximized = locale.maximize();
console.log(maximized.toString());
// Output: "en-Latn-JP"
该方法会为语言添加最可能的书写系统。如果结果符合预期模式,则该组合是合理的。
从已构建的 locale 读取组件
构建 locale 后,可以通过属性读取其各个组件。
language 属性返回语言代码:
const locale = new Intl.Locale("fr", { region: "CA" });
console.log(locale.language);
// Output: "fr"
region 属性返回地区代码:
const locale = new Intl.Locale("fr", { region: "CA" });
console.log(locale.region);
// Output: "CA"
如果指定,script 属性返回书写系统代码:
const locale = new Intl.Locale("zh", {
script: "Hans",
region: "CN"
});
console.log(locale.script);
// Output: "Hans"
如果未指定 script,该属性将返回 undefined:
const locale = new Intl.Locale("en", { region: "US" });
console.log(locale.script);
// Output: undefined
baseName 属性返回不带扩展的完整标识符:
const locale = new Intl.Locale("ar", {
region: "SA",
calendar: "islamic",
numberingSystem: "arab"
});
console.log(locale.baseName);
// Output: "ar-SA"
这样可以获得不含格式偏好的语言-脚本-区域部分。
将 locale 标识符转换为字符串
toString() 方法会以字符串形式返回完整的 locale 标识符:
const locale = new Intl.Locale("es", { region: "MX" });
const identifier = locale.toString();
console.log(identifier);
// Output: "es-MX"
你可以将该字符串与其他 Intl API 一起使用:
const locale = new Intl.Locale("de", { region: "DE" });
const formatter = new Intl.NumberFormat(locale.toString());
const price = 1234.56;
console.log(formatter.format(price));
// Output: "1.234,56"
格式化器可以接受字符串表示形式。
大多数 Intl API 也可以直接接受 locale 对象:
const locale = new Intl.Locale("de", { region: "DE" });
const formatter = new Intl.NumberFormat(locale);
在需要时,API 会在内部调用 toString()。
实际应用场景
通过组件构建 locale 标识符可以解决国际化应用中的多个常见问题。
创建 locale 选择器
用户界面通常允许用户分别选择语言和地区。你可以将这些选择组合起来:
function createLocaleFromPicker(languageSelect, regionSelect) {
const language = languageSelect.value;
const region = regionSelect.value;
const locale = new Intl.Locale(language, { region });
return locale.toString();
}
// User selects "Spanish" and "Mexico"
const selectedLocale = createLocaleFromPicker(
{ value: "es" },
{ value: "MX" }
);
console.log(selectedLocale);
// Output: "es-MX"
生成 locale 变体
你可以通过单一语言代码生成多个地区变体:
function generateRegionalVariants(languageCode, regionCodes) {
return regionCodes.map(regionCode => {
const locale = new Intl.Locale(languageCode, {
region: regionCode
});
return locale.toString();
});
}
const englishVariants = generateRegionalVariants("en", [
"US",
"GB",
"CA",
"AU",
"NZ"
]);
console.log(englishVariants);
// Output: ["en-US", "en-GB", "en-CA", "en-AU", "en-NZ"]
这会为不同的英语地区创建 locale 标识符列表。
通过 URL 参数构建 locale
URL 通常将 locale 偏好作为独立参数进行编码。你可以通过这些参数构建 locale:
function getLocaleFromURL(url) {
const params = new URL(url).searchParams;
const language = params.get("lang");
const region = params.get("region");
if (!language) {
return null;
}
const options = {};
if (region) {
options.region = region;
}
try {
const locale = new Intl.Locale(language, options);
return locale.toString();
} catch (error) {
return null;
}
}
const locale1 = getLocaleFromURL("https://example.com?lang=fr®ion=CA");
console.log(locale1);
// Output: "fr-CA"
const locale2 = getLocaleFromURL("https://example.com?lang=ja");
console.log(locale2);
// Output: "ja"
规范化 locale 标识符
你可以通过解析并重构 locale 标识符来实现规范化:
function normalizeLocale(identifier) {
try {
const locale = new Intl.Locale(identifier);
return locale.toString();
} catch (error) {
return null;
}
}
console.log(normalizeLocale("EN-us"));
// Output: "en-US"
console.log(normalizeLocale("zh_Hans_CN"));
// Output: null (invalid separator)
构造函数会规范化大小写并验证结构。
按用户偏好配置格式化器
你可以根据用户设置,结合格式化偏好来构建 locale 标识符:
function buildFormatterLocale(language, region, preferences) {
const locale = new Intl.Locale(language, {
region,
hourCycle: preferences.use24Hour ? "h23" : "h12",
numberingSystem: preferences.numberingSystem
});
return locale;
}
const userPreferences = {
use24Hour: true,
numberingSystem: "latn"
};
const locale = buildFormatterLocale("fr", "FR", userPreferences);
const timeFormatter = new Intl.DateTimeFormat(locale, {
hour: "numeric",
minute: "numeric"
});
const now = new Date("2025-10-15T14:30:00");
console.log(timeFormatter.format(now));
// Output: "14:30" (24-hour format)
locale 包含了来自用户设置的格式化偏好。
何时从组件构建 locale
在特定场景下,从组件构建 locale 非常有用。当你拥有独立的语言和地区数据、处理用户输入或以编程方式生成 locale 变体时,建议采用此方法。
对于固定的 locale,请使用字面量字符串:
// Good for fixed locales
const locale = new Intl.Locale("en-US");
当值来自变量时,从组件构建:
// Good for dynamic locales
const locale = new Intl.Locale(userLanguage, {
region: userRegion
});
构造函数会验证组件并创建格式正确的标识符。
浏览器支持
Intl.Locale 构造函数在所有现代浏览器中均可用。Chrome、Firefox、Safari 和 Edge 均支持该构造函数及其用于从组件构建 locale 的 options 对象。
Node.js 从 12 版本开始支持 Intl.Locale,14 及更高版本对所有构造函数选项提供完整支持。
总结
Intl.Locale 构造函数可通过各个组件构建 locale 标识符。你需要将语言代码作为第一个参数,并在 options 对象中提供脚本、地区和格式化偏好。
关键概念:
- locale 标识符由语言、脚本和地区组件组成
- 构造函数接受包含
language、script和region属性的 options 对象 - 你可以通过将现有 locale 作为第一个参数来覆盖组件
calendar和hourCycle等格式化偏好会以 Unicode 扩展形式出现toString()方法返回完整的标识符字符串language、region和script等属性可用于读取组件- 构造函数只验证语法,不验证语义正确性
当需要根据用户输入构建 locale、生成区域变体,或组合单独的语言和地区选择时,请使用此方法。对于固定的 locale,建议直接使用字符串字面量。