如何检查 locale 标识符是否有效
在使用 locale 标识符格式化日期、数字和货币前先进行验证
简介
当应用程序从用户输入、API 响应或配置文件中接收 locale 标识符时,必须在使用前验证其有效性。无效的 locale 标识符会导致格式化函数抛出错误或产生意外结果。
验证可以确保 en-US 这样的字符串在结构上符合国际标准。这可以防止在将 locale 标识符传递给 Intl API 或其他国际化库时出现运行时错误。
JavaScript 提供了两种内置方法来验证 locale 标识符。这两种方法都会根据 BCP 47 标准检查标识符的结构,该标准定义了语言标签的格式。
什么是有效的 locale 标识符
locale 标识符遵循 BCP 47 语言标签标准。该标准定义了组合语言、脚本、地区和扩展组件的结构和规则。
有效的 locale 标识符使用连字符分隔各个部分,不能使用下划线或其他字符。语言代码必须是公认的 ISO 639 代码,地区代码必须是公认的 ISO 3166-1 代码。
有效 locale 标识符示例:
en(英语)en-US(美式英语)zh-Hans(简体中文)zh-Hans-CN(中国大陆使用的简体中文)en-US-u-ca-gregory(带有公历的美式英语)
无效 locale 标识符示例:
en_US(使用下划线而不是连字符)english(不是公认的语言代码)en-USA(地区代码必须为两个字母,不能是三个)EN-us(语言代码必须为小写)abc-XY(语言代码不存在)
验证方法会检查这些结构规则,并确认代码是否为公认标准。
使用 Intl.getCanonicalLocales 进行验证
Intl.getCanonicalLocales() 方法用于验证 locale 标识符,并以规范形式返回。该方法可接受单个 locale 标识符或标识符数组。
const result = Intl.getCanonicalLocales("en-US");
console.log(result);
// Output: ["en-US"]
该方法会将输入标准化,转换为标准格式。即使传入大小写不正确的 locale 标识符,也会返回正确的规范形式:
const result = Intl.getCanonicalLocales("EN-us");
console.log(result);
// Output: ["en-US"]
如果传入无效的 locale 标识符,该方法会抛出 RangeError:
try {
Intl.getCanonicalLocales("en_US");
} catch (error) {
console.error(error.name);
// Output: "RangeError"
console.error(error.message);
// Output: "en_US is not a structurally valid language tag"
}
该错误表示标识符不符合 BCP 47 结构。你可以捕获此错误,以便优雅地处理无效输入。
验证多个 locale 标识符
Intl.getCanonicalLocales() 方法可接受一个数组,一次性验证多个 locale 标识符。该方法会为所有有效标识符返回规范形式的数组。
const locales = ["en-US", "fr-FR", "es-MX"];
const result = Intl.getCanonicalLocales(locales);
console.log(result);
// Output: ["en-US", "fr-FR", "es-MX"]
该方法还会从结果中移除重复的 locale 标识符:
const locales = ["en-US", "EN-us", "en-US"];
const result = Intl.getCanonicalLocales(locales);
console.log(result);
// Output: ["en-US"]
这三个输入值都表示同一个 locale,因此方法只返回一个规范形式。
如果数组中有任何无效的 locale,整个方法会抛出错误:
try {
Intl.getCanonicalLocales(["en-US", "invalid", "fr-FR"]);
} catch (error) {
console.error(error.message);
// Output: "invalid is not a structurally valid language tag"
}
在验证用户提供的列表时,应单独验证每个 locale,以便识别具体哪些标识符无效。
使用 Intl.Locale 构造函数进行验证
Intl.Locale 构造函数提供了另一种验证 locale 标识符的方法。当你用无效标识符创建 locale 对象时,构造函数会抛出 RangeError。
try {
const locale = new Intl.Locale("en-US");
console.log("Valid locale");
} catch (error) {
console.error("Invalid locale");
}
// Output: "Valid locale"
构造函数会针对无效的标识符抛出错误:
try {
const locale = new Intl.Locale("en_US");
console.log("Valid locale");
} catch (error) {
console.error("Invalid locale");
console.error(error.message);
}
// Output: "Invalid locale"
// Output: "invalid language subtag: en_US"
与 Intl.getCanonicalLocales() 不同,Intl.Locale 构造函数不会自动规范大小写。它要求标识符使用正确的大小写:
const locale1 = new Intl.Locale("en-US");
console.log(locale1.baseName);
// Output: "en-US"
const locale2 = new Intl.Locale("EN-US");
console.log(locale2.baseName);
// Output: "en-US"
构造函数同时接受大写和小写的语言代码,并会将其规范化为标准形式。
选择验证方法
两种验证方法各自适用于不同场景,并提供不同的功能。
当你需要以下操作时,使用 Intl.getCanonicalLocales():
- 将 locale 标识符规范化为标准形式
- 验证并去重 locale 标识符列表
- 将不一致的大小写转换为标准格式
- 在不创建对象的情况下验证 locale 标识符
当你需要以下操作时,使用 Intl.Locale 构造函数:
- 验证 locale 标识符并直接操作其属性
- 从标识符中提取语言、地区或脚本等组件
- 创建 locale 对象以配合其他 Intl API 使用
- 同时验证和处理 locale 标识符
Intl.Locale 构造函数更为强大,因为它可以创建可查询和修改的对象。但如果你只需要验证和规范化,Intl.getCanonicalLocales() 更为简单。
验证用户输入
当接收用户输入的 locale 标识符时,务必在应用中使用前进行验证。这可以防止错误,并在用户输入无效值时提供明确的反馈。
function validateUserLocale(input) {
try {
const canonicalLocales = Intl.getCanonicalLocales(input);
return {
valid: true,
locale: canonicalLocales[0]
};
} catch (error) {
return {
valid: false,
error: "Please enter a valid locale identifier like en-US or fr-FR"
};
}
}
const result1 = validateUserLocale("en-US");
console.log(result1);
// Output: { valid: true, locale: "en-US" }
const result2 = validateUserLocale("english");
console.log(result2);
// Output: { valid: false, error: "Please enter a valid locale..." }
此函数会验证输入,并返回规范化的 locale 或用户友好的错误信息。
验证配置数据
应用程序通常会从配置文件或环境变量加载 locale 标识符。请在应用启动时验证这些值,以便及早发现配置错误。
function loadLocaleConfig(configLocales) {
const validLocales = [];
const invalidLocales = [];
for (const locale of configLocales) {
try {
const canonical = Intl.getCanonicalLocales(locale);
validLocales.push(canonical[0]);
} catch (error) {
invalidLocales.push(locale);
}
}
if (invalidLocales.length > 0) {
console.warn("Invalid locale identifiers found:", invalidLocales);
}
return validLocales;
}
const config = ["en-US", "fr-FR", "invalid", "es_MX", "de-DE"];
const locales = loadLocaleConfig(config);
console.log(locales);
// Output: ["en-US", "fr-FR", "de-DE"]
// Warning: Invalid locale identifiers found: ["invalid", "es_MX"]
此函数会过滤掉无效的 locale 标识符并记录警告,从而使应用程序能够继续使用有效的 locale。
验证 API 响应
当从外部 API 接收 locale 标识符时,需在应用中使用前进行验证。API 可能会返回非标准格式或包含错误的 locale 标识符。
function processApiLocale(apiResponse) {
const locale = apiResponse.preferredLocale;
try {
const validated = new Intl.Locale(locale);
return {
success: true,
language: validated.language,
region: validated.region,
baseName: validated.baseName
};
} catch (error) {
console.error("API returned invalid locale:", locale);
return {
success: false,
fallback: "en-US"
};
}
}
const response1 = { preferredLocale: "fr-CA" };
console.log(processApiLocale(response1));
// Output: { success: true, language: "fr", region: "CA", baseName: "fr-CA" }
const response2 = { preferredLocale: "invalid_locale" };
console.log(processApiLocale(response2));
// Output: { success: false, fallback: "en-US" }
此函数会验证 API 响应并提取有关 locale 的结构化信息,或者在 locale 无效时提供回退值。