UNPKG

@gratcy/angka-terbilang-indonesia

Version:

Angka Terbilang in NodeJS for Converting Decimal to an Indonesian Wording format

248 lines (239 loc) 7.59 kB
// Definisi Array Angka dan Satuan type LangKey = 'id' | 'en'; interface LangArr { [key: string]: { angka: string[]; satuan: string[]; sepuluh: string; sebelas: string; belas: string; seratus: string; seribu: string; puluh: string; ratus: string; nol: string; koma: string; two?: string; three?: string; four?: string; five?: string; six?: string; seven?: string; eight?: string; nine?: string; duabelas?: string; tigabelas?: string; }; } const langArr: LangArr = { id: { angka: ['', 'satu', 'dua', 'tiga', 'empat', 'lima', 'enam', 'tujuh', 'delapan', 'sembilan'], satuan: ['', 'ribu', 'juta', 'milyar', 'triliun', 'quadriliun', 'quintiliun', 'sextiliun', 'septiliun', 'oktiliun', 'noniliun', 'desiliun', 'undesiliun', 'duodesiliun', 'tredesiliun', 'quattuordesiliun', 'quindesiliun', 'sexdesiliun', 'septendesiliun', 'oktodesiliun', 'novemdesiliun', 'vigintiliun'], sepuluh: 'sepuluh', sebelas: 'sebelas', belas: 'belas', seratus: 'seratus', seribu: 'seribu', puluh: 'puluh', ratus: 'ratus', nol: 'nol', koma: 'koma', }, en: { angka: ['', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'], satuan: ['', 'thousand', 'million', 'billion', 'trillion', 'quadrillion', 'quintillion', 'sextillion', 'septillion', 'octillion', 'nonillion', 'decillion', 'undecillion', 'duodecillion', 'tredecilion', 'quattuordecilion', 'quindecilion', 'sexdecilion', 'septendecilion', 'octodecilion', 'novemdesiliun', 'vigintillion'], sepuluh: 'ten', sebelas: 'eleven', belas: 'teen', seratus: 'one hundred', seribu: 'one thousand', puluh: 'ty', ratus: 'hundred', nol: 'zero', koma: 'and', two: 'twen', three: 'thir', four: 'for', five: 'fif', six: 'six', seven: 'seven', eight: 'eight', nine: 'nine', duabelas: 'twelve', tigabelas: 'thirteen', }, }; interface ToTerbilangConfig { dec?: string; lang?: LangKey; } let arrAngka: string[] = langArr.id.angka; let arrSatuan: string[] = langArr.id.satuan; let lang: LangKey = 'id'; export function toTerbilang(strAngka: string | number, config: ToTerbilangConfig = { dec: '.', lang: 'id' }): string { strAngka = String(strAngka); const angkaArr = strAngka.split(config.dec || '.'); if (config.lang === 'en') { arrAngka = langArr.en.angka; arrSatuan = langArr.en.satuan; lang = 'en'; } else { arrAngka = langArr.id.angka; arrSatuan = langArr.id.satuan; lang = 'id'; } let strA = ''; for (let i = 0; i < angkaArr.length; ++i) { if (i === 1) { strA += ` ${langArr[lang].koma} ` + terbilangDecimal(angkaArr[i]); } else { strA += terbilang(angkaArr[i]); } } return strA.trim(); } function replaceString(str: string, rep: string): string { return str.replace(rep, ''); } function terbilangDecimal(strAngka: string): string { let angkaArr = strAngka.split('') let str = '' for (let i = 0; i < angkaArr.length; ++i) { if (angkaArr[i] === '0') { str += ' ' + langArr[lang].nol } else { str += ' ' + langArr[lang].angka[parseInt(angkaArr[i])] } } return str.trim() } function terbilang(strAngka: string): string { if (isNaN(Number(strAngka))) { return 'Error, input is not a valid number!'; } const lenAngka = strAngka.length - 1; if (lenAngka === 0 && Number(strAngka[0]) === 0) { return langArr[lang].nol; } if (lenAngka / 3 > arrSatuan.length) { return 'Error, number is to big!'; } let resTerbilang = ''; let cntZero = 0; for (let i = 0; i <= lenAngka; i++) { let tmpTerbilang = ''; let posDigit = lenAngka - i; let grpDigit = posDigit % 3; let intAngka = Number(strAngka[i]); switch (intAngka) { case 1: switch (grpDigit) { case 2: tmpTerbilang += langArr[lang].seratus; break; case 1: { let nextIntAngka = Number(strAngka[i + 1]); switch (nextIntAngka) { case 1: tmpTerbilang += langArr[lang].sebelas; break; case 0: tmpTerbilang += langArr[lang].sepuluh; break; default: if (lang === 'en') { if (arrAngka[nextIntAngka] === 'two') { tmpTerbilang += langArr[lang].duabelas; } else if (arrAngka[nextIntAngka] === 'three') { tmpTerbilang += langArr[lang].tigabelas; } else { // Type-safe teen prefix lookup const teenPrefixes: Record<string, string | undefined> = { one: '', two: langArr[lang].two, three: langArr[lang].three, four: langArr[lang].four, five: langArr[lang].five, six: langArr[lang].six, seven: langArr[lang].seven, eight: langArr[lang].eight, nine: langArr[lang].nine, }; const prefix = teenPrefixes[arrAngka[nextIntAngka]] ?? ''; tmpTerbilang += prefix + langArr[lang].belas; } } else { tmpTerbilang += arrAngka[nextIntAngka] + ` ${langArr[lang].belas}`; } break; } i++; posDigit--; grpDigit--; break; } case 0: if ((intAngka === 1 && posDigit === 3) && (cntZero === 2 || lenAngka === 3)) { if (resTerbilang !== '') { resTerbilang += ' '; } resTerbilang += langArr[lang].seribu; cntZero = 0; continue; } else { tmpTerbilang += arrAngka[intAngka]; } break; } break; case 0: cntZero++; break; default: tmpTerbilang += arrAngka[intAngka]; switch (grpDigit) { case 2: tmpTerbilang += ` ${langArr[lang].ratus}`; break; case 1: if (lang === 'en') { // Type-safe puluh prefix lookup const puluhPrefixes: Record<string, string | undefined> = { one: '', two: langArr[lang].two, three: langArr[lang].three, four: langArr[lang].four, five: langArr[lang].five, six: langArr[lang].six, seven: langArr[lang].seven, eight: langArr[lang].eight, nine: langArr[lang].nine, }; const prefix = puluhPrefixes[arrAngka[intAngka]] ?? ''; tmpTerbilang += prefix + langArr[lang].puluh; tmpTerbilang = replaceString(tmpTerbilang, arrAngka[intAngka]); } else { tmpTerbilang += ` ${langArr[lang].puluh}`; } break; } break; } if (tmpTerbilang !== '') { if (resTerbilang !== '') { resTerbilang += ' ' + tmpTerbilang; } else { resTerbilang += tmpTerbilang; } } let posSatuan = posDigit / 3; if (grpDigit === 0 && posSatuan !== 0) { if (cntZero !== 3) { resTerbilang += ' ' + arrSatuan[posSatuan]; } cntZero = 0; } } return resTerbilang; } export default toTerbilang;