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-numbers

v1.1.0

Published

Converts words (including decimal points) into numbers & currency. The reverse of to-words.

Downloads

344

Readme

to-numbers

npm version npm downloads build coverage minzipped size TypeScript node license

Convert words to numbers with comprehensive locale, currency, and decimal support. The reverse of the to-words package. Ideal for parsing written amounts in invoicing, voice input, e-commerce, and financial applications.

📑 Table of Contents

💼 Use Cases

  • Financial Applications — Parse amount-in-words from invoices, cheques, and financial documents
  • Voice/Speech Input — Convert spoken numbers from speech-to-text to numeric values
  • Data Processing — Extract numeric data from textual documents and forms
  • OCR Post-Processing — Parse numbers recognized from scanned documents
  • Chatbots & NLP — Understand numeric inputs in natural language
  • Accessibility — Support users who input numbers as words
  • Localization — Parse numbers in 124 languages and regions

✨ Features

  • 124 Locales — The most comprehensive locale coverage available
  • High Performance — Optimized parsing paths with benchmark coverage for real-world inputs
  • Reverse of to-words — Perfectly complements the to-words package
  • Multiple Numbering Systems — Short scale, Long scale, Indian, East Asian, Burmese, Khmer, and scale-first ordering
  • Currency Parsing — Parse locale-specific currency with fractional units
  • Ordinal Numbers — Parse ordinals across all 124 locales
  • Structured Parse Metadataparse() returns flags such as isCurrency, isNegative, and isOrdinal
  • Decimal Numbers — Handle "Point" notation and fractional units
  • Case Insensitive — Works with any case combination
  • 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

⚡ Performance

Benchmarked on Apple M2, Node.js v24.13.0, using vitest bench. Throughput varies by locale and input shape, so the table below uses the current sampled-locale ranges from bench/to-numbers.bench.ts rather than a single headline number.

| Benchmark Case | Example | Throughput Range | | ----------------------- | --------------------------------------------------- | ---------------------- | | Small Integer | "Forty Two" | ~1.1M to ~3.1M ops/sec | | Medium Integer | "Twelve Thousand Three Hundred Forty Five" | ~117K to ~1.0M ops/sec | | Large Integer | "Nine Trillion Eight Hundred Seventy Six..." | ~155K to ~567K ops/sec | | Currency Parsing | "One Thousand Two Hundred Rupees And Fifty Paise" | ~336K to ~851K ops/sec | | Ordinal Parsing | "Twenty First" | ~1.5M to ~4.9M ops/sec | | parse() with Metadata | parse('Twelve Thousand Three Hundred Forty Five') | ~508K to ~1.0M ops/sec | | Fraction-Style Decimal | "Forty Five Hundredths" | ~1.3M ops/sec | | Gendered Input | "Veintiuna" | ~3.1M ops/sec | | Formal Chinese | "玖拾" | ~1.8M ops/sec |

Run npm run bench on your target hardware for current throughput.

🚀 Quick Start

import { ToNumbers } from 'to-numbers';

const toNumbers = new ToNumbers();
toNumbers.convert('Twelve Thousand Three Hundred Forty Five');
// 12345

📦 Installation

Runtime requirement: Node.js >= 20 for Node.js and CLI usage.

npm / yarn / pnpm

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

CDN (Browser)

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

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

📖 Usage

Importing

// ESM
import { ToNumbers, toNumbers } from 'to-numbers';

// CommonJS
const { ToNumbers, toNumbers } = require('to-numbers');

// Tree-shakeable per-locale import
import { ToNumbers as EnUsToNumbers, toNumbers as enUsToNumbers } from 'to-numbers/en-US';

Basic Conversion

const toNumbers = new ToNumbers({ localeCode: 'en-US' });

toNumbers.convert('One Hundred Twenty Three');
// 123

toNumbers.convert('One Hundred Twenty Three Point Four Five');
// 123.45

toNumbers.convert('Minus Fifty');
// -50

Case Insensitivity

const toNumbers = new ToNumbers({ localeCode: 'en-US' });

toNumbers.convert('one hundred twenty three');
// 123

toNumbers.convert('ONE HUNDRED TWENTY THREE');
// 123

toNumbers.convert('One Hundred Twenty Three');
// 123

Ordinal Numbers

Parse ordinal words automatically — no special options needed:

const toNumbers = new ToNumbers({ localeCode: 'en-US' });

toNumbers.convert('First');
// 1

toNumbers.convert('Twenty Third');
// 23

toNumbers.convert('One Hundredth');
// 100

toNumbers.convert('One Thousand Two Hundred Thirty Fourth');
// 1234

Currency Parsing

const toNumbers = new ToNumbers({ localeCode: 'en-IN' });

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

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

// Works without "Only" suffix too
toNumbers.convert('Four Hundred Fifty Two Rupees', { currency: true });
// 452

// Fractional units only
toNumbers.convert('Thirty Six Paise Only', { currency: true });
// 0.36

Fraction-Style Decimals

Locales with fraction denominator vocabularies can parse decimal phrases without digit-by-digit notation:

const toNumbers = new ToNumbers({ localeCode: 'en-US' });

toNumbers.convert('Forty Five Hundredths');
// 0.45

toNumbers.convert('Zero Point Three Hundredths');
// 0.03

This is available across the locales that ship fractionDenominatorMapping, including English, Spanish, French, German, Hindi, Persian, and other fraction-style locales.

Gendered Number Forms

Gender-aware locales accept the feminine or masculine forms that to-words emits:

const spanish = new ToNumbers({ localeCode: 'es-ES' });

spanish.convert('Veintiuna');
// 21

spanish.convert('Doscientas');
// 200

This is especially relevant for Spanish, Portuguese, Arabic, Hebrew, and several Slavic locales.

Formal Characters

Chinese financial and formal numerals are supported through the locale's formal character map:

const chinese = new ToNumbers({ localeCode: 'zh-CN' });

chinese.convert('玖拾');
// 90

chinese.convert('萬');
// 10000

Custom Currency

Override currency settings while keeping the locale's language:

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

toNumbers.convert('One Hundred Euros And Fifty Cents Only');
// 100.50

Functional API

Use the functional helper when you want a one-liner without managing a class instance:

import { toNumbers } from 'to-numbers';

toNumbers('One Hundred Twenty Three', { localeCode: 'en-US' });
// 123

toNumbers('One Crore');
// 10000000 (default locale: en-IN)

import { toNumbers as enUsToNumbers } from 'to-numbers/en-US';

enUsToNumbers('One Hundred Twenty Three');
// 123

toNumbers('One Hundred Dollars Only', {
  localeCode: 'en-US',
  currency: true,
});
// 100

The root helper caches parser instances by locale code, so repeated calls do not recreate locale classes. Per-locale helpers such as to-numbers/en-US use a single cached instance and do not require localeCode.

Tree-Shakeable Imports

Import only the locales you need for smaller bundle sizes:

// Import specific locale directly (includes both the class and functional helper)
import { ToNumbers, toNumbers as enUsToNumbers } from 'to-numbers/en-US';

const toNumbers = new ToNumbers();
toNumbers.convert('Twelve Thousand Three Hundred Forty Five');
// 12345

enUsToNumbers('One Hundred Twenty Three');
// 123

Browser Usage (UMD)

<!-- Single locale (recommended, smaller bundle) -->
<script src="https://cdn.jsdelivr.net/npm/to-numbers/dist/umd/en-US.min.js"></script>
<script>
  // ToNumbers is pre-configured for en-US
  const toNumbers = new ToNumbers();
  console.log(toNumbers.convert('Twelve Thousand'));
  // 12000
</script>

<!-- Full bundle with all locales -->
<script src="https://cdn.jsdelivr.net/npm/to-numbers/dist/umd/to-numbers.min.js"></script>
<script>
  // Specify locale when using full bundle
  const toNumbers = new ToNumbers({ localeCode: 'fr-FR' });
  console.log(toNumbers.convert('Douze Mille'));
  // 12000
</script>

🖥️ CLI

npx to-numbers --words "One Hundred Twenty Three" --locale en-US
# 123

npx to-numbers --words "One Hundred Dollars Only" --locale en-US --currency
# 100

npx to-numbers "Forty Five Hundredths" --locale en-US
# 0.45

npx to-numbers --help

Supported flags:

| Flag | Description | | ----------------- | ---------------------------------------- | | --words <text> | Provide the text to parse explicitly | | --locale <code> | Choose the locale, defaulting to en-IN | | --currency | Parse the input as a currency amount | | -h, --help | Show help and usage examples |

You can also pass the input as positional text instead of --words, but not both at the same time.

⚛️ Framework Integration

React

import { ToNumbers } from 'to-numbers/en-US';

const toNumbers = new ToNumbers();

function ParsedAmount({ text }: { text: string }) {
  const amount = toNumbers.convert(text, { currency: true });
  return <span className="amount">${amount.toFixed(2)}</span>;
}

// Usage: <ParsedAmount text="One Thousand Two Hundred Thirty Four Dollars" />
// Renders: $1234.00

Vue 3

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

const props = defineProps<{ text: string }>();
const toNumbers = new ToNumbers();

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

<template>
  <span class="amount">${{ amount.toFixed(2) }}</span>
</template>

Angular

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

@Pipe({ name: 'toNumbers', standalone: true })
export class ToNumbersPipe implements PipeTransform {
  private toNumbers = new ToNumbers();

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

// Usage: {{ 'One Thousand Dollars' | toNumbers:true }}

Svelte

<script lang="ts">
  import { ToNumbers } from 'to-numbers/en-US';

  export let text: string;

  const toNumbers = new ToNumbers();
  $: amount = toNumbers.convert(text, { currency: true });
</script>

<span class="amount">${amount.toFixed(2)}</span>

🌍 Numbering Systems

Different regions use different numbering systems. This library supports Western, Indian, East Asian, and locale-specific traditional groupings.

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 |

const toNumbers = new ToNumbers({ localeCode: 'en-US' });
toNumbers.convert('One Quintillion');
// 1000000000000000000

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 |

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

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 toNumbers = new ToNumbers({ localeCode: 'en-IN' });
toNumbers.convert('Five Lakh Twenty Three Thousand');
// 523000

toNumbers.convert('Two Crore Fifty Lakh');
// 25000000

const toNumbersHindi = new ToNumbers({ localeCode: 'hi-IN' });
toNumbersHindi.convert('एक करोड़');
// 10000000

East Asian System

Used in: Japan, China, Taiwan, Hong Kong, and Korea.

| Number | Character | | ------ | ------------- | | 10^4 | 万 (Man/Wan) | | 10^8 | 億 (Oku/Yi) | | 10^12 | 兆 (Chō/Zhao) |

const toNumbers = new ToNumbers({ localeCode: 'zh-CN' });
toNumbers.convert('一亿');
// 100000000

Burmese System

Used in: Myanmar.

| Number | Word | | ------ | ------ | | 10^4 | သောင်း | | 10^5 | သိန်း | | 10^6 | သန်း |

const toNumbers = new ToNumbers({ localeCode: 'my-MM' });
toNumbers.convert('တစ်သိန်း');
// 100000

Khmer System

Used in: Cambodia.

| Number | Word | | ------ | ---- | | 10^4 | មុឺន | | 10^5 | សែន | | 10^6 | លាន |

const toNumbers = new ToNumbers({ localeCode: 'km-KH' });
toNumbers.convert('មួយសែន');
// 100000

Scale-First Ordering

Used in: Igbo (ig-NG).

const toNumbers = new ToNumbers({ localeCode: 'ig-NG' });
toNumbers.convert('Puku Abụọ');
// 2000

⚙️ API Reference

Constructor Options

interface ToNumbersOptions {
  localeCode?: string; // Default: 'en-IN'
  converterOptions?: {
    currency?: boolean; // Default: false
    currencyOptions?: {
      // Override locale's currency settings
      name: string;
      singular: string;
      plural: string;
      symbol: string;
      fractionalUnit: {
        name: string;
        singular: string;
        plural: string;
        symbol: string;
      };
    };
  };
}

Methods

convert(text, options?)

Converts words to a number.

  • text: string — The text containing number words to convert
  • options: ConverterOptions — Override instance options
  • returns: number — The parsed numeric value
const toNumbers = new ToNumbers({ localeCode: 'en-US' });

toNumbers.convert('One Hundred Twenty Three');
// 123

toNumbers.convert('Fifty Dollars Only', { currency: true });
// 50

parse(text, options?)

Parses words and returns metadata about the result.

  • text: string — The text containing number words to convert
  • options: ConverterOptions — Override instance options
  • returns: ParseResult — Numeric value plus flags such as isCurrency, isNegative, and isOrdinal
const toNumbers = new ToNumbers({ localeCode: 'zh-CN' });

toNumbers.parse('玖拾');
// { value: 90, isCurrency: false, isNegative: false }

toNumbers(text, options?)

Functional equivalent of convert() for the full bundle.

  • Accepts the same converter options as convert() plus localeCode
  • Uses cached instances internally
  • Defaults to en-IN when localeCode is omitted

Converter Options

| Option | Type | Default | Description | | ----------------- | ------- | --------- | ------------------------------------------------- | | currency | boolean | false | Parse as currency with locale-specific formatting | | currencyOptions | object | undefined | Override locale's default currency settings |

🧪 Benchmarks

The benchmark suite covers the common parsing paths plus newer parser features such as:

  • Fraction-style decimals in en-US
  • Gendered forms in es-ES
  • Formal characters in zh-CN

Run them locally with:

npm run bench

📏 Bundle Sizes

| Import Method | Raw | Gzip | | ------------------------------ | --------- | -------- | | Full bundle (all 124 locales) | 713.93 KB | 70.41 KB | | Smallest locale bundle (si-LK) | 22.67 KB | 6.32 KB | | Average locale bundle | — | 6.77 KB | | Largest locale bundle (ta-IN) | 43.55 KB | 7.74 KB |

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

🌐 Browser Compatibility

| Browser | Version | | ------- | ------- | | Chrome | 49+ | | Firefox | 52+ | | Safari | 10+ | | Edge | 14+ | | Opera | 36+ |

🗺️ Supported Locales

All 124 locales with their currencies and numbering systems:

| Locale | Language | Country | Currency | Scale | | ------ | --------------- | ------------------- | ------------- | ---------- | | 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 | | as-IN | Assamese | India | টকা | Indian | | az-AZ | Azerbaijani | Azerbaijan | Manat | Short | | be-BY | Belarusian | Belarus | Рубель | Short | | bg-BG | Bulgarian | Bulgaria | Лев | Short | | bn-BD | Bengali | Bangladesh | টাকা | Indian | | bn-IN | Bengali | India | টাকা | Indian | | ca-ES | Catalan | Spain | Euro | Short | | cs-CZ | Czech | Czech Republic | Koruna | Short | | da-DK | Danish | Denmark | Krone | Long | | de-AT | German | Austria | Euro | Long | | de-CH | German | Switzerland | Franken | 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-HK | English | Hong Kong | Dollar | Short | | en-IE | English | Ireland | Euro | Short | | en-IN | English | India | Rupee | Indian | | en-JM | English | Jamaica | Dollar | Short | | en-KE | English | Kenya | Shilling | Short | | en-LK | English | Sri Lanka | Rupee | 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-TT | English | Trinidad and Tobago | Dollar | Short | | en-TZ | English | Tanzania | Shilling | Short | | en-UG | English | Uganda | Shilling | Short | | en-US | English | USA | Dollar | Short | | en-ZA | English | South Africa | Rand | Short | | en-ZW | English | Zimbabwe | Zimbabwe Gold | Short | | es-AR | Spanish | Argentina | Peso | Short | | es-CL | Spanish | Chile | Peso | Short | | es-CO | Spanish | Colombia | 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-CA | French | Canada | Dollar | Long | | fr-CH | French | Switzerland | Franc | Long | | fr-FR | French | France | Euro | Long | | fr-MA | French | Morocco | Dirham | Long | | fr-SA | French | Saudi Arabia | Riyal | Long | | gu-IN | Gujarati | India | રૂપિયો | Indian | | 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 | | ig-NG | Igbo | Nigeria | Naira | Short | | is-IS | Icelandic | Iceland | Króna | Short | | it-IT | Italian | Italy | Euro | Short | | ja-JP | Japanese | Japan | 円 | East Asian | | jv-ID | Javanese | Indonesia | Rupiah | Short | | ka-GE | Georgian | Georgia | ლარი | Short | | km-KH | Khmer | Cambodia | រៀល | Khmer | | kn-IN | Kannada | India | ರೂಪಾಯಿ | Indian | | ko-KR | Korean | South Korea | 원 | East Asian | | lt-LT | Lithuanian | Lithuania | Euras | Short | | lv-LV | Latvian | Latvia | Eiro | Short | | ml-IN | Malayalam | India | രൂപ | Indian | | mr-IN | Marathi | India | रुपया | Indian | | ms-MY | Malay | Malaysia | Ringgit | Short | | ms-SG | Malay | Singapore | Dolar | Short | | my-MM | Burmese | Myanmar | ကျပ် | Burmese | | nb-NO | Norwegian | Norway | Krone | Long | | nl-NL | Dutch | Netherlands | Euro | Short | | nl-SR | Dutch | Suriname | Dollar | Short | | np-NP | Nepali | Nepal | रुपैयाँ | Indian | | or-IN | Odia | India | ଟଙ୍କା | Indian | | pa-IN | Punjabi | India | ਰੁਪਇਆ | Indian | | pl-PL | Polish | Poland | Złoty | Short | | pt-AO | Portuguese | Angola | Kwanza | Short | | pt-BR | Portuguese | Brazil | Real | Short | | pt-MZ | Portuguese | Mozambique | Metical | Short | | pt-PT | Portuguese | Portugal | Euro | Short | | ro-RO | Romanian | Romania | Leu | Short | | ru-RU | Russian | Russia | Рубль | Short | | si-LK | Sinhala | Sri Lanka | රුපියල | Indian | | 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 | | sw-TZ | Swahili | Tanzania | Shilingi | Short | | ta-IN | Tamil | India | ரூபாய் | Indian | | te-IN | Telugu | India | రూపాయి | Indian | | th-TH | Thai | Thailand | บาท | Short | | tr-TR | Turkish | Turkey | Lira | Short | | uk-UA | Ukrainian | Ukraine | Гривня | Short | | ur-PK | Urdu | Pakistan | روپیہ | Indian | | uz-UZ | Uzbek | Uzbekistan | So'm | Short | | vi-VN | Vietnamese | Vietnam | Đồng | Short | | yo-NG | Yoruba | Nigeria | Naira | Short | | yue-HK | Cantonese | Hong Kong | 元 | East Asian | | zh-CN | Chinese | China | 元 | East Asian | | zh-TW | Chinese | Taiwan | 元 | East Asian | | zu-ZA | Zulu | South Africa | Rand | Short |

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 (万, 億, 兆, 京...)
  • Burmese — Burmese traditional scale (သောင်း = 10k, သိန်း = 100k, သန်း = 1M)
  • Khmer — Khmer traditional scale (មុឺន = 10k, សែន = 100k, លាន = 1M)

Ordinal Coverage: all 124 locales ship ordinal data, so convert() and parse() can recognise ordinal inputs without extra flags.

Formal Numerals: zh-CN and zh-TW support formal and financial Chinese numerals (大写 / 大寫).

Scale-First Ordering: ig-NG uses scale-first phrases such as Puku Abụọ for 2000.

⚠️ Error Handling

The library throws descriptive errors for invalid inputs:

Invalid Input

const toNumbers = new ToNumbers();

toNumbers.convert('');
// Error: Invalid Input ""

toNumbers.convert('   ');
// Error: Invalid Input "   "

Unknown Locale

const toNumbers = new ToNumbers({ localeCode: 'xx-XX' });
toNumbers.convert('One');
// Error: Unknown Locale "xx-XX"

Handling Errors

try {
  const amount = toNumbers.convert(userInput, { currency: true });
  console.log('Parsed amount:', amount);
} catch (error) {
  console.error('Parsing failed:', error.message);
}

💖 Support

If to-numbers is useful in your work, consider supporting ongoing maintenance through GitHub Sponsors.

After installation, npm fund to-numbers surfaces the same funding link from npm metadata.

🤝 Contributing

Contributions are welcome. This project follows the Code of Conduct.

For security issues, follow SECURITY.md and use private disclosure rather than a public issue.

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 parsing.

  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

to-numbers is the reverse of to-words. While to-words converts 123"One Hundred Twenty Three", to-numbers converts "One Hundred Twenty Three"123.

They share the same locale support and are designed to work together:

import { ToWords } from 'to-words';
import { ToNumbers } from 'to-numbers';

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

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

const number = toNumbers.convert(words);
// 12345 ✓ Round-trip complete!

No! The parser is fully case-insensitive:

toNumbers.convert('one hundred'); // 100
toNumbers.convert('ONE HUNDRED'); // 100
toNumbers.convert('One Hundred'); // 100
toNumbers.convert('oNe HuNdReD'); // 100

Yes! Each locale has its own currency configuration:

// Indian Rupees
const tnIN = new ToNumbers({ localeCode: 'en-IN' });
tnIN.convert('Five Hundred Rupees Only', { currency: true });
// 500

// US Dollars
const tnUS = new ToNumbers({ localeCode: 'en-US' });
tnUS.convert('Five Hundred Dollars Only', { currency: true });
// 500

// French Euros
const tnFR = new ToNumbers({ localeCode: 'fr-FR' });
tnFR.convert('Cinq Cents Euros', { currency: true });
// 500

Yes! Use the UMD bundles via CDN:

<script src="https://cdn.jsdelivr.net/npm/to-numbers/dist/umd/en-US.min.js"></script>
<script>
  const toNumbers = new ToNumbers();
  console.log(toNumbers.convert('One Hundred Twenty Three'));
  // 123
</script>

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

Ordinal parsing is available across all 124 locales in the current release. convert() and parse() automatically detect ordinal inputs, including suffix-, prefix-, and exact-form ordinals:

const english = new ToNumbers({ localeCode: 'en-US' });
english.convert('Twenty Third'); // 23

const chinese = new ToNumbers({ localeCode: 'zh-CN' });
chinese.convert('第三'); // 3

const turkish = new ToNumbers({ localeCode: 'tr-TR' });
turkish.convert('Birinci'); // 1

📋 Changelog

See CHANGELOG.md for a detailed history of changes.

📄 License

MIT