DEV Community

Akmal Urunboev
Akmal Urunboev

Posted on

Most languages don't have two plural forms. Your i18n setup assumes they do.

If you localize an app into Russian and your string files only have one and other, your Russian
is wrong. Not awkward — wrong, in a way native speakers notice immediately and most English-speaking
teams never see.

I build multilingual mobile apps that run in ten languages, and this was the first thing that genuinely
embarrassed me.

The thing English teaches you to assume

English has two plural forms. One question, two questions. The rule is "is it 1?" and after that you
stop thinking about it. Every i18n tutorial reflects that, so the ARB or JSON you write looks like:

{
  "questionCount": "{count, plural, one{{count} question} other{{count} questions}}"
}
Enter fullscreen mode Exit fullscreen mode

That is a complete specification of English. It is not a complete specification of anything else, and
the structure you write in your source language is the structure translators are handed.

What Russian actually needs

Russian uses four CLDR plural categories: one, few, many, other.

Category Applies to Example
one 1, 21, 31, 41, 101 … 1 вопрос
few 2–4, 22–24, 32–34 … 2 вопроса
many 0, 5–20, 25–30 … 5 вопросов
other fractions 1.5 вопроса

Read the one row again, because it is the part that breaks code rather than translations.

21 is one in Russian. So is 31, 41, 101, 1021. If anywhere in your codebase you have written
if (count == 1) to decide singular versus plural, that branch is wrong in Russian for roughly one
number in ten. It will look fine in every test you write, because your tests use 1, 2 and 5.

Arabic goes further with six categories, including distinct zero and two. Polish, Czech,
Ukrainian and Lithuanian each have their own arrangement. The point is not to memorize them. The
point is that the number of forms is a property of the language, not of your code, and CLDR already
knows all of them.

Where it actually goes wrong

Three failure modes, in the order I hit them.

1. The source string constrains the translation. You ship an ARB with only one and other.
The translator opens it and has nowhere to put few and many. A good translator flags it. A
translator working through a spreadsheet at volume picks the closest slot and moves on, and you have
now shipped "5 вопроса" — which reads roughly like "5 questions-of" — to every user who answers
five of anything.

2. Manual pluralization in code. Somewhere there is a helper like
count == 1 ? singular : plural. It predates the i18n work, it is three lines long, and nobody
remembers it exists. It is correct in English forever and wrong in Russian from the moment you
launch.

3. Interpolated counts inside longer sentences. The plural form often has to agree with a verb
or adjective elsewhere in the sentence, which means the whole sentence is the translation unit, not
the noun. Splitting a sentence into fragments and concatenating them produces text no amount of
good translation can save.

What I do now

Write the source string with every category you might ever need, even though English collapses
most of them. Intl.plural in Dart accepts zero, one, two, few, many, other. Fill in
what English needs and leave the rest for the languages that use them, rather than handing
translators a shape that cannot hold their grammar.

Delete every manual plural branch. Grep for == 1 near anything user-facing. This is a
twenty-minute job and it finds things.

Never build a sentence by concatenation. One string, one complete sentence, placeholders inside
it. If that produces an awkward English string, the awkwardness is a signal about word order you'd
otherwise discover in production.

Test with 1, 2, 5, 21 and 0. Those five numbers hit every Russian category including the one
that catches == 1. Add 11 if you want to be thorough, since 11 is many despite ending in 1.

The part worth internalizing

This is not really a Russian problem. It is what happens when a structure designed around one
language's grammar becomes the container every other language has to fit into. Plurals are just the
most legible instance — the same thing happens with date formats, name order, honorifics and text
expansion.

The fix is cheap if you do it before translation and expensive afterwards, because by then the wrong
shape is baked into thousands of strings and a translation memory that will faithfully reproduce it.

If you are about to localize something, spend an afternoon on CLDR plural rules first. It is the
highest-return afternoon in the whole project.


I build and operate multilingual mobile applications, shipped across ten languages.
More at akmalu.com.

Top comments (0)