Intl.PluralRules

發佈於 · 標籤為 Intl

國際化很困難。處理複數形式是許多問題中的一個,看起來很簡單,直到你發現每種語言都有自己的複數形式規則。

對於英文複數形式,只有兩種可能的結果。我們以「cat」這個字為例

  • 1 cat,也就是 'one' 形式,在英文中稱為單數
  • 2 cats,還有 42 cats、0.5 cats 等,也就是 '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 支援透過選項引數上的 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 支援 #