npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

to-words

v5.1.0

Published

Converts numbers (including decimal points) into words & currency.

Downloads

374,994

Readme

to-words

npm version npm downloads build coverage minzipped size TypeScript license

🎮 Demo

Convert numbers to words with comprehensive locale, currency, and ordinal support. Ideal for invoicing, e-commerce, financial apps, and educational tools.

📑 Table of Contents

💼 Use Cases

  • Invoicing & Billing — Display amounts in words on invoices, receipts, and financial documents
  • Check Printing — Banks and financial institutions require amounts in words for check validation
  • E-commerce — Show order totals in words for clarity and accessibility
  • Legal Documents — Contracts and agreements often require written-out amounts
  • Educational Apps — Teach number pronunciation and spelling in different languages
  • Accessibility — Screen readers benefit from properly formatted number-to-text conversion
  • Localization — Support global users with region-specific number formatting

✨ Features

  • 94 Locales — The most comprehensive locale coverage available
  • BigInt Support — Handle numbers up to 10^63 (Vigintillion) and beyond
  • Multiple Numbering Systems — Short scale, Long scale, Indian, and East Asian
  • Currency Formatting — Locale-specific currency with fractional units
  • Ordinal Numbers — First, Second, Third, etc.
  • Tree-Shakeable — Import only the locales you need
  • TypeScript Native — Full type definitions included
  • Multiple Formats — ESM, CommonJS, and UMD browser bundles
  • Zero Dependencies — Lightweight and self-contained
  • High Performance — 4M+ conversions per second
  • Wide Browser Support — All modern browsers + IE11

🚀 Quick Start

import { ToWords } from 'to-words';

const toWords = new ToWords();
toWords.convert(12345);
// "Twelve Thousand Three Hundred Forty Five"

📦 Installation

npm / yarn / pnpm

npm install to-words
# or
yarn add to-words
# or
pnpm add to-words

CDN (Browser)

<!-- Full bundle with all locales -->
<script src="https://cdn.jsdelivr.net/npm/to-words/dist/umd/to-words.min.js"></script>

<!-- Single locale bundle (smaller, recommended) -->
<script src="https://cdn.jsdelivr.net/npm/to-words/dist/umd/en-US.min.js"></script>

📖 Usage

Importing

// ESM
import { ToWords } from 'to-words';

// CommonJS
const { ToWords } = require('to-words');

Basic Conversion

const toWords = new ToWords({ localeCode: 'en-US' });

toWords.convert(123);
// "One Hundred Twenty Three"

toWords.convert(123.45);
// "One Hundred Twenty Three Point Four Five"

toWords.convert(123.045);
// "One Hundred Twenty Three Point Zero Four Five"

Note: When the fractional part starts with zero, digits after the decimal point are converted individually.

BigInt & Large Numbers

Handle numbers beyond JavaScript's safe integer limit:

const toWords = new ToWords({ localeCode: 'en-US' });

// Using BigInt
toWords.convert(1000000000000000000n);
// "One Quintillion"

toWords.convert(1000000000000000000000000000000000000000000000000000000000000000n);
// "One Vigintillion"

// Using string for precision
toWords.convert('9007199254740993');
// "Nine Quadrillion Seven Trillion..."

Currency Conversion

const toWords = new ToWords({ localeCode: 'en-IN' });

toWords.convert(452, { currency: true });
// "Four Hundred Fifty Two Rupees Only"

toWords.convert(452.36, { currency: true });
// "Four Hundred Fifty Two Rupees And Thirty Six Paise Only"

// Without "Only" suffix
toWords.convert(452, { currency: true, doNotAddOnly: true });
// "Four Hundred Fifty Two Rupees"

// Ignore decimal/fractional part
toWords.convert(452.36, { currency: true, ignoreDecimal: true });
// "Four Hundred Fifty Two Rupees Only"

// Ignore zero currency
toWords.convert(0.36, { currency: true, ignoreZeroCurrency: true });
// "Thirty Six Paise Only"

Custom Currency

Override currency settings while keeping the locale's language:

const toWords = new ToWords({
  localeCode: 'en-US',
  converterOptions: {
    currency: true,
    currencyOptions: {
      name: 'Euro',
      plural: 'Euros',
      symbol: '€',
      fractionalUnit: {
        name: 'Cent',
        plural: 'Cents',
        symbol: '',
      },
    },
  },
});

toWords.convert(100.50);
// "One Hundred Euros And Fifty Cents Only"

Ordinal Numbers

const toWords = new ToWords({ localeCode: 'en-US' });

toWords.toOrdinal(1);    // "First"
toWords.toOrdinal(21);   // "Twenty First"
toWords.toOrdinal(100);  // "One Hundredth"

Note: Full ordinal word mappings are available for English, Spanish, French, Portuguese, Turkish, and Dutch locales. Other locales use suffix-based ordinals.

Tree-Shakeable Imports

Import only the locales you need for smaller bundle sizes:

// Import specific locale directly (includes ToWords configured for that locale)
import { ToWords } from 'to-words/en-US';

const toWords = new ToWords();
toWords.convert(12345);
// "Twelve Thousand Three Hundred Forty Five"

Browser Usage (UMD)

<!-- Single locale (recommended, ~3 KB gzip) -->
<script src="https://cdn.jsdelivr.net/npm/to-words/dist/umd/en-US.min.js"></script>
<script>
  // ToWords is pre-configured for en-US
  const toWords = new ToWords();
  console.log(toWords.convert(12345));
  // "Twelve Thousand Three Hundred Forty Five"
</script>

<!-- Full bundle with all locales (~54 KB gzip) -->
<script src="https://cdn.jsdelivr.net/npm/to-words/dist/umd/to-words.min.js"></script>
<script>
  // Specify locale when using full bundle
  const toWords = new ToWords({ localeCode: 'fr-FR' });
  console.log(toWords.convert(12345));
  // "Douze Mille Trois Cent Quarante-Cinq"
</script>

⚛️ Framework Integration

React

import { ToWords } from 'to-words/en-US';

const toWords = new ToWords();

function PriceInWords({ amount }: { amount: number }) {
  const words = toWords.convert(amount, { currency: true });
  return <span className="price-words">{words}</span>;
}

// Usage: <PriceInWords amount={1234.56} />
// Renders: "One Thousand Two Hundred Thirty Four Dollars And Fifty Six Cents Only"

Vue 3

<script setup lang="ts">
import { computed } from 'vue';
import { ToWords } from 'to-words/en-US';

const props = defineProps<{ amount: number }>();
const toWords = new ToWords();

const words = computed(() => 
  toWords.convert(props.amount, { currency: true })
);
</script>

<template>
  <span class="price-words">{{ words }}</span>
</template>

Angular

import { Pipe, PipeTransform } from '@angular/core';
import { ToWords } from 'to-words/en-US';

@Pipe({ name: 'toWords', standalone: true })
export class ToWordsPipe implements PipeTransform {
  private toWords = new ToWords();

  transform(value: number, currency = false): string {
    return this.toWords.convert(value, { currency });
  }
}

// Usage: {{ 1234.56 | toWords:true }}

Svelte

<script lang="ts">
  import { ToWords } from 'to-words/en-US';
  
  export let amount: number;
  
  const toWords = new ToWords();
  $: words = toWords.convert(amount, { currency: true });
</script>

<span class="price-words">{words}</span>

🌍 Numbering Systems

Different regions use different numbering systems. This library supports all major systems:

Short Scale (Western)

Used in: USA, UK, Canada, Australia, and most English-speaking countries.

| Number | Name | |--------|------| | 10^6 | Million | | 10^9 | Billion | | 10^12 | Trillion | | 10^15 | Quadrillion | | ... | ... | | 10^63 | Vigintillion |

const toWords = new ToWords({ localeCode: 'en-US' });
toWords.convert(1000000000000000000n);
// "One Quintillion"

Long Scale (European)

Used in: Germany, France, and many European countries.

| Number | German | French | |--------|--------|--------| | 10^6 | Million | Million | | 10^9 | Milliarde | Milliard | | 10^12 | Billion | Billion | | 10^15 | Billiarde | Billiard |

const toWords = new ToWords({ localeCode: 'de-DE' });
toWords.convert(1000000000);
// "Eins Milliarde"

Indian System

Used in: India, Bangladesh, Nepal, Pakistan.

| Number | Name | |--------|------| | 10^5 | Lakh | | 10^7 | Crore | | 10^9 | Arab | | 10^11 | Kharab | | 10^13 | Neel | | 10^15 | Padma | | 10^17 | Shankh |

const toWords = new ToWords({ localeCode: 'en-IN' });
toWords.convert(100000000000000000n);
// "One Shankh"

const toWordsHindi = new ToWords({ localeCode: 'hi-IN' });
toWordsHindi.convert(100000000000000000n);
// "एक शंख"

East Asian System

Used in: Japan, China, Korea.

| Number | Character | |--------|-----------| | 10^4 | 万 (Man/Wan) | | 10^8 | 億 (Oku/Yi) | | 10^12 | 兆 (Chō/Zhao) | | 10^16 | 京 (Kei/Jing) | | 10^20 | 垓 (Gai) |

const toWords = new ToWords({ localeCode: 'ja-JP' });
toWords.convert(100000000);
// "一 億"

⚙️ API Reference

Constructor Options

interface ToWordsOptions {
  localeCode?: string;           // Default: 'en-IN'
  converterOptions?: {
    currency?: boolean;          // Default: false
    ignoreDecimal?: boolean;     // Default: false
    ignoreZeroCurrency?: boolean;// Default: false
    doNotAddOnly?: boolean;      // Default: false
    currencyOptions?: {
      name: string;
      plural: string;
      symbol: string;
      fractionalUnit: {
        name: string;
        plural: string;
        symbol: string;
      };
    };
  };
}

Methods

convert(number, options?)

Converts a number to words.

  • number: number | bigint | string — The number to convert
  • options: ConverterOptions — Override instance options
  • returns: string — The number in words

toOrdinal(number)

Converts a number to ordinal words.

  • number: number — The number to convert (must be non-negative integer)
  • returns: string — The ordinal in words (e.g., "First", "Twenty Third")

Converter Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | currency | boolean | false | Convert as currency with locale-specific formatting | | ignoreDecimal | boolean | false | Ignore fractional part when converting | | ignoreZeroCurrency | boolean | false | Skip zero main currency (e.g., show only "Thirty Six Paise") | | doNotAddOnly | boolean | false | Omit "Only" suffix in currency mode | | currencyOptions | object | undefined | Override locale's default currency settings |

📏 Bundle Sizes

| Import Method | Raw | Gzip | |--------------|-----|------| | Full bundle (all 94 locales) | 564 KB | 54 KB | | Single locale (en-US) | 11.5 KB | 3.2 KB | | Single locale (en-IN) | 9.3 KB | 3.1 KB |

Tip: Use tree-shakeable imports or single-locale UMD bundles for the smallest bundle size.

⚡ Performance

Benchmarked on Apple M2 (Node.js 23):

| Operation | Throughput | |-----------|------------| | Small integers (42) | ~4.7M ops/sec | | Medium integers (12,345) | ~2.2M ops/sec | | Large integers (15 digits) | ~700K ops/sec | | Currency conversion | ~1M ops/sec | | BigInt (30+ digits) | ~225K ops/sec |

Run benchmarks locally:

npm run bench

🌐 Browser Compatibility

| Browser | Version | |---------|--------| | Chrome | 49+ | | Firefox | 52+ | | Safari | 10+ | | Edge | 14+ | | Opera | 36+ | | IE | 11 (with polyfills) |

BigInt Support: Chrome 67+, Firefox 68+, Safari 14+, Edge 79+. For older browsers, pass large numbers as strings.

🗺️ Supported Locales

All 94 locales with their features:

| Locale | Language | Country | Currency | Scale | Ordinal | |--------|----------|---------|----------|-------|---------| | af-ZA | Afrikaans | South Africa | Rand | Short | ✓ | | am-ET | Amharic | Ethiopia | ብር | Short | ✓ | | ar-AE | Arabic | UAE | درهم | Short | ✓ | | ar-LB | Arabic | Lebanon | ليرة | Short | ✓ | | ar-MA | Arabic | Morocco | درهم | Short | ✓ | | ar-SA | Arabic | Saudi Arabia | ريال | Short | ✓ | | az-AZ | Azerbaijani | Azerbaijan | Manat | Short | ✓ | | be-BY | Belarusian | Belarus | Рубель | Short | ✓ | | bg-BG | Bulgarian | Bulgaria | Лев | Short | ✓ | | bn-IN | Bengali | India | টাকা | Short | ✓ | | ca-ES | Catalan | Spain | Euro | Short | ✓ | | cs-CZ | Czech | Czech Republic | Koruna | Short | ✓ | | da-DK | Danish | Denmark | Krone | Long | ✓ | | de-DE | German | Germany | Euro | Long | ✓ | | ee-EE | Estonian | Estonia | Euro | Short | ✓ | | el-GR | Greek | Greece | Ευρώ | Short | ✓ | | en-AE | English | UAE | Dirham | Short | ✓ | | en-AU | English | Australia | Dollar | Short | ✓ | | en-BD | English | Bangladesh | Taka | Indian | ✓ | | en-CA | English | Canada | Dollar | Short | ✓ | | en-GB | English | United Kingdom | Pound | Short | ✓ | | en-GH | English | Ghana | Cedi | Short | ✓ | | en-IE | English | Ireland | Euro | Short | ✓ | | en-IN | English | India | Rupee | Indian | ✓ | | en-KE | English | Kenya | Shilling | Short | ✓ | | en-MA | English | Morocco | Dirham | Short | ✓ | | en-MM | English | Myanmar | Kyat | Short | ✓ | | en-MU | English | Mauritius | Rupee | Indian | ✓ | | en-MY | English | Malaysia | Ringgit | Short | ✓ | | en-NG | English | Nigeria | Naira | Short | ✓ | | en-NP | English | Nepal | Rupee | Indian | ✓ | | en-NZ | English | New Zealand | Dollar | Short | ✓ | | en-OM | English | Oman | Rial | Short | ✓ | | en-PH | English | Philippines | Peso | Short | ✓ | | en-PK | English | Pakistan | Rupee | Indian | ✓ | | en-SA | English | Saudi Arabia | Riyal | Short | ✓ | | en-SG | English | Singapore | Dollar | Short | ✓ | | en-US | English | USA | Dollar | Short | ✓ | | en-ZA | English | South Africa | Rand | Short | ✓ | | es-AR | Spanish | Argentina | Peso | Short | ✓ | | es-ES | Spanish | Spain | Euro | Short | ✓ | | es-MX | Spanish | Mexico | Peso | Short | ✓ | | es-US | Spanish | USA | Dólar | Short | ✓ | | es-VE | Spanish | Venezuela | Bolívar | Short | ✓ | | fa-IR | Persian | Iran | تومان | Short | ✓ | | fi-FI | Finnish | Finland | Euro | Short | ✓ | | fil-PH | Filipino | Philippines | Piso | Short | ✓ | | fr-BE | French | Belgium | Euro | Long | ✓ | | fr-FR | French | France | Euro | Long | ✓ | | fr-MA | French | Morocco | Dirham | Long | ✓ | | fr-SA | French | Saudi Arabia | Riyal | Long | ✓ | | gu-IN | Gujarati | India | રૂપિયો | Short | ✓ | | ha-NG | Hausa | Nigeria | Naira | Short | ✓ | | hbo-IL | Biblical Hebrew | Israel | שקל | Short | ✓ | | he-IL | Hebrew | Israel | שקל | Short | ✓ | | hi-IN | Hindi | India | रुपया | Indian | ✓ | | hr-HR | Croatian | Croatia | Euro | Short | ✓ | | hu-HU | Hungarian | Hungary | Forint | Short | ✓ | | id-ID | Indonesian | Indonesia | Rupiah | Short | ✓ | | is-IS | Icelandic | Iceland | Króna | Short | ✓ | | it-IT | Italian | Italy | Euro | Short | ✓ | | ja-JP | Japanese | Japan | 円 | East Asian | ✓ | | ka-GE | Georgian | Georgia | ლარი | Short | ✓ | | kn-IN | Kannada | India | ರೂಪಾಯಿ | Short | ✓ | | ko-KR | Korean | South Korea | 원 | Short | ✓ | | lt-LT | Lithuanian | Lithuania | Euras | Short | ✓ | | lv-LV | Latvian | Latvia | Eiro | Short | ✓ | | mr-IN | Marathi | India | रुपया | Indian | ✓ | | ms-MY | Malay | Malaysia | Ringgit | Short | ✓ | | nb-NO | Norwegian | Norway | Krone | Long | ✓ | | nl-NL | Dutch | Netherlands | Euro | Short | ✓ | | nl-SR | Dutch | Suriname | Dollar | Short | ✓ | | np-NP | Nepali | Nepal | रुपैयाँ | Indian | ✓ | | pa-IN | Punjabi | India | ਰੁਪਇਆ | Short | ✓ | | pl-PL | Polish | Poland | Złoty | Short | ✓ | | pt-BR | Portuguese | Brazil | Real | Short | ✓ | | pt-PT | Portuguese | Portugal | Euro | Short | ✓ | | ro-RO | Romanian | Romania | Leu | Short | ✓ | | ru-RU | Russian | Russia | Рубль | Short | ✓ | | sk-SK | Slovak | Slovakia | Euro | Short | ✓ | | sl-SI | Slovenian | Slovenia | Euro | Short | ✓ | | sq-AL | Albanian | Albania | Lek | Short | ✓ | | sr-RS | Serbian | Serbia | Dinar | Short | ✓ | | sv-SE | Swedish | Sweden | Krona | Short | ✓ | | sw-KE | Swahili | Kenya | Shilingi | Short | ✓ | | ta-IN | Tamil | India | ரூபாய் | Short | ✓ | | te-IN | Telugu | India | రూపాయి | Short | ✓ | | th-TH | Thai | Thailand | บาท | Short | ✓ | | tr-TR | Turkish | Turkey | Lira | Short | ✓ | | uk-UA | Ukrainian | Ukraine | Гривня | Short | ✓ | | ur-PK | Urdu | Pakistan | روپیہ | Short | ✓ | | vi-VN | Vietnamese | Vietnam | Đồng | Short | ✓ | | yo-NG | Yoruba | Nigeria | Naira | Short | ✓ | | zh-CN | Chinese | China | 元 | East Asian | ✓ |

Scale Legend:

  • Short — Western short scale (Million, Billion, Trillion...)
  • Long — European long scale (Million, Milliard, Billion, Billiard...)
  • Indian — Indian numbering (Lakh, Crore, Arab, Kharab...)
  • East Asian — East Asian numbering (万, 億, 兆, 京...)

⚠️ Error Handling

The library throws descriptive errors for invalid inputs:

Invalid Number

toWords.convert('abc');
// Error: Invalid Number "abc"

toWords.convert(NaN);
// Error: Invalid Number "NaN"

toWords.convert(Infinity);
// Error: Invalid Number "Infinity"

Unknown Locale

const toWords = new ToWords({ localeCode: 'xx-XX' });
toWords.convert(123);
// Error: Unknown Locale "xx-XX"

Invalid Ordinal Input

toWords.toOrdinal(-5);
// Error: Ordinal numbers must be non-negative integers, got "-5"

toWords.toOrdinal(3.14);
// Error: Ordinal numbers must be non-negative integers, got "3.14"

Handling Errors

try {
  const words = toWords.convert(userInput);
  console.log(words);
} catch (error) {
  console.error('Conversion failed:', error.message);
}

🤝 Contributing

Adding a New Locale

  1. Create the locale file: Add src/locales/<locale-code>.ts implementing LocaleInterface from src/types.ts. Use an existing locale as a template.

  2. Register the locale: Import your class in src/locales/index.ts and add it to the LOCALES map.

  3. Add tests: Create __tests__/<locale-code>.test.ts covering integers, negatives, decimals, and currency.

  4. Update documentation: Add the locale to the Supported Locales section above.

  5. Build and test: Run npm test and npm run build, then submit your PR.

❓ FAQ

Use BigInt or pass the number as a string:

// Using BigInt
toWords.convert(9007199254740993n);

// Using string
toWords.convert('9007199254740993');

JavaScript automatically converts large numbers to scientific notation. Pass them as strings or BigInt instead:

// ❌ This may give unexpected results
toWords.convert(123456789012345678901);

// ✅ Use string or BigInt
toWords.convert('123456789012345678901');
toWords.convert(123456789012345678901n);

Yes! Override the currency options:

toWords.convert(1234.56, {
  currency: true,
  currencyOptions: {
    name: 'Bitcoin',
    plural: 'Bitcoins',
    symbol: '₿',
    fractionalUnit: { name: 'Satoshi', plural: 'Satoshis', symbol: 'sat' }
  }
});
// "One Thousand Two Hundred Thirty Four Bitcoins And Fifty Six Satoshis Only"

Yes! Use the UMD bundles via CDN:

<script src="https://cdn.jsdelivr.net/npm/to-words/dist/umd/en-US.min.js"></script>
<script>
  const toWords = new ToWords();
  console.log(toWords.convert(123));
</script>

See the Contributing section above. You'll need to create a locale file implementing the LocaleInterface and add tests.

📋 Changelog

See CHANGELOG.md for a detailed history of changes.

📄 License

MIT