Guide to Intl.PluralRules in JavaScript

The Intl.PluralRules object is a native JavaScript API designed to handle language-sensitive pluralization by determining the correct grammatical plural category for any given number and locale. While many developers assume pluralization is as simple as distinguishing between singular (1) and plural (not 1), different languages use complex grammatical rules involving dual forms, paucal forms, and specific fractional behavior. This article explains how Intl.PluralRules works, how it resolves locale-specific plural categories, and how to implement it effectively in modern applications.

What is Intl.PluralRules?

Part of the ECMAScript Internationalization API (ECMA-402), Intl.PluralRules does not format text or output translated strings directly. Instead, it acts as a decision engine. When provided a number and a locale, it returns one of the standard Unicode Common Locale Data Repository (CLDR) plural categories:

Every language supported by the runtime maps numbers to a subset of these categories based on its linguistic rules. In all languages, the other category serves as the mandatory fallback.

Basic Syntax

To create a plural rule matcher, instantiate the object with an optional locale and options object:

const pluralRules = new Intl.PluralRules(locales, options);

Cardinal Pluralization

Cardinal numbers represent quantities (e.g., 0 cars, 1 car, 5 cars).

In English, cardinal numbers only distinguish between one and other:

const enRules = new Intl.PluralRules('en-US');

console.log(enRules.select(0)); // "other"
console.log(enRules.select(1)); // "one"
console.log(enRules.select(2)); // "other"
console.log(enRules.select(5)); // "other"

Languages with richer plural systems require more categories. For example, Arabic utilizes all six plural forms:

const arRules = new Intl.PluralRules('ar-EG');

console.log(arRules.select(0));   // "zero"
console.log(arRules.select(1));   // "one"
console.log(arRules.select(2));   // "two"
console.log(arRules.select(3));   // "few" (numbers 3-10)
console.log(arRules.select(11));  // "many" (numbers 11-99)
console.log(arRules.select(100)); // "other"

Ordinal Pluralization

Ordinal numbers indicate sequence or rank (e.g., 1st, 2nd, 3rd). By setting the type option to 'ordinal', Intl.PluralRules returns the rule category applicable to positions:

const enOrdinalRules = new Intl.PluralRules('en-US', { type: 'ordinal' });

console.log(enOrdinalRules.select(1));  // "one"   -> 1st
console.log(enOrdinalRules.select(2));  // "two"   -> 2nd
console.log(enOrdinalRules.select(3));  // "few"   -> 3rd
console.log(enOrdinalRules.select(4));  // "other" -> 4th
console.log(enOrdinalRules.select(21)); // "one"   -> 21st
console.log(enOrdinalRules.select(22)); // "two"   -> 22nd

Practical Implementation: Building a Pluralization Function

Because Intl.PluralRules only returns category strings, you use those categories to look up matching localized strings.

Example: Cardinal Messages

function formatItems(count, locale = 'en-US') {
  const rules = new Intl.PluralRules(locale);
  const rule = rules.select(count);

  const messages = {
    'en-US': {
      one: `${count} item selected`,
      other: `${count} items selected`
    },
    'ru': {
      one: `${count} элемент выбран`,
      few: `${count} элемента выбрано`,
      many: `${count} элементов выбрано`,
      other: `${count} элементов выбрано`
    }
  };

  const localeMessages = messages[locale] || messages['en-US'];
  return localeMessages[rule] || localeMessages['other'];
}

console.log(formatItems(1, 'en-US'));  // "1 item selected"
console.log(formatItems(5, 'en-US'));  // "5 items selected"
console.log(formatItems(1, 'ru'));     // "1 элемент выбран"
console.log(formatItems(2, 'ru'));     // "2 элемента выбрано"
console.log(formatItems(5, 'ru'));     // "5 элементов выбрано"

Example: Ordinal Suffixes

function getOrdinalSuffix(number, locale = 'en-US') {
  const rules = new Intl.PluralRules(locale, { type: 'ordinal' });
  const rule = rules.select(number);

  const suffixes = {
    one: 'st',
    two: 'nd',
    few: 'rd',
    other: 'th'
  };

  return `${number}${suffixes[rule] || suffixes.other}`;
}

console.log(getOrdinalSuffix(1));  // "1st"
console.log(getOrdinalSuffix(2));  // "2nd"
console.log(getOrdinalSuffix(3));  // "3rd"
console.log(getOrdinalSuffix(11)); // "11th"
console.log(getOrdinalSuffix(21)); // "21st"

Determining Supported Categories

To inspect which plural categories a particular locale supports without guessing, use the resolvedOptions() method:

const rules = new Intl.PluralRules('ru');
console.log(rules.resolvedOptions().pluralCategories);
// Output: ["one", "few", "many", "other"]

Summary

Intl.PluralRules removes the burden of writing custom, fragile condition trees for plural strings across languages. By offloading linguistic logic directly to the browser or runtime, applications can achieve full internationalization compliance with minimal code.