Pluralization framework
npm install @rom98m/pluralizeThis framework was designed to align the way of pluralization in Web apps. It's powered by Intl.PluralRules; check the documentation. \
The main principle is:
1. GIVEN a Term, a Number and the Locale.
1. DEFINE the PluralTag by the Locale and Number.
1. IF the Term appears in ExceptionsDictionary ⇒ use it.
1. OTHERWISE apply Rule(Term).
>
``shell`
npm install --save @rom98m/pluralize
Preparation:
`ts`
import { Plural } from "@rom98m/pluralize"
const en = new Plural("en")
Add default pluralization rule for English cardinal terms:
`ts`
en.registerRule((cat, term) => {
if (cat === "one") return term
if (/(s|x|z|sh|ch)$/.test(term)) return term + "es"
if (/y$/.test(term)) return term.replace(/y$/, "i") + "es"
return term + "s"
})
Add some exception terms:
`ts`
en
.registerException("child", { other: "children" })
.registerException("person", { other: "people" })
🚀 Ready to pluralize:
`ts`
en.pluralize(1, "box") // "box"
en.pluralize(5, "box") // "boxes"
en.pluralize(5, "city") // "cities"
en.pluralize(5, "item") // "items"
en.pluralize(1, "person") // "person"
en.pluralize(5, "person") // "people"
The constructor uses same params as Intl.PluralRules.
`ts`
/**
* @param {string} locale
* @param {object} [options={}]
* @param {"cardinal" | "ordinal"} [options.type="cardinal"]
*/
constructor(
locale: string,
{ type = "cardinal" }: { type?: PluralRulesType } = {}
)
Following props mimic semantically appropriate ones of the Intl.PluralRules options:
`ts
public readonly locale: string
public readonly type: PluralRulesType
// "zero" | "one" | "two" | "few" | "many" | "other"
public readonly categories: Intl.LDMLPluralRule[]
`
Define the language-default way of pluralizing words. \
Mind that _"way of pluralizing"_ is a function which might have intricated logic.
`ts(cat, word) => cat === "one" ? word : (word + "s")
/**
* @param rule The rule to pluralize regular words.
* E.g., pure man's English rule:
* `
* @returns {Plural} Instance of the object (therefore, chainable).
*/
registerRule(rule: (pluralCategory: Intl.LDMLPluralRule, term: string) => string): Plural
Some termas don't go along well with pluralization rules, e.g., _"person"_ ↔ _"people"_. \
Those words should be registred separately.
`ts{ one: "person", other: "people" }
/**
* @param {string} term The term that uses non-standard pluralization.
* E.g., "person" – "people".
* @param {PluralForms} pluralForms Plural forms of the term.
* The keys of the object are the {@link categories}.
* E.g., `
* @returns {Plural} Instance of the object (therefore, chainable).
*/
registerException(term: string, pluralForms: PluralForms): Plural
⚠️ Mind that all locale-specific plural catagories should be covered; the "one" might be omitted; the term as-given is used in that case:`ts
en.registerException("person", { / one: "person", / other: "people" }) // ✅
// Following will warn as there's no "few" category
// for English/cardinal:
en.registerException("child", { few: "children" }) // ⚠️
`
Pluralizes given term as per given number.
`ts`
/**
* @param {number} number
* @param {string} term
* @returns {string} Pluralized term.
*/
pluralize(number: number, term: string): string
⚠️ The method warns if rule was not defined beforehand or if exception category is missing. _The term as-given_ is returned in such cases.
Design rationalization: missing rules/exceptions should occur pretty rare; better to return something (even wrong) rather than fail/throw in this case.
All methods are chainable:
`ts`
const en = new Plural(en)
.registerRule(...)
.registerException(...)
.registerException(...)
The framework works well in browsers and in NodeJS (as per Intp.PluralRules support).
1. Yes, it requires that amount of preparation. \
Luckily, there's not too many exception terms used in the app; it makes sense to register only those which are used.
1. When cardinal/ordinal pluralization is needed, 2 separate instances should be created (as the rules are different):
`ts`
const enCardinal = new Plural("en")
const enOrdinal = new Plural("en", { type: "ordinal" })
new Plural("…")`.
1. Obviously, each language/locale should instantiate its own
1. …and should define its own rule and register exceptions 🤷♂️
Roman Melnyk, https://melnyk.site \
Use at own risk.