如何在 JavaScript 中使用本地化分隔符格式化数组?
使用 Intl.ListFormat 自动为任意语言应用正确的逗号、空格和标点符号。
简介
当你将数组转换为可读字符串时,需要用逗号或其他标点符号分隔各项。不同语言使用的分隔符不同。英文用逗号和空格,日文用顿号(、),阿拉伯语则使用不同的标点和词序。
Intl.ListFormat API 可以将数组转换为带有本地化分隔符的字符串,确保你的列表在每种语言下都自然易读。
为什么数组分隔符因语言而异
你可能以为所有语言都用逗号分隔列表项,其实并非如此。
英文用逗号和空格分隔各项。
// English: "red, green, blue"
日文用顿号(、)且不加空格。
// Japanese: "赤、緑、青"
中文同样使用顿号(、)作为分隔符。
// Chinese: "红、绿、蓝"
阿拉伯语使用不同的逗号(،),并且从右向左书写。
// Arabic: "أحمر، أخضر، أزرق"
这些差异在 Intl.ListFormat 中会自动处理,无需手动了解每种语言的标点规则。
join() 方法的问题
Array.prototype.join() 方法会用你指定的分隔符将数组转换为字符串。
const colors = ["red", "green", "blue"];
console.log(colors.join(", "));
// "red, green, blue"
这种方式会将英文标点硬编码,逗号加空格的分隔符不适用于其他语言。
const colors = ["赤", "緑", "青"];
console.log(colors.join(", "));
// "赤, 緑, 青" (wrong - should use 、 instead of ,)
你无法根据语言手动切换分隔符,因为这需要维护一份所有语言的标点规则映射表,这既不完整也难以维护。
使用 Intl.ListFormat 实现本地化分隔符
Intl.ListFormat 构造函数会创建一个格式化器,根据不同的本地化设置自动应用正确的分隔符。
const formatter = new Intl.ListFormat("en");
const colors = ["red", "green", "blue"];
console.log(formatter.format(colors));
// "red, green, and blue"
该格式化器会自动使用指定语言环境的正确标点符号。你需要将语言环境代码作为第一个参数传递。
const enFormatter = new Intl.ListFormat("en");
const jaFormatter = new Intl.ListFormat("ja");
const arFormatter = new Intl.ListFormat("ar");
const colors = ["red", "green", "blue"];
console.log(enFormatter.format(colors));
// "red, green, and blue"
console.log(jaFormatter.format(["赤", "緑", "青"]));
// "赤、緑、青"
console.log(arFormatter.format(["أحمر", "أخضر", "أزرق"]));
// "أحمر، أخضر، أزرق"
浏览器会提供标点符号规则,无需维护任何特定于本地化的代码。
不同语言的分隔符差异
格式化器会根据语言环境应用不同的分隔符。以下示例展示了同一个数组在不同语言下的格式化效果。
英语使用逗号、空格和单词 "and"。
const formatter = new Intl.ListFormat("en");
console.log(formatter.format(["apple", "orange", "banana"]));
// "apple, orange, and banana"
西班牙语使用逗号、空格和单词 "y"。
const formatter = new Intl.ListFormat("es");
console.log(formatter.format(["manzana", "naranja", "plátano"]));
// "manzana, naranja y plátano"
法语使用逗号、空格和单词 "et"。
const formatter = new Intl.ListFormat("fr");
console.log(formatter.format(["pomme", "orange", "banane"]));
// "pomme, orange et banane"
德语使用逗号、空格和单词 "und"。
const formatter = new Intl.ListFormat("de");
console.log(formatter.format(["Apfel", "Orange", "Banane"]));
// "Apfel, Orange und Banane"
日语使用顿号 、 和字符 、。
const formatter = new Intl.ListFormat("ja");
console.log(formatter.format(["りんご", "オレンジ", "バナナ"]));
// "りんご、オレンジ、バナナ"
中文使用顿号 、 和词语 和。
const formatter = new Intl.ListFormat("zh");
console.log(formatter.format(["苹果", "橙子", "香蕉"]));
// "苹果、橙子和香蕉"
韩语使用逗号和助词 및。
const formatter = new Intl.ListFormat("ko");
console.log(formatter.format(["사과", "오렌지", "바나나"]));
// "사과, 오렌지 및 바나나"
格式化器会自动处理所有这些差异。你可以为每种语言编写相同的代码。
使用用户的语言环境
你可以从浏览器设置中检测用户的首选语言环境,并用它来格式化列表。
const userLocale = navigator.language;
const formatter = new Intl.ListFormat(userLocale);
const items = ["first", "second", "third"];
console.log(formatter.format(items));
这样可以确保列表使用符合用户期望的分隔符。设置为法语的用户会看到法语标点,设置为日语的用户会看到日语标点。
不带连接词的数组格式化
默认的 Intl.ListFormat 行为会在最后一项前添加类似“和”的连接词。你可以通过使用 unit 类型来禁用此功能。
const formatter = new Intl.ListFormat("en", { type: "unit" });
console.log(formatter.format(["5 km", "12 minutes", "100 calories"]));
// "5 km, 12 minutes, 100 calories"
unit 类型只使用分隔符,不添加连接词。这对于技术列表、计量单位或不适合使用连接词的数据非常有用。
const enFormatter = new Intl.ListFormat("en", { type: "unit" });
const jaFormatter = new Intl.ListFormat("ja", { type: "unit" });
console.log(enFormatter.format(["Item A", "Item B", "Item C"]));
// "Item A, Item B, Item C"
console.log(jaFormatter.format(["項目A", "項目B", "項目C"]));
// "項目A、項目B、項目C"
即使没有连接词,分隔符的标点仍然遵循本地化规则。
创建可复用的格式化器
你可以只创建一次格式化器,并在多个数组中复用。这样比为每个数组都新建一个格式化器更高效。
const formatter = new Intl.ListFormat("en");
console.log(formatter.format(["red", "green"]));
// "red and green"
console.log(formatter.format(["a", "b", "c", "d"]));
// "a, b, c, and d"
console.log(formatter.format(["one"]));
// "one"
同一个格式化器适用于任意长度的数组。它会根据数组项的数量自动应用正确的分隔符和连接词。
处理空数组
当你格式化一个空数组时,格式化器会返回一个空字符串。
const formatter = new Intl.ListFormat("en");
console.log(formatter.format([]));
// ""
如果你需要不同的处理方式,应在格式化前检查数组是否为空。
function formatList(items, locale) {
if (items.length === 0) {
return "No items";
}
const formatter = new Intl.ListFormat(locale);
return formatter.format(items);
}
console.log(formatList([], "en"));
// "No items"
console.log(formatList(["apple"], "en"));
// "apple"
这样你就可以灵活控制空数组在用户界面上的显示效果。
浏览器支持
Intl.ListFormat API 在所有现代浏览器中都可用。从 2021 年 4 月起,Chrome、Firefox、Safari 和 Edge 均已支持。
你可以在使用前检查该 API 是否存在。
if (typeof Intl.ListFormat !== "undefined") {
const formatter = new Intl.ListFormat("en");
console.log(formatter.format(["a", "b", "c"]));
} else {
console.log("Intl.ListFormat is not supported");
}
对于旧版浏览器,可以回退到 join() 方法。这样可以提供基础格式化,但不支持本地化分隔符。
function formatList(items, locale) {
if (typeof Intl.ListFormat !== "undefined") {
const formatter = new Intl.ListFormat(locale);
return formatter.format(items);
}
return items.join(", ");
}
console.log(formatList(["red", "green", "blue"], "en"));
// "red, green, and blue" (or "red, green, blue" in older browsers)
这样可以确保您的代码在所有浏览器中都能正常运行,并在现代浏览器中提供最佳体验。