
CLDR Plural Rules: Validate i18n Plural Categories Across Languages
English has 2 plural forms. Arabic has 6. Russian has 4. If your i18n setup only handles 'one' and 'other', your app is broken in most languages. This guide explains CLDR plural rules and how to validate them.
What Are CLDR Plural Rules?
The Unicode CLDR (Common Locale Data Repository) defines six plural categories: zero, one, two, few, many, and other. Every language uses a subset of these categories with specific numeric rules. English uses one (exactly 1) and other (everything else). But most languages are more complex — and getting plural forms wrong causes grammatically broken text that makes your app feel amateur.
// English has 2 plural forms: one, other
// "1 item" vs "2 items"
// But many languages have more:
// Arabic: 6 forms (zero, one, two, few, many, other)
// Polish: 3 forms (one, few, other)
// Japanese: 1 form (other)
// Czech: 3 forms (one, few, other)
// If you only provide "one" and "other",
// Arabic and Polish users see broken text.The Six Plural Categories
CLDR defines exactly six plural categories. Not every language uses all six — English only uses two, Arabic uses all six. Your i18n files must define the categories that each target language requires, or users see crashes, raw keys, or grammatically wrong text.
// CLDR defines 6 plural categories:
// zero - 0 items (Arabic, Latvian)
// one - 1 item (most languages)
// two - 2 items (Arabic, Welsh)
// few - 2-4 items (Polish, Czech, Russian)
// many - 5-19 items (Arabic, Polish, Russian)
// other - everything else (required for ALL languages)
// Examples by language:
// English: one, other (2 forms)
// French: one, many, other (3 forms)
// Arabic: zero, one, two, few, many, other (6 forms)
// Japanese: other (1 form)
// Polish: one, few, many, other (4 forms)
// Russian: one, few, many, other (4 forms)Plural Categories by Language
Quick reference for plural categories required by common target languages. Use this when defining plural forms in your translation files.
// MISTAKE 1: Only providing "one" and "other"
// en.json
{
"items_one": "{{count}} item",
"items_other": "{{count}} items"
}
// This breaks for Arabic (missing zero, two, few, many)
// MISTAKE 2: Hardcoded plural logic
// WRONG:
const text = count === 1 ? "1 item" : `${count} items`
// This fails for languages where "1" isn't the only "one" form
// MISTAKE 3: Missing "other" category
// "other" is REQUIRED for every language
// Without it, some numbers show raw keys
// MISTAKE 4: Translating plural RULES instead of text
// The CLDR rules (one, few, many) are universal
// Only the TEXT after each rule should be translatedAutomated Plural Validation
i18n-validate checks that every plural key in your translation files defines all CLDR categories required by the target language. If your Russian file only has 'one' and 'other' forms, the tool flags the missing 'few' and 'many' categories as errors. Run it in CI to catch plural issues before they reach users.
# Validate plural forms match CLDR requirements
npx i18n-validate --check-plurals \
--source locales/en.json \
--targets 'locales/*.json'
# Output:
# locales/ar.json:
# items: missing plural forms: zero, two, few, many
# Expected: zero, one, two, few, many, other
# Found: one, other
#
# locales/pl.json:
# items: missing plural forms: few, many
# Expected: one, few, many, other
# Found: one, other
# Fix: Add all required forms for each language
# See https://unicode.org/cldr/charts/latest/supplemental/language_plural_rules.htmlICU MessageFormat for Plurals
The recommended way to define plural translations is ICU MessageFormat. It uses a single string with embedded plural rules: {count, plural, one {# item} other {# items}'}. ICU is supported by react-intl, vue-i18n, Angular Transloco, Flutter, and most modern i18n frameworks.
// ICU MessageFormat handles plurals correctly
// It uses CLDR rules internally
// en.json
{
"items": "{count, plural, one {# item} other {# items}}"
}
// ar.json
{
"items": "{count, plural, zero {لا عناصر} one {عنصر واحد} two {عنصران} few {# عناصر} many {# عنصرًا} other {# عنصر}}"
}
// pl.json
{
"items": "{count, plural, one {# element} few {# elementy} many {# elementów} other {# elementu}}"
}
// ICU also handles ordinals:
{
"ranking": "{pos, selectordinal, one {#st} two {#nd} few {#rd} other {#th}}"
}# Validate ICU message syntax
npx i18n-validate --check-icu \
--source locales/en.json \
--targets 'locales/*.json'
# Catches:
# - Missing plural categories for the target language
# - Syntax errors in ICU messages
# - Mismatched variable names
# - Missing "other" (always required)Try i18n Agent Now
Drop your translation file here
JSON, YAML, PO, XML, CSV, Markdown, Properties
or click to browse
Target languages