← 中文资源

简体中文版本

按 Intl.PluralRules 选择复数形式

依据 CLDR 复数类别为不同语言选择单复数形式,并支持 two、few 等自定义词形。

阅读英文原文

功能说明

pluralize 根据数量与语言选择正确的名词形式,英语只需单复数,俄语、阿拉伯语等可能需要 two、few、many 等类别。第三个参数既可传复数字符串,也可传按类别组织的对象,便于覆盖特殊词形。pluralizeWithNumber 还会用 Intl.NumberFormat 格式化数字,使千分位与本地数字样式一致,适合计数标签与统计摘要。

关键代码

Intl.PluralRules 的 select 返回 CLDR 类别,代码先兼容字符串形式的复数参数,再与自定义对象合并,最后按类别取值并以 other 作为兜底。数字与词之间只拼接一个空格,保持简单可预测。第二个函数先格式化数字,再复用第一个函数得到的文本,通过第一个空格定位并替换数字部分,避免重复实现类别判断。

使用注意

不同语言的复数规则不只是加 s,应始终传入正确 locale,不能默认英语。对象形式必须提供 other,否则特殊类别可能回退到单数。数量为 1.0 与 1 在部分语言中类别不同,若业务只接受整数应在外层校验。函数返回字符串而不是数值,不应参与排序;占位符式翻译应使用 ICU MessageFormat 而非字符串拼接。

验证方式

测试英语的 0、1、2 与小数,确认 one 与 other 正确。用俄语或阿拉伯语验证 two、few、many 分支,并传入自定义对象覆盖类别。测试复数字符串与对象两种参数、缺少 other 的兜底行为。第二个函数检查千分位、负数和 locale 格式化结果,同时覆盖 NaN、字符串计数与空词形等异常输入。

代码示例

export function pluralize(count, singular, plural, locale = "en") {
  if (typeof count !== "number" || !Number.isFinite(count)) {
    throw new TypeError("count must be a finite number");
  }
  const rules = new Intl.PluralRules(locale);
  const category = rules.select(count);
  const forms = typeof plural === "string"
    ? { one: singular, other: plural }
    : { one: singular, other: singular, ...plural };
  const word = forms[category] ?? forms.other ?? singular;
  return String(count) + " " + word;
}

export function pluralizeWithNumber(count, singular, plural, locale = "en") {
  const formatted = new Intl.NumberFormat(locale).format(count);
  const text = pluralize(count, singular, plural, locale);
  const separator = text.indexOf(" ");
  return separator === -1 ? text : formatted + text.slice(separator);
}