@rom98m/pluralize
v1.0.0
Published
Pluralization framework
Maintainers
Readme
Pluralization framework
This 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:
- GIVEN a
Term, aNumberand theLocale. - DEFINE the
PluralTagby theLocaleandNumber. - IF the
Termappears inExceptionsDictionary⇒ use it. - OTHERWISE apply
Rule(Term).
It was created to straighten the process.
Installation
npm install --save @rom98m/pluralizeUsage
Preparation:
import { Plural } from "@rom98m/pluralize"
const en = new Plural("en")Add default pluralization rule for English cardinal terms:
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:
en
.registerException("child", { other: "children" })
.registerException("person", { other: "people" })🚀 Ready to pluralize:
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"API
new Plural()
The constructor uses same params as Intl.PluralRules.
/**
* @param {string} locale
* @param {object} [options={}]
* @param {"cardinal" | "ordinal"} [options.type="cardinal"]
*/
constructor(
locale: string,
{ type = "cardinal" }: { type?: PluralRulesType } = {}
)Instance props
Following props mimic semantically appropriate ones of the Intl.PluralRules options:
public readonly locale: string
public readonly type: PluralRulesType
// "zero" | "one" | "two" | "few" | "many" | "other"
public readonly categories: Intl.LDMLPluralRule[].registerRule()
Define the language-default way of pluralizing words.
Mind that "way of pluralizing" is a function which might have intricated logic.
/**
* @param rule The rule to pluralize regular words.
* E.g., pure man's English rule:
* `(cat, word) => cat === "one" ? word : (word + "s")`
* @returns {Plural} Instance of the object (therefore, chainable).
*/
registerRule(rule: (pluralCategory: Intl.LDMLPluralRule, term: string) => string): Plural.registerException()
Some termas don't go along well with pluralization rules, e.g., "person" ↔ "people".
Those words should be registred separately.
/**
* @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., `{ one: "person", other: "people" }`
* @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:
en.registerException("person", { /* one: "person", */ other: "people" }) // ✅
// Following will warn as there's no "few" category
// for English/cardinal:
en.registerException("child", { few: "children" }) // ⚠️.pluralize()
Pluralizes given term as per given number.
/**
* @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.
Etc
All methods are chainable:
const en = new Plural(en)
.registerRule(...)
.registerException(...)
.registerException(...)The framework works well in browsers and in NodeJS (as per Intp.PluralRules support).
Caveats
- 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. - When cardinal/ordinal pluralization is needed, 2 separate instances should be created (as the rules are different):
const enCardinal = new Plural("en") const enOrdinal = new Plural("en", { type: "ordinal" }) - Obviously, each language/locale should instantiate its own
new Plural("…"). - …and should define its own rule and register exceptions 🤷♂️
Credits
Roman Melnyk, https://melnyk.site
Use at own risk.
