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

plural-categories.mddocs/

Plural Categories

Metadata about available plural categories for each language, including both cardinal and ordinal categories. This module provides the category information without the pluralization logic.

Capabilities

Category Objects

Each language provides an object with arrays of available categories for cardinal and ordinal pluralization.

/**
 * Language category metadata
 */
interface LanguageCategories {
  cardinal: PluralCategory[];
  ordinal: PluralCategory[];
}

type PluralCategory = "zero" | "one" | "two" | "few" | "many" | "other";

Import Pattern

import * as Categories from "make-plural/pluralCategories";
// Or import specific languages
import { en, ar, fr } from "make-plural/pluralCategories";

Language Category Objects

All 219 languages provide category metadata:

Examples by Complexity:

Simple Two-Category Languages:

Categories.en.cardinal    // ["one", "other"]  
Categories.de.cardinal    // ["one", "other"]
Categories.nl.cardinal    // ["one", "other"]
Categories.sv.cardinal    // ["one", "other"]

Three-Category Languages:

Categories.fr.cardinal    // ["one", "many", "other"]
Categories.pt.cardinal    // ["one", "many", "other"] 
Categories.es.cardinal    // ["one", "many", "other"]
Categories.it.cardinal    // ["one", "many", "other"]

Four-Category Languages:

Categories.pl.cardinal    // ["one", "few", "many", "other"]
Categories.ru.cardinal    // ["one", "few", "many", "other"]
Categories.uk.cardinal    // ["one", "few", "many", "other"]
Categories.hr.cardinal    // ["one", "few", "many", "other"]

Complex Six-Category Languages:

Categories.ar.cardinal    // ["zero", "one", "two", "few", "many", "other"]
Categories.cy.cardinal    // ["zero", "one", "two", "few", "many", "other"]

Single-Category Languages:

Categories.zh.cardinal    // ["other"]
Categories.ja.cardinal    // ["other"]
Categories.ko.cardinal    // ["other"]
Categories.vi.cardinal    // ["other"]

Ordinal Categories

Languages with ordinal rules (105 languages) provide ordinal category arrays:

English Ordinals:

Categories.en.cardinal    // ["one", "other"]
Categories.en.ordinal     // ["one", "two", "few", "other"]

Welsh Complex Ordinals:

Categories.cy.cardinal    // ["zero", "one", "two", "few", "many", "other"]
Categories.cy.ordinal     // ["zero", "one", "two", "few", "many", "other"]

French Simple Ordinals:

Categories.fr.cardinal    // ["one", "many", "other"]
Categories.fr.ordinal     // ["one", "other"]

Languages Without Ordinal Rules:

Categories.zh.cardinal    // ["other"]
Categories.zh.ordinal     // ["other"]

Categories.ja.cardinal    // ["other"]  
Categories.ja.ordinal     // ["other"]

Usage Examples

Checking Available Categories:

import * as Categories from "make-plural/pluralCategories";

// Check what categories a language supports
function getLanguageInfo(lang) {
  const langCategories = Categories[lang];
  return {
    cardinalCount: langCategories.cardinal.length,
    ordinalCount: langCategories.ordinal.length,
    hasComplexCardinals: langCategories.cardinal.length > 2,
    hasComplexOrdinals: langCategories.ordinal.length > 2,
    categories: langCategories
  };
}

console.log(getLanguageInfo('en'));
// {
//   cardinalCount: 2,
//   ordinalCount: 4, 
//   hasComplexCardinals: false,
//   hasComplexOrdinals: true,
//   categories: { cardinal: ["one", "other"], ordinal: ["one", "two", "few", "other"] }
// }

console.log(getLanguageInfo('ar'));
// {
//   cardinalCount: 6,
//   ordinalCount: 1,
//   hasComplexCardinals: true, 
//   hasComplexOrdinals: false,
//   categories: { cardinal: ["zero", "one", "two", "few", "many", "other"], ordinal: ["other"] }
// }

Building Localization Systems:

import * as Categories from "make-plural/pluralCategories";

// Generate template objects for translations
function generateTranslationTemplate(languages) {
  const template = {};
  
  for (const lang of languages) {
    template[lang] = {
      cardinal: {},
      ordinal: {}
    };
    
    // Create empty slots for each category
    Categories[lang].cardinal.forEach(category => {
      template[lang].cardinal[category] = "";
    });
    
    Categories[lang].ordinal.forEach(category => {
      template[lang].ordinal[category] = "";  
    });
  }
  
  return template;
}

const template = generateTranslationTemplate(['en', 'fr', 'ar']);
console.log(template);
// {
//   en: {
//     cardinal: { one: "", other: "" },
//     ordinal: { one: "", two: "", few: "", other: "" }
//   },
//   fr: {
//     cardinal: { one: "", many: "", other: "" },
//     ordinal: { one: "", other: "" }
//   },
//   ar: {
//     cardinal: { zero: "", one: "", two: "", few: "", many: "", other: "" },
//     ordinal: { other: "" }
//   }
// }

Validation and Analysis:

import * as Categories from "make-plural/pluralCategories";

// Analyze language complexity
function analyzeLanguageComplexity() {
  const analysis = {
    simple: [],        // 1-2 categories
    moderate: [],      // 3-4 categories  
    complex: []        // 5-6 categories
  };
  
  for (const [lang, categories] of Object.entries(Categories)) {
    const cardinalCount = categories.cardinal.length;
    
    if (cardinalCount <= 2) {
      analysis.simple.push(lang);
    } else if (cardinalCount <= 4) {
      analysis.moderate.push(lang);
    } else {
      analysis.complex.push(lang);
    }
  }
  
  return analysis;
}

// Find languages with ordinal rules
function getOrdinalLanguages() {
  return Object.entries(Categories)
    .filter(([lang, categories]) => 
      categories.ordinal.length > 1 || 
      (categories.ordinal.length === 1 && categories.ordinal[0] !== "other")
    )
    .map(([lang]) => lang);
}

console.log(getOrdinalLanguages().length); // 105

Practical Applications

Form Generation:

import * as Categories from "make-plural/pluralCategories";

// Generate form fields for translation interface
function generatePluralForm(language, type = 'cardinal') {
  const categories = Categories[language][type];
  
  return categories.map(category => ({
    field: `${language}_${type}_${category}`,
    label: `${language} ${type} ${category}`,
    placeholder: `Enter ${category} form...`
  }));
}

Validation:

import * as Categories from "make-plural/pluralCategories";

// Validate translation completeness
function validateTranslations(translations, language) {
  const required = Categories[language];
  const errors = [];
  
  // Check cardinal categories
  required.cardinal.forEach(category => {
    if (!translations[language]?.cardinal?.[category]) {
      errors.push(`Missing cardinal ${category} for ${language}`);
    }
  });
  
  // Check ordinal categories
  required.ordinal.forEach(category => {
    if (!translations[language]?.ordinal?.[category]) {
      errors.push(`Missing ordinal ${category} for ${language}`);
    }
  });
  
  return errors;
}

Category Distribution

By Cardinal Category Count:

  • 1 category (other only): 44 languages (Chinese, Japanese, Korean, etc.)
  • 2 categories (one, other): 81 languages (English, German, Italian, etc.)
  • 3 categories: 34 languages (French, Portuguese, Spanish, etc.)
  • 4 categories: 37 languages (Polish, Russian, Czech, etc.)
  • 5 categories: 8 languages (Romanian, Lithuanian, etc.)
  • 6 categories: 15 languages (Arabic, Welsh, Breton, etc.)

Ordinal Complexity:

  • 105 languages have specific ordinal rules
  • 114 languages use default "other" category for ordinals
  • English has the most complex common ordinal system (4 categories)
  • Welsh and other Celtic languages have the most complex ordinal systems (6 categories)

docs

cardinal-pluralization.md

core-pluralization.md

example-values.md

index.md

ordinal-pluralization.md

plural-categories.md

range-pluralization.md

tile.json