功能说明
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);
}