Skip to main content

Examples

Basic formatting

import { RuleBasedNumberFormat } from "@pointnet/cldr-spellout";

const en = RuleBasedNumberFormat.fromLocale("en");

en.format(0); // "zero"
en.format(1); // "one"
en.format(13); // "thirteen"
en.format(100); // "one hundred"
en.format(1000); // "one thousand"
en.format(1000000); // "one million"
en.format(1000000000); // "one billion"

Negative numbers

en.format(-1);   // "minus one"
en.format(-42); // "minus thirty-six"

Decimal numbers

en.format(3.14);    // "three point one four"
en.format(0.5); // "zero point five"
en.format(1.001); // "one point zero zero one"

Ordinals

Use the %digits-ordinal rule set when available:

const fmt = RuleBasedNumberFormat.fromLocale("en");

fmt.format(1, "%digits-ordinal"); // "1st"
fmt.format(2, "%digits-ordinal"); // "2nd"
fmt.format(3, "%digits-ordinal"); // "3rd"
fmt.format(4, "%digits-ordinal"); // "4th"
fmt.format(11, "%digits-ordinal"); // "11th"
fmt.format(21, "%digits-ordinal"); // "21st"
fmt.format(22, "%digits-ordinal"); // "22nd"

French ordinals spell out fully:

const fr = RuleBasedNumberFormat.fromLocale("fr");

fr.format(1, "%spellout-ordinal"); // "premier"
fr.format(2, "%spellout-ordinal"); // "deuxième"
fr.format(42, "%spellout-ordinal"); // "quarante-deuxième"

Changing the default rule set

const fmt = RuleBasedNumberFormat.fromLocale("en");
fmt.setDefaultRuleSet("%digits-ordinal");

fmt.format(1); // "1st"
fmt.format(2); // "2nd"
fmt.format(3); // "3rd"

Parse: words → number

const fmt = RuleBasedNumberFormat.fromLocale("en");

fmt.parse("forty-two"); // 42
fmt.parse("one thousand"); // 1000
fmt.parse("minus thirty-six"); // -36

Round-trip:

const n = 12345;
const text = fmt.format(n); // "twelve thousand three hundred forty-five"
const back = fmt.parse(text); // 12345
console.log(n === back); // true

Listing rule sets

const de = RuleBasedNumberFormat.fromLocale("de");
de.getRuleSetNames();
// ["%spellout-numbering-year", "%spellout-numbering",
// "%spellout-cardinal-masculine", "%spellout-cardinal-feminine",
// "%spellout-cardinal-neuter", "%spellout-ordinal",
// "%digits-ordinal-masculine", "%digits-ordinal-feminine",
// "%digits-ordinal-neuter", ...]

Complex grammatical genders (German)

German has masculine/feminine/neuter cardinal forms:

const de = RuleBasedNumberFormat.fromLocale("de");

de.format(1, "%spellout-cardinal-masculine"); // "ein"
de.format(1, "%spellout-cardinal-feminine"); // "eine"
de.format(1, "%spellout-cardinal-neuter"); // "ein"

de.format(2, "%spellout-cardinal-masculine"); // "zwei"
de.format(2, "%spellout-cardinal-feminine"); // "zwei"

Large numbers

const en = RuleBasedNumberFormat.fromLocale("en");

en.format(1e6); // "one million"
en.format(1e9); // "one billion"
en.format(1e12); // "one trillion"
en.format(1e15); // "one quadrillion"

Special values

en.format(Infinity);   // "∞"
en.format(-Infinity); // "-∞"
en.format(NaN); // "NaN"

Custom RBNF rules

You can construct a formatter from a raw ICU RBNF rule string:

import { RuleBasedNumberFormat } from "@pointnet/cldr-spellout";

const fmt = new RuleBasedNumberFormat(
`%dozens:
10: << dozen[s];
100: <<[, >>];
1000: <<[, >>];`,
"en",
);

fmt.format(10); // "1 dozen"
fmt.format(20); // "2 dozens"
fmt.format(120); // "12 dozens"

Loading custom locale data

Supply your own CLDR RBNF JSON if you need a locale not in the built-in set, or want to override the rules. The duration example below defines a custom rule set that formats seconds as H:MM:SS:

import { RuleBasedNumberFormat } from "@pointnet/cldr-spellout";
import type { IRBNFData } from "@pointnet/cldr-spellout";

const durationData: IRBNFData = {
rbnf: {
identity: { language: "en" },
rbnf: {
DurationRules: {
"%%min-sec": [["0", ":=00="]],
"%duration": [
["0", "=%%seconds="],
["60/60", "<0<>%%min-sec>"],
["3600/3600", "<0<:>%%min-sec>"],
],
"%%seconds": [
["0", "0 sec."],
["1", "1 sec."],
["2", "=#,##0= sec."],
],
},
},
},
};

const fmt = RuleBasedNumberFormat.fromCldrData(durationData);
fmt.format(3662); // "1:01:02"

Get all supported locales

import { RuleBasedNumberFormat } from "@pointnet/cldr-spellout";

const locales = RuleBasedNumberFormat.getSupportedLocales();
console.log(locales.length); // 89
console.log(locales[0]); // "af"