n2words
Version:
n2words converts a numerical number into a written one, supports 28 languages and has zero dependencies.
157 lines (142 loc) • 4.13 kB
JavaScript
import AbstractLanguage from '../classes/abstract-language.js';
export class N2WordsID extends AbstractLanguage {
base = {
0: [],
1: ['satu'],
2: ['dua'],
3: ['tiga'],
4: ['empat'],
5: ['lima'],
6: ['enam'],
7: ['tujuh'],
8: ['delapan'],
9: ['sembilan'],
};
thousands = {
3: 'ribu', // 10^3
6: 'juta', // 10^6
9: 'miliar', // 10^9
12: 'triliun',
15: 'kuadriliun',
18: 'kuantiliun',
21: 'sekstiliun',
24: 'septiliun',
27: 'oktiliun',
30: 'noniliun',
33: 'desiliun',
};
constructor(options) {
options = Object.assign({
negativeWord: 'min',
separatorWord: 'koma',
zero: 'nol'
}, options);
super(options);
}
splitBy3(number) {
// Split to groups of 3 numbers: 1234567 -> [['1'], ['234'], ['567']]
let blocks = [];
let stringNumber = number.toString();
let length = stringNumber.length;
let firstBlock;
if (length < 3) {
blocks.push([stringNumber]);
} else {
let firstBlockLength = length % 3;
if (firstBlockLength > 0) {
firstBlock = [stringNumber.slice(0, firstBlockLength)];
blocks.push(firstBlock);
}
for (let index = firstBlockLength; index < length; index += 3) {
let nextBlock = [stringNumber.slice(index, index + 3)];
blocks.push(nextBlock);
}
}
return blocks;
}
spell(blocks) {
// Example:
// blocks: [['1'], ['234']]
// return: [['1', ['satu']], ['234', ['dua', 'ratus', 'tiga', 'puluh', ['empat']]]]
let wordBlocks = [];
let spelling;
let firstBlock = blocks[0];
if (firstBlock[0].length == 1) {
spelling = firstBlock[0] == '0' ? ['nol'] : this.base[Math.trunc(firstBlock[0])];
} else if (firstBlock[0].length == 2) {
spelling = this.getTens(firstBlock[0]);
} else {
spelling = [...this.getHundreds(firstBlock[0][0]), ...this.getTens(firstBlock[0].slice(1, 3))];
}
wordBlocks = [...wordBlocks, [firstBlock[0], spelling]];
for (let index = 1; index < blocks.length; index++) {
let block = blocks[index];
spelling = [...this.getHundreds(block[0][0]), ...this.getTens(block[0].slice(1, 3))];
block = [...block, spelling];
wordBlocks = [...wordBlocks, block];
}
return wordBlocks;
}
getHundreds(number) { // 'ratus'
if (number == '1') {
return ['seratus'];
} else if (number == '0') {
return [];
} else {
return [...this.base[Math.trunc(number)], 'ratus'];
}
}
getTens(number) { // 'puluh'
if (number[0] == '1') {
if (number[1] == '0') {
return ['sepuluh'];
} else if (number[1] == '1') {
return ['sebelas'];
} else {
return [...this.base[Math.trunc(number[1])], 'belas'];
}
} else if (number[0] == '0') {
return this.base[Math.trunc(number[1])];
} else {
return [...this.base[Math.trunc(number[0])], 'puluh', this.base[Math.trunc(number[1])]];
}
}
join(wordBlocks) {
let wordList = [];
let length = wordBlocks.length - 1;
let firstBlock = [wordBlocks[0]];
let start = 0;
if (length == 1 && firstBlock[0][0] == '1') {
wordList.push('seribu');
start = 1;
}
for (let index = start; index < length + 1; index++) {
wordList = [...wordList, ...wordBlocks[index][1]];
if (wordBlocks[index][1].length === 0) {
continue;
}
if (index == length) {
break;
}
wordList = [...wordList, this.thousands[(length - index) * 3]];
}
return wordList.join(' ');
}
toCardinal(number) {
return this.join(
this.spell(
this.splitBy3(number)
)
).trim();
}
}
/**
* Converts a value to cardinal (written) form.
* @param {number|string|bigint} value Number to be convert.
* @param {object} [options] Options for class.
* @returns {string} Value in cardinal (written) format.
* @throws {Error} Value cannot be invalid.
*/
export default function floatToCardinal (value, options = {}) {
return new N2WordsID(options).floatToCardinal(value);
}