├── .npmrc ├── .gitignore ├── wrapEach.tmpl ├── src ├── maxSafeInteger.js ├── index.js ├── isSafeNumber.js ├── isFinite.js ├── toWordsOrdinal.js ├── toOrdinal.js ├── makeOrdinal.js └── toWords.js ├── .prettierrc ├── spec ├── support │ └── jasmine.json ├── indexSpec.js ├── index.html ├── isSafeNumberSpec.js ├── toOrdinalSpec.js ├── toWordsOrdinalSpec.js ├── phantom │ └── run-jasmine3.js └── toWordsSpec.js ├── ROADMAP.md ├── .eslintrc ├── .editorconfig ├── wrapBundle.tmpl ├── LICENSE ├── bower.json ├── gulpfile.js ├── package.json ├── numberToWords.min.js ├── README.md └── numberToWords.js /.npmrc: -------------------------------------------------------------------------------- 1 | save-exact = true 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | node_modules 4 | notes.md 5 | -------------------------------------------------------------------------------- /wrapEach.tmpl: -------------------------------------------------------------------------------- 1 | // ========== file: <%= file.path.replace(file.cwd, '') %> ========== 2 | <%= file.contents %> -------------------------------------------------------------------------------- /src/maxSafeInteger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var MAX_SAFE_INTEGER = 9007199254740991; 4 | 5 | module.exports = MAX_SAFE_INTEGER; 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "singleQuote": true, 4 | "tabWidth": 4, 5 | "trailingComma": "none" 6 | } 7 | -------------------------------------------------------------------------------- /spec/support/jasmine.json: -------------------------------------------------------------------------------- 1 | { 2 | "spec_dir": "spec", 3 | "spec_files": [ 4 | "**/*[sS]pec.js" 5 | ], 6 | "helpers": [ 7 | "helpers/**/*.js" 8 | ] 9 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | toOrdinal: require('./toOrdinal'), 5 | toWords: require('./toWords'), 6 | toWordsOrdinal: require('./toWordsOrdinal') 7 | }; 8 | -------------------------------------------------------------------------------- /ROADMAP.md: -------------------------------------------------------------------------------- 1 | # Number To Words — Roadmap 2 | 3 | ### Version 2.0 4 | - Rework the API 5 | - Add pluggable languages files for multi-language support 6 | - Remove 1.x deprecated code 7 | - Run tests with Karma 8 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "node": true 5 | }, 6 | "parserOptions": { 7 | "ecmaVersion": 5, 8 | "sourceType": "script" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/isSafeNumber.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var MAX_SAFE_INTEGER = require('./maxSafeInteger'); 4 | 5 | function isSafeNumber(value) { 6 | return typeof value === 'number' && Math.abs(value) <= MAX_SAFE_INTEGER; 7 | } 8 | 9 | module.exports = isSafeNumber; 10 | -------------------------------------------------------------------------------- /src/isFinite.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Simplified https://gist.github.com/marlun78/885eb0021e980c6ce0fb 4 | function isFinite(value) { 5 | return !(typeof value !== 'number' || value !== value || value === Infinity || value === -Infinity); 6 | } 7 | 8 | module.exports = isFinite; 9 | -------------------------------------------------------------------------------- /src/toWordsOrdinal.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var makeOrdinal = require('./makeOrdinal'); 4 | var toWords = require('./toWords'); 5 | 6 | /** 7 | * Converts a number into ordinal words. 8 | * @example toWordsOrdinal(12) => 'twelfth' 9 | * @param {number|string} number 10 | * @returns {string} 11 | */ 12 | function toWordsOrdinal(number) { 13 | var words = toWords(number); 14 | return makeOrdinal(words); 15 | } 16 | 17 | module.exports = toWordsOrdinal; 18 | -------------------------------------------------------------------------------- /spec/indexSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var index = typeof require !== 'undefined' ? require('../src') : window.numberToWords; 4 | 5 | describe('index', function () { 6 | it('should expose a toOrdinal method', function () { 7 | expect(index.toOrdinal).toEqual(jasmine.any(Function)); 8 | }); 9 | it('should expose a toWords method', function () { 10 | expect(index.toWords).toEqual(jasmine.any(Function)); 11 | }); 12 | it('should expose a toWordsOrdinal method', function () { 13 | expect(index.toWordsOrdinal).toEqual(jasmine.any(Function)); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | # Matches multiple files with brace expansion notation 12 | # Set default charset 13 | [*.{css,js,json}] 14 | charset = utf-8 15 | indent_style = space 16 | indent_size = 4 17 | 18 | # Tab indentation (no size specified) 19 | [Makefile] 20 | indent_style = tab 21 | 22 | # Matches the exact files either package.json 23 | [{package.json}] 24 | indent_style = space 25 | indent_size = 2 26 | -------------------------------------------------------------------------------- /spec/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Jasmine Spec Runner 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /wrapBundle.tmpl: -------------------------------------------------------------------------------- 1 | /*! 2 | * Number-To-Words util 3 | * @version v<%= data.version %> 4 | * @link <%= data.homepage %> 5 | * @author <%= data.author %> 6 | * @contributors <%= data.contributors %> 7 | * @license <%= data.license %> 8 | */ 9 | (function () { 10 | 'use strict'; 11 | 12 | var root = typeof self == 'object' && self.self === self && self || 13 | typeof global == 'object' && global.global === global && global || 14 | this; 15 | 16 | <%= data.contents %> 17 | 18 | var numberToWords = { 19 | toOrdinal: toOrdinal, 20 | toWords: toWords, 21 | toWordsOrdinal: toWordsOrdinal 22 | }; 23 | 24 | if (typeof exports != 'undefined') { 25 | if (typeof module != 'undefined' && module.exports) { 26 | exports = module.exports = numberToWords; 27 | } 28 | exports.numberToWords = numberToWords; 29 | } else { 30 | root.numberToWords = numberToWords; 31 | } 32 | 33 | }()); 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Martin Eneqvist (https://github.com/marlun78) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /src/toOrdinal.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var isFinite = require('./isFinite'); 4 | var isSafeNumber = require('./isSafeNumber'); 5 | 6 | /** 7 | * Converts an integer into a string with an ordinal postfix. 8 | * If number is decimal, the decimals will be removed. 9 | * @example toOrdinal(12) => '12th' 10 | * @param {number|string} number 11 | * @returns {string} 12 | */ 13 | function toOrdinal(number) { 14 | var num = parseInt(number, 10); 15 | 16 | if (!isFinite(num)) { 17 | throw new TypeError( 18 | 'Not a finite number: ' + number + ' (' + typeof number + ')' 19 | ); 20 | } 21 | if (!isSafeNumber(num)) { 22 | throw new RangeError( 23 | 'Input is not a safe number, it’s either too large or too small.' 24 | ); 25 | } 26 | var str = String(num); 27 | var lastTwoDigits = Math.abs(num % 100); 28 | var betweenElevenAndThirteen = lastTwoDigits >= 11 && lastTwoDigits <= 13; 29 | var lastChar = str.charAt(str.length - 1); 30 | return str + (betweenElevenAndThirteen ? 'th' 31 | : lastChar === '1' ? 'st' 32 | : lastChar === '2' ? 'nd' 33 | : lastChar === '3' ? 'rd' 34 | : 'th'); 35 | } 36 | 37 | module.exports = toOrdinal; 38 | -------------------------------------------------------------------------------- /spec/isSafeNumberSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var MAX_SAFE_INTEGER = require('../src/maxSafeInteger'); 4 | var isSafeNumber = require('../src/isSafeNumber'); 5 | 6 | describe('isSafeNumber', function() { 7 | it('should return true if input is a number between -MAX_SAFE_INTEGER and MAX_SAFE_INTEGER (including)', function() { 8 | expect(isSafeNumber(-MAX_SAFE_INTEGER)).toBe(true); 9 | expect(isSafeNumber(-1)).toBe(true); 10 | expect(isSafeNumber(0)).toBe(true); 11 | expect(isSafeNumber(1)).toBe(true); 12 | expect(isSafeNumber(MAX_SAFE_INTEGER)).toBe(true); 13 | }); 14 | it('should return false if input is too large or too small', function() { 15 | var unsafe = MAX_SAFE_INTEGER + 100; 16 | 17 | expect(isSafeNumber(unsafe)).toBe(false); 18 | expect(isSafeNumber(-unsafe)).toBe(false); 19 | }); 20 | it('should return false if input is not a number', function() { 21 | expect(isSafeNumber()).toBe(false); 22 | expect(isSafeNumber(null)).toBe(false); 23 | expect(isSafeNumber([])).toBe(false); 24 | expect(isSafeNumber({})).toBe(false); 25 | expect(isSafeNumber('')).toBe(false); 26 | expect(isSafeNumber('x')).toBe(false); 27 | expect(isSafeNumber(function() {})).toBe(false); 28 | expect(isSafeNumber(NaN)).toBe(false); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "number-to-words", 3 | "description": "Contains some util methods for converting numbers into words, ordinal words and ordinal numbers.", 4 | "version": "1.2.4", 5 | "main": "./numberToWords.min.js", 6 | "authors": [ 7 | "Martin Eneqvist (https://github.com/marlun78)" 8 | ], 9 | "contributors": [ 10 | "Aleksey Pilyugin (https://github.com/pilyugin)", 11 | "Jeremiah Hall (https://github.com/jeremiahrhall)", 12 | "Adriano Melo (https://github.com/adrianomelo)", 13 | "dmrzn (https://github.com/dmrzn)" 14 | ], 15 | "homepage": "https://github.com/marlun78/number-to-words", 16 | "moduleType": [ 17 | "globals", 18 | "node" 19 | ], 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/marlun78/number-to-words" 23 | }, 24 | "keywords": [ 25 | "converter", 26 | "number", 27 | "ordinal", 28 | "string", 29 | "tool", 30 | "word" 31 | ], 32 | "license": "MIT", 33 | "ignore": [ 34 | "bower_components", 35 | "node_modules", 36 | "spec", 37 | ".editorconfig", 38 | ".eslint", 39 | ".npmrc", 40 | ".prettierrc", 41 | "gulpfile.js", 42 | "wrapBundle.tmpl", 43 | "wrapEach.tmpl" 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /src/makeOrdinal.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var ENDS_WITH_DOUBLE_ZERO_PATTERN = /(hundred|thousand|(m|b|tr|quadr)illion)$/; 4 | var ENDS_WITH_TEEN_PATTERN = /teen$/; 5 | var ENDS_WITH_Y_PATTERN = /y$/; 6 | var ENDS_WITH_ZERO_THROUGH_TWELVE_PATTERN = /(zero|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve)$/; 7 | var ordinalLessThanThirteen = { 8 | zero: 'zeroth', 9 | one: 'first', 10 | two: 'second', 11 | three: 'third', 12 | four: 'fourth', 13 | five: 'fifth', 14 | six: 'sixth', 15 | seven: 'seventh', 16 | eight: 'eighth', 17 | nine: 'ninth', 18 | ten: 'tenth', 19 | eleven: 'eleventh', 20 | twelve: 'twelfth' 21 | }; 22 | 23 | /** 24 | * Converts a number-word into an ordinal number-word. 25 | * @example makeOrdinal('one') => 'first' 26 | * @param {string} words 27 | * @returns {string} 28 | */ 29 | function makeOrdinal(words) { 30 | // Ends with *00 (100, 1000, etc.) or *teen (13, 14, 15, 16, 17, 18, 19) 31 | if (ENDS_WITH_DOUBLE_ZERO_PATTERN.test(words) || ENDS_WITH_TEEN_PATTERN.test(words)) { 32 | return words + 'th'; 33 | } 34 | // Ends with *y (20, 30, 40, 50, 60, 70, 80, 90) 35 | else if (ENDS_WITH_Y_PATTERN.test(words)) { 36 | return words.replace(ENDS_WITH_Y_PATTERN, 'ieth'); 37 | } 38 | // Ends with one through twelve 39 | else if (ENDS_WITH_ZERO_THROUGH_TWELVE_PATTERN.test(words)) { 40 | return words.replace(ENDS_WITH_ZERO_THROUGH_TWELVE_PATTERN, replaceWithOrdinalVariant); 41 | } 42 | return words; 43 | } 44 | 45 | function replaceWithOrdinalVariant(match, numberWord) { 46 | return ordinalLessThanThirteen[numberWord]; 47 | } 48 | 49 | module.exports = makeOrdinal; 50 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'); 4 | var gulp = require('gulp'); 5 | var gulpPlugins = { 6 | concat: require('gulp-concat'), 7 | rename: require('gulp-rename'), 8 | replace: require('gulp-replace'), 9 | uglify: require('gulp-uglify'), 10 | wrap: require('gulp-wrap') 11 | }; 12 | var log = require('fancy-log'); 13 | var license = require('uglify-save-license'); 14 | 15 | var pkg = require('./package.json'); 16 | 17 | function bundleTask() { 18 | var USE_STRICT_PATTERN = /(['"]use strict['"];?\n?)/g; 19 | var REQUIRE_PATTERN = /((?:var |,)[^=]+=\s*require\([^\)]+\);?\n?)/g; 20 | var EXPORT_PATTERN = /((?:module\.)?exports\s*=\s*[^,;]+;?\n?)/g; 21 | 22 | var files = [ 23 | './src/maxSafeInteger.js', 24 | './src/isFinite.js', 25 | './src/isSafeNumber.js', 26 | './src/makeOrdinal.js', 27 | './src/toOrdinal.js', 28 | './src/toWords.js', 29 | './src/toWordsOrdinal.js' 30 | ]; 31 | 32 | return gulp.src(files) 33 | .on('error', log.error) 34 | .pipe(gulpPlugins.wrap({ src: 'wrapEach.tmpl' })) 35 | .pipe(gulpPlugins.replace(USE_STRICT_PATTERN, '')) 36 | .pipe(gulpPlugins.replace(REQUIRE_PATTERN, '')) 37 | .pipe(gulpPlugins.replace(EXPORT_PATTERN, '')) 38 | .pipe(gulpPlugins.concat('numberToWords.js')) 39 | .pipe(gulpPlugins.wrap({ src: 'wrapBundle.tmpl' }, pkg, { variable: 'data' })) 40 | .pipe(gulp.dest('./')) 41 | // Minified version 42 | .pipe(gulpPlugins.uglify({ output: { comments: license } })) 43 | .pipe(gulpPlugins.rename('numberToWords.min.js')) 44 | .pipe(gulp.dest('./')); 45 | } 46 | 47 | module.exports = { 48 | build: gulp.parallel(bundleTask) 49 | }; 50 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "number-to-words", 3 | "description": "Contains some util methods for converting numbers into words, ordinal words and ordinal numbers.", 4 | "version": "1.2.4", 5 | "main": "./src", 6 | "browser": "./numberToWords.min.js", 7 | "author": "Martin Eneqvist (https://github.com/marlun78)", 8 | "contributors": [ 9 | "Aleksey Pilyugin (https://github.com/pilyugin)", 10 | "Jeremiah Hall (https://github.com/jeremiahrhall)", 11 | "Adriano Melo (https://github.com/adrianomelo)", 12 | "dmrzn (https://github.com/dmrzn)" 13 | ], 14 | "devDependencies": { 15 | "eslint": "5.3.0", 16 | "fancy-log": "1.3.2", 17 | "gulp": "4.0.0", 18 | "gulp-concat": "2.6.1", 19 | "gulp-rename": "1.4.0", 20 | "gulp-replace": "1.0.0", 21 | "gulp-uglify": "3.0.1", 22 | "gulp-wrap": "0.14.0", 23 | "http-server": "0.11.1", 24 | "jasmine": "3.2.0", 25 | "phantomjs-prebuilt": "2.1.16", 26 | "uglify-save-license": "0.4.1" 27 | }, 28 | "scripts": { 29 | "build": "gulp build", 30 | "lint": "node node_modules/eslint/bin/eslint.js .", 31 | "test": "npm run lint && npm run test:node", 32 | "test:node": "jasmine", 33 | "test:phantom": "phantomjs ./spec/phantom/run-jasmine3.js 'http://localhost:3456/spec/'", 34 | "test:server": "http-server ./ -p 3456 -c-1" 35 | }, 36 | "repository": { 37 | "type": "git", 38 | "url": "https://github.com/marlun78/number-to-words" 39 | }, 40 | "license": "MIT", 41 | "bugs": { 42 | "url": "https://github.com/marlun78/number-to-words/issues" 43 | }, 44 | "homepage": "https://github.com/marlun78/number-to-words", 45 | "keywords": [ 46 | "converter", 47 | "number", 48 | "ordinal", 49 | "string", 50 | "tool", 51 | "word" 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /spec/toOrdinalSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var toOrdinal = typeof require !== 'undefined' ? require('../src/toOrdinal') : window.numberToWords.toOrdinal; 4 | var MAX_SAFE_INTEGER = 9007199254740991; 5 | 6 | describe('toOrdinal', function () { 7 | var tests = [ 8 | { input: -121, expect: '-121st' }, 9 | { input: -13, expect: '-13th' }, 10 | { input: -12, expect: '-12th' }, 11 | { input: -11, expect: '-11th' }, 12 | { input: -3, expect: '-3rd' }, 13 | { input: -2, expect: '-2nd' }, 14 | { input: -1, expect: '-1st' }, 15 | { input: 0, expect: '0th' }, 16 | { input: 1, expect: '1st' }, 17 | { input: 1.9, expect: '1st' }, 18 | { input: 2, expect: '2nd' }, 19 | { input: 3, expect: '3rd' }, 20 | { input: 4, expect: '4th' }, 21 | { input: 5, expect: '5th' }, 22 | { input: 6, expect: '6th' }, 23 | { input: 7, expect: '7th' }, 24 | { input: 8, expect: '8th' }, 25 | { input: 9, expect: '9th' }, 26 | { input: 10, expect: '10th' }, 27 | { input: 11, expect: '11th' }, 28 | { input: 12, expect: '12th' }, 29 | { input: 13, expect: '13th' }, 30 | { input: 121, expect: '121st' } 31 | ]; 32 | 33 | function addTest(test) { 34 | it('should, if passed ' + test.input + ', return ' + test.expect, function () { 35 | expect(toOrdinal(test.input)).toEqual(test.expect); 36 | }); 37 | } 38 | 39 | tests.forEach(addTest); 40 | 41 | it('should throw a RangeError if input is greater or lesser than MAX_SAFE_INTEGER', function() { 42 | var unsafe = MAX_SAFE_INTEGER + 100; 43 | 44 | expect(function() { 45 | toOrdinal(unsafe); 46 | }).toThrowError(/Input is not a safe number/); 47 | 48 | expect(function() { 49 | toOrdinal(-unsafe); 50 | }).toThrowError(/Input is not a safe number/); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /numberToWords.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Number-To-Words util 3 | * @version v1.2.4 4 | * @link https://github.com/marlun78/number-to-words 5 | * @author Martin Eneqvist (https://github.com/marlun78) 6 | * @contributors Aleksey Pilyugin (https://github.com/pilyugin),Jeremiah Hall (https://github.com/jeremiahrhall),Adriano Melo (https://github.com/adrianomelo),dmrzn (https://github.com/dmrzn) 7 | * @license MIT 8 | */ 9 | !function(){"use strict";var e="object"==typeof self&&self.self===self&&self||"object"==typeof global&&global.global===global&&global||this,t=9007199254740991;function f(e){return!("number"!=typeof e||e!=e||e===1/0||e===-1/0)}function l(e){return"number"==typeof e&&Math.abs(e)<=t}var n=/(hundred|thousand|(m|b|tr|quadr)illion)$/,r=/teen$/,o=/y$/,i=/(zero|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve)$/,s={zero:"zeroth",one:"first",two:"second",three:"third",four:"fourth",five:"fifth",six:"sixth",seven:"seventh",eight:"eighth",nine:"ninth",ten:"tenth",eleven:"eleventh",twelve:"twelfth"};function h(e){return n.test(e)||r.test(e)?e+"th":o.test(e)?e.replace(o,"ieth"):i.test(e)?e.replace(i,a):e}function a(e,t){return s[t]}var u=10,d=100,p=1e3,v=1e6,b=1e9,y=1e12,c=1e15,g=9007199254740992,m=["zero","one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen"],w=["zero","ten","twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety"];function x(e,t){var n,r=parseInt(e,10);if(!f(r))throw new TypeError("Not a finite number: "+e+" ("+typeof e+")");if(!l(r))throw new RangeError("Input is not a safe number, it’s either too large or too small.");return n=function e(t){var n,r,o=arguments[1];if(0===t)return o?o.join(" ").replace(/,$/,""):"zero";o||(o=[]);t<0&&(o.push("minus"),t=Math.abs(t));t<20?(n=0,r=m[t]):t “21st” 23 | ``` 24 | 25 | #### `toWords(number)` 26 | Converts an integer into words. 27 | If number is decimal, the decimals will be removed. 28 | ```js 29 | var converter = require('number-to-words'); 30 | converter.toWords(13); // => “thirteen” 31 | 32 | // Decimal numbers: 33 | converter.toWords(2.9); // => “two” 34 | 35 | // Negative numbers: 36 | converter.toWords(-3); // => “minus three” 37 | 38 | // Large numbers: 39 | converter.toWords(9007199254740992); // => “nine quadrillion, seven trillion, one hundred ninety-nine billion, two hundred fifty-four million, seven hundred forty thousand, nine hundred ninety-two” 40 | ``` 41 | 42 | #### `toWordsOrdinal(number)` 43 | Converts a number into ordinal words. 44 | If number is decimal, the decimals will be removed. 45 | ```js 46 | var converter = require('number-to-words'); 47 | converter.toWordsOrdinal(21); // => “twenty-first” 48 | ``` 49 | 50 | 51 | ### Contributions, Comments and Bugs 52 | Contributions, comments and/or bug reports are much appreciated. Open a pull request or add comments on the 53 | [issues page](https://github.com/marlun78/number-to-words/issues). Thanks! 54 | 55 | 56 | ### Upcoming v2.0 57 | See [roadmap](ROADMAP.md) for details. 58 | 59 | 60 | ### Change Log 61 | 62 | ##### Version 1.2.4 (final 1.x release) 63 | - Bug fix in `toOrdinal`. When passed -11, -12 and -13 it returned an incorrect suffix ([#15](https://github.com/marlun78/number-to-words/issues/15)). Thanks to @dmrzn. 64 | - `toOrdinal` and `toWords` now throws a more precise error when passed an unsafe number ([#13](https://github.com/marlun78/number-to-words/pull/13)). Thanks to @adrianomelo. 65 | 66 | ##### Version 1.2.3 67 | - Bug fix in `isFinite` for Phantom and IE ([#10](https://github.com/marlun78/number-to-words/pull/10)). Thanks to @jeremiahrhall. 68 | 69 | ##### Version 1.2.2 70 | - Bug fix in `toOrdinal`. Input 11, 12, and 13 now yields the correct suffix ([#8](https://github.com/marlun78/number-to-words/pull/8)). Thanks to @pilyugin. 71 | 72 | ##### Version 1.2.1 73 | - Bower package 74 | 75 | ##### Version 1.2.0 76 | - Bundles are now available for browsers (`./numberToWords.js` and `./numberToWords.min.js`). They export a global `numberToWords` variable. 77 | - Made unit tests runnable in browser. To run the unit tests in the browser, start a local server and visit localhost/spec with a browser. 78 | - `toOrdinal`, `toWords` and `toWordsOrdinal` now also allow string values as input (replaced `Math.floor` with `parseInt`). 79 | 80 | ##### 1.1.0 81 | - New methods `toOrdinal` and `toWordsOrdinal` 82 | - Deprecated `toWords` second optional `asOrdinal` parameter, use `toWordsOrdinal()`-method instead 83 | - `toWords` now converts any decimal input to an integer (with `Math.floor`) 84 | - Bug fixed returning _“zeroth”_ instead of _“zero”_ when converting a number word into its ordinal 85 | 86 | ##### 1.0.1 87 | - Minor package tweaks 88 | 89 | ##### 1.0.0 90 | - Initial release 91 | -------------------------------------------------------------------------------- /src/toWords.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var makeOrdinal = require('./makeOrdinal'); 4 | var isFinite = require('./isFinite'); 5 | var isSafeNumber = require('./isSafeNumber'); 6 | 7 | var TEN = 10; 8 | var ONE_HUNDRED = 100; 9 | var ONE_THOUSAND = 1000; 10 | var ONE_MILLION = 1000000; 11 | var ONE_BILLION = 1000000000; // 1.000.000.000 (9) 12 | var ONE_TRILLION = 1000000000000; // 1.000.000.000.000 (12) 13 | var ONE_QUADRILLION = 1000000000000000; // 1.000.000.000.000.000 (15) 14 | var MAX = 9007199254740992; // 9.007.199.254.740.992 (15) 15 | 16 | var LESS_THAN_TWENTY = [ 17 | 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 18 | 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen' 19 | ]; 20 | 21 | var TENTHS_LESS_THAN_HUNDRED = [ 22 | 'zero', 'ten', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety' 23 | ]; 24 | 25 | /** 26 | * Converts an integer into words. 27 | * If number is decimal, the decimals will be removed. 28 | * @example toWords(12) => 'twelve' 29 | * @param {number|string} number 30 | * @param {boolean} [asOrdinal] - Deprecated, use toWordsOrdinal() instead! 31 | * @returns {string} 32 | */ 33 | function toWords(number, asOrdinal) { 34 | var words; 35 | var num = parseInt(number, 10); 36 | 37 | if (!isFinite(num)) { 38 | throw new TypeError( 39 | 'Not a finite number: ' + number + ' (' + typeof number + ')' 40 | ); 41 | } 42 | if (!isSafeNumber(num)) { 43 | throw new RangeError( 44 | 'Input is not a safe number, it’s either too large or too small.' 45 | ); 46 | } 47 | words = generateWords(num); 48 | return asOrdinal ? makeOrdinal(words) : words; 49 | } 50 | 51 | function generateWords(number) { 52 | var remainder, word, 53 | words = arguments[1]; 54 | 55 | // We’re done 56 | if (number === 0) { 57 | return !words ? 'zero' : words.join(' ').replace(/,$/, ''); 58 | } 59 | // First run 60 | if (!words) { 61 | words = []; 62 | } 63 | // If negative, prepend “minus” 64 | if (number < 0) { 65 | words.push('minus'); 66 | number = Math.abs(number); 67 | } 68 | 69 | if (number < 20) { 70 | remainder = 0; 71 | word = LESS_THAN_TWENTY[number]; 72 | 73 | } else if (number < ONE_HUNDRED) { 74 | remainder = number % TEN; 75 | word = TENTHS_LESS_THAN_HUNDRED[Math.floor(number / TEN)]; 76 | // In case of remainder, we need to handle it here to be able to add the “-” 77 | if (remainder) { 78 | word += '-' + LESS_THAN_TWENTY[remainder]; 79 | remainder = 0; 80 | } 81 | 82 | } else if (number < ONE_THOUSAND) { 83 | remainder = number % ONE_HUNDRED; 84 | word = generateWords(Math.floor(number / ONE_HUNDRED)) + ' hundred'; 85 | 86 | } else if (number < ONE_MILLION) { 87 | remainder = number % ONE_THOUSAND; 88 | word = generateWords(Math.floor(number / ONE_THOUSAND)) + ' thousand,'; 89 | 90 | } else if (number < ONE_BILLION) { 91 | remainder = number % ONE_MILLION; 92 | word = generateWords(Math.floor(number / ONE_MILLION)) + ' million,'; 93 | 94 | } else if (number < ONE_TRILLION) { 95 | remainder = number % ONE_BILLION; 96 | word = generateWords(Math.floor(number / ONE_BILLION)) + ' billion,'; 97 | 98 | } else if (number < ONE_QUADRILLION) { 99 | remainder = number % ONE_TRILLION; 100 | word = generateWords(Math.floor(number / ONE_TRILLION)) + ' trillion,'; 101 | 102 | } else if (number <= MAX) { 103 | remainder = number % ONE_QUADRILLION; 104 | word = generateWords(Math.floor(number / ONE_QUADRILLION)) + 105 | ' quadrillion,'; 106 | } 107 | 108 | words.push(word); 109 | return generateWords(remainder, words); 110 | } 111 | 112 | module.exports = toWords; 113 | -------------------------------------------------------------------------------- /spec/phantom/run-jasmine3.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var system = require('system'); 3 | 4 | /** 5 | * Wait until the test condition is true or a timeout occurs. Useful for waiting 6 | * on a server response or for a ui change (fadeIn, etc.) to occur. 7 | * 8 | * @param testFx javascript condition that evaluates to a boolean, 9 | * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or 10 | * as a callback function. 11 | * @param onReady what to do when testFx condition is fulfilled, 12 | * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or 13 | * as a callback function. 14 | * @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used. 15 | */ 16 | function waitFor(testFx, onReady, timeOutMillis) { 17 | var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3001, //< Default Max Timeout is 3s 18 | start = new Date().getTime(), 19 | condition = false, 20 | interval = setInterval(function() { 21 | if (new Date().getTime() - start < maxtimeOutMillis && !condition) { 22 | // If not time-out yet and condition not yet fulfilled 23 | condition = 24 | typeof testFx === 'string' ? eval(testFx) : testFx(); //< defensive code 25 | } else { 26 | if (!condition) { 27 | // If condition still not fulfilled (timeout but condition is 'false') 28 | console.log("'waitFor()' timeout"); 29 | phantom.exit(1); 30 | } else { 31 | // Condition fulfilled (timeout and/or condition is 'true') 32 | console.log( 33 | "'waitFor()' finished in " + 34 | (new Date().getTime() - start) + 35 | 'ms.' 36 | ); 37 | typeof onReady === 'string' ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled 38 | clearInterval(interval); //< Stop this interval 39 | } 40 | } 41 | }, 100); //< repeat check every 100ms 42 | } 43 | 44 | if (system.args.length !== 2) { 45 | console.log('Usage: run-jasmine2.js URL'); 46 | phantom.exit(1); 47 | } 48 | 49 | var page = require('webpage').create(); 50 | 51 | // Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this") 52 | page.onConsoleMessage = function(msg) { 53 | console.log(msg); 54 | }; 55 | 56 | page.open(system.args[1], function(status) { 57 | if (status !== 'success') { 58 | console.log('Unable to access network'); 59 | phantom.exit(); 60 | } else { 61 | waitFor( 62 | function() { 63 | return page.evaluate(function() { 64 | var summary = document.body.querySelector( 65 | '.jasmine-results .jasmine-summary' 66 | ); 67 | var duration = document.body.querySelector( 68 | '.jasmine-duration' 69 | ); 70 | 71 | return summary !== null && duration !== null; 72 | }); 73 | }, 74 | function() { 75 | var exitCode = page.evaluate(function() { 76 | console.log(''); 77 | 78 | var title = 'Jasmine'; 79 | var version = document.body.querySelector( 80 | '.jasmine-version' 81 | ).innerText; 82 | console.log(title + ' ' + version); 83 | 84 | var result = document.body.querySelector( 85 | '.jasmine-overall-result.jasmine-bar' 86 | ).innerText; 87 | console.log(result); 88 | 89 | var duration = document.body.querySelector( 90 | '.jasmine-duration' 91 | ).innerText; 92 | console.log(duration); 93 | 94 | var list = document.body.querySelectorAll( 95 | '.jasmine-results > .jasmine-failures > .jasmine-spec-detail.jasmine-failed' 96 | ); 97 | if (list && list.length > 0) { 98 | console.log(''); 99 | console.log(list.length + ' test(s) FAILED:'); 100 | for (i = 0; i < list.length; ++i) { 101 | var el = list[i], 102 | desc = el.querySelector('.jasmine-description'), 103 | msg = el.querySelector( 104 | '.jasmine-messages > .jasmine-result-message' 105 | ); 106 | console.log(''); 107 | console.log(desc.innerText); 108 | console.log(' ' + msg.innerText); 109 | console.log(''); 110 | } 111 | return 1; 112 | } else { 113 | return 0; 114 | } 115 | }); 116 | phantom.exit(exitCode); 117 | } 118 | ); 119 | } 120 | }); 121 | -------------------------------------------------------------------------------- /spec/toWordsSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var MAX_SAFE_INTEGER = 9007199254740991; 4 | var toWords = typeof require !== 'undefined' ? require('../src/toWords') : window.numberToWords.toWords; 5 | 6 | describe('toWords', function () { 7 | var tests = [ 8 | { input: -1, expect: 'minus one' }, 9 | { input: 0, expect: 'zero' }, 10 | { input: 1, expect: 'one' }, 11 | { input: 1.9, expect: 'one' }, 12 | { input: 2, expect: 'two' }, 13 | { input: 3, expect: 'three' }, 14 | { input: 4, expect: 'four' }, 15 | { input: 5, expect: 'five' }, 16 | { input: 6, expect: 'six' }, 17 | { input: 7, expect: 'seven' }, 18 | { input: 8, expect: 'eight' }, 19 | { input: 9, expect: 'nine' }, 20 | { input: 10, expect: 'ten' }, 21 | { input: 11, expect: 'eleven' }, 22 | { input: 12, expect: 'twelve' }, 23 | { input: 13, expect: 'thirteen' }, 24 | { input: 14, expect: 'fourteen' }, 25 | { input: 15, expect: 'fifteen' }, 26 | { input: 16, expect: 'sixteen' }, 27 | { input: 17, expect: 'seventeen' }, 28 | { input: 18, expect: 'eighteen' }, 29 | { input: 19, expect: 'nineteen' }, 30 | { input: 20, expect: 'twenty' }, 31 | { input: 22, expect: 'twenty-two' }, 32 | { input: 33, expect: 'thirty-three' }, 33 | { input: 44, expect: 'forty-four' }, 34 | { input: 55, expect: 'fifty-five' }, 35 | { input: 66, expect: 'sixty-six' }, 36 | { input: 77, expect: 'seventy-seven' }, 37 | { input: 88, expect: 'eighty-eight' }, 38 | { input: 99, expect: 'ninety-nine' }, 39 | { input: 100, expect: 'one hundred' }, 40 | { input: 111, expect: 'one hundred eleven' }, 41 | { input: 1000, expect: 'one thousand' }, 42 | { input: 2222, expect: 'two thousand, two hundred twenty-two' }, 43 | { input: 10000, expect: 'ten thousand' }, 44 | { input: 33333, expect: 'thirty-three thousand, three hundred thirty-three' }, 45 | { input: 100000, expect: 'one hundred thousand' }, 46 | { input: 444444, expect: 'four hundred forty-four thousand, four hundred forty-four' }, 47 | { input: 1000000, expect: 'one million' }, 48 | { input: 5555555, expect: 'five million, five hundred fifty-five thousand, five hundred fifty-five' }, 49 | { input: 10000000, expect: 'ten million' }, 50 | { input: 66666666, expect: 'sixty-six million, six hundred sixty-six thousand, six hundred sixty-six' }, 51 | { input: 100000000, expect: 'one hundred million' }, 52 | { 53 | input: 777777777, 54 | expect: 'seven hundred seventy-seven million, seven hundred seventy-seven thousand, seven hundred seventy-seven' 55 | }, 56 | { input: 1000000000, expect: 'one billion' }, 57 | { 58 | input: 8888888888, 59 | expect: 'eight billion, eight hundred eighty-eight million, eight hundred eighty-eight thousand, eight hundred eighty-eight' 60 | }, 61 | { input: 10000000000, expect: 'ten billion' }, 62 | { 63 | input: 99999999999, 64 | expect: 'ninety-nine billion, nine hundred ninety-nine million, nine hundred ninety-nine thousand, nine hundred ninety-nine' 65 | }, 66 | { input: 100000000000, expect: 'one hundred billion' }, 67 | { 68 | input: 111111111111, 69 | expect: 'one hundred eleven billion, one hundred eleven million, one hundred eleven thousand, one hundred eleven' 70 | }, 71 | { input: 1000000000000, expect: 'one trillion' }, 72 | { 73 | input: 2222222222222, 74 | expect: 'two trillion, two hundred twenty-two billion, two hundred twenty-two million, two hundred twenty-two thousand, two hundred twenty-two' 75 | }, 76 | { input: 10000000000000, expect: 'ten trillion' }, 77 | { 78 | input: 33333333333333, 79 | expect: 'thirty-three trillion, three hundred thirty-three billion, three hundred thirty-three million, three hundred thirty-three thousand, three hundred thirty-three' 80 | }, 81 | { input: 100000000000000, expect: 'one hundred trillion' }, 82 | { 83 | input: 444444444444444, 84 | expect: 'four hundred forty-four trillion, four hundred forty-four billion, four hundred forty-four million, four hundred forty-four thousand, four hundred forty-four' 85 | }, 86 | { input: 1000000000000000, expect: 'one quadrillion' }, 87 | { 88 | input: 5555555555555555, 89 | expect: 'five quadrillion, five hundred fifty-five trillion, five hundred fifty-five billion, five hundred fifty-five million, five hundred fifty-five thousand, five hundred fifty-five' 90 | }, 91 | { 92 | input: MAX_SAFE_INTEGER, 93 | expect: 'nine quadrillion, seven trillion, one hundred ninety-nine billion, two hundred fifty-four million, seven hundred forty thousand, nine hundred ninety-one' 94 | } 95 | ]; 96 | 97 | function addTest(test) { 98 | it('should, if passed ' + formatNumber(test.input) + ', return ' + test.expect, function () { 99 | expect(toWords(test.input)).toEqual(test.expect); 100 | }); 101 | } 102 | 103 | tests.forEach(addTest); 104 | 105 | // Note! This is deprecated, use toWordsOrdinal() instead! 106 | it('should return the number with an ordinal word if passed a second truthy argument', function () { 107 | expect(toWords(1, true)).toEqual('first'); 108 | expect(toWords(2, true)).toEqual('second'); 109 | expect(toWords(3, true)).toEqual('third'); 110 | expect(toWords(10, true)).toEqual('tenth'); 111 | expect(toWords(17, true)).toEqual('seventeenth'); 112 | expect(toWords(30, true)).toEqual('thirtieth'); 113 | expect(toWords(123, true)).toEqual('one hundred twenty-third'); 114 | }); 115 | 116 | it('should throw a RangeError if input is greater or lesser than MAX_SAFE_INTEGER', function() { 117 | var unsafe = MAX_SAFE_INTEGER + 100; 118 | 119 | expect(function() { 120 | toWords(unsafe); 121 | }).toThrowError(/Input is not a safe number/); 122 | 123 | expect(function() { 124 | toWords(-unsafe); 125 | }).toThrowError(/Input is not a safe number/); 126 | }); 127 | }); 128 | 129 | function formatNumber(number) { 130 | var result = String(number).split('').reverse().map(function (num, index) { 131 | if (index % 3 === 2) return '.' + num; 132 | return num; 133 | }).reverse(); 134 | var length = result.length; 135 | return result.join('') + ' (' + length + ')'; 136 | } 137 | -------------------------------------------------------------------------------- /numberToWords.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Number-To-Words util 3 | * @version v1.2.4 4 | * @link https://github.com/marlun78/number-to-words 5 | * @author Martin Eneqvist (https://github.com/marlun78) 6 | * @contributors Aleksey Pilyugin (https://github.com/pilyugin),Jeremiah Hall (https://github.com/jeremiahrhall),Adriano Melo (https://github.com/adrianomelo),dmrzn (https://github.com/dmrzn) 7 | * @license MIT 8 | */ 9 | (function () { 10 | 'use strict'; 11 | 12 | var root = typeof self == 'object' && self.self === self && self || 13 | typeof global == 'object' && global.global === global && global || 14 | this; 15 | 16 | // ========== file: /src/maxSafeInteger.js ========== 17 | 18 | var MAX_SAFE_INTEGER = 9007199254740991; 19 | 20 | 21 | // ========== file: /src/isFinite.js ========== 22 | 23 | // Simplified https://gist.github.com/marlun78/885eb0021e980c6ce0fb 24 | function isFinite(value) { 25 | return !(typeof value !== 'number' || value !== value || value === Infinity || value === -Infinity); 26 | } 27 | 28 | 29 | // ========== file: /src/isSafeNumber.js ========== 30 | 31 | 32 | function isSafeNumber(value) { 33 | return typeof value === 'number' && Math.abs(value) <= MAX_SAFE_INTEGER; 34 | } 35 | 36 | 37 | // ========== file: /src/makeOrdinal.js ========== 38 | 39 | var ENDS_WITH_DOUBLE_ZERO_PATTERN = /(hundred|thousand|(m|b|tr|quadr)illion)$/; 40 | var ENDS_WITH_TEEN_PATTERN = /teen$/; 41 | var ENDS_WITH_Y_PATTERN = /y$/; 42 | var ENDS_WITH_ZERO_THROUGH_TWELVE_PATTERN = /(zero|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve)$/; 43 | var ordinalLessThanThirteen = { 44 | zero: 'zeroth', 45 | one: 'first', 46 | two: 'second', 47 | three: 'third', 48 | four: 'fourth', 49 | five: 'fifth', 50 | six: 'sixth', 51 | seven: 'seventh', 52 | eight: 'eighth', 53 | nine: 'ninth', 54 | ten: 'tenth', 55 | eleven: 'eleventh', 56 | twelve: 'twelfth' 57 | }; 58 | 59 | /** 60 | * Converts a number-word into an ordinal number-word. 61 | * @example makeOrdinal('one') => 'first' 62 | * @param {string} words 63 | * @returns {string} 64 | */ 65 | function makeOrdinal(words) { 66 | // Ends with *00 (100, 1000, etc.) or *teen (13, 14, 15, 16, 17, 18, 19) 67 | if (ENDS_WITH_DOUBLE_ZERO_PATTERN.test(words) || ENDS_WITH_TEEN_PATTERN.test(words)) { 68 | return words + 'th'; 69 | } 70 | // Ends with *y (20, 30, 40, 50, 60, 70, 80, 90) 71 | else if (ENDS_WITH_Y_PATTERN.test(words)) { 72 | return words.replace(ENDS_WITH_Y_PATTERN, 'ieth'); 73 | } 74 | // Ends with one through twelve 75 | else if (ENDS_WITH_ZERO_THROUGH_TWELVE_PATTERN.test(words)) { 76 | return words.replace(ENDS_WITH_ZERO_THROUGH_TWELVE_PATTERN, replaceWithOrdinalVariant); 77 | } 78 | return words; 79 | } 80 | 81 | function replaceWithOrdinalVariant(match, numberWord) { 82 | return ordinalLessThanThirteen[numberWord]; 83 | } 84 | 85 | 86 | // ========== file: /src/toOrdinal.js ========== 87 | 88 | 89 | /** 90 | * Converts an integer into a string with an ordinal postfix. 91 | * If number is decimal, the decimals will be removed. 92 | * @example toOrdinal(12) => '12th' 93 | * @param {number|string} number 94 | * @returns {string} 95 | */ 96 | function toOrdinal(number) { 97 | var num = parseInt(number, 10); 98 | 99 | if (!isFinite(num)) { 100 | throw new TypeError( 101 | 'Not a finite number: ' + number + ' (' + typeof number + ')' 102 | ); 103 | } 104 | if (!isSafeNumber(num)) { 105 | throw new RangeError( 106 | 'Input is not a safe number, it’s either too large or too small.' 107 | ); 108 | } 109 | var str = String(num); 110 | var lastTwoDigits = Math.abs(num % 100); 111 | var betweenElevenAndThirteen = lastTwoDigits >= 11 && lastTwoDigits <= 13; 112 | var lastChar = str.charAt(str.length - 1); 113 | return str + (betweenElevenAndThirteen ? 'th' 114 | : lastChar === '1' ? 'st' 115 | : lastChar === '2' ? 'nd' 116 | : lastChar === '3' ? 'rd' 117 | : 'th'); 118 | } 119 | 120 | 121 | // ========== file: /src/toWords.js ========== 122 | 123 | 124 | var TEN = 10; 125 | var ONE_HUNDRED = 100; 126 | var ONE_THOUSAND = 1000; 127 | var ONE_MILLION = 1000000; 128 | var ONE_BILLION = 1000000000; // 1.000.000.000 (9) 129 | var ONE_TRILLION = 1000000000000; // 1.000.000.000.000 (12) 130 | var ONE_QUADRILLION = 1000000000000000; // 1.000.000.000.000.000 (15) 131 | var MAX = 9007199254740992; // 9.007.199.254.740.992 (15) 132 | 133 | var LESS_THAN_TWENTY = [ 134 | 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 135 | 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen' 136 | ]; 137 | 138 | var TENTHS_LESS_THAN_HUNDRED = [ 139 | 'zero', 'ten', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety' 140 | ]; 141 | 142 | /** 143 | * Converts an integer into words. 144 | * If number is decimal, the decimals will be removed. 145 | * @example toWords(12) => 'twelve' 146 | * @param {number|string} number 147 | * @param {boolean} [asOrdinal] - Deprecated, use toWordsOrdinal() instead! 148 | * @returns {string} 149 | */ 150 | function toWords(number, asOrdinal) { 151 | var words; 152 | var num = parseInt(number, 10); 153 | 154 | if (!isFinite(num)) { 155 | throw new TypeError( 156 | 'Not a finite number: ' + number + ' (' + typeof number + ')' 157 | ); 158 | } 159 | if (!isSafeNumber(num)) { 160 | throw new RangeError( 161 | 'Input is not a safe number, it’s either too large or too small.' 162 | ); 163 | } 164 | words = generateWords(num); 165 | return asOrdinal ? makeOrdinal(words) : words; 166 | } 167 | 168 | function generateWords(number) { 169 | var remainder, word, 170 | words = arguments[1]; 171 | 172 | // We’re done 173 | if (number === 0) { 174 | return !words ? 'zero' : words.join(' ').replace(/,$/, ''); 175 | } 176 | // First run 177 | if (!words) { 178 | words = []; 179 | } 180 | // If negative, prepend “minus” 181 | if (number < 0) { 182 | words.push('minus'); 183 | number = Math.abs(number); 184 | } 185 | 186 | if (number < 20) { 187 | remainder = 0; 188 | word = LESS_THAN_TWENTY[number]; 189 | 190 | } else if (number < ONE_HUNDRED) { 191 | remainder = number % TEN; 192 | word = TENTHS_LESS_THAN_HUNDRED[Math.floor(number / TEN)]; 193 | // In case of remainder, we need to handle it here to be able to add the “-” 194 | if (remainder) { 195 | word += '-' + LESS_THAN_TWENTY[remainder]; 196 | remainder = 0; 197 | } 198 | 199 | } else if (number < ONE_THOUSAND) { 200 | remainder = number % ONE_HUNDRED; 201 | word = generateWords(Math.floor(number / ONE_HUNDRED)) + ' hundred'; 202 | 203 | } else if (number < ONE_MILLION) { 204 | remainder = number % ONE_THOUSAND; 205 | word = generateWords(Math.floor(number / ONE_THOUSAND)) + ' thousand,'; 206 | 207 | } else if (number < ONE_BILLION) { 208 | remainder = number % ONE_MILLION; 209 | word = generateWords(Math.floor(number / ONE_MILLION)) + ' million,'; 210 | 211 | } else if (number < ONE_TRILLION) { 212 | remainder = number % ONE_BILLION; 213 | word = generateWords(Math.floor(number / ONE_BILLION)) + ' billion,'; 214 | 215 | } else if (number < ONE_QUADRILLION) { 216 | remainder = number % ONE_TRILLION; 217 | word = generateWords(Math.floor(number / ONE_TRILLION)) + ' trillion,'; 218 | 219 | } else if (number <= MAX) { 220 | remainder = number % ONE_QUADRILLION; 221 | word = generateWords(Math.floor(number / ONE_QUADRILLION)) + 222 | ' quadrillion,'; 223 | } 224 | 225 | words.push(word); 226 | return generateWords(remainder, words); 227 | } 228 | 229 | 230 | // ========== file: /src/toWordsOrdinal.js ========== 231 | 232 | 233 | /** 234 | * Converts a number into ordinal words. 235 | * @example toWordsOrdinal(12) => 'twelfth' 236 | * @param {number|string} number 237 | * @returns {string} 238 | */ 239 | function toWordsOrdinal(number) { 240 | var words = toWords(number); 241 | return makeOrdinal(words); 242 | } 243 | 244 | 245 | 246 | var numberToWords = { 247 | toOrdinal: toOrdinal, 248 | toWords: toWords, 249 | toWordsOrdinal: toWordsOrdinal 250 | }; 251 | 252 | if (typeof exports != 'undefined') { 253 | if (typeof module != 'undefined' && module.exports) { 254 | exports = module.exports = numberToWords; 255 | } 256 | exports.numberToWords = numberToWords; 257 | } else { 258 | root.numberToWords = numberToWords; 259 | } 260 | 261 | }()); --------------------------------------------------------------------------------