如何在 JavaScript 中使用语言特定的分隔符格式化数组?

使用 Intl.ListFormat 自动为任何语言应用正确的逗号、空格和标点符号。

介绍

当您将数组转换为可读的字符串时,需要用逗号或其他标点符号分隔各项。不同语言使用不同的分隔符。英语使用逗号和空格,日语使用顿号「、」,而阿拉伯语则使用不同的标点符号和词序。

Intl.ListFormat API 可以将数组转换为带有适合语言环境的分隔符的字符串。这确保了您的列表在每种语言中看起来都很自然。

为什么数组分隔符因语言环境而异

您可能会认为所有语言都使用逗号来分隔列表项。但事实并非如此。

英语使用逗号和空格分隔项。

// 英语: "red, green, blue"

日语使用顿号「、」,且不加空格。

// 日语: "赤、緑、青"

中文使用相同的顿号「、」。

// 中文: "红、绿、蓝"

阿拉伯语使用不同的逗号字符「،」,并从右到左书写。

// 阿拉伯语: "أحمر، أخضر، أزرق"

这些差异在 Intl.ListFormat 中是自动处理的。您无需了解每种语言的标点规则。

join() 的问题

Array.prototype.join() 方法使用您指定的分隔符将数组转换为字符串。

const colors = ["red", "green", "blue"];
console.log(colors.join(", "));
// "red, green, blue"

这会硬编码英语的标点符号。逗号和空格的分隔符不适用于其他语言。

const colors = ["赤", "緑", "青"];
console.log(colors.join(", "));
// "赤, 緑, 青" (错误 - 应使用「、」而不是「,」)

您无法手动根据语言环境切换分隔符,因为这需要维护一个每种语言及其标点规则的映射。这种映射既不完整,也难以维护。

使用 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 行为会在最后一项之前添加一个连接词,例如“和”。您可以通过使用单元类型来禁用此功能。

const formatter = new Intl.ListFormat("en", { type: "unit" });
console.log(formatter.format(["5 km", "12 minutes", "100 calories"]));
// "5 km, 12 minutes, 100 calories"

单元类型仅使用分隔符,而不添加连接词。这对于技术列表、测量值或不适合使用连接词的数据非常有用。

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 "没有项目";
  }
  const formatter = new Intl.ListFormat(locale);
  return formatter.format(items);
}

console.log(formatList([], "en"));
// "没有项目"

console.log(formatList(["apple"], "en"));
// "apple"

这样可以让您控制空数组在用户面前的显示方式。

浏览器支持

Intl.ListFormat API 在所有现代浏览器中都可用。从 2021 年 4 月起,Chrome、Firefox、Safari 和 Edge 都已支持该 API。

在使用之前,您可以检查该 API 是否存在。

if (typeof Intl.ListFormat !== "undefined") {
  const formatter = new Intl.ListFormat("en");
  console.log(formatter.format(["a", "b", "c"]));
} else {
  console.log("Intl.ListFormat 不受支持");
}

对于较旧的浏览器,您可以回退到使用 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"(或在较旧的浏览器中为 "red, green, blue")

这可以确保您的代码在所有浏览器中都能运行,同时在现代浏览器中提供最佳体验。