Plural Rules & ICU MessageFormat
See how any language pluralises any number, plus why “n === 1 ? singular : plural” is wrong in most of them and why Russian treats 21 as singular.
Every category here is read from your browser's own Intl data, which follows CLDR — so it is the same table a translation framework would use, not a copy of one. Nothing is uploaded.
"n === 1 ? singular : plural" is wrong in most languages
Across the 37 languages below, the familiar one-or-many test reproduces the real rule in 13 and fails in 24. Every language it matches has exactly two categories; the rest need between one and six.
| Categories | Languages | Which |
|---|---|---|
| 1 | 6 | Indonesian, Japanese, Chinese, Korean, Thai, Vietnamese |
| 2 | 18 | English, German, Dutch, Swedish, Danish, Norwegian Bokmål, Italian, Spanish, Catalan, Portuguese, French, Hindi, Turkish, Hungarian, Finnish, Greek, Icelandic, Persian |
| 3 | 3 | Hebrew, Latvian, Romanian |
| 4 | 6 | Russian, Ukrainian, Polish, Czech, Lithuanian, Slovenian |
| 5 | 2 | Maltese, Irish |
| 6 | 2 | Arabic, Welsh |
When the naive rule fails it fails early — every failing language disagrees at some number at or below 21, so this is not a corner case waiting in the tail. Japanese, Chinese, Korean, Thai and Vietnamese make no grammatical number distinction at all, which means an interface that pluralises by branching on the count is inventing a distinction those languages do not have.
The proportion is worth reading carefully rather than quoting. This list was chosen to span the plural systems, from one category to six, rather than sampled at random — so it says the naive rule covers one family shape and misses the others, not that some exact fraction of the world's languages defeat it.
The "one" category is not the number one
The categories are grammatical, not arithmetic. Russian uses its "one" form for 9 of the first hundred integers — every number ending in a single 1 except 11 itself. French and Hindi extend theirs to cover zero.
| Language | Integers 0–100 in the "one" category | How many |
|---|---|---|
| English | 1 | 1 |
| Russian | 1, 21, 31, 41, 51, 61, 71, 81, 91 | 9 |
| Polish | 1 | 1 |
| French | 0, 1 | 2 |
| Hindi | 0, 1 | 2 |
| Arabic | 1 | 1 |
| Welsh | 1 | 1 |
So a rule keyed on the value is the wrong shape however many branches you give it. In
Russian, 21 takes the same form as 1 and 11 does not — a pattern no amount of
if (n === 1) reproduces. The count has to be handed to the language's own
classifier and the answer used to pick a branch.
Ordinals are a different rule set again
English has two cardinal categories and 4 ordinal ones — which is exactly the st/nd/rd/th pattern usually hand-written as a switch on the last digit. Reading it from the ordinal rules gets the teens right for free.
| Number | Category | Correct | Last-digit rule gives |
|---|---|---|---|
| 1 | one | 1st | — |
| 2 | two | 2nd | — |
| 3 | few | 3rd | — |
| 4 | other | 4th | — |
| 11 | other | 11th | 11st |
| 12 | other | 12th | 12nd |
| 13 | other | 13th | 13rd |
| 21 | one | 21st | — |
| 22 | two | 22nd | — |
| 23 | few | 23rd | — |
| 101 | one | 101st | — |
| 111 | other | 111th | 111st |
A switch on the final digit gets 4 of these wrong: 11, 12, 13, 111. The first three are the well-known teens. The fourth is 111, which catches the same bug a second time at a different scale, because the real rule keys on the last two digits rather than the last one.
What a message actually needs
An ICU message needs one arm per category the target language uses, which means an English source string does not carry enough branches for its own Russian translation. This is the practical consequence: the count of branches is a property of the target, not the source.
| Language | Message skeleton |
|---|---|
| English | {count, plural, one {…} other {…}} |
| Russian | {count, plural, one {…} few {…} many {…} other {…}} |
| Arabic | {count, plural, zero {…} one {…} two {…} few {…} many {…} other {…}} |
| Japanese | {count, plural, other {…}} |
How to use
- Pick a language and type a number.
- See which grammatical category that number falls in.
- Compare it against the naive one-or-many rule.
- The table shows every integer in every category.
Frequently asked questions
Is “n === 1 ? singular : plural” good enough?
Not in most languages. Across the thirty-seven checked here it reproduces the real rule in thirteen and fails in twenty-four. Every language it matches has exactly two grammatical number categories, and the rest have between one and six.
How many plural forms can a language have?
Between one and six. Japanese, Chinese, Korean, Thai and Vietnamese make no grammatical number distinction at all, English and most of western Europe have two, Polish and Russian have four, and Arabic and Welsh have six.
Why does Russian treat 21 as singular?
Because the categories are grammatical rather than arithmetic. Russian uses its “one” form for every number ending in a single 1 except 11 itself, which is nine of the first hundred integers: 1, 21, 31, 41 and so on. No amount of checking whether the value equals one reproduces that.
Does any language treat zero as singular?
Yes. French and Hindi both put 0 in the “one” category, so “0 result” is correct French where “0 results” is correct English. This is why the count has to be handed to the language’s own classifier rather than compared against a number.
Are ordinals the same rules?
No, they are a separate rule set. English has two cardinal categories and four ordinal ones, which is exactly the st/nd/rd/th pattern. Reading it from the ordinal rules gets 11th, 12th and 13th right automatically.
What is wrong with switching on the last digit for ordinals?
It gets the teens wrong, and it gets them wrong at every scale. The real rule keys on the last two digits, so a last-digit switch produces 11st, 12nd and 13rd — and also 111st, which catches the same bug again a hundred later.
Why does my English source string not translate cleanly?
Because the number of message branches is a property of the target language, not the source. An English string carries two arms and a Russian translation needs four, so there is nowhere for the translator to put the missing forms unless the message format allows them.
Where does this data come from?
Your own browser, through the Intl.PluralRules API, which follows the CLDR data that translation frameworks use. Nothing here is a hand-maintained table, so it stays correct as that data is updated rather than drifting away from it.
Does this send anything anywhere?
No. Everything is computed in your browser, and nothing is uploaded.
🔒 This tool runs entirely in your browser. Nothing you enter is uploaded, logged, or stored.