n2words 1.24.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +49 -0
- package/README.md +183 -156
- package/dist/languages/am-Latn.js +3 -0
- package/dist/languages/am-Latn.js.map +1 -0
- package/dist/languages/am.js +3 -0
- package/dist/languages/am.js.map +1 -0
- package/dist/languages/ar.js +3 -2
- package/dist/languages/ar.js.map +1 -1
- package/dist/languages/az.js +3 -2
- package/dist/languages/az.js.map +1 -1
- package/dist/languages/bn.js +3 -2
- package/dist/languages/bn.js.map +1 -1
- package/dist/languages/cs.js +3 -2
- package/dist/languages/cs.js.map +1 -1
- package/dist/languages/da.js +3 -2
- package/dist/languages/da.js.map +1 -1
- package/dist/languages/de.js +3 -2
- package/dist/languages/de.js.map +1 -1
- package/dist/languages/el.js +3 -2
- package/dist/languages/el.js.map +1 -1
- package/dist/languages/en.js +3 -2
- package/dist/languages/en.js.map +1 -1
- package/dist/languages/es.js +3 -2
- package/dist/languages/es.js.map +1 -1
- package/dist/languages/fa.js +3 -2
- package/dist/languages/fa.js.map +1 -1
- package/dist/languages/fi.js +3 -0
- package/dist/languages/fi.js.map +1 -0
- package/dist/languages/fil.js +3 -2
- package/dist/languages/fil.js.map +1 -1
- package/dist/languages/fr-BE.js +3 -2
- package/dist/languages/fr-BE.js.map +1 -1
- package/dist/languages/fr.js +3 -2
- package/dist/languages/fr.js.map +1 -1
- package/dist/languages/gu.js +3 -2
- package/dist/languages/gu.js.map +1 -1
- package/dist/languages/ha.js +3 -0
- package/dist/languages/ha.js.map +1 -0
- package/dist/languages/hbo.js +3 -0
- package/dist/languages/hbo.js.map +1 -0
- package/dist/languages/he.js +3 -2
- package/dist/languages/he.js.map +1 -1
- package/dist/languages/hi.js +3 -2
- package/dist/languages/hi.js.map +1 -1
- package/dist/languages/hr.js +3 -2
- package/dist/languages/hr.js.map +1 -1
- package/dist/languages/hu.js +3 -2
- package/dist/languages/hu.js.map +1 -1
- package/dist/languages/id.js +3 -2
- package/dist/languages/id.js.map +1 -1
- package/dist/languages/it.js +3 -2
- package/dist/languages/it.js.map +1 -1
- package/dist/languages/ja.js +3 -2
- package/dist/languages/ja.js.map +1 -1
- package/dist/languages/kn.js +3 -2
- package/dist/languages/kn.js.map +1 -1
- package/dist/languages/ko.js +3 -2
- package/dist/languages/ko.js.map +1 -1
- package/dist/languages/lt.js +3 -2
- package/dist/languages/lt.js.map +1 -1
- package/dist/languages/lv.js +3 -2
- package/dist/languages/lv.js.map +1 -1
- package/dist/languages/mr.js +3 -2
- package/dist/languages/mr.js.map +1 -1
- package/dist/languages/ms.js +3 -2
- package/dist/languages/ms.js.map +1 -1
- package/dist/languages/nb.js +3 -2
- package/dist/languages/nb.js.map +1 -1
- package/dist/languages/nl.js +3 -2
- package/dist/languages/nl.js.map +1 -1
- package/dist/languages/pa.js +3 -0
- package/dist/languages/pa.js.map +1 -0
- package/dist/languages/pl.js +3 -2
- package/dist/languages/pl.js.map +1 -1
- package/dist/languages/pt.js +3 -2
- package/dist/languages/pt.js.map +1 -1
- package/dist/languages/ro.js +3 -2
- package/dist/languages/ro.js.map +1 -1
- package/dist/languages/ru.js +3 -2
- package/dist/languages/ru.js.map +1 -1
- package/dist/languages/sr-Cyrl.js +3 -0
- package/dist/languages/sr-Cyrl.js.map +1 -0
- package/dist/languages/sr-Latn.js +3 -2
- package/dist/languages/sr-Latn.js.map +1 -1
- package/dist/languages/sv.js +3 -2
- package/dist/languages/sv.js.map +1 -1
- package/dist/languages/sw.js +3 -2
- package/dist/languages/sw.js.map +1 -1
- package/dist/languages/ta.js +3 -2
- package/dist/languages/ta.js.map +1 -1
- package/dist/languages/te.js +3 -2
- package/dist/languages/te.js.map +1 -1
- package/dist/languages/th.js +3 -2
- package/dist/languages/th.js.map +1 -1
- package/dist/languages/tr.js +3 -2
- package/dist/languages/tr.js.map +1 -1
- package/dist/languages/uk.js +3 -2
- package/dist/languages/uk.js.map +1 -1
- package/dist/languages/ur.js +3 -2
- package/dist/languages/ur.js.map +1 -1
- package/dist/languages/vi.js +3 -2
- package/dist/languages/vi.js.map +1 -1
- package/dist/languages/zh-Hans.js +3 -2
- package/dist/languages/zh-Hans.js.map +1 -1
- package/dist/languages/zh-Hant.js +3 -0
- package/dist/languages/zh-Hant.js.map +1 -0
- package/dist/n2words.js +3 -2
- package/dist/n2words.js.map +1 -1
- package/lib/languages/am-Latn.d.ts +7 -0
- package/lib/languages/am-Latn.js +164 -0
- package/lib/languages/am.d.ts +7 -0
- package/lib/languages/am.js +164 -0
- package/lib/languages/ar.d.ts +17 -0
- package/lib/languages/ar.js +171 -209
- package/lib/languages/az.d.ts +7 -0
- package/lib/languages/az.js +167 -49
- package/lib/languages/bn.d.ts +7 -0
- package/lib/languages/bn.js +142 -123
- package/lib/languages/cs.d.ts +18 -0
- package/lib/languages/cs.js +303 -176
- package/lib/languages/da.d.ts +14 -0
- package/lib/languages/da.js +267 -139
- package/lib/languages/de.d.ts +17 -0
- package/lib/languages/de.js +310 -113
- package/lib/languages/el.d.ts +14 -0
- package/lib/languages/el.js +225 -98
- package/lib/languages/en.d.ts +17 -0
- package/lib/languages/en.js +235 -102
- package/lib/languages/es.d.ts +21 -0
- package/lib/languages/es.js +307 -125
- package/lib/languages/fa.d.ts +7 -0
- package/lib/languages/fa.js +115 -108
- package/lib/languages/fi.d.ts +14 -0
- package/lib/languages/fi.js +245 -0
- package/lib/languages/fil.d.ts +7 -0
- package/lib/languages/fil.js +199 -139
- package/lib/languages/fr-BE.d.ts +11 -0
- package/lib/languages/fr-BE.js +287 -48
- package/lib/languages/fr.d.ts +21 -0
- package/lib/languages/fr.js +343 -119
- package/lib/languages/gu.d.ts +7 -0
- package/lib/languages/gu.js +125 -144
- package/lib/languages/ha.d.ts +7 -0
- package/lib/languages/ha.js +230 -0
- package/lib/languages/hbo.d.ts +13 -0
- package/lib/languages/hbo.js +300 -0
- package/lib/languages/he.d.ts +13 -0
- package/lib/languages/he.js +230 -283
- package/lib/languages/hi.d.ts +7 -0
- package/lib/languages/hi.js +142 -123
- package/lib/languages/hr.d.ts +11 -0
- package/lib/languages/hr.js +190 -129
- package/lib/languages/hu.d.ts +7 -0
- package/lib/languages/hu.js +194 -133
- package/lib/languages/id.d.ts +7 -0
- package/lib/languages/id.js +167 -140
- package/lib/languages/it.d.ts +19 -0
- package/lib/languages/it.js +337 -108
- package/lib/languages/ja.d.ts +17 -0
- package/lib/languages/ja.js +224 -155
- package/lib/languages/kn.d.ts +7 -0
- package/lib/languages/kn.js +128 -62
- package/lib/languages/ko.d.ts +14 -0
- package/lib/languages/ko.js +250 -70
- package/lib/languages/lt.d.ts +18 -0
- package/lib/languages/lt.js +287 -148
- package/lib/languages/lv.d.ts +18 -0
- package/lib/languages/lv.js +291 -123
- package/lib/languages/mr.d.ts +7 -0
- package/lib/languages/mr.js +125 -144
- package/lib/languages/ms.d.ts +7 -0
- package/lib/languages/ms.js +171 -112
- package/lib/languages/nb.d.ts +14 -0
- package/lib/languages/nb.js +275 -100
- package/lib/languages/nl.d.ts +26 -0
- package/lib/languages/nl.js +307 -174
- package/lib/languages/pa.d.ts +7 -0
- package/lib/languages/pa.js +163 -0
- package/lib/languages/pl.d.ts +22 -0
- package/lib/languages/pl.js +299 -158
- package/lib/languages/pt.d.ts +17 -0
- package/lib/languages/pt.js +279 -120
- package/lib/languages/ro.d.ts +18 -0
- package/lib/languages/ro.js +214 -337
- package/lib/languages/ru.d.ts +11 -0
- package/lib/languages/ru.js +219 -95
- package/lib/languages/sr-Cyrl.d.ts +11 -0
- package/lib/languages/sr-Cyrl.js +215 -0
- package/lib/languages/sr-Latn.d.ts +11 -0
- package/lib/languages/sr-Latn.js +190 -132
- package/lib/languages/sv.d.ts +14 -0
- package/lib/languages/sv.js +280 -103
- package/lib/languages/sw.d.ts +7 -0
- package/lib/languages/sw.js +135 -103
- package/lib/languages/ta.d.ts +7 -0
- package/lib/languages/ta.js +133 -205
- package/lib/languages/te.d.ts +7 -0
- package/lib/languages/te.js +148 -213
- package/lib/languages/th.d.ts +7 -0
- package/lib/languages/th.js +139 -101
- package/lib/languages/tr.d.ts +18 -0
- package/lib/languages/tr.js +246 -66
- package/lib/languages/uk.d.ts +11 -0
- package/lib/languages/uk.js +197 -101
- package/lib/languages/ur.d.ts +7 -0
- package/lib/languages/ur.js +160 -123
- package/lib/languages/vi.d.ts +17 -0
- package/lib/languages/vi.js +287 -164
- package/lib/languages/zh-Hans.d.ts +11 -0
- package/lib/languages/zh-Hans.js +159 -142
- package/lib/languages/zh-Hant.d.ts +11 -0
- package/lib/languages/zh-Hant.js +202 -0
- package/lib/n2words.d.ts +53 -0
- package/lib/n2words.js +91 -227
- package/lib/utils/is-plain-object.d.ts +13 -0
- package/lib/utils/is-plain-object.js +17 -0
- package/lib/utils/parse-numeric.d.ts +17 -0
- package/lib/utils/parse-numeric.js +108 -0
- package/lib/utils/validate-options.d.ts +8 -0
- package/lib/utils/validate-options.js +16 -0
- package/package.json +118 -67
- package/dist/languages/pa-Guru.js +0 -2
- package/dist/languages/pa-Guru.js.map +0 -1
- package/lib/classes/abstract-language.js +0 -261
- package/lib/classes/greedy-scale-language.js +0 -195
- package/lib/classes/slavic-language.js +0 -251
- package/lib/classes/south-asian-language.js +0 -161
- package/lib/classes/turkic-language.js +0 -63
- package/lib/languages/pa-Guru.js +0 -126
- package/typings/classes/abstract-language.d.ts +0 -144
- package/typings/classes/greedy-scale-language.d.ts +0 -148
- package/typings/classes/slavic-language.d.ts +0 -145
- package/typings/classes/south-asian-language.d.ts +0 -101
- package/typings/classes/turkic-language.d.ts +0 -42
- package/typings/languages/ar.d.ts +0 -93
- package/typings/languages/az.d.ts +0 -25
- package/typings/languages/bn.d.ts +0 -1
- package/typings/languages/cs.d.ts +0 -120
- package/typings/languages/da.d.ts +0 -53
- package/typings/languages/de.d.ts +0 -26
- package/typings/languages/el.d.ts +0 -11
- package/typings/languages/en.d.ts +0 -30
- package/typings/languages/es.d.ts +0 -43
- package/typings/languages/fa.d.ts +0 -81
- package/typings/languages/fil.d.ts +0 -12
- package/typings/languages/fr-BE.d.ts +0 -41
- package/typings/languages/fr.d.ts +0 -43
- package/typings/languages/gu.d.ts +0 -12
- package/typings/languages/he.d.ts +0 -197
- package/typings/languages/hi.d.ts +0 -1
- package/typings/languages/hr.d.ts +0 -110
- package/typings/languages/hu.d.ts +0 -37
- package/typings/languages/id.d.ts +0 -69
- package/typings/languages/it.d.ts +0 -51
- package/typings/languages/ja.d.ts +0 -58
- package/typings/languages/kn.d.ts +0 -11
- package/typings/languages/ko.d.ts +0 -25
- package/typings/languages/lt.d.ts +0 -110
- package/typings/languages/lv.d.ts +0 -99
- package/typings/languages/mr.d.ts +0 -12
- package/typings/languages/ms.d.ts +0 -37
- package/typings/languages/nb.d.ts +0 -27
- package/typings/languages/nl.d.ts +0 -65
- package/typings/languages/pa-Guru.d.ts +0 -1
- package/typings/languages/pl.d.ts +0 -116
- package/typings/languages/pt.d.ts +0 -39
- package/typings/languages/ro.d.ts +0 -229
- package/typings/languages/ru.d.ts +0 -108
- package/typings/languages/sr-Latn.d.ts +0 -98
- package/typings/languages/sv.d.ts +0 -30
- package/typings/languages/sw.d.ts +0 -1
- package/typings/languages/ta.d.ts +0 -1
- package/typings/languages/te.d.ts +0 -1
- package/typings/languages/th.d.ts +0 -1
- package/typings/languages/tr.d.ts +0 -46
- package/typings/languages/uk.d.ts +0 -117
- package/typings/languages/ur.d.ts +0 -1
- package/typings/languages/vi.d.ts +0 -116
- package/typings/languages/zh-Hans.d.ts +0 -57
- package/typings/n2words.d.ts +0 -177
package/lib/languages/id.js
CHANGED
|
@@ -1,174 +1,201 @@
|
|
|
1
|
-
import AbstractLanguage from '../classes/abstract-language.js'
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
|
-
* Indonesian language converter
|
|
5
|
-
*
|
|
6
|
-
* Converts numbers to Indonesian words following Indonesian conventions:
|
|
7
|
-
* - Simple base-10 structure
|
|
8
|
-
* - "Se-" prefix for one (e.g., "seratus" = one hundred, "seribu" = one thousand)
|
|
9
|
-
* - Space-separated number components
|
|
10
|
-
* - Straightforward grouping by thousands
|
|
2
|
+
* Indonesian language converter - Functional Implementation
|
|
11
3
|
*
|
|
12
|
-
*
|
|
13
|
-
* - Base number mapping (base) for single digits 0-9
|
|
14
|
-
* - Magnitude scale (thousands) mapping powers of 10 to Indonesian words
|
|
15
|
-
* - Group-based algorithm:
|
|
16
|
-
* 1. Split number into groups of 3 digits
|
|
17
|
-
* 2. For each group, convert ones/tens/hundreds using base and naming rules
|
|
18
|
-
* 3. Apply "se-" prefix for 1 (seratus, seribu, sejuta)
|
|
19
|
-
* 4. Combine with magnitude words
|
|
20
|
-
* 5. Join all parts with spaces
|
|
21
|
-
* - Regular patterns (puluh for tens, ratus for hundreds, ribu for thousands)
|
|
22
|
-
* - Clear grouping: ribu (10³), juta (10⁶), miliar (10⁹), triliun (10¹²)
|
|
4
|
+
* Self-contained converter with precomputed lookup tables.
|
|
23
5
|
*
|
|
24
|
-
*
|
|
25
|
-
* - "Se-" prefix
|
|
26
|
-
* -
|
|
6
|
+
* Key features:
|
|
7
|
+
* - "Se-" prefix for 100 (seratus) and 1000 (seribu)
|
|
8
|
+
* - Regular patterns (puluh for tens, ratus for hundreds)
|
|
9
|
+
* - Teens with "belas" suffix
|
|
10
|
+
* - Indonesian uses "satu juta" (not "sejuta") for millions+
|
|
27
11
|
*/
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
12
|
+
|
|
13
|
+
import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
14
|
+
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// Vocabulary
|
|
17
|
+
// ============================================================================
|
|
18
|
+
|
|
19
|
+
const ONES = ['', 'satu', 'dua', 'tiga', 'empat', 'lima', 'enam', 'tujuh', 'delapan', 'sembilan']
|
|
20
|
+
const TEENS = ['sepuluh', 'sebelas', 'dua belas', 'tiga belas', 'empat belas', 'lima belas', 'enam belas', 'tujuh belas', 'delapan belas', 'sembilan belas']
|
|
21
|
+
const TENS = ['', '', 'dua puluh', 'tiga puluh', 'empat puluh', 'lima puluh', 'enam puluh', 'tujuh puluh', 'delapan puluh', 'sembilan puluh']
|
|
22
|
+
|
|
23
|
+
const HUNDRED_WORD = 'ratus'
|
|
24
|
+
const THOUSAND_WORD = 'ribu'
|
|
25
|
+
const SCALE_WORDS = ['juta', 'miliar', 'triliun', 'kuadriliun', 'kuantiliun', 'sekstiliun', 'septiliun', 'oktiliun', 'noniliun', 'desiliun']
|
|
26
|
+
|
|
27
|
+
const ZERO = 'nol'
|
|
28
|
+
const NEGATIVE = 'min'
|
|
29
|
+
const DECIMAL_SEP = 'koma'
|
|
30
|
+
|
|
31
|
+
// ============================================================================
|
|
32
|
+
// Precomputed Lookup Tables
|
|
33
|
+
// ============================================================================
|
|
34
|
+
|
|
35
|
+
function buildSegment (n) {
|
|
36
|
+
if (n === 0) return ''
|
|
37
|
+
|
|
38
|
+
const onesDigit = n % 10
|
|
39
|
+
const tensDigit = Math.floor(n / 10) % 10
|
|
40
|
+
const hundredsDigit = Math.floor(n / 100)
|
|
41
|
+
|
|
42
|
+
const parts = []
|
|
43
|
+
|
|
44
|
+
// Hundreds: seratus (100) or N ratus (200-900)
|
|
45
|
+
if (hundredsDigit > 0) {
|
|
46
|
+
if (hundredsDigit === 1) {
|
|
47
|
+
parts.push('se' + HUNDRED_WORD)
|
|
48
|
+
} else {
|
|
49
|
+
parts.push(ONES[hundredsDigit] + ' ' + HUNDRED_WORD)
|
|
50
|
+
}
|
|
43
51
|
}
|
|
44
52
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
// Tens and ones
|
|
54
|
+
const tensOnes = n % 100
|
|
55
|
+
|
|
56
|
+
if (tensOnes === 0) {
|
|
57
|
+
// Just hundreds
|
|
58
|
+
} else if (tensOnes < 10) {
|
|
59
|
+
parts.push(ONES[tensOnes])
|
|
60
|
+
} else if (tensOnes < 20) {
|
|
61
|
+
parts.push(TEENS[tensOnes - 10])
|
|
62
|
+
} else if (onesDigit === 0) {
|
|
63
|
+
parts.push(TENS[tensDigit])
|
|
64
|
+
} else {
|
|
65
|
+
parts.push(TENS[tensDigit] + ' ' + ONES[onesDigit])
|
|
57
66
|
}
|
|
58
67
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const blocks = []
|
|
62
|
-
const stringNumber = number.toString()
|
|
63
|
-
const length = stringNumber.length
|
|
64
|
-
let firstBlock
|
|
68
|
+
return parts.join(' ')
|
|
69
|
+
}
|
|
65
70
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
const SEGMENTS = new Array(1000)
|
|
72
|
+
for (let i = 0; i < 1000; i++) {
|
|
73
|
+
SEGMENTS[i] = buildSegment(i)
|
|
74
|
+
}
|
|
70
75
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
76
|
+
// ============================================================================
|
|
77
|
+
// Conversion Functions
|
|
78
|
+
// ============================================================================
|
|
75
79
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return blocks
|
|
80
|
+
function integerToWords (n) {
|
|
81
|
+
if (n === 0n) return ZERO
|
|
82
|
+
|
|
83
|
+
if (n < 1000n) {
|
|
84
|
+
return SEGMENTS[Number(n)]
|
|
82
85
|
}
|
|
83
86
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
spelling = this.getTens(firstBlock[0])
|
|
87
|
+
if (n < 1_000_000n) {
|
|
88
|
+
const thousands = Number(n / 1000n)
|
|
89
|
+
const remainder = Number(n % 1000n)
|
|
90
|
+
|
|
91
|
+
let result
|
|
92
|
+
if (thousands === 1) {
|
|
93
|
+
result = 'se' + THOUSAND_WORD
|
|
92
94
|
} else {
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
wordBlocks = [...wordBlocks, [firstBlock[0], spelling]]
|
|
96
|
-
for (let index = 1; index < blocks.length; index++) {
|
|
97
|
-
let block = blocks[index]
|
|
98
|
-
spelling = [...this.getHundreds(block[0][0]), ...this.getTens(block[0].slice(1, 3))]
|
|
99
|
-
block = [...block, spelling]
|
|
100
|
-
wordBlocks = [...wordBlocks, block]
|
|
95
|
+
result = SEGMENTS[thousands] + ' ' + THOUSAND_WORD
|
|
101
96
|
}
|
|
102
|
-
return wordBlocks
|
|
103
|
-
}
|
|
104
97
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
return ['seratus']
|
|
108
|
-
} else if (number === '0') {
|
|
109
|
-
return []
|
|
110
|
-
} else {
|
|
111
|
-
return [...this.base[Math.trunc(number)], 'ratus']
|
|
98
|
+
if (remainder > 0) {
|
|
99
|
+
result += ' ' + SEGMENTS[remainder]
|
|
112
100
|
}
|
|
101
|
+
|
|
102
|
+
return result
|
|
113
103
|
}
|
|
114
104
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (number[1] === '0') {
|
|
118
|
-
return ['sepuluh']
|
|
119
|
-
} else if (number[1] === '1') {
|
|
120
|
-
return ['sebelas']
|
|
121
|
-
}
|
|
122
|
-
return [...this.base[Math.trunc(number[1])], 'belas']
|
|
123
|
-
}
|
|
105
|
+
return buildLargeNumberWords(n)
|
|
106
|
+
}
|
|
124
107
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
108
|
+
function buildLargeNumberWords (n) {
|
|
109
|
+
const numStr = n.toString()
|
|
110
|
+
const len = numStr.length
|
|
128
111
|
|
|
129
|
-
|
|
112
|
+
const segments = []
|
|
113
|
+
const segmentSize = 3
|
|
114
|
+
|
|
115
|
+
const remainderLen = len % segmentSize
|
|
116
|
+
let pos = 0
|
|
117
|
+
if (remainderLen > 0) {
|
|
118
|
+
segments.push(Number(numStr.slice(0, remainderLen)))
|
|
119
|
+
pos = remainderLen
|
|
120
|
+
}
|
|
121
|
+
while (pos < len) {
|
|
122
|
+
segments.push(Number(numStr.slice(pos, pos + segmentSize)))
|
|
123
|
+
pos += segmentSize
|
|
130
124
|
}
|
|
131
125
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
126
|
+
const parts = []
|
|
127
|
+
let scaleIndex = segments.length - 1
|
|
128
|
+
|
|
129
|
+
for (let i = 0; i < segments.length; i++) {
|
|
130
|
+
const segment = segments[i]
|
|
131
|
+
|
|
132
|
+
if (segment !== 0) {
|
|
133
|
+
if (scaleIndex === 0) {
|
|
134
|
+
parts.push(SEGMENTS[segment])
|
|
135
|
+
} else if (scaleIndex === 1) {
|
|
136
|
+
if (segment === 1) {
|
|
137
|
+
parts.push('se' + THOUSAND_WORD)
|
|
138
|
+
} else {
|
|
139
|
+
parts.push(SEGMENTS[segment] + ' ' + THOUSAND_WORD)
|
|
140
|
+
}
|
|
141
|
+
} else {
|
|
142
|
+
// Indonesian: "satu juta" not "sejuta"
|
|
143
|
+
const scaleWord = SCALE_WORDS[scaleIndex - 2]
|
|
144
|
+
parts.push(SEGMENTS[segment] + ' ' + scaleWord)
|
|
148
145
|
}
|
|
149
|
-
wordList = [...wordList, this.thousands[(length - index) * 3]]
|
|
150
146
|
}
|
|
151
|
-
|
|
147
|
+
|
|
148
|
+
scaleIndex--
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return parts.join(' ')
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function decimalPartToWords (decimalPart) {
|
|
155
|
+
let result = ''
|
|
156
|
+
|
|
157
|
+
let i = 0
|
|
158
|
+
while (i < decimalPart.length && decimalPart[i] === '0') {
|
|
159
|
+
if (result) result += ' '
|
|
160
|
+
result += ZERO
|
|
161
|
+
i++
|
|
152
162
|
}
|
|
153
163
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
)
|
|
159
|
-
).trim()
|
|
164
|
+
const remainder = decimalPart.slice(i)
|
|
165
|
+
if (remainder) {
|
|
166
|
+
if (result) result += ' '
|
|
167
|
+
result += integerToWords(BigInt(remainder))
|
|
160
168
|
}
|
|
169
|
+
|
|
170
|
+
return result
|
|
161
171
|
}
|
|
162
172
|
|
|
163
173
|
/**
|
|
164
|
-
* Converts a
|
|
174
|
+
* Converts a numeric value to Indonesian words.
|
|
165
175
|
*
|
|
166
|
-
* @param {number|string|bigint} value The
|
|
167
|
-
* @
|
|
168
|
-
* @returns {string} The number expressed in Indonesian words.
|
|
169
|
-
* @throws {TypeError} If value is NaN or invalid type.
|
|
170
|
-
* @throws {Error} If value is an invalid number string.
|
|
176
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
177
|
+
* @returns {string} The number in Indonesian words
|
|
171
178
|
*/
|
|
172
|
-
|
|
173
|
-
|
|
179
|
+
function toWords (value) {
|
|
180
|
+
const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
|
|
181
|
+
|
|
182
|
+
let result = ''
|
|
183
|
+
|
|
184
|
+
if (isNegative) {
|
|
185
|
+
result = NEGATIVE + ' '
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
result += integerToWords(integerPart)
|
|
189
|
+
|
|
190
|
+
if (decimalPart) {
|
|
191
|
+
result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return result
|
|
174
195
|
}
|
|
196
|
+
|
|
197
|
+
// ============================================================================
|
|
198
|
+
// Exports
|
|
199
|
+
// ============================================================================
|
|
200
|
+
|
|
201
|
+
export { toWords }
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a numeric value to Italian words.
|
|
3
|
+
*
|
|
4
|
+
* This is the main public API. It accepts any valid numeric input
|
|
5
|
+
* (number, string, or bigint) and handles parsing internally.
|
|
6
|
+
*
|
|
7
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
8
|
+
* @returns {string} The number in Italian words
|
|
9
|
+
* @throws {TypeError} If value is not a valid numeric type
|
|
10
|
+
* @throws {Error} If value is not a valid number format
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* toWords(28) // 'ventotto'
|
|
14
|
+
* toWords(23) // 'ventitré'
|
|
15
|
+
* toWords(1000) // 'mille'
|
|
16
|
+
* toWords(2000) // 'duemila'
|
|
17
|
+
* toWords(1000000) // 'un milione'
|
|
18
|
+
*/
|
|
19
|
+
export function toWords(value: number | string | bigint): string;
|