Convert numbers to words in multiple languages and numeral systems — English, Indian, Hindi, German, French — with full TypeScript support, zero dependencies and < 3kb size.
registerAllBuiltInLocales()
convert(1_000_124) // "One million one hundred and twenty-four"
convert(12.34) // "Twelve point three four"
convert("150.50") // "One hundred and fifty point five zero"
convert(1_000_124, { locale: "in" }) // "Ten lakh one hundred twenty-four"
convert(1_000_124, { locale: "hi" }) // "दस लाख एक सौ चौबीस"
convert("12.34", { locale: "hi" }) // "बारह दशमलव तीन चार"
convert(1_000_124, { locale: "de" }) // "Eine Million einhundertvierundzwanzig"
convert(1_000_124, { locale: "fr" }) // "Un million cent vingt-quatre"
en, in, hi, de, frnpm install @gks101/numtowords
import { convert, registerAllBuiltInLocales } from '@gks101/numtowords';
registerAllBuiltInLocales();
convert(0); // "Zero"
convert(42); // "Forty-two"
convert(1_000_000); // "One million"
convert(12.34); // "Twelve point three four"
convert('150.50'); // "One hundred and fifty point five zero"
Built-in locales are explicit. Register them once during app startup.
import {
registerBuiltInLocale,
registerAllBuiltInLocales,
} from '@gks101/numtowords';
registerAllBuiltInLocales(); // registers en, in, hi, de, fr
// or registerBuiltInLocale('en'); // register only one locale
All examples below assume locales are registered.
Decimal values are supported with . as the decimal separator. The integer part is converted normally, and the fractional part is converted digit by digit using the selected locale.
convert(12.34); // "Twelve point three four"
convert('150.50'); // "One hundred and fifty point five zero"
convert('-0.25'); // "Negative zero point two five"
convert('12.34', { locale: 'in' }); // "Twelve point three four"
convert('12.34', { locale: 'hi' }); // "बारह दशमलव तीन चार"
convert('12.34', { locale: 'de' }); // "Zwölf komma drei vier"
convert('12.34', { locale: 'fr' }); // "Douze virgule trois quatre"
Use a string when trailing zeros are meaningful:
convert(150.5); // "One hundred and fifty point five"
convert('150.50'); // "One hundred and fifty point five zero"
convert(1_00_000, { locale: 'in' }); // "One lakh"
convert(10_00_000, { locale: 'in' }); // "Ten lakh"
convert(1_00_00_000, { locale: 'in' }); // "One crore"
convert(1_00_000, { locale: 'hi' }); // "एक लाख"
convert(1_00_00_000, { locale: 'hi' }); // "एक करोड़"
convert(21, { locale: 'de' }); // "Einundzwanzig"
convert(1_000_000, { locale: 'de' }); // "Eine Million"
convert(2_000_000, { locale: 'de' }); // "Zwei Millionen"
convert(70, { locale: 'fr' }); // "Soixante-dix"
convert(80, { locale: 'fr' }); // "Quatre-vingts"
convert(1_000_000, { locale: 'fr' }); // "Un million"
convert(input, options?)| Parameter | Type | Description |
|---|---|---|
input |
number | bigint | string |
The number to convert. Negative numbers, decimals with ., string input with commas/underscores, and BigInts are all supported. |
options |
ConvertOptions |
Optional configuration (see below). |
Returns string
ConvertOptions| Option | Type | Default | Description |
|---|---|---|---|
locale |
"en" | "in" | "hi" | "de" | "fr" | "auto" |
"en" |
Target language / numeral system |
capitalize |
boolean |
true |
Capitalise the first letter |
useAnd |
boolean |
true |
Include "and" connector (English only) |
currency |
boolean | string | CurrencyOptions |
false |
true = locale currency words, string = append label (legacy), object = full currency configuration |
ordinal |
boolean |
false |
Convert integer to ordinal words |
import {
toWords,
toOrdinalWords,
toCurrencyWords,
detectRuntimeLocale,
registerBuiltInLocale,
registerAllBuiltInLocales,
availableLocales,
registerLocale,
getLocale,
} from '@gks101/numtowords';
registerBuiltInLocale('en');
registerBuiltInLocale('fr');
// or registerAllBuiltInLocales()
toWords(42); // "Forty-two"
toOrdinalWords(21, { locale: 'en' }); // "Twenty-first"
toCurrencyWords('12.34', { locale: 'en' }); // "Twelve dollars and thirty-four cents"
detectRuntimeLocale(); // e.g. "en"
availableLocales(); // e.g. ["en", "fr"]
convert(9_007_199_254_740_993n); // beyond Number.MAX_SAFE_INTEGER
convert(1_00_00_00_00_000n, { locale: 'in' }); // "One arab"
convert(42, { capitalize: false }); // "forty-two"
convert(101, { useAnd: false }); // "One hundred one"
convert('200.42', { locale: 'en', currency: true }); // "Two hundred dollars and forty-two cents"
convert('200.42', { locale: 'in', currency: true }); // "Two hundred rupees and forty-two paise"
convert('200.42', { locale: 'hi', currency: true }); // "दो सौ रुपये और बयालीस पैसे"
convert('200.42', { locale: 'de', currency: true }); // "Zweihundert euro und zweiundvierzig cent"
convert('200.42', { locale: 'fr', currency: true }); // "Deux cents euros et quarante-deux centimes"
convert(5, { currency: 'USD' }); // "Five USD" (legacy suffix mode)
convert('12.34', {
locale: 'en',
currency: {
enabled: true,
rules: {
major: { one: 'credit', other: 'credits' },
minor: { one: 'point', other: 'points' },
joinWord: 'and',
minorBase: 100,
},
},
}); // "Twelve credits and thirty-four points"
CurrencyOptions (configuration)When currency is an object, you can fully control how currency values are rendered.
type CurrencyOptions = {
enabled?: boolean;
code?: string; // resolves locale currencyDefaults (e.g. "USD", "INR", "EUR")
roundMinor?: 'truncate' | 'round';
includeOnly?: 'both' | 'major' | 'minor';
rules?: {
major: { one: string; other: string };
minor: { one: string; other: string };
joinWord?: string;
minorBase?: 10 | 100 | 1000;
hideZeroMinor?: boolean;
};
};
Examples:
// Resolve by currency code (uses locale defaults when available)
convert('1.01', { locale: 'en', currency: { enabled: true, code: 'USD' } }); // "One dollar and one cent"
// Round minor part (1.236 -> 1.24)
convert('1.236', {
locale: 'en',
currency: { enabled: true, roundMinor: 'round' },
}); // "One dollar and twenty-four cents"
// Only major / only minor
convert('12.34', {
locale: 'en',
currency: { enabled: true, includeOnly: 'major' },
}); // "Twelve dollars"
convert('12.34', {
locale: 'en',
currency: { enabled: true, includeOnly: 'minor' },
}); // "Thirty-four cents"
// Show zero minor part
convert('12.00', {
locale: 'en',
currency: {
enabled: true,
rules: {
major: { one: 'dollar', other: 'dollars' },
minor: { one: 'cent', other: 'cents' },
hideZeroMinor: false,
},
},
}); // "Twelve dollars and zero cents"
toOrdinalWords(1, { locale: 'en' }); // "First"
toOrdinalWords(21, { locale: 'en' }); // "Twenty-first"
convert(3, { locale: 'en', ordinal: true }); // "Third"
Notes:
en and in. Other locales can support ordinals by implementing convertOrdinal."3.2").convert(5, { locale: 'auto' }); // uses navigator.language / LANG fallback
convert(-1_500); // "Negative one thousand five hundred"
You can add locales at runtime by calling registerLocale() with a LocaleDefinition. The convert function receives a bigint and the resolved options — return a string (do not capitalise; the library handles optional capitalization).
Minimal stub:
import { registerLocale, convert } from '@gks101/numtowords';
registerLocale('es', {
name: 'Spanish',
decimalPoint: 'punto',
decimalDigits: [
'cero',
'uno',
'dos',
'tres',
'cuatro',
'cinco',
'seis',
'siete',
'ocho',
'nueve',
],
convert(n, _opts) {
// minimal implementation — handle zero and fall back to a placeholder
if (n === 0n) return 'cero';
return 'número';
},
defaultCurrencyCode: 'EUR',
currencyDefaults: {
EUR: {
major: { one: 'euro', other: 'euros' },
minor: { one: 'centimo', other: 'centimos' },
joinWord: 'y',
minorBase: 100,
hideZeroMinor: true,
},
},
convertOrdinal(n, opts) {
// Optional: implement real Spanish ordinals as needed; this is a placeholder.
return `${this.convert(n, opts)}o`;
},
});
convert(5, { locale: 'es' }); // "Número" (capitalisation applied by library)
convert('5.25', { locale: 'es' }); // "Número punto dos cinco"
Practical Spanish examples
// Basic numbers
convert(0, { locale: 'es' }); // "Cero"
convert(1, { locale: 'es' }); // "Uno"
// Hundreds and thousands
convert(100, { locale: 'es' }); // "Cien"
convert(101, { locale: 'es' }); // "Ciento uno"
// Millions, accents and plurals
convert(1_000_000, { locale: 'es' }); // "Un millón"
convert(2_000_000, { locale: 'es' }); // "Dos millones"
// Negative and currency examples
convert(-5, { locale: 'es' }); // "Negativo cinco"
convert(1, { locale: 'es', currency: 'EUR' }); // "Uno EUR" (legacy suffix mode)
Notes
convert should accept n: bigint and return the words in lowercase (prefer returning canonical forms with proper accents); the main library applies capitalization when capitalize: true.convertOrdinal(n, opts) for native ordinal support in your locale.currencyDefaults and defaultCurrencyCode for locale-native currency rendering.decimalPoint and optionally decimalDigits to localize decimal output. Without decimalDigits, fractional digits fall back to calling your locale's convert for each digit.| File | Format | Use case |
|---|---|---|
dist/index.esm.js |
ES Module | Bundlers (Vite, webpack, Rollup) |
dist/index.cjs.js |
CommonJS | Node.js (require) |
dist/index.umd.js |
UMD | Browser <script> tags |
<script src="dist/index.umd.js"></script>
<script>
console.log(NumToWords.convert(1000000)); // "One million"
</script>
npm install
npm run build # Rollup → dist/
npm test # Jest test suite
npm run test:coverage # Jest coverage report (coverage/lcov-report/index.html)
npm run lint # TypeScript type check
| Value | Indian Name | English equivalent |
|---|---|---|
| 1,000 | Thousand | Thousand |
| 1,00,000 | Lakh | Hundred Thousand |
| 1,00,00,000 | Crore | Ten Million |
| 1,00,00,00,000 | Arab | Billion |
| 1,00,00,00,00,000 | Kharab | Hundred Billion |
| 1,00,00,00,00,00,000 | Neel | Ten Trillion |
| 1,00,00,00,00,00,00,000 | Padma | Quadrillion |
| 1,00,00,00,00,00,00,00,000 | Shankh | Hundred Quadrillion |
MIT