Intl.PluralRules

发布时间 · 标签:Intl

国际化很困难。处理复数是许多看似简单的问题之一,直到你意识到每种语言都有自己的复数规则。

对于英语复数,只有两种可能的结果。让我们以“cat”为例

  • 1 只猫,即 'one' 形式,在英语中称为单数
  • 2 只猫,但也包括 42 只猫、0.5 只猫等,即 'other' 形式(唯一的其他形式),在英语中称为复数。

全新的 Intl.PluralRules API 会根据给定的数字告诉你哪种形式适用于你选择的语言。

const pr = new Intl.PluralRules('en-US');
pr.select(0); // 'other' (e.g. '0 cats')
pr.select(0.5); // 'other' (e.g. '0.5 cats')
pr.select(1); // 'one' (e.g. '1 cat')
pr.select(1.5); // 'other' (e.g. '0.5 cats')
pr.select(2); // 'other' (e.g. '0.5 cats')

与其他国际化 API 不同,Intl.PluralRules 是一个低级 API,它本身不执行任何格式化操作。相反,你可以在它之上构建自己的格式化程序

const suffixes = new Map([
// Note: in real-world scenarios, you wouldn’t hardcode the plurals
// like this; they’d be part of your translation files.
['one', 'cat'],
['other', 'cats'],
]);
const pr = new Intl.PluralRules('en-US');
const formatCats = (n) => {
const rule = pr.select(n);
const suffix = suffixes.get(rule);
return `${n} ${suffix}`;
};

formatCats(1); // '1 cat'
formatCats(0); // '0 cats'
formatCats(0.5); // '0.5 cats'
formatCats(1.5); // '1.5 cats'
formatCats(2); // '2 cats'

对于相对简单的英语复数规则,这可能看起来有点过头;然而,并非所有语言都遵循相同的规则。有些语言只有一个复数形式,而有些语言有多个形式。例如,威尔士语 有六种不同的复数形式!

const suffixes = new Map([
['zero', 'cathod'],
['one', 'gath'],
// Note: the `two` form happens to be the same as the `'one'`
// form for this word specifically, but that is not true for
// all words in Welsh.
['two', 'gath'],
['few', 'cath'],
['many', 'chath'],
['other', 'cath'],
]);
const pr = new Intl.PluralRules('cy');
const formatWelshCats = (n) => {
const rule = pr.select(n);
const suffix = suffixes.get(rule);
return `${n} ${suffix}`;
};

formatWelshCats(0); // '0 cathod'
formatWelshCats(1); // '1 gath'
formatWelshCats(1.5); // '1.5 cath'
formatWelshCats(2); // '2 gath'
formatWelshCats(3); // '3 cath'
formatWelshCats(6); // '6 chath'
formatWelshCats(42); // '42 cath'

为了在支持多种语言的同时实现正确的复数化,需要一个包含语言及其复数规则的数据库。 Unicode CLDR 包含这些数据,但要在 JavaScript 中使用它,必须将其嵌入并与你的其他 JavaScript 代码一起发布,从而增加加载时间、解析时间和内存使用量。Intl.PluralRules API 将这种负担转移到 JavaScript 引擎,从而实现更高效的国际化复数化。

注意:虽然 CLDR 数据包含每种语言的形式映射,但它不包含单个单词的单数/复数形式列表。你仍然需要像以前一样自己翻译和提供这些形式。

序数 #

Intl.PluralRules API 通过可选 options 参数的 type 属性支持各种选择规则。它的隐式默认值(如上述示例中使用的那样)是 'cardinal'。要找出给定数字的序数指示符(例如,11st22nd 等),请使用 { type: 'ordinal' }

const pr = new Intl.PluralRules('en-US', {
type: 'ordinal'
});
const suffixes = new Map([
['one', 'st'],
['two', 'nd'],
['few', 'rd'],
['other', 'th'],
]);
const formatOrdinals = (n) => {
const rule = pr.select(n);
const suffix = suffixes.get(rule);
return `${n}${suffix}`;
};

formatOrdinals(0); // '0th'
formatOrdinals(1); // '1st'
formatOrdinals(2); // '2nd'
formatOrdinals(3); // '3rd'
formatOrdinals(4); // '4th'
formatOrdinals(11); // '11th'
formatOrdinals(21); // '21st'
formatOrdinals(42); // '42nd'
formatOrdinals(103); // '103rd'

Intl.PluralRules 是一个低级 API,尤其是在与其他国际化功能相比时。因此,即使你没有直接使用它,你可能正在使用依赖它的库或框架。

随着这个 API 的普及,你会发现像 Globalize 这样的库会放弃对硬编码 CLDR 数据库的依赖,转而使用原生功能,从而提高加载时间性能、解析时间性能、运行时性能和内存使用量。

Intl.PluralRules 支持 #