n2words 3.0.0 → 3.1.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 +15 -0
- package/dist/languages/am-Latn.js +2 -2
- package/dist/languages/am-Latn.js.map +1 -1
- package/dist/languages/am.js +2 -2
- package/dist/languages/am.js.map +1 -1
- package/dist/languages/ar.js +1 -1
- package/dist/languages/az.js +2 -2
- package/dist/languages/az.js.map +1 -1
- package/dist/languages/bn.js +2 -2
- package/dist/languages/bn.js.map +1 -1
- package/dist/languages/cs.js +2 -2
- package/dist/languages/cs.js.map +1 -1
- package/dist/languages/da.js +2 -2
- package/dist/languages/da.js.map +1 -1
- package/dist/languages/de.js +2 -2
- package/dist/languages/de.js.map +1 -1
- package/dist/languages/el.js +2 -2
- package/dist/languages/el.js.map +1 -1
- package/dist/languages/en.js +2 -2
- package/dist/languages/en.js.map +1 -1
- package/dist/languages/es.js +2 -2
- package/dist/languages/es.js.map +1 -1
- package/dist/languages/fa.js +1 -1
- package/dist/languages/fi.js +2 -2
- package/dist/languages/fi.js.map +1 -1
- package/dist/languages/fil.js +2 -2
- package/dist/languages/fil.js.map +1 -1
- package/dist/languages/fr-BE.js +2 -2
- package/dist/languages/fr-BE.js.map +1 -1
- package/dist/languages/fr.js +2 -2
- package/dist/languages/fr.js.map +1 -1
- package/dist/languages/gu.js +2 -2
- package/dist/languages/gu.js.map +1 -1
- package/dist/languages/ha.js +2 -2
- package/dist/languages/ha.js.map +1 -1
- package/dist/languages/hbo.js +2 -2
- package/dist/languages/hbo.js.map +1 -1
- package/dist/languages/he.js +2 -2
- package/dist/languages/he.js.map +1 -1
- package/dist/languages/hi.js +2 -2
- package/dist/languages/hi.js.map +1 -1
- package/dist/languages/hr.js +2 -2
- package/dist/languages/hr.js.map +1 -1
- package/dist/languages/hu.js +1 -1
- package/dist/languages/id.js +2 -2
- package/dist/languages/id.js.map +1 -1
- package/dist/languages/it.js +2 -2
- package/dist/languages/it.js.map +1 -1
- package/dist/languages/ja.js +2 -2
- package/dist/languages/ja.js.map +1 -1
- package/dist/languages/ka.js +3 -0
- package/dist/languages/ka.js.map +1 -0
- package/dist/languages/kn.js +2 -2
- package/dist/languages/kn.js.map +1 -1
- package/dist/languages/ko.js +2 -2
- package/dist/languages/ko.js.map +1 -1
- package/dist/languages/lt.js +2 -2
- package/dist/languages/lt.js.map +1 -1
- package/dist/languages/lv.js +2 -2
- package/dist/languages/lv.js.map +1 -1
- package/dist/languages/mr.js +2 -2
- package/dist/languages/mr.js.map +1 -1
- package/dist/languages/ms.js +2 -2
- package/dist/languages/ms.js.map +1 -1
- package/dist/languages/nb.js +2 -2
- package/dist/languages/nb.js.map +1 -1
- package/dist/languages/nl.js +2 -2
- package/dist/languages/nl.js.map +1 -1
- package/dist/languages/pa.js +2 -2
- package/dist/languages/pa.js.map +1 -1
- package/dist/languages/pl.js +2 -2
- package/dist/languages/pl.js.map +1 -1
- package/dist/languages/pt.js +2 -2
- package/dist/languages/pt.js.map +1 -1
- package/dist/languages/ro.js +1 -1
- package/dist/languages/ru.js +2 -2
- package/dist/languages/ru.js.map +1 -1
- package/dist/languages/sr-Cyrl.js +2 -2
- package/dist/languages/sr-Cyrl.js.map +1 -1
- package/dist/languages/sr-Latn.js +2 -2
- package/dist/languages/sr-Latn.js.map +1 -1
- package/dist/languages/sv.js +2 -2
- package/dist/languages/sv.js.map +1 -1
- package/dist/languages/sw.js +1 -1
- package/dist/languages/ta.js +2 -2
- package/dist/languages/ta.js.map +1 -1
- package/dist/languages/te.js +2 -2
- package/dist/languages/te.js.map +1 -1
- package/dist/languages/th.js +1 -1
- package/dist/languages/tr.js +2 -2
- package/dist/languages/tr.js.map +1 -1
- package/dist/languages/uk.js +2 -2
- package/dist/languages/uk.js.map +1 -1
- package/dist/languages/ur.js +2 -2
- package/dist/languages/ur.js.map +1 -1
- package/dist/languages/vi.js +2 -2
- package/dist/languages/vi.js.map +1 -1
- package/dist/languages/yo.js +3 -0
- package/dist/languages/yo.js.map +1 -0
- package/dist/languages/zh-Hans.js +1 -1
- package/dist/languages/zh-Hant.js +1 -1
- package/dist/n2words.js +2 -2
- package/dist/n2words.js.map +1 -1
- package/lib/languages/am-Latn.js +4 -9
- package/lib/languages/am.js +4 -9
- package/lib/languages/az.js +4 -9
- package/lib/languages/bn.js +51 -30
- package/lib/languages/cs.js +9 -26
- package/lib/languages/da.js +6 -13
- package/lib/languages/de.js +21 -33
- package/lib/languages/el.js +6 -13
- package/lib/languages/en.js +44 -58
- package/lib/languages/es.js +10 -30
- package/lib/languages/fi.js +6 -13
- package/lib/languages/fil.js +6 -17
- package/lib/languages/fr-BE.js +17 -26
- package/lib/languages/fr.js +18 -31
- package/lib/languages/gu.js +43 -30
- package/lib/languages/ha.js +4 -9
- package/lib/languages/hbo.js +7 -25
- package/lib/languages/he.js +7 -18
- package/lib/languages/hi.js +55 -30
- package/lib/languages/hr.js +61 -55
- package/lib/languages/id.js +8 -13
- package/lib/languages/it.js +64 -99
- package/lib/languages/ja.js +8 -20
- package/lib/languages/ka.d.ts +17 -0
- package/lib/languages/ka.js +291 -0
- package/lib/languages/kn.js +43 -30
- package/lib/languages/ko.js +6 -13
- package/lib/languages/lt.js +6 -15
- package/lib/languages/lv.js +6 -15
- package/lib/languages/mr.js +43 -30
- package/lib/languages/ms.js +8 -13
- package/lib/languages/nb.js +13 -23
- package/lib/languages/nl.js +11 -29
- package/lib/languages/pa.js +32 -37
- package/lib/languages/pl.js +7 -20
- package/lib/languages/pt.js +17 -31
- package/lib/languages/ru.js +64 -59
- package/lib/languages/sr-Cyrl.js +58 -52
- package/lib/languages/sr-Latn.js +58 -52
- package/lib/languages/sv.js +14 -24
- package/lib/languages/ta.js +55 -42
- package/lib/languages/te.js +33 -41
- package/lib/languages/tr.js +7 -18
- package/lib/languages/uk.js +61 -55
- package/lib/languages/ur.js +32 -37
- package/lib/languages/vi.js +23 -43
- package/lib/languages/yo.d.ts +7 -0
- package/lib/languages/yo.js +303 -0
- package/lib/n2words.d.ts +3 -1
- package/lib/n2words.js +4 -0
- package/package.json +1 -1
package/lib/languages/vi.js
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Vietnamese language converter - Functional Implementation
|
|
2
|
+
* Vietnamese language converter - Functional Implementation
|
|
3
3
|
*
|
|
4
|
-
* A performance-optimized number-to-words converter using precomputed lookup tables.
|
|
5
4
|
* Self-contained module with its own input validation, ready for subpath exports.
|
|
6
5
|
*
|
|
7
|
-
*
|
|
8
|
-
* This eliminates all per-call string manipulation for segment conversion.
|
|
9
|
-
*
|
|
10
|
-
* Vietnamese-specific rules (handled in precomputation):
|
|
6
|
+
* Vietnamese-specific rules:
|
|
11
7
|
* - Special pronunciation: "lăm" for 5 in tens position, "mốt" for final 1
|
|
12
8
|
* - "Lẻ" (odd/extra) marker when tens place is zero after hundreds/scales
|
|
13
9
|
* - Short scale system with Vietnamese words (nghìn, triệu, tỷ)
|
|
@@ -42,12 +38,11 @@ const MOT_FINAL = 'mốt' // 1 in tens position (21, 31, etc.)
|
|
|
42
38
|
const LAM = 'lăm' // 5 in tens position (25, 35, etc.)
|
|
43
39
|
|
|
44
40
|
// ============================================================================
|
|
45
|
-
//
|
|
41
|
+
// Segment Building
|
|
46
42
|
// ============================================================================
|
|
47
43
|
|
|
48
44
|
/**
|
|
49
45
|
* Builds word for 0-99 with special forms (mốt, lăm).
|
|
50
|
-
* Only used during table construction.
|
|
51
46
|
*/
|
|
52
47
|
function buildBelowHundred (n) {
|
|
53
48
|
if (n === 0) return ONES[0]
|
|
@@ -74,7 +69,6 @@ function buildBelowHundred (n) {
|
|
|
74
69
|
|
|
75
70
|
/**
|
|
76
71
|
* Builds segment word for 0-999.
|
|
77
|
-
* Only used during table construction.
|
|
78
72
|
*/
|
|
79
73
|
function buildSegment (n) {
|
|
80
74
|
if (n === 0) return ''
|
|
@@ -101,37 +95,23 @@ function buildSegment (n) {
|
|
|
101
95
|
} else {
|
|
102
96
|
// 10-99 after hundreds
|
|
103
97
|
if (result) result += ' '
|
|
104
|
-
result +=
|
|
98
|
+
result += buildBelowHundred(remainder)
|
|
105
99
|
}
|
|
106
100
|
}
|
|
107
101
|
|
|
108
102
|
return result
|
|
109
103
|
}
|
|
110
104
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
for (let i = 0; i < 1000; i++) {
|
|
122
|
-
SEGMENTS[i] = buildSegment(i)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Precompute "lẻ" prefixed versions for small remainders after scale words
|
|
126
|
-
// LE_SEGMENTS[n] gives "lẻ X" for n in range 1-99
|
|
127
|
-
const LE_SEGMENTS = new Array(100)
|
|
128
|
-
LE_SEGMENTS[0] = ''
|
|
129
|
-
for (let i = 1; i < 10; i++) {
|
|
130
|
-
// Use "năm" not "lăm" after lẻ
|
|
131
|
-
LE_SEGMENTS[i] = LE + ' ' + (i === 5 ? 'năm' : ONES[i])
|
|
132
|
-
}
|
|
133
|
-
for (let i = 10; i < 100; i++) {
|
|
134
|
-
LE_SEGMENTS[i] = LE + ' ' + BELOW_100[i]
|
|
105
|
+
/**
|
|
106
|
+
* Builds "lẻ" prefixed word for small remainders (1-99) after scale words.
|
|
107
|
+
*/
|
|
108
|
+
function buildLeSegment (n) {
|
|
109
|
+
if (n === 0) return ''
|
|
110
|
+
if (n < 10) {
|
|
111
|
+
// Use "năm" not "lăm" after lẻ
|
|
112
|
+
return LE + ' ' + (n === 5 ? 'năm' : ONES[n])
|
|
113
|
+
}
|
|
114
|
+
return LE + ' ' + buildBelowHundred(n)
|
|
135
115
|
}
|
|
136
116
|
|
|
137
117
|
// ============================================================================
|
|
@@ -147,14 +127,14 @@ for (let i = 10; i < 100; i++) {
|
|
|
147
127
|
function integerToWords (n) {
|
|
148
128
|
if (n === 0n) return ZERO
|
|
149
129
|
|
|
150
|
-
// Fast path: numbers < 100
|
|
130
|
+
// Fast path: numbers < 100
|
|
151
131
|
if (n < 100n) {
|
|
152
|
-
return
|
|
132
|
+
return buildBelowHundred(Number(n))
|
|
153
133
|
}
|
|
154
134
|
|
|
155
|
-
// Fast path: numbers < 1000
|
|
135
|
+
// Fast path: numbers < 1000
|
|
156
136
|
if (n < 1000n) {
|
|
157
|
-
return
|
|
137
|
+
return buildSegment(Number(n))
|
|
158
138
|
}
|
|
159
139
|
|
|
160
140
|
// Fast path: numbers < 1,000,000 (thousands)
|
|
@@ -162,7 +142,7 @@ function integerToWords (n) {
|
|
|
162
142
|
const thousands = Number(n / 1000n)
|
|
163
143
|
const remainder = Number(n % 1000n)
|
|
164
144
|
|
|
165
|
-
const thousandsWords =
|
|
145
|
+
const thousandsWords = buildSegment(thousands) + ' ' + SCALES[1]
|
|
166
146
|
|
|
167
147
|
if (remainder === 0) {
|
|
168
148
|
return thousandsWords
|
|
@@ -170,10 +150,10 @@ function integerToWords (n) {
|
|
|
170
150
|
|
|
171
151
|
// Check if remainder needs "lẻ" marker (< 100)
|
|
172
152
|
if (remainder < 100) {
|
|
173
|
-
return thousandsWords + ' ' +
|
|
153
|
+
return thousandsWords + ' ' + buildLeSegment(remainder)
|
|
174
154
|
}
|
|
175
155
|
|
|
176
|
-
return thousandsWords + ' ' +
|
|
156
|
+
return thousandsWords + ' ' + buildSegment(remainder)
|
|
177
157
|
}
|
|
178
158
|
|
|
179
159
|
// For numbers >= 1,000,000, use scale decomposition
|
|
@@ -212,7 +192,7 @@ function buildLargeNumberWords (n) {
|
|
|
212
192
|
for (let i = 0; i < segments.length; i++) {
|
|
213
193
|
const segment = segments[i]
|
|
214
194
|
if (segment !== 0) {
|
|
215
|
-
const words =
|
|
195
|
+
const words = buildSegment(segment)
|
|
216
196
|
if (words) {
|
|
217
197
|
if (scaleIndex > 0) {
|
|
218
198
|
parts.push(words + ' ' + SCALES[scaleIndex])
|
|
@@ -237,7 +217,7 @@ function buildLargeNumberWords (n) {
|
|
|
237
217
|
for (let i = 1; i < partsLen - 1; i++) {
|
|
238
218
|
result += ' ' + parts[i]
|
|
239
219
|
}
|
|
240
|
-
return result + ' ' +
|
|
220
|
+
return result + ' ' + buildLeSegment(lastSegment)
|
|
241
221
|
}
|
|
242
222
|
|
|
243
223
|
// Join with spaces
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Yoruba language converter - Functional Implementation
|
|
3
|
+
*
|
|
4
|
+
* A number-to-words converter for Yoruba (yo), a Niger-Congo language
|
|
5
|
+
* spoken by ~45 million people in Nigeria, Benin, and Togo.
|
|
6
|
+
*
|
|
7
|
+
* Yoruba uses a complex vigesimal (base-20) system with:
|
|
8
|
+
* - Additive patterns: 1-4 added to decade (lé = "plus")
|
|
9
|
+
* - Subtractive patterns: 5-9 subtracted from next decade (dín = "minus")
|
|
10
|
+
* - Odd decades (30,50,70,90) formed by subtracting 10 from next even decade
|
|
11
|
+
* - Even decades (20,40,60,80,100) are multiples of 20
|
|
12
|
+
*
|
|
13
|
+
* Examples:
|
|
14
|
+
* - 21 = ọ̀kan lé lógún (1 + 20)
|
|
15
|
+
* - 15 = àrùndínlógún (20 - 5)
|
|
16
|
+
* - 50 = àádọ́ta (60 - 10)
|
|
17
|
+
* - 45 = àrùndínláàádọ́ta (50 - 5)
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
21
|
+
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// Vocabulary (module-level constants)
|
|
24
|
+
// ============================================================================
|
|
25
|
+
|
|
26
|
+
// Basic numbers 1-10
|
|
27
|
+
const ONES = [
|
|
28
|
+
'',
|
|
29
|
+
'ọ̀kan', // 1
|
|
30
|
+
'èjì', // 2
|
|
31
|
+
'ẹ̀ta', // 3
|
|
32
|
+
'ẹ̀rin', // 4
|
|
33
|
+
'àrùn', // 5
|
|
34
|
+
'ẹ̀fà', // 6
|
|
35
|
+
'èje', // 7
|
|
36
|
+
'ẹ̀jọ', // 8
|
|
37
|
+
'ẹ̀sán', // 9
|
|
38
|
+
'ẹ̀wá' // 10
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
// Numbers 11-14 (additive: X + 10, using "lá")
|
|
42
|
+
const TEENS_ADD = [
|
|
43
|
+
'',
|
|
44
|
+
'ọ̀kànlá', // 11 = 1 + 10
|
|
45
|
+
'èjìlá', // 12 = 2 + 10
|
|
46
|
+
'ẹ̀talá', // 13 = 3 + 10
|
|
47
|
+
'ẹ̀rinlá' // 14 = 4 + 10
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
// Numbers 15-19 (subtractive: 20 - X, using "dín")
|
|
51
|
+
const TEENS_SUB = [
|
|
52
|
+
'àrùndínlógún', // 15 = 20 - 5
|
|
53
|
+
'ẹ̀rìndínlógún', // 16 = 20 - 4
|
|
54
|
+
'ẹ̀tadínlógún', // 17 = 20 - 3
|
|
55
|
+
'èjìdínlógún', // 18 = 20 - 2
|
|
56
|
+
'ọ̀kàndínlógún' // 19 = 20 - 1
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
// Decades (base-20 structure)
|
|
60
|
+
// Even decades are multiples of 20
|
|
61
|
+
// Odd decades subtract 10 from next even decade
|
|
62
|
+
const DECADES = {
|
|
63
|
+
20: 'ogún', // 20 = 20 × 1
|
|
64
|
+
30: 'ọgbọ̀n', // 30 = 20 + 10 (special word)
|
|
65
|
+
40: 'ogójì', // 40 = 20 × 2
|
|
66
|
+
50: 'àádọ́ta', // 50 = 60 - 10
|
|
67
|
+
60: 'ogóta', // 60 = 20 × 3
|
|
68
|
+
70: 'àádọ́rin', // 70 = 80 - 10
|
|
69
|
+
80: 'ogórin', // 80 = 20 × 4
|
|
70
|
+
90: 'àádọ́rùn', // 90 = 100 - 10
|
|
71
|
+
100: 'ọgọ́rùn' // 100 = 20 × 5
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Prefixes for adding to decades (lé lógún, lé lọgbọ̀n, etc.)
|
|
75
|
+
const DECADE_ADD_SUFFIX = {
|
|
76
|
+
20: 'lógún',
|
|
77
|
+
30: 'lọgbọ̀n',
|
|
78
|
+
40: 'lógójì',
|
|
79
|
+
50: 'láàádọ́ta',
|
|
80
|
+
60: 'lógóta',
|
|
81
|
+
70: 'láàádọ́rin',
|
|
82
|
+
80: 'lógórin',
|
|
83
|
+
90: 'láàádọ́rùn',
|
|
84
|
+
100: 'lọ́gọ́rùn'
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Prefixes for subtracting from decades (dín lógójì, etc.)
|
|
88
|
+
const DECADE_SUB_SUFFIX = {
|
|
89
|
+
20: 'dínlógún',
|
|
90
|
+
30: 'dínlọgbọ̀n',
|
|
91
|
+
40: 'dínlógójì',
|
|
92
|
+
50: 'dínláàádọ́ta',
|
|
93
|
+
60: 'dínlógóta',
|
|
94
|
+
70: 'dínláàádọ́rin',
|
|
95
|
+
80: 'dínlógórin',
|
|
96
|
+
90: 'dínláàádọ́rùn',
|
|
97
|
+
100: 'dínlọ́gọ́rùn'
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Scale words
|
|
101
|
+
const HUNDRED = 'ọgọ́rùn'
|
|
102
|
+
const TWO_HUNDRED = 'igba' // 200 (special word, historically 200 cowries)
|
|
103
|
+
const FOUR_HUNDRED = 'irinwó' // 400 (20 × 20)
|
|
104
|
+
const THOUSAND = 'ẹgbẹ̀rún' // 1000
|
|
105
|
+
const TEN_THOUSAND = 'ẹgbàárùn' // 10,000 (special)
|
|
106
|
+
const TWENTY_THOUSAND = 'ọ̀kẹ́' // 20,000 (bag of cowries)
|
|
107
|
+
const MILLION = 'mílíọ̀nù' // million (loanword)
|
|
108
|
+
|
|
109
|
+
const ZERO = 'òdo'
|
|
110
|
+
const NEGATIVE = 'àìní'
|
|
111
|
+
const DECIMAL_SEP = 'àmì'
|
|
112
|
+
const AND = 'ó lé' // "and" / "plus" connector
|
|
113
|
+
|
|
114
|
+
// ============================================================================
|
|
115
|
+
// Segment Building
|
|
116
|
+
// ============================================================================
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Builds word for numbers 0-99
|
|
120
|
+
*/
|
|
121
|
+
function buildUnder100 (n) {
|
|
122
|
+
if (n === 0) return ''
|
|
123
|
+
if (n <= 10) return ONES[n]
|
|
124
|
+
|
|
125
|
+
// 11-14: additive from 10
|
|
126
|
+
if (n <= 14) return TEENS_ADD[n - 10]
|
|
127
|
+
|
|
128
|
+
// 15-19: subtractive from 20
|
|
129
|
+
if (n <= 19) return TEENS_SUB[n - 15]
|
|
130
|
+
|
|
131
|
+
// Exact decades
|
|
132
|
+
if (n % 10 === 0) return DECADES[n]
|
|
133
|
+
|
|
134
|
+
const decade = Math.floor(n / 10) * 10
|
|
135
|
+
const unit = n % 10
|
|
136
|
+
|
|
137
|
+
// 1-4 are added to current decade (21 = 1 + 20, not 1 + 30)
|
|
138
|
+
if (unit <= 4) {
|
|
139
|
+
return ONES[unit] + ' lé ' + DECADE_ADD_SUFFIX[decade]
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// 5-9 are subtracted from next decade
|
|
143
|
+
const nextDecade = decade + 10
|
|
144
|
+
const subtractAmount = 10 - unit
|
|
145
|
+
return ONES[subtractAmount] + DECADE_SUB_SUFFIX[nextDecade]
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ============================================================================
|
|
149
|
+
// Conversion Functions
|
|
150
|
+
// ============================================================================
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Converts hundreds (100-999)
|
|
154
|
+
*/
|
|
155
|
+
function convertHundreds (n) {
|
|
156
|
+
if (n < 100) return buildUnder100(n)
|
|
157
|
+
|
|
158
|
+
const hundreds = Math.floor(n / 100)
|
|
159
|
+
const remainder = n % 100
|
|
160
|
+
|
|
161
|
+
let result
|
|
162
|
+
|
|
163
|
+
// Special cases for 200 and 400
|
|
164
|
+
if (hundreds === 2 && remainder === 0) {
|
|
165
|
+
return TWO_HUNDRED
|
|
166
|
+
}
|
|
167
|
+
if (hundreds === 4 && remainder === 0) {
|
|
168
|
+
return FOUR_HUNDRED
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Build hundreds
|
|
172
|
+
if (hundreds === 1) {
|
|
173
|
+
result = HUNDRED
|
|
174
|
+
} else if (hundreds === 2) {
|
|
175
|
+
result = TWO_HUNDRED
|
|
176
|
+
} else if (hundreds === 4) {
|
|
177
|
+
result = FOUR_HUNDRED
|
|
178
|
+
} else {
|
|
179
|
+
// Other hundreds: X ọgọ́rùn
|
|
180
|
+
result = ONES[hundreds] + ' ' + HUNDRED
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (remainder > 0) {
|
|
184
|
+
result += ' ' + AND + ' ' + buildUnder100(remainder)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return result
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Converts a non-negative integer to Yoruba words.
|
|
192
|
+
*
|
|
193
|
+
* @param {bigint} n - Non-negative integer to convert
|
|
194
|
+
* @returns {string} Yoruba words
|
|
195
|
+
*/
|
|
196
|
+
function integerToWords (n) {
|
|
197
|
+
if (n === 0n) return ZERO
|
|
198
|
+
|
|
199
|
+
// Fast path: numbers < 100
|
|
200
|
+
if (n < 100n) {
|
|
201
|
+
return buildUnder100(Number(n))
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Numbers < 1000
|
|
205
|
+
if (n < 1000n) {
|
|
206
|
+
return convertHundreds(Number(n))
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Build from segments
|
|
210
|
+
const parts = []
|
|
211
|
+
let remaining = n
|
|
212
|
+
|
|
213
|
+
// Millions
|
|
214
|
+
if (remaining >= 1_000_000n) {
|
|
215
|
+
const millions = remaining / 1_000_000n
|
|
216
|
+
remaining = remaining % 1_000_000n
|
|
217
|
+
if (millions === 1n) {
|
|
218
|
+
parts.push(MILLION + ' kan')
|
|
219
|
+
} else {
|
|
220
|
+
parts.push(MILLION + ' ' + integerToWords(millions))
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Thousands
|
|
225
|
+
if (remaining >= 1000n) {
|
|
226
|
+
const thousands = remaining / 1000n
|
|
227
|
+
remaining = remaining % 1000n
|
|
228
|
+
|
|
229
|
+
if (thousands === 1n) {
|
|
230
|
+
parts.push(THOUSAND + ' kan')
|
|
231
|
+
} else if (thousands === 10n) {
|
|
232
|
+
parts.push(TEN_THOUSAND)
|
|
233
|
+
} else if (thousands === 20n) {
|
|
234
|
+
parts.push(TWENTY_THOUSAND)
|
|
235
|
+
} else if (thousands < 100n) {
|
|
236
|
+
parts.push(THOUSAND + ' ' + buildUnder100(Number(thousands)))
|
|
237
|
+
} else {
|
|
238
|
+
parts.push(THOUSAND + ' ' + convertHundreds(Number(thousands)))
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Hundreds and below
|
|
243
|
+
if (remaining > 0n) {
|
|
244
|
+
if (remaining < 100n) {
|
|
245
|
+
if (parts.length > 0) {
|
|
246
|
+
parts.push(AND + ' ' + buildUnder100(Number(remaining)))
|
|
247
|
+
} else {
|
|
248
|
+
parts.push(buildUnder100(Number(remaining)))
|
|
249
|
+
}
|
|
250
|
+
} else {
|
|
251
|
+
if (parts.length > 0) {
|
|
252
|
+
parts.push(AND + ' ' + convertHundreds(Number(remaining)))
|
|
253
|
+
} else {
|
|
254
|
+
parts.push(convertHundreds(Number(remaining)))
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return parts.join(', ')
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Converts decimal digits to Yoruba words.
|
|
264
|
+
*
|
|
265
|
+
* @param {string} decimalPart - Decimal digits
|
|
266
|
+
* @returns {string} Yoruba words for decimal
|
|
267
|
+
*/
|
|
268
|
+
function decimalPartToWords (decimalPart) {
|
|
269
|
+
const parts = []
|
|
270
|
+
|
|
271
|
+
for (const digit of decimalPart) {
|
|
272
|
+
const d = parseInt(digit, 10)
|
|
273
|
+
parts.push(d === 0 ? ZERO : ONES[d])
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return parts.join(' ')
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Converts a numeric value to Yoruba words.
|
|
281
|
+
*
|
|
282
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
283
|
+
* @returns {string} The number in Yoruba words
|
|
284
|
+
*/
|
|
285
|
+
function toWords (value) {
|
|
286
|
+
const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
|
|
287
|
+
|
|
288
|
+
let result = ''
|
|
289
|
+
|
|
290
|
+
if (isNegative) {
|
|
291
|
+
result = NEGATIVE + ' '
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
result += integerToWords(integerPart)
|
|
295
|
+
|
|
296
|
+
if (decimalPart) {
|
|
297
|
+
result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart)
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return result
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export { toWords }
|
package/lib/n2words.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ import { toWords as hu } from './languages/hu.js';
|
|
|
24
24
|
import { toWords as id } from './languages/id.js';
|
|
25
25
|
import { toWords as it } from './languages/it.js';
|
|
26
26
|
import { toWords as ja } from './languages/ja.js';
|
|
27
|
+
import { toWords as ka } from './languages/ka.js';
|
|
27
28
|
import { toWords as kn } from './languages/kn.js';
|
|
28
29
|
import { toWords as ko } from './languages/ko.js';
|
|
29
30
|
import { toWords as lt } from './languages/lt.js';
|
|
@@ -48,6 +49,7 @@ import { toWords as tr } from './languages/tr.js';
|
|
|
48
49
|
import { toWords as uk } from './languages/uk.js';
|
|
49
50
|
import { toWords as ur } from './languages/ur.js';
|
|
50
51
|
import { toWords as vi } from './languages/vi.js';
|
|
52
|
+
import { toWords as yo } from './languages/yo.js';
|
|
51
53
|
import { toWords as zhHans } from './languages/zh-Hans.js';
|
|
52
54
|
import { toWords as zhHant } from './languages/zh-Hant.js';
|
|
53
|
-
export { am, amLatn, ar, az, bn, cs, da, de, el, en, es, fa, fi, fil, fr, frBE, gu, ha, hbo, he, hi, hr, hu, id, it, ja, kn, ko, lt, lv, mr, ms, nb, nl, pa, pl, pt, ro, ru, srCyrl, srLatn, sv, sw, ta, te, th, tr, uk, ur, vi, zhHans, zhHant };
|
|
55
|
+
export { am, amLatn, ar, az, bn, cs, da, de, el, en, es, fa, fi, fil, fr, frBE, gu, ha, hbo, he, hi, hr, hu, id, it, ja, ka, kn, ko, lt, lv, mr, ms, nb, nl, pa, pl, pt, ro, ru, srCyrl, srLatn, sv, sw, ta, te, th, tr, uk, ur, vi, yo, zhHans, zhHant };
|
package/lib/n2words.js
CHANGED
|
@@ -39,6 +39,7 @@ import { toWords as hu } from './languages/hu.js'
|
|
|
39
39
|
import { toWords as id } from './languages/id.js'
|
|
40
40
|
import { toWords as it } from './languages/it.js'
|
|
41
41
|
import { toWords as ja } from './languages/ja.js'
|
|
42
|
+
import { toWords as ka } from './languages/ka.js'
|
|
42
43
|
import { toWords as kn } from './languages/kn.js'
|
|
43
44
|
import { toWords as ko } from './languages/ko.js'
|
|
44
45
|
import { toWords as lt } from './languages/lt.js'
|
|
@@ -63,6 +64,7 @@ import { toWords as tr } from './languages/tr.js'
|
|
|
63
64
|
import { toWords as uk } from './languages/uk.js'
|
|
64
65
|
import { toWords as ur } from './languages/ur.js'
|
|
65
66
|
import { toWords as vi } from './languages/vi.js'
|
|
67
|
+
import { toWords as yo } from './languages/yo.js'
|
|
66
68
|
import { toWords as zhHans } from './languages/zh-Hans.js'
|
|
67
69
|
import { toWords as zhHant } from './languages/zh-Hant.js'
|
|
68
70
|
|
|
@@ -93,6 +95,7 @@ export {
|
|
|
93
95
|
id,
|
|
94
96
|
it,
|
|
95
97
|
ja,
|
|
98
|
+
ka,
|
|
96
99
|
kn,
|
|
97
100
|
ko,
|
|
98
101
|
lt,
|
|
@@ -117,6 +120,7 @@ export {
|
|
|
117
120
|
uk,
|
|
118
121
|
ur,
|
|
119
122
|
vi,
|
|
123
|
+
yo,
|
|
120
124
|
zhHans,
|
|
121
125
|
zhHant
|
|
122
126
|
}
|
package/package.json
CHANGED