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