◉RORK LABJP
●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Beta since 09/15 with no stable date yet; running projects in Expo Go has required login since 09/03●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Beta since 09/15 with no stable date yet; running projects in Expo Go has required login since 09/03●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…
Articles/Dev Tools
⬡ Dev Tools/2026-07-13Advanced

When "{n} items" Breaks Across Languages — Designing Quantity Strings with CLDR Plural Categories and Intl.PluralRules

The assumption that one is singular and everything else is plural falls apart in Russian and Arabic. Here is how to hold the CLDR plural categories as a map and render quantities correctly with Intl.PluralRules and i18next, drawn from localizing an indie wallpaper app into sixteen languages.

Rork585Localization8PluralsIntl.PluralRulesi18next

✦ Premium Article

A few days after shipping a wallpaper app in sixteen languages, I got a short note from a Russian-speaking user: the favorites count "looked off somehow." On my own iPhone, in Japanese and in English, nothing was wrong.

It took me a while to trace it. I had written the count as n === 1 ? "1 item" : n + " items". If you only ever look at English and Japanese, that branch looks permanently correct. But in Russian the word form changes between two and five, and then twenty-one snaps back to the same form as one. The very premise of the ternary simply did not exist in that language.

This article reframes how quantity strings branch per language through the map of CLDR plural categories, then walks through selecting the right form with Intl.PluralRules and i18next. When you send a Rork or Expo app out into the world, this is the quiet trap I want to close before release.

Where "one is singular, everything else is plural" stops holding

The singular-versus-plural split we carry around unconsciously is really just a convenience of one language: English. Look across the world's languages and quantity forms are far more varied.

Japanese has no grammatical plural at all. "1 item" and "3 items" share the same form; you just drop n in. English is special only at one, then flat. If that were the whole world, a ternary would be enough.

The trouble starts beyond that. Russian and Ukrainian pick among three forms based on the trailing digits. Polish is similarly intricate, and Arabic carries six forms: zero, one, two, few, many, and other. A single "everything else is plural" branch cannot render any of those languages correctly.

So quantity bugs surface only in the languages a developer can't read. They never reproduce on your own device, so review never catches them. That is exactly why the per-language rules should live in a standardized map, not in your head.

Hold the CLDR plural categories as a map

That map is the CLDR (Unicode Common Locale Data Repository) plural categories. CLDR defines each language's quantity rules as a mapping onto one of six categories.

CategoryMeaningRepresentative languages
oneSingular-likeEnglish, German, Spanish (at 1)
otherDefault / everything elseJapanese, Chinese, Korean (only this)
fewSmall countsRussian, Polish, Czech
manyLarge countsRussian, Polish, Arabic
twoDualArabic, Slovenian, Welsh
zeroZeroArabic, Latvian

The point is that these are not numbers but a language's own partitioning of word forms. Russian classifying 21 as one is counterintuitive, yet you never have to memorize the rules. Let CLDR hold the map; you only supply one string per category name.

In a language like Japanese that has only other, the translator writes a single string. Whether more categories exist is the language's business, and the calling code should absorb that difference behind one identical call.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦Why a ternary plural breaks in Russian, Arabic, and Polish, explained through CLDR categories
✦A reusable helper that selects the right form with Intl.PluralRules, plus a Hermes fallback
✦How to keep cardinals and ordinals apart, and how to test the languages that actually break
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

⬡ Dev Tools2026-10-15
When EXPO_PUBLIC_ Values Read Fine in Dev but Come Back undefined in Production: Telling the Spellings Apart
The API URL reads fine while developing and turns undefined once the app is built. The cause was how process.env was written. I lined up babel-preset-expo's output for dev and production and tabulated which spellings get replaced and which are left behind.
⬡ Dev Tools2026-10-13
Before You Ship: Go Looking for Your Own Keys Inside the Exported Expo Bundle
A key can be missing from your source and still be sitting inside the finished app. I ran expo export on Expo SDK 57, searched the bundle with grep and a short Node script, and recorded which secrets show up and which don't.
⬡ Dev Tools2026-10-07
Japanese Headings Won't Turn Bold on Android: How to Trace and Fix a fontWeight That Does Nothing
A troubleshooting note for Rork apps where headings look bold on iPhone but stay thin on Android. How to tell the symptoms apart, pick weights through fontFamily, and verify the fix.