Unicode CLDR pluralization rules as JavaScript functions for internationalization applications
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Functions for determining the pluralization of numerical ranges (e.g., "1-5 items", "3-7 books"). Only 91 of the 217 supported languages have specific range pluralization rules.
Languages with range rules provide functions that determine the appropriate plural category for a numerical range based on the plural categories of the start and end values.
/**
* Determines the plural category for a numerical range
* @param start - Plural category of the range start value
* @param end - Plural category of the range end value
* @returns The appropriate plural category for the range
*/
(start: PluralCategory, end: PluralCategory) => PluralCategory;
type PluralCategory = "zero" | "one" | "two" | "few" | "many" | "other";import { en, ro, pl, ar } from "make-plural/ranges";93 languages with range rules include:
Simple Range Rules:
en - English: Always returns "other"de - German: Always returns "other"es - Spanish: Always returns "other"fr - French: Always returns "other"Complex Range Rules:
ro - Romanian: Complex logic based on end categorypl - Polish: Returns "one" | "few" | "many" | "other"ru - Russian: Complex Slavic range rulesuk - Ukrainian: Complex Slavic range rulesVariable Range Rules:
lt - Lithuanian: 5 different possible outcomeslv - Latvian: Complex range calculationscs - Czech: Slavic range patternsEnglish Range Pluralization:
import { en } from "make-plural/ranges";
// English always uses 'other' for ranges
en('one', 'one'); // 'other' (1-1 items)
en('one', 'other'); // 'other' (1-5 items)
en('other', 'other'); // 'other' (2-10 items)
en('other', 'one'); // 'other' (5-1 items - unusual but possible)Romanian Range Pluralization:
import { ro } from "make-plural/ranges";
// Romanian has complex range rules based on end category
ro('one', 'few'); // 'few' (1-3 items)
ro('few', 'one'); // 'few' (3-1 items)
ro('one', 'other'); // 'other' (1-20 items)
ro('few', 'other'); // 'other' (3-20 items)
ro('other', 'other'); // 'other' (20-100 items)Polish Range Pluralization:
import { pl } from "make-plural/ranges";
// Polish range rules follow specific patterns
pl('one', 'few'); // 'few' (1-3 items)
pl('few', 'few'); // 'few' (2-4 items)
pl('few', 'many'); // 'many' (3-10 items)
pl('many', 'many'); // 'many' (5-20 items)
pl('one', 'many'); // 'many' (1-10 items)Lithuanian Range Pluralization:
import { lt } from "make-plural/ranges";
// Lithuanian has complex 5-outcome range rules
lt('one', 'one'); // 'one'
lt('one', 'few'); // 'few'
lt('few', 'many'); // 'many'
lt('many', 'other'); // 'other'
lt('other', 'one'); // 'many' // Complex ruleBuilding Localized Range Messages:
import { en, ro, pl } from "make-plural/ranges";
import { en as enPlural, ro as roPlural, pl as plPlural } from "make-plural";
function formatRange(start, end, language) {
// Get plural categories for start and end
const startCategory = language.plural(start);
const endCategory = language.plural(end);
// Get range category
const rangeCategory = language.range(startCategory, endCategory);
// Use appropriate translation based on range category
return language.translations.range[rangeCategory]
.replace('{start}', start)
.replace('{end}', end);
}
// Example with different languages
const languages = {
en: {
plural: enPlural,
range: en,
translations: {
range: {
other: '{start}-{end} items'
}
}
},
ro: {
plural: roPlural,
range: ro,
translations: {
range: {
one: '{start}-{end} element',
few: '{start}-{end} elemente',
other: '{start}-{end} de elemente'
}
}
}
};
console.log(formatRange(1, 3, languages.en)); // "1-3 items"
console.log(formatRange(1, 3, languages.ro)); // "1-3 elemente"Range Category Calculation:
import { en, ro, pl } from "make-plural/ranges";
import { en as enPlural, ro as roPlural, pl as plPlural } from "make-plural";
function getRangeInfo(start, end, rangeFn, pluralFn) {
const startCategory = pluralFn(start);
const endCategory = pluralFn(end);
const rangeCategory = rangeFn(startCategory, endCategory);
return {
start,
end,
startCategory,
endCategory,
rangeCategory
};
}
// English examples
console.log(getRangeInfo(1, 5, en, enPlural));
// { start: 1, end: 5, startCategory: 'one', endCategory: 'other', rangeCategory: 'other' }
// Romanian examples
console.log(getRangeInfo(1, 3, ro, roPlural));
// { start: 1, end: 3, startCategory: 'one', endCategory: 'few', rangeCategory: 'few' }
// Polish examples
console.log(getRangeInfo(2, 4, pl, plPlural));
// { start: 2, end: 4, startCategory: 'few', endCategory: 'few', rangeCategory: 'few' }English Range Rules:
"other" regardless of input categoriesRomanian Range Rules:
"few", return "few""other", return "other"Polish Range Rules:
"one" to "few" transitionsLithuanian Range Rules (Most Complex):
"one", "few", "many", "other"Range functions expect valid plural categories as input:
import { en, ro } from "make-plural/ranges";
// Valid usage
en('one', 'other'); // 'other'
ro('few', 'many'); // 'other'
// Invalid usage (will cause errors)
// en('invalid', 'other'); // Error: invalid category
// ro('one', 'seven'); // Error: invalid categoryUse range pluralization when:
Common applications:
Language Coverage:
Range Logic:
Fallback Strategy:
import { en } from "make-plural/ranges";
import { fr } from "make-plural";
// For languages without range rules, use a fallback
function getRangeCategory(start, end, language) {
try {
// Try to use range function if available
const rangeFn = require(`make-plural/ranges`)[language];
const startCat = require(`make-plural`)[language](start);
const endCat = require(`make-plural`)[language](end);
return rangeFn(startCat, endCat);
} catch (e) {
// Fallback: ranges are typically 'other' or use end category
const endCat = require(`make-plural`)[language](end);
return endCat === 'one' ? 'other' : endCat;
}
}