Skip to content
Devix Open Source
UI component v1.0.0 MIT Stable

Number Words

Numbers and money in words, with the grammar — and any currency in any language.

npm install @devix-labs/number-words
Vanilla JS TypeScript
An invoice line Open

Arabic that agrees with what it counts: gender polarity, duals, the tamyīz, the construct state. Urdu with its own word for every number to ninety-nine, and lakh and crore. English in both numbering systems. Then the parts nobody else ships: any currency spelled in any language — including AED in English, which is what a Dubai invoice is — the cheque line with “only” in the right language, and counting your own nouns. 5.1 KB, zero dependencies, identical to its PHP twin.

What you get

Arabic that agrees

Polarity (ثلاثة كتب but ثلاث سيارات), duals (درهمان), the tamyīz (أحد عشر درهمًا), the genitive after a round hundred, and the construct state (مئتا درهم).

Any currency, any language

AED in English, PKR in Urdu, INR in Arabic. Every other library locks the currency to its locale — which is why none of them can spell a Dubai invoice.

The cheque line

“AED twelve thousand … and fifty fils only”, with فقط لا غير or صرف in the right language, and both halves named even when one is zero.

Count your own nouns

Give Arabic the four forms of فاتورة once and every number agrees — ثلاث فواتير, إحدى عشرة فاتورةً, ألفا فاتورة.

Urdu, all ninety-nine of them

No rule derives اکتالیس from چالیس, so every numeral is written out — with lakh, crore and arab above a thousand.

Never a float

Money is split and rounded on the digits, and the integer side is bigint, so amounts past a double stay exact.

Number Words — overview

Why it exists

Spelling a number is solved in JavaScript: n2words does it well, in a hundred languages. This package does not claim otherwise.

It exists for the three things that are still missing, in every library we ran:

  1. Currency and language are locked together. No library will spell an AED amount in English — which is what a Dubai invoice is. Ours takes any currency in any language.
  2. No cheque line. Banks want "AED twelve thousand … and fifty fils only", in the cheque's own language. Ours prints it.
  3. You cannot count your own nouns. Arabic needs four forms of فاتورة to say ثلاث فواتير and إحدى عشرة فاتورةً. Ours takes them.

And in PHP, where ICU writes خمسة مائة, gets the gender of eleven wrong, has no Arabic ordinals and answers in English when asked for Urdu, the whole thing is missing. That is the companion package, devix/laravel-number-words.

Shape of the package

Export What
toWords, toOrdinal the number, in words
toMoney, toCheque an amount, with its currency's grammar
counted, noun your own nouns, agreeing
registerCurrency, registerLanguage extend either
en, ar, ur the languages, if you want one directly

Not in 1.0

Languages beyond these three — registerLanguage() takes yours — and invoice or cheque templates, which are the Pro edition's shape.

How it compares

Questions

Isn't this solved already?

For spelling a number in JavaScript, largely yes — n2words is good and we say so in the teardown. This package exists for three things still missing everywhere: spelling any currency in any language (a Dubai invoice in English, priced in dirhams, which n2words and to-words both refuse), the cheque line with “only” in the right language, and counting your own nouns in Arabic. In PHP nothing usable exists at all.

What is wrong with Arabic in other libraries?

Usually the agreement. Three takes the opposite gender of what it counts (ثلاثة كتب but ثلاث سيارات), two is a dual (درهمان), eleven to ninety-nine take the accusative (أحد عشر درهمًا), a round hundred takes the genitive singular (مئة درهم), and a dual before its noun loses its nūn (مئتا درهم, never مئتان درهم). PHP's ICU gets several of these wrong and writes خمسة مائة for five hundred.

Can I count something other than money?

Yes, and it is the feature we are proudest of. Give counted() the four Arabic forms of your noun once — فاتورة, فاتورتان, فواتير, فاتورةً — and every number agrees, including ألفا فاتورة for two thousand.

Will the amount survive floating point?

Amounts are split and rounded on the digits, never on a float, and the integer side uses bigint, so values past what a double can hold are exact. Pass a string for money that came from a database.

Which currencies are included?

AED, SAR, QAR, KWD, BHD, JOD, OMR, EGP, PKR, INR, USD, EUR and GBP, each with words in English, Arabic and Urdu. KWD, BHD, JOD and OMR divide into a thousand and keep all three digits. registerCurrency() takes your own.