CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-make-plural

Unicode CLDR pluralization rules as JavaScript functions for internationalization applications

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

range-pluralization.mddocs/

Range Pluralization

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.

Capabilities

Range Functions

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 Pattern

import { en, ro, pl, ar } from "make-plural/ranges";

Language Coverage

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 category
  • pl - Polish: Returns "one" | "few" | "many" | "other"
  • ru - Russian: Complex Slavic range rules
  • uk - Ukrainian: Complex Slavic range rules

Variable Range Rules:

  • lt - Lithuanian: 5 different possible outcomes
  • lv - Latvian: Complex range calculations
  • cs - Czech: Slavic range patterns

Usage Examples

English 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 rule

Practical Range Usage

Building 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' }

Language-Specific Range Rules

English Range Rules:

  • All ranges return "other" regardless of input categories
  • Simple rule: ranges are always plural

Romanian Range Rules:

  • If end is "few", return "few"
  • If end is "other", return "other"
  • Otherwise return start category

Polish Range Rules:

  • Complex logic based on both start and end categories
  • Generally returns the "more plural" of the two categories
  • Special handling for "one" to "few" transitions

Lithuanian Range Rules (Most Complex):

  • 5 possible outcomes: "one", "few", "many", "other"
  • Complex matrix-based rules considering all combinations
  • Different outcomes for different start/end combinations

Error Handling

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 category

When to Use Ranges

Use range pluralization when:

  1. Range Messages: Displaying ranges like "1-5 items", "3-10 results"
  2. Localization: Building internationalized range displays
  3. Complex Languages: Working with languages that have specific range rules
  4. Comprehensive Support: Need full CLDR compliance for range pluralization

Common applications:

  • Search result counts ("Showing 1-10 of 100 results")
  • Pagination displays ("Items 21-30")
  • Quantity ranges ("Select 2-5 options")
  • Date ranges with counts ("1-3 days remaining")

Limitations

Language Coverage:

  • Only 93 of 219 languages have specific range rules
  • Languages without range rules are not included in this module
  • Use main plurals module for fallback behavior

Range Logic:

  • Range functions operate on plural categories, not raw numbers
  • You must calculate start/end categories first using pluralization functions
  • Range direction (start > end) may produce unexpected results in some languages

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;
  }
}

docs

cardinal-pluralization.md

core-pluralization.md

example-values.md

index.md

ordinal-pluralization.md

plural-categories.md

range-pluralization.md

tile.json