2

I'm in need to convert the dollar amount that is entered in an input field to text dynamically. The closest solution I've been able to find comes close to resolve my needs, however, I was expecting the result text to include the words "Dollars" and remove the word "point" with "Cents" at the end of the sentence.

Here's the starting prototype and the current outcome:

function amountToWords(amountInDigits){
// American Numbering System
var th = ['','thousand','million', 'billion','trillion'];

var dg = ['zero','one','two','three','four', 'five','six','seven','eight','nine'];
var tn = ['ten','eleven','twelve','thirteen', 'fourteen','fifteen','sixteen', 'seventeen','eighteen','nineteen'];
var tw = ['twenty','thirty','forty','fifty', 'sixty','seventy','eighty','ninety'];
function toWords(s){
  s = s.toString();
  s = s.replace(/[\, ]/g,'');
  if (s != parseFloat(s))
  return 'not a number';
  var x = s.indexOf('.');
  if (x == -1) x = s.length;
  if (x > 15) return 'too big';
  var n = s.split('');
  var str = '';
  var sk = 0;
  for (var i=0; i < x; i++){
    if ((x-i)%3==2){
      if (n[i] == '1') {
        str += tn[Number(n[i+1])] + ' ';
        i++; sk=1;
      } else if (n[i]!=0) {
          str += tw[n[i]-2] + ' ';sk=1;
        }
      } else if (n[i]!=0) {
        str += dg[n[i]] +' ';
        if ((x-i)%3==0)
        str += 'hundred ';
        sk=1;
      } if ((x-i)%3==1) {
        if (sk) str += th[(x-i-1)/3] + ' ';sk=0;
      }
    }
    if (x != s.length) {
      var y = s.length;
      str += 'point ';
      for (var i=x+1; i<y; i++) str += dg[n[i]] +' ';
    }
    return str.replace(/\s+/g,' ');
  }

  return toWords(amountInDigits);

}

<input type="text" name="number" placeholder="Number OR Amount" onkeyup="word.innerHTML=amountToWords(this.value)" />

So, if a User enters the amount of $1234.56 in the input box, the desired text output would spell "one thousand two hundred thirty Four Dollars Fifty Six Cents"

Any suggestions?

  • 3
    Hi. There seem to be multiple code samples online. Have you tried them ? Here is one - https://www.onlinecode.org/convert-number-words-javascript/ – Nisanth Reddy May 10 '21 at 21:01
  • That does not work? Did you try the link yourself? – Marcelo Martins May 10 '21 at 21:09
  • my bad. how about this one ? it is interactive so you can check it right there. https://karvitt.com/misc/currency-in-words – Nisanth Reddy May 10 '21 at 21:25
  • The codes I have seen online and on StackOverflow are either too complex or do not deal with numbers properly when handling currencies. – Mohsen Alyafei Mar 05 '22 at 08:48
  • @MarceloMartins . I have posted the short function below that can allow you to do that in any currency. Just create the US Dollar names as an object and pass them to the function along with your number that has fractions. You could change the words to lower case if you wish. You can format the decimal part with 3 available options. – Mohsen Alyafei Mar 05 '22 at 09:05
  • @NisanthReddy the code at https://karvitt.com/misc/currency-in-words is an overkill. – Mohsen Alyafei Mar 05 '22 at 10:42
  • @MohsenAlyafei unfortunately that's the price to pay for wanting to convert numbers into a human made up word system which follows proper grammar. (i.e., English) – Nisanth Reddy Mar 06 '22 at 18:45

2 Answers2

1

Details commented in example below

/*
These arrays are indexed to the number that each element represents
*/
const ones = ['', 'one ', 'two ', 'three ', 'four ', 'five ', 'six ', 'seven ', 'eight ', 'nine '];
const teen = ['ten ', 'eleven ', 'twelve ', 'thirteen ', 'fourteen ', 'fifteen ', 'sixteen ', 'seventeen ', 'eighteen ', 'nineteen '];
const tens = ['twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety'];
const high = ['hundred ', 'thousand ', 'million ', 'billion '];
// Helper function - a simple logger
const log = data => console.log(data);

/*
This function takes 2 numbers and matches the first parameter to the index of the 
tens or teen array. The second parameter matches to the index of the ones array. 
A word number between 1 and 99 is returned. 
*/
const tensOnes = (t, o) => +t == 0 ? ones[+o] : +t == 1 ? teen[+o] : +t > 1 && +o == 0 ? tens[+t - 2] : tens[+t - 2] + '-' + ones[+o];

// function takes a number and returns a string number with 2 decimals
const fltN = float => [...parseFloat(float).toFixed(2)];

/* 
This function takes an array created by moneyToEng() function and returns a word
version of the given number. A switch() with 10 cases (9,999,999,999 is max) is 
used to call tensOnes() function. Before the string is returned, there are a few
fixes to make it grammatically correct.
*/
const stepper = array => {
  const D = array[0];
  const C = array[1];
  let size = D.length;
  let word;
  switch (size) {
    case 0:
      word = C;
      break;
    case 1:
      word = tensOnes(0, D[0]) + 'dollars ' + C;
      break;
    case 2:
      word = tensOnes(D[1], D[0]) + 'dollars ' + C;
      break;
    case 3:
      word = tensOnes(0, D[2]) + high[0] + tensOnes(D[1], D[0]) + 'dollars ' + C;
      break;
    case 4:
      word = tensOnes(0, D[3]) + high[1] + tensOnes(0, D[2]) + high[0] + tensOnes(D[1], D[0]) + 'dollars ' + C;
      break;
    case 5:
      word = tensOnes(D[4], D[3]) + high[1] + tensOnes(0, D[2]) + high[0] + tensOnes(D[1], D[0]) + 'dollars ' + C;
      break;
    case 6:
      word = tensOnes(0, D[5]) + high[0] + tensOnes(D[4], D[3]) + high[1] + tensOnes(0, D[2]) + high[0] + tensOnes(D[1], D[0]) + 'dollars ' + C;
      break;
    case 7:
      word = tensOnes(0, D[6]) + high[2] + tensOnes(0, D[5]) + high[0] + tensOnes(D[4], D[3]) + high[1] + tensOnes(0, D[2]) + high[0] + tensOnes(D[1], D[0]) + 'dollars ' + C;
      break;
    case 8:
      word = tensOnes(D[7], D[6]) + high[2] + tensOnes(0, D[5]) + high[0] + tensOnes(D[4], D[3]) + high[1] + tensOnes(0, D[2]) + high[0] + tensOnes(D[1], D[0]) + 'dollars ' + C;
      break;
    case 9:
      word = tensOnes(0, D[8]) + high[0] + tensOnes(D[7], D[6]) + high[2] + tensOnes(0, D[5]) + high[0] + tensOnes(D[4], D[3]) + high[1] + tensOnes(0, D[2]) + high[0] + tensOnes(D[1], D[0]) + 'dollars ' + C;
      break;
    case 10:
      word = tensOnes(0, D[9]) + high[3] + tensOnes(0, D[8]) + high[0] + tensOnes(D[7], D[6]) + high[2] + tensOnes(0, D[5]) + high[0] + tensOnes(D[4], D[3]) + high[1] + tensOnes(0, D[2]) + high[0] + tensOnes(D[1], D[0]) + 'dollars ' + C;
      break;
    default:
      break;
  }
  word = word.trim();
  word = word == 'one dollars' ? 'one dollar' : word == 'dollars and one cent' ? 'one cent' : word == 'one dollars and one cent' ? 'one dollar and one cent' : word == 'and undefined-undefinedcents' ? '' : word;
  word = word.replace(/(thousand|million)\s(hundred)/g, '$1').replace(/(million)\s(thousand)/g, '$1').replace(/(tycents)/g, 'ty cents').replace(/(tydollars)/g, 'ty dollars');
  return word;
};

/*
This takes a number and returns a string of words that represent the given 
number as money. It prepares the input for further processing by the stepper() 
function.
*/
const moneyToEng = number => {
  let R = fltN(number);
  let dec, c, cents;
  dec = R.splice(-3, 3);
  c = tensOnes(dec[1], dec[2]);
  cents = c == 'one ' ? 'and one cent' : c == '' ? '' : `and ${c}cents`;
  return stepper([R.reverse(), cents]);
};

// Reference the form
const form = document.forms[0];

// Bind form listen for input event
form.addEventListener('input', dataManager);

// Pass the Event Object
function dataManager(e) {
  /*
  All of form's form controls which is every element in this simple layout.
  */
  const io = this.elements;
  // The fieldset typed into
  const input = e.target;
  // if you are typing into #editor...
  if (input.matches('#editor')) {
    /*
    ...get the text of #editor and have it converted to words by moneyToEng()
    */
    let txt = moneyToEng(input.textContent);
    // Display on #mirror
    io.mirror.textContent = txt;
  }
};
/*
log('100.23 \n'+ moneyToEng(100.23));
log('5600 \n'+moneyToEng(5600));
log('900000003.58 \n'+ moneyToEng(900000003.58));
log('1 \n'+moneyToEng(1));
log('.01 \n'+moneyToEng(.01));
log('1111111111.11 \n'+moneyToEng(1111111111.11));
*/
form {
  font: 2ch/1.15 Consolas;
}

#editor {
  min-height: 2.15ch;
  padding-top: 1.5ch;
  background: lightgrey;
  color: #930;
}

#editor::before {
  content: '$';
}

#mirror {
  min-height: 2.15ch;
}
<form>
  <fieldset>
    <legend>Enter an Amount in USD</legend>
    <fieldset id='editor' contenteditable></fieldset>
    <fieldset id='mirror'></fieldset>
  </fieldset>
</form>
zer00ne
  • 41,936
  • 6
  • 41
  • 68
0

March 2022

Generic and Short 'Currency to Words' Javascript Function

Handle all Currencies in English

With three (3) Common Output Formats for Fractions


I have developed the following short Javascript function that can convert any Currency Number into words including decimal places (fractions) using the Arabic-Latin Numbering System (i.e. used internationally).

The function uses US English Grammer for writing numbers into words.

The function is short and simple and you can just copy and paste it into your own code.

If you want to deal with very very large numbers, then pass the number as a string.

You can increase the sales table sclT beyond Quadrillion to handle very large numbers if you wish.

I have given below a few examples of use for better understanding.

Syntax

currencyToWords(number, currancy, format={})

number    : any numeric or number in string form for large numbers
currency  : object holding the currency information as follows:
            {
             country    : the country Name       (e.g.: 'US')
             majorSingle: Major Unit Single Name (e.g.: 'Dollar')
             majorPlural: Major Unit Plural Name (e.g.: 'Dollars')
             minorSingle: Minor Sub-Unit Single  (e.g.: 'Cent')
             minorPlural: Minor Sub-Unit Plural  (e.g.: 'Cents')
             fraction   : Decimal Places Number  (e.g.: 2)
             };
format    : object holding the format for the minor (sub-units) using
            'minor' parameters, as follows:
            'numeric' : Sub-Units in Numeric Form (i.g. 35 Cents)
            'fraction': Sub-Units in Fractional Form (i.g. 35/100 US Dollar)
            empty or other (default): Sub-Units in Words Form
----------------------------------------------------------------------------

Example 1: Convert US Dollars in Default Mode

    let currancy = {
    country    : "US",     // country Name
    majorSingle: "Dollar", // Major Unit Single
    majorPlural: "Dollars",// Major Unit Plural
    minorSingle: "Cent",   // Minor Sub-Unit Single
    minorPlural: "Cents",  // Minor Sub-Unit Plural
    fraction   : 2,        // Decimal Places
    };

console.log(currencyToWords(50,currancy));
// Fifty US Dollars

console.log(currencyToWords(20.23,currancy));
// Twenty US Dollars, and Twenty-Three Cents

console.log(currencyToWords(0.99,currancy));
// Zero US Dollar, and Ninety-Nine Cents

console.log(currencyToWords(100.2,currancy));
// One Hundred US Dollars, and Twenty Cents

console.log(currencyToWords(1.01,currancy));
// One US Dollar, and One Cent

console.log(currencyToWords(0.01,currancy));
// Zero US Dollar, and One Cent

console.log(currencyToWords(520.01,currancy));
// Five Hundred Twenty US Dollars, and One Cent

Example 2: Convert US Dollars with Sub-Units (Minor) in 'numeric' Format

console.log(currencyToWords(50,currancy,{minor:"numeric"}));
// Fifty US Dollars

console.log(currencyToWords(20.23,currancy,{minor:"numeric"}));
// Twenty US Dollars, and 23 Cents

console.log(currencyToWords(0.99,currancy,{minor:"numeric"}));
// Zero US Dollar, and 99 Cents

console.log(currencyToWords(100.2,currancy,{minor:"numeric"}));
// One Hundred US Dollars, and 20 Cents

console.log(currencyToWords(1.01,currancy,{minor:"numeric"}));
// One US Dollar, and 1 Cent

console.log(currencyToWords(0.01,currancy,{minor:"numeric"}));
// Zero US Dollar, and 1 Cent

console.log(currencyToWords(520.01,currancy,{minor:"numeric"}));
// Five Hundred Twenty US Dollars, and 1 Cent

Example 2: Convert US Dollars with Sub-Units (Minor) in 'fraction' Format

console.log(currencyToWords(50,currancy,{minor:"fraction"}));
// Fifty US Dollars

console.log(currencyToWords(20.23,currancy,{minor:"fraction"}));
// Twenty, and 23/100 US Dollars

console.log(currencyToWords(0.99,currancy,{minor:"fraction"}));
// Zero, and 99/100 US Dollar

console.log(currencyToWords(100.2,currancy,{minor:"fraction"}));
// One Hundred, and 20/100 US Dollars

console.log(currencyToWords(1.01,currancy,{minor:"fraction"}));
// One, and 1/100 US Dollar

console.log(currencyToWords(0.01,currancy,{minor:"fraction"}));
// Zero, and 1/100 US Dollar

console.log(currencyToWords(520.01,currancy,{minor:"fraction"}));
// Five Hundred Twenty, and 1/100 US Dollars

Changing the Currency

You can specify the name of the country, major and minor currency names (singular and plural). The fraction is the number of decimal places for the minor (sub-unit). For US Dollars it is 2 for a Euro: 2, for Kuwait Dinar: 3, or Omani Riyal: 3, etc.

If you want to have a currency without the country name, then set the country name to an empty string ''.

/********************************************************
* @function    : currencyToWords(number, currancy, [format])
* @purpose     : Converts Currency to Words
* @version     : 1.00
* @author      : Mohsen Alyafei
* @licence     : MIT
* @date        : 27 Feb 2022
* @param       : number   [required] numeric or string
*                curr [required] object description
*                format   [optional] with the following parameters:
*                minor: 'numeric' or 'fraction' or none (default)
* @returns     : {string} Currency String in Words
********************************************************/
function currencyToWords(num=0, curr, format={}) {
format=format.minor;
format ??= "";
num=(num+="").split((0.1).toLocaleString().substring(1,2));
let frc = (num[1]+"000").substring(0,curr.fraction), a=", and ",
    cc  = " "+curr.country+(curr.country?" ":"")+(num[0]>1?curr.majorPlural:curr.majorSingle),
    out = numToWords(num[0])+(format=="fraction" && num[1]?"":cc);
if (num[1] && curr.fraction) {
    let sub=frc>1?curr.minorPlural:curr.minorSingle;
    if      (format=="numeric")  out+=a+(+frc)+" "+sub;
    else if (format=="fraction") out+=a+(+frc)+"/1"+"0".repeat(curr.fraction)+cc;
    else    out+=a+numToWords(frc)+" "+sub;
}
return out;
//----------------------------------------------------------------
function numToWords(num = 0) {
if (num == 0) return "Zero";
num= ("0".repeat(2*(num+="").length%3)+num).match(/.{3}/g);
let out="",
    T10s=["","One","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten","Eleven","Twelve","Thirteen","Fourteen","Fifteen","Sixteen","Seventeen","Eighteen","Nineteen"],
    T20s=["","","Twenty","Thirty","Forty","Fifty","Sixty","Seventy","Eighty","Ninety"],
    sclT=["","Thousand","Million","Billion","Trillion","Quadrillion"];
return num.forEach((n,i) => {
if (+n) {
 let h=+n[0], t=+n.substring(1), scl=sclT[num.length-i-1];
 out+=(out?" ":"")+(h?T10s[h]+" Hundred":"")+(h && t?" ":"")+(t<20?T10s[t]:T20s[+n[1]]+(+n[2]?"-":"")+T10s[+n[2]]);
 out+=(out && scl?" ":"")+scl;
}}),out;
}
}
//----------------------------------------------------------------










//=========================================
//             Test Code
//=========================================

let currancy = {
country    : "US",     // country Name
majorSingle: "Dollar", // Major Unit Single
majorPlural: "Dollars",// Major Unit Plural
minorSingle: "Cent",   // Minor Sub-Unit Single
minorPlural: "Cents",  // Minor Sub-Unit Plural
fraction   : 2,        // Decimal Places
};

// default. sub-units in word format
console.log(currencyToWords(50,currancy));
console.log(currencyToWords(20.23,currancy));
console.log(currencyToWords(0.99,currancy));
console.log(currencyToWords(100.2,currancy));
console.log(currencyToWords(1.01,currancy));
console.log(currencyToWords(0.01,currancy));
console.log(currencyToWords(520.01,currancy));
console.log("-".repeat(50));

// sub-units in numeric format
console.log(currencyToWords(50,currancy,{minor:"numeric"}));
console.log(currencyToWords(20.23,currancy,{minor:"numeric"}));
console.log(currencyToWords(0.99,currancy,{minor:"numeric"}));
console.log(currencyToWords(100.2,currancy,{minor:"numeric"}));
console.log(currencyToWords(1.01,currancy,{minor:"numeric"}));
console.log(currencyToWords(0.01,currancy,{minor:"numeric"}));
console.log(currencyToWords(520.01,currancy,{minor:"numeric"}));
console.log("-".repeat(50));

// sub-units in fractional format
console.log(currencyToWords(50,currancy,{minor:"fraction"}));
console.log(currencyToWords(20.23,currancy,{minor:"fraction"}));
console.log(currencyToWords(0.99,currancy,{minor:"fraction"}));
console.log(currencyToWords(100.2,currancy,{minor:"fraction"}));
console.log(currencyToWords(1.01,currancy,{minor:"fraction"}));
console.log(currencyToWords(0.01,currancy,{minor:"fraction"}));
console.log(currencyToWords(520.01,currancy,{minor:"fraction"}));
console.log("-".repeat(50));

currancy = {
    country    : "Omani",  // country Name
    majorSingle: "Riyal", // Major Unit Single
    majorPlural: "Riyals",// Major Unit Plural
    minorSingle: "Baisa",  // Minor Sub-Unit Single
    minorPlural: "Baisa",  // Minor Sub-Unit Plural
    fraction   : 3,        // Decimal Places
    };

console.log(currencyToWords(50,currancy,{minor:"fraction"}));
console.log(currencyToWords(200.234,currancy,{minor:"fraction"}));
console.log(currencyToWords(2000.99,currancy,{minor:"fraction"}));
console.log(currencyToWords(30100.2,currancy,{minor:"fraction"}));
console.log(currencyToWords(3456.001,currancy,{minor:"fraction"}));
console.log(currencyToWords(500.01,currancy,{minor:"fraction"}));
console.log(currencyToWords(22.1,currancy,{minor:"fraction"}));
console.log(currencyToWords(0.45,currancy,{minor:"fraction"}));
Mohsen Alyafei
  • 4,765
  • 3
  • 30
  • 42
  • Make sure that round your decimals properly before passing to the function because the function does not do rounding of decimals. So, if you pass `35.789 dollars`, it will use it as `35.78 dollars` (i.e. just use the last 2 decimals). The job of the function is to convert numbers given to words (i.e. translate it to words) not do rounding and other math. – Mohsen Alyafei Mar 05 '22 at 08:47