@ww-samuel/to-words
Version:
Converts numbers (including decimal points) into words & currency.
265 lines (264 loc) • 11.5 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ToWords = exports.DefaultToWordsOptions = exports.DefaultConverterOptions = void 0;
const en_AE_1 = __importDefault(require("./locales/en-AE"));
const en_BD_1 = __importDefault(require("./locales/en-BD"));
const en_GH_1 = __importDefault(require("./locales/en-GH"));
const en_IN_1 = __importDefault(require("./locales/en-IN"));
const en_MM_1 = __importDefault(require("./locales/en-MM"));
const en_MU_1 = __importDefault(require("./locales/en-MU"));
const en_NG_1 = __importDefault(require("./locales/en-NG"));
const en_NP_1 = __importDefault(require("./locales/en-NP"));
const en_US_1 = __importDefault(require("./locales/en-US"));
const en_GB_1 = __importDefault(require("./locales/en-GB"));
const fa_IR_1 = __importDefault(require("./locales/fa-IR"));
const fr_FR_1 = __importDefault(require("./locales/fr-FR"));
const gu_IN_1 = __importDefault(require("./locales/gu-IN"));
const hi_IN_1 = __importDefault(require("./locales/hi-IN"));
const mr_IN_1 = __importDefault(require("./locales/mr-IN"));
const pt_BR_1 = __importDefault(require("./locales/pt-BR"));
const tr_TR_1 = __importDefault(require("./locales/tr-TR"));
const nl_SR_1 = __importDefault(require("./locales/nl-SR"));
const ee_EE_1 = __importDefault(require("./locales/ee-EE"));
exports.DefaultConverterOptions = {
currency: false,
ignoreDecimal: false,
ignoreZeroCurrency: false,
doNotAddOnly: false,
};
exports.DefaultToWordsOptions = {
localeCode: 'en-IN',
converterOptions: exports.DefaultConverterOptions,
};
class ToWords {
constructor(options = {}) {
this.options = {};
this.locale = undefined;
this.options = Object.assign({}, exports.DefaultToWordsOptions, options);
}
getLocaleClass() {
/* eslint-disable @typescript-eslint/no-var-requires */
switch (this.options.localeCode) {
case 'ee-EE':
return ee_EE_1.default;
case 'en-AE':
return en_AE_1.default;
case 'en-BD':
return en_BD_1.default;
case 'en-GH':
return en_GH_1.default;
case 'en-IN':
return en_IN_1.default;
case 'en-MM':
return en_MM_1.default;
case 'en-MU':
return en_MU_1.default;
case 'en-NG':
return en_NG_1.default;
case 'en-NP':
return en_NP_1.default;
case 'en-US':
return en_US_1.default;
case 'en-GB':
return en_GB_1.default;
case 'fa-IR':
return fa_IR_1.default;
case 'fr-FR':
return fr_FR_1.default;
case 'gu-IN':
return gu_IN_1.default;
case 'hi-IN':
return hi_IN_1.default;
case 'mr-IN':
return mr_IN_1.default;
case 'pt-BR':
return pt_BR_1.default;
case 'tr-TR':
return tr_TR_1.default;
case 'nl-SR':
return nl_SR_1.default;
}
/* eslint-enable @typescript-eslint/no-var-requires */
throw new Error(`Unknown Locale "${this.options.localeCode}"`);
}
getLocale() {
if (this.locale === undefined) {
const LocaleClass = this.getLocaleClass();
this.locale = new LocaleClass();
}
return this.locale;
}
convert(number, options = {}) {
options = Object.assign({}, this.options.converterOptions, options);
if (!this.isValidNumber(number)) {
throw new Error(`Invalid Number "${number}"`);
}
if (options.ignoreDecimal) {
number = Number.parseInt(number.toString());
}
let words = [];
if (options.currency) {
words = this.convertCurrency(number, options);
}
else {
words = this.convertNumber(number);
}
return words.join(' ');
}
convertNumber(number) {
var _a, _b, _c;
const locale = this.getLocale();
const isNegativeNumber = number < 0;
if (isNegativeNumber) {
number = Math.abs(number);
}
const split = number.toString().split('.');
const ignoreZero = this.isNumberZero(number) && locale.config.ignoreZeroInDecimals;
let words = this.convertInternal(Number(split[0]));
const isFloat = this.isFloat(number);
if (isFloat && ignoreZero) {
words = [];
}
const wordsWithDecimal = [];
if (isFloat) {
if (!ignoreZero) {
wordsWithDecimal.push(locale.config.texts.point);
}
if (split[1].startsWith('0') && !((_a = locale.config) === null || _a === void 0 ? void 0 : _a.decimalLengthWordMapping)) {
const zeroWords = [];
for (const num of split[1]) {
zeroWords.push(...this.convertInternal(Number(num)));
}
wordsWithDecimal.push(...zeroWords);
}
else {
wordsWithDecimal.push(...this.convertInternal(Number(split[1])));
const decimalLengthWord = (_c = (_b = locale.config) === null || _b === void 0 ? void 0 : _b.decimalLengthWordMapping) === null || _c === void 0 ? void 0 : _c[split[1].length];
if (decimalLengthWord) {
wordsWithDecimal.push(decimalLengthWord);
}
}
}
const isEmpty = words.length <= 0;
if (!isEmpty && isNegativeNumber) {
words.unshift(locale.config.texts.minus);
}
words.push(...wordsWithDecimal);
return words;
}
convertCurrency(number, options = {}) {
var _a, _b, _c, _d;
const locale = this.getLocale();
const currencyOptions = (_a = options.currencyOptions) !== null && _a !== void 0 ? _a : locale.config.currency;
const isNegativeNumber = number < 0;
if (isNegativeNumber) {
number = Math.abs(number);
}
number = this.toFixed(number);
// Extra check for isFloat to overcome 1.999 rounding off to 2
const split = number.toString().split('.');
let words = [...this.convertInternal(Number(split[0]))];
if (currencyOptions.plural) {
words.push(currencyOptions.plural);
}
const ignoreZero = this.isNumberZero(number) &&
(options.ignoreZeroCurrency || (((_b = locale.config) === null || _b === void 0 ? void 0 : _b.ignoreZeroInDecimals) && number !== 0));
if (ignoreZero) {
words = [];
}
const wordsWithDecimal = [];
const isFloat = this.isFloat(number);
if (isFloat) {
if (!ignoreZero) {
wordsWithDecimal.push(locale.config.texts.and);
}
wordsWithDecimal.push(...this.convertInternal(Number(split[1]) * (!locale.config.decimalLengthWordMapping ? Math.pow(10, 2 - split[1].length) : 1)));
const decimalLengthWord = (_d = (_c = locale.config) === null || _c === void 0 ? void 0 : _c.decimalLengthWordMapping) === null || _d === void 0 ? void 0 : _d[split[1].length];
if (decimalLengthWord === null || decimalLengthWord === void 0 ? void 0 : decimalLengthWord.length) {
wordsWithDecimal.push(decimalLengthWord);
}
wordsWithDecimal.push(currencyOptions.fractionalUnit.plural);
}
else if (locale.config.decimalLengthWordMapping && words.length) {
wordsWithDecimal.push(currencyOptions.fractionalUnit.plural);
}
const isEmpty = words.length <= 0 && wordsWithDecimal.length <= 0;
if (!isEmpty && isNegativeNumber) {
words.unshift(locale.config.texts.minus);
}
if (!isEmpty && locale.config.texts.only && !options.doNotAddOnly && !locale.config.onlyInFront) {
wordsWithDecimal.push(locale.config.texts.only);
}
if (wordsWithDecimal.length) {
words.push(...wordsWithDecimal);
}
if (!isEmpty && !options.doNotAddOnly && locale.config.onlyInFront) {
words.splice(0, 0, locale.config.texts.only);
}
return words;
}
convertInternal(number) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
const locale = this.getLocale();
if (locale.config.exactWordsMapping) {
const exactMatch = (_b = (_a = locale.config) === null || _a === void 0 ? void 0 : _a.exactWordsMapping) === null || _b === void 0 ? void 0 : _b.find((elem) => {
return number === elem.number;
});
if (exactMatch) {
return [exactMatch.value];
}
}
const match = locale.config.numberWordsMapping.find((elem) => {
return number >= elem.number;
});
const words = [];
if (number <= 100 || (number < 1000 && locale.config.namedLessThan1000)) {
words.push(match.value);
number -= match.number;
if (number > 0) {
if ((_d = (_c = locale.config) === null || _c === void 0 ? void 0 : _c.splitWord) === null || _d === void 0 ? void 0 : _d.length) {
words.push(locale.config.splitWord);
}
words.push(...this.convertInternal(number));
}
return words;
}
const quotient = Math.floor(number / match.number);
const remainder = number % match.number;
let matchValue = match.value;
if (quotient > 1 && ((_f = (_e = locale.config) === null || _e === void 0 ? void 0 : _e.pluralWords) === null || _f === void 0 ? void 0 : _f.find((word) => word === match.value)) && ((_g = locale.config) === null || _g === void 0 ? void 0 : _g.pluralMark)) {
matchValue += locale.config.pluralMark;
}
if (quotient === 1 && ((_j = (_h = locale.config) === null || _h === void 0 ? void 0 : _h.ignoreOneForWords) === null || _j === void 0 ? void 0 : _j.includes(matchValue))) {
words.push(matchValue);
}
else {
words.push(...this.convertInternal(quotient), matchValue);
}
if (remainder > 0) {
if ((_l = (_k = locale.config) === null || _k === void 0 ? void 0 : _k.splitWord) === null || _l === void 0 ? void 0 : _l.length) {
if (!((_o = (_m = locale.config) === null || _m === void 0 ? void 0 : _m.noSplitWordAfter) === null || _o === void 0 ? void 0 : _o.find((word) => word === match.value))) {
words.push(locale.config.splitWord);
}
}
words.push(...this.convertInternal(remainder));
}
return words;
}
toFixed(number, precision = 2) {
return Number(Number(number).toFixed(precision));
}
isFloat(number) {
return Number(number) === number && number % 1 !== 0;
}
isValidNumber(number) {
return !isNaN(parseFloat(number)) && isFinite(number);
}
isNumberZero(number) {
return number >= 0 && number < 1;
}
}
exports.ToWords = ToWords;