Pluralisasi memilih bentuk kata menurut jumlah; gender memilih bentuk kata menurut siapa yang dibicarakan. Bayangin Bu Sri punya satu set stempel untuk menulis lama menginap di kuitansi. Untuk bahasa Indonesia cukup satu stempel: "2 malam", "11 malam". Untuk bahasa Inggris dua: "1 night" dan "2 nights". Untuk bahasa Arab enam, termasuk satu stempel khusus untuk tepat dua malam. Intl.PluralRules adalah petugas yang membaca angkanya lalu menyerahkan stempel yang benar.
🧪 Tebakan cepat: Dalam bahasa Arab, apakah 3 malam dan 103 malam memakai bentuk kata yang sama? Bagaimana dengan 2 malam dan 102 malam? Jawabannya ada di bagian "Angka mana masuk kategori mana".
Kategori jamak CLDR
CLDR (data locale yang dibawa browser) memberi tiap bahasa sebagian dari enam kategori: zero, one, two, few, many, other. Intl.PluralRules memberi tahu kategori sebuah angka:
new Intl.PluralRules('ar-EG').select(3); // "few"
new Intl.PluralRules('en-US').select(1); // "one"
new Intl.PluralRules('id-ID').resolvedOptions().pluralCategories; // ["other"]
| Locale | Kategori | Contoh "malam" |
|---|---|---|
id-ID |
other | 1 malam, 2 malam |
en-US |
one, other | 1 night, 2 nights |
ja-JP |
other | 1泊, 2泊 |
ar-EG |
zero, one, two, few, many, other | ليلة واحدة, ليلتان, ٣ ليالٍ, ١١ ليلة |
Kategori itu nama, bukan angka. Di bahasa Prancis, 0 dan 1,5 juga one; di bahasa Rusia, 21 juga one. other wajib ada di setiap bahasa. Bahasa Indonesia dan Jepang gak punya penanda jamak, jadi satu bentuk other cukup.
Angka mana masuk kategori mana
Kategori bahasa Arab dihitung dari dua digit terakhir. Hasil new Intl.PluralRules('ar-EG').select(n), sama di Chromium 147, Firefox 146, WebKit 26.4, dan Node 22.22.1:
| n | Kategori | Pesan nights (dari pelajaran react-intl) |
|---|---|---|
| 0 | zero | ٠ ليلة |
| 1 | one | ليلة واحدة |
| 2 | two | ليلتان (bentuk dual, tanpa angka) |
| 3 sampai 10 | few | ٣ ليالٍ |
| 11 sampai 99 | many | ١١ ليلة |
| 100, 101, 102 | other | ١٠٠ ليلة |
| 103 sampai 110 | few | ١٠٣ ليالٍ |
| 111 sampai 199 | many | ١١١ ليلة |
| 1,5 | other | ١٫٥ ليلة |
Jadi 3 dan 103 sama-sama few, sedangkan 2 itu two dan 102 itu other. Itu jawaban tebakannya. Pesan nights kami gak punya cabang zero, jadi 0 memakai other. Satu beda kecil antar mesin: urutan pluralCategories di Node 22.22.1 adalah few, many, one, two, zero, other, di tiga browser zero, one, two, few, many, other. Isinya sama.
Kenapa count === 1 ? ... : ... rusak
const nf = new Intl.NumberFormat('ar-EG');
const naive = (n) => (n === 1 ? 'ليلة واحدة' : nf.format(n) + ' ليالٍ'); // pola "satu atau banyak"
| n | naive(n) |
Yang benar |
|---|---|---|
| 2 | ٢ ليالٍ | ليلتان |
| 11 | ١١ ليالٍ | ١١ ليلة |
| 100 | ١٠٠ ليالٍ | ١٠٠ ليلة |
Pola dua cabang cuma cocok untuk bahasa yang punya dua bentuk. Bahasa Arab punya enam, bahasa Rusia punya one, few, many, dan other. Simpan semua bentuk di kamus, lalu biarkan Intl.PluralRules (lewat ICU plural atau akhiran _few di i18next) yang memilih. Angka desimal juga beda: new Intl.PluralRules('en-US', { minimumFractionDigits: 1 }).select(1) memberi "other", karena yang tertulis "1.0 nights".
Bilangan urutan: type: 'ordinal'
"Menginap ke-21" butuh aturan lain: ordinal.
const ord = new Intl.PluralRules('en-US', { type: 'ordinal' });
[1, 2, 3, 4, 11, 12, 13, 21, 22, 23, 111].map((n) => ord.select(n));
// ["one", "two", "few", "other", "other", "other", "other", "one", "two", "few", "other"]
{n, selectordinal, one {Your #st stay} two {Your #nd stay} few {Your #rd stay} other {Your #th stay}}
- Bahasa Inggris: 1st, 2nd, 3rd, 4th, lalu 11th, 12th, 13th (bukan 11st), 21st, 22nd, 23rd, 111th.
id-ID,ja-JP, danar-EGcuma punyaotheruntuk ordinal: "Menginap ke-21", "21回目のご宿泊".- Di ICU namanya
selectordinal; di i18next,t('stay', { count: 21, ordinal: true })membaca keystay_ordinal_one,stay_ordinal_two,stay_ordinal_few,stay_ordinal_other.
Gender dengan select
id-ID: Terima kasih, {gender, select, male {Pak} female {Bu} other {Kak}} {name}!
ar-EG: {gender, select, female {شكرًا لكِ يا {name}!} other {شكرًا لكَ يا {name}!}}
en-US: Thank you, {name}!
- Di
id-ID, pilihannya sapaan: Pak Hadi, Bu Rina, Kak Alex. Diar-EG, pilihannya tata bahasa: kata "kamu" berakhiran berbeda untuk laki-laki (لكَ) dan perempuan (لكِ). Bahasa Inggris dan Jepang gak butuh keduanya. - Gender tata bahasa bukan gender tamu. Kata ليلة (malam) dalam bahasa Arab berjenis feminin, jadi "satu malam" selalu ليلة واحدة dengan واحدة bentuk feminin, siapa pun tamunya. Kata benda di bahasa Prancis atau Jerman juga punya gender sendiri.
- Sediakan
other. ICU melemparSyntaxError: MISSING_OTHER_CLAUSEtanpa cabang itu, dan tamu berhak gak menyebut gendernya. Jangan menebak dari nama ("Alex" bisa siapa saja): simpan pilihan sapaan yang diisi tamu sendiri, dan pakaiotherkalau kosong.
Plural dan select dalam satu pesan
Taruh select di luar dan plural di dalam, dengan kalimat utuh di tiap cabang, supaya penerjemah melihat kalimat lengkap:
en-US: {gender, select,
male {He booked {n, plural, one {# night} other {# nights}}.}
female {She booked {n, plural, one {# night} other {# nights}}.}
other {They booked {n, plural, one {# night} other {# nights}}.}}
id-ID: {gender, select, male {Pak {name}} female {Bu {name}} other {Kak {name}}} memesan {n, plural, other {# malam}}.
intl-messageformat 12.1.3 memberi "She booked 2 nights.", "They booked 1 night.", dan "Bu Rina memesan 2 malam.". Di i18next, gabungannya memakai context plus count: key booked_male_one, booked_female_other, booked_one, booked_other, lalu t('booked', { context: gender, count: n }). Untuk gender yang gak diketahui, kirim context: undefined, bukan 'other': dengan 'other', i18next 26.4.3 membaca key booked_other (bentuk jamak) dan menulis "They booked 1 nights."
⚠️ Jebakan yang sering ketemu
count === 1 ? ... : .... Benar untuk bahasa Inggris, salah untuk 2, 11, dan 100 malam dalam bahasa Arab.- Mengira
oneberarti angka 1. Di bahasa Prancis 0 jugaone; di bahasa Rusia 21 jugaone. - Memakai aturan kardinal untuk urutan. Hasilnya "21th" atau "11st". Pakai
type: 'ordinal'atauselectordinal. - Menebak gender dari nama, atau lupa
other. Tanya tamu, dan sediakan cabangother.
TL;DR: CLDR punya enam kategori jamak: zero, one, two, few, many, other. Intl.PluralRules adalah API browser yang menentukan kategori sebuah angka untuk sebuah locale: id-ID dan ja-JP cuma other, en-US one dan other, ar-EG keenamnya (0 zero, 1 one, 2 two, 3 sampai 10 few, 11 sampai 99 many, 100 sampai 102 other, lalu 103 few lagi). Pluralisasi gak bisa sekadar mengecek count === 1, karena beberapa bahasa punya lebih dari dua bentuk jamak. Urutan memakai { type: 'ordinal' } (1st, 2nd, 3rd, 4th, 11th, 21st) atau ICU selectordinal. Gender memakai select dengan cabang other yang wajib: sapaan Pak/Bu/Kak di id-ID, لكَ/لكِ di ar-EG; gender tata bahasa (ليلة feminin) gak ada hubungannya dengan gender tamu, dan gender gak boleh ditebak dari nama. Gabungkan select di luar dan plural di dalam; di i18next pakai context plus count, dan kirim context: undefined untuk gender yang gak diketahui.