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/gu.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Gujarati language converter - Functional Implementation
|
|
3
3
|
*
|
|
4
|
-
* Self-contained
|
|
4
|
+
* Self-contained module with its own input validation, ready for subpath exports.
|
|
5
5
|
*
|
|
6
6
|
* Key features:
|
|
7
7
|
* - Indian numbering system (હજાર, લાખ, કરોડ)
|
|
@@ -39,26 +39,13 @@ const BELOW_HUNDRED = [
|
|
|
39
39
|
const SCALE_WORDS = ['', 'હજાર', 'લાખ', 'કરોડ', 'અબજ', 'ખરબ', 'નીલ', 'પદ્મ', 'શંખ']
|
|
40
40
|
|
|
41
41
|
// ============================================================================
|
|
42
|
-
// Segment
|
|
42
|
+
// Segment Building
|
|
43
43
|
// ============================================================================
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const segments = []
|
|
50
|
-
segments.unshift(Number(numStr.slice(-3)))
|
|
51
|
-
|
|
52
|
-
let remaining = numStr.slice(0, -3)
|
|
53
|
-
while (remaining.length > 0) {
|
|
54
|
-
segments.unshift(Number(remaining.slice(-2)))
|
|
55
|
-
remaining = remaining.slice(0, -2)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return segments
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function segmentToWords (n) {
|
|
45
|
+
/**
|
|
46
|
+
* Builds words for a 0-999 segment.
|
|
47
|
+
*/
|
|
48
|
+
function buildSegment (n) {
|
|
62
49
|
if (n === 0) return ''
|
|
63
50
|
if (n < 100) return BELOW_HUNDRED[n]
|
|
64
51
|
|
|
@@ -75,25 +62,51 @@ function segmentToWords (n) {
|
|
|
75
62
|
// Conversion Functions
|
|
76
63
|
// ============================================================================
|
|
77
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Converts a non-negative integer to Gujarati words.
|
|
67
|
+
*
|
|
68
|
+
* Uses BigInt modulo for segment extraction (faster than string slicing).
|
|
69
|
+
* South Asian 3-2-2 grouping: first 3 digits, then groups of 2.
|
|
70
|
+
*
|
|
71
|
+
* @param {bigint} n - Non-negative integer to convert
|
|
72
|
+
* @returns {string} Gujarati words
|
|
73
|
+
*/
|
|
78
74
|
function integerToWords (n) {
|
|
79
75
|
if (n === 0n) return ZERO
|
|
80
76
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
77
|
+
// Fast path: numbers < 1000 (direct lookup)
|
|
78
|
+
if (n < 1000n) {
|
|
79
|
+
return buildSegment(Number(n))
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Extract segments using BigInt modulo
|
|
83
|
+
const segments = []
|
|
84
|
+
segments.push(Number(n % 1000n))
|
|
85
|
+
let temp = n / 1000n
|
|
86
|
+
|
|
87
|
+
while (temp > 0n) {
|
|
88
|
+
segments.push(Number(temp % 100n))
|
|
89
|
+
temp = temp / 100n
|
|
90
|
+
}
|
|
84
91
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
92
|
+
// Build result string (process from most-significant to least)
|
|
93
|
+
const words = []
|
|
94
|
+
for (let i = segments.length - 1; i >= 0; i--) {
|
|
95
|
+
const segment = segments[i]
|
|
96
|
+
if (segment === 0) continue
|
|
97
|
+
|
|
98
|
+
if (i === 0) {
|
|
99
|
+
words.push(buildSegment(segment))
|
|
100
|
+
} else {
|
|
101
|
+
words.push(BELOW_HUNDRED[segment])
|
|
102
|
+
}
|
|
88
103
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (scaleIndex > 0 && SCALE_WORDS[scaleIndex]) {
|
|
92
|
-
words.push(SCALE_WORDS[scaleIndex])
|
|
104
|
+
if (i > 0 && SCALE_WORDS[i]) {
|
|
105
|
+
words.push(SCALE_WORDS[i])
|
|
93
106
|
}
|
|
94
107
|
}
|
|
95
108
|
|
|
96
|
-
return words.join(' ')
|
|
109
|
+
return words.join(' ')
|
|
97
110
|
}
|
|
98
111
|
|
|
99
112
|
function decimalPartToWords (decimalPart) {
|
package/lib/languages/ha.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Hausa language converter - Functional Implementation
|
|
3
3
|
*
|
|
4
|
-
* Self-contained
|
|
4
|
+
* Self-contained module with its own input validation, ready for subpath exports.
|
|
5
5
|
*
|
|
6
6
|
* Key features:
|
|
7
7
|
* - Authentic Boko orthography with ɗ (hooked d) and ' (glottal stop)
|
|
@@ -88,11 +88,6 @@ function buildSegment (n) {
|
|
|
88
88
|
return parts.join(' ')
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
const SEGMENTS = new Array(1000)
|
|
92
|
-
for (let i = 0; i < 1000; i++) {
|
|
93
|
-
SEGMENTS[i] = buildSegment(i)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
91
|
// ============================================================================
|
|
97
92
|
// Conversion Functions
|
|
98
93
|
// ============================================================================
|
|
@@ -101,7 +96,7 @@ function integerToWords (n) {
|
|
|
101
96
|
if (n === 0n) return ZERO
|
|
102
97
|
|
|
103
98
|
if (n < 1000n) {
|
|
104
|
-
return
|
|
99
|
+
return buildSegment(Number(n))
|
|
105
100
|
}
|
|
106
101
|
|
|
107
102
|
return buildLargeNumberWords(n)
|
|
@@ -143,9 +138,9 @@ function buildLargeNumberWords (n) {
|
|
|
143
138
|
const scaleWord = SCALE_WORDS[scaleIndex] || ''
|
|
144
139
|
|
|
145
140
|
if (scaleIndex === 0) {
|
|
146
|
-
rawParts.push(
|
|
141
|
+
rawParts.push(buildSegment(segment))
|
|
147
142
|
} else {
|
|
148
|
-
rawParts.push(
|
|
143
|
+
rawParts.push(buildSegment(segment))
|
|
149
144
|
rawParts.push(scaleWord)
|
|
150
145
|
}
|
|
151
146
|
}
|
package/lib/languages/hbo.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Biblical Hebrew language converter - Functional Implementation
|
|
3
3
|
*
|
|
4
|
-
* Self-contained
|
|
4
|
+
* Self-contained module with its own input validation, ready for subpath exports.
|
|
5
5
|
*
|
|
6
6
|
* Key features:
|
|
7
7
|
* - Gender agreement (masculine default, feminine via option)
|
|
@@ -9,8 +9,6 @@
|
|
|
9
9
|
* - Special 1-9 thousands construct state
|
|
10
10
|
* - "ו" (ve) conjunction rules vary by position
|
|
11
11
|
* - Per-digit decimal reading
|
|
12
|
-
*
|
|
13
|
-
* Optimization: Precomputed segment lookup tables for both genders.
|
|
14
12
|
*/
|
|
15
13
|
|
|
16
14
|
import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
@@ -44,7 +42,7 @@ const NEGATIVE = 'מינוס'
|
|
|
44
42
|
const DECIMAL_SEP = 'נקודה'
|
|
45
43
|
|
|
46
44
|
// ============================================================================
|
|
47
|
-
//
|
|
45
|
+
// Segment Building
|
|
48
46
|
// ============================================================================
|
|
49
47
|
|
|
50
48
|
/**
|
|
@@ -145,19 +143,6 @@ function buildUnitsSegment (n, andWord, ONES, TEENS, HUNDREDS_ARR) {
|
|
|
145
143
|
return result
|
|
146
144
|
}
|
|
147
145
|
|
|
148
|
-
// Precompute all 1000 segment words for masculine (default) with default conjunction
|
|
149
|
-
const SCALE_SEGMENTS_MASC = new Array(1000)
|
|
150
|
-
const UNITS_SEGMENTS_MASC = new Array(1000)
|
|
151
|
-
const SCALE_SEGMENTS_FEM = new Array(1000)
|
|
152
|
-
const UNITS_SEGMENTS_FEM = new Array(1000)
|
|
153
|
-
|
|
154
|
-
for (let i = 0; i < 1000; i++) {
|
|
155
|
-
SCALE_SEGMENTS_MASC[i] = buildScaleSegment(i, 'ו', ONES_MASC, TEENS_MASC, HUNDREDS)
|
|
156
|
-
UNITS_SEGMENTS_MASC[i] = buildUnitsSegment(i, 'ו', ONES_MASC, TEENS_MASC, HUNDREDS)
|
|
157
|
-
SCALE_SEGMENTS_FEM[i] = buildScaleSegment(i, 'ו', ONES_FEM, TEENS_FEM, HUNDREDS_FEM)
|
|
158
|
-
UNITS_SEGMENTS_FEM[i] = buildUnitsSegment(i, 'ו', ONES_FEM, TEENS_FEM, HUNDREDS_FEM)
|
|
159
|
-
}
|
|
160
|
-
|
|
161
146
|
// ============================================================================
|
|
162
147
|
// Conversion Functions
|
|
163
148
|
// ============================================================================
|
|
@@ -175,19 +160,16 @@ function integerToWords (n, options) {
|
|
|
175
160
|
const andWord = options.andWord ?? 'ו'
|
|
176
161
|
const gender = options.gender || 'masculine'
|
|
177
162
|
const isFeminine = gender === 'feminine'
|
|
178
|
-
const usePrecomputed = andWord === 'ו'
|
|
179
163
|
|
|
180
164
|
// Select vocabulary based on gender
|
|
181
165
|
const ONES = isFeminine ? ONES_FEM : ONES_MASC
|
|
182
166
|
const TEENS = isFeminine ? TEENS_FEM : TEENS_MASC
|
|
183
167
|
const THOUSANDS_SPECIAL = isFeminine ? THOUSANDS_FEM : THOUSANDS_MASC
|
|
184
168
|
const HUNDREDS_ARR = isFeminine ? HUNDREDS_FEM : HUNDREDS
|
|
185
|
-
const SCALE_SEGS = isFeminine ? SCALE_SEGMENTS_FEM : SCALE_SEGMENTS_MASC
|
|
186
|
-
const UNITS_SEGS = isFeminine ? UNITS_SEGMENTS_FEM : UNITS_SEGMENTS_MASC
|
|
187
169
|
|
|
188
|
-
// Fast path: numbers < 1000
|
|
170
|
+
// Fast path: numbers < 1000
|
|
189
171
|
if (n < 1000n) {
|
|
190
|
-
return
|
|
172
|
+
return buildUnitsSegment(Number(n), andWord, ONES, TEENS, HUNDREDS_ARR)
|
|
191
173
|
}
|
|
192
174
|
|
|
193
175
|
// Extract segments using BigInt modulo
|
|
@@ -207,7 +189,7 @@ function integerToWords (n, options) {
|
|
|
207
189
|
|
|
208
190
|
if (i === 0) {
|
|
209
191
|
// Units segment (no scale word)
|
|
210
|
-
const segmentWord =
|
|
192
|
+
const segmentWord = buildUnitsSegment(segment, andWord, ONES, TEENS, HUNDREDS_ARR)
|
|
211
193
|
if (result) {
|
|
212
194
|
// Add "ו" before single-digit units when following scale words
|
|
213
195
|
if (segment <= 9) {
|
|
@@ -224,7 +206,7 @@ function integerToWords (n, options) {
|
|
|
224
206
|
if (result) result += ' '
|
|
225
207
|
result += THOUSANDS_SPECIAL[segment]
|
|
226
208
|
} else {
|
|
227
|
-
const segmentWord =
|
|
209
|
+
const segmentWord = buildScaleSegment(segment, andWord, ONES, TEENS, HUNDREDS_ARR)
|
|
228
210
|
if (result) result += ' '
|
|
229
211
|
result += segmentWord + ' ' + SCALE[1]
|
|
230
212
|
}
|
|
@@ -234,7 +216,7 @@ function integerToWords (n, options) {
|
|
|
234
216
|
if (result) result += ' '
|
|
235
217
|
result += SCALE[i]
|
|
236
218
|
} else {
|
|
237
|
-
const segmentWord =
|
|
219
|
+
const segmentWord = buildScaleSegment(segment, andWord, ONES, TEENS, HUNDREDS_ARR)
|
|
238
220
|
if (result) result += ' '
|
|
239
221
|
result += segmentWord + ' ' + SCALE_PLURAL[i]
|
|
240
222
|
}
|
package/lib/languages/he.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Modern Hebrew language converter - Functional Implementation
|
|
3
3
|
*
|
|
4
|
-
* Self-contained
|
|
4
|
+
* Self-contained module with its own input validation, ready for subpath exports.
|
|
5
5
|
*
|
|
6
6
|
* Key features:
|
|
7
7
|
* - Feminine grammatical forms (default in Modern Hebrew)
|
|
@@ -9,8 +9,6 @@
|
|
|
9
9
|
* - Special 1-9 thousands construct state
|
|
10
10
|
* - "ו" (ve) conjunction rules vary by position
|
|
11
11
|
* - Per-digit decimal reading
|
|
12
|
-
*
|
|
13
|
-
* Optimization: Precomputed segment lookup tables for 0-999.
|
|
14
12
|
*/
|
|
15
13
|
|
|
16
14
|
import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
@@ -38,7 +36,7 @@ const NEGATIVE = 'מינוס'
|
|
|
38
36
|
const DECIMAL_SEP = 'נקודה'
|
|
39
37
|
|
|
40
38
|
// ============================================================================
|
|
41
|
-
//
|
|
39
|
+
// Segment Building
|
|
42
40
|
// ============================================================================
|
|
43
41
|
|
|
44
42
|
/**
|
|
@@ -139,14 +137,6 @@ function buildUnitsSegment (n, andWord) {
|
|
|
139
137
|
return result
|
|
140
138
|
}
|
|
141
139
|
|
|
142
|
-
// Precompute all 1000 segment words with default conjunction
|
|
143
|
-
const SCALE_SEGMENTS = new Array(1000)
|
|
144
|
-
const UNITS_SEGMENTS = new Array(1000)
|
|
145
|
-
for (let i = 0; i < 1000; i++) {
|
|
146
|
-
SCALE_SEGMENTS[i] = buildScaleSegment(i, 'ו')
|
|
147
|
-
UNITS_SEGMENTS[i] = buildUnitsSegment(i, 'ו')
|
|
148
|
-
}
|
|
149
|
-
|
|
150
140
|
// ============================================================================
|
|
151
141
|
// Conversion Functions
|
|
152
142
|
// ============================================================================
|
|
@@ -162,11 +152,10 @@ function integerToWords (n, options) {
|
|
|
162
152
|
if (n === 0n) return ZERO
|
|
163
153
|
|
|
164
154
|
const andWord = options.andWord ?? 'ו'
|
|
165
|
-
const usePrecomputed = andWord === 'ו'
|
|
166
155
|
|
|
167
|
-
// Fast path: numbers < 1000
|
|
156
|
+
// Fast path: numbers < 1000
|
|
168
157
|
if (n < 1000n) {
|
|
169
|
-
return
|
|
158
|
+
return buildUnitsSegment(Number(n), andWord)
|
|
170
159
|
}
|
|
171
160
|
|
|
172
161
|
// Extract segments using BigInt modulo
|
|
@@ -186,7 +175,7 @@ function integerToWords (n, options) {
|
|
|
186
175
|
|
|
187
176
|
if (i === 0) {
|
|
188
177
|
// Units segment (no scale word)
|
|
189
|
-
const segmentWord =
|
|
178
|
+
const segmentWord = buildUnitsSegment(segment, andWord)
|
|
190
179
|
if (result) {
|
|
191
180
|
// Add "ו" before single-digit units when following scale words
|
|
192
181
|
if (segment <= 9) {
|
|
@@ -203,7 +192,7 @@ function integerToWords (n, options) {
|
|
|
203
192
|
if (result) result += ' '
|
|
204
193
|
result += THOUSANDS_SPECIAL[segment]
|
|
205
194
|
} else {
|
|
206
|
-
const segmentWord =
|
|
195
|
+
const segmentWord = buildScaleSegment(segment, andWord)
|
|
207
196
|
if (result) result += ' '
|
|
208
197
|
result += segmentWord + ' ' + SCALE[1]
|
|
209
198
|
}
|
|
@@ -213,7 +202,7 @@ function integerToWords (n, options) {
|
|
|
213
202
|
if (result) result += ' '
|
|
214
203
|
result += SCALE[i]
|
|
215
204
|
} else {
|
|
216
|
-
const segmentWord =
|
|
205
|
+
const segmentWord = buildScaleSegment(segment, andWord)
|
|
217
206
|
if (result) result += ' '
|
|
218
207
|
result += segmentWord + ' ' + SCALE_PLURAL[i]
|
|
219
208
|
}
|
package/lib/languages/hi.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Hindi language converter - Functional Implementation
|
|
3
3
|
*
|
|
4
|
-
* Self-contained
|
|
4
|
+
* Self-contained module with its own input validation, ready for subpath exports.
|
|
5
5
|
*
|
|
6
6
|
* Key features:
|
|
7
7
|
* - Indian numbering system (हज़ार, लाख, करोड़)
|
|
8
8
|
* - Devanagari script
|
|
9
9
|
* - 3-2-2 grouping pattern (last 3 digits, then groups of 2)
|
|
10
10
|
* - Complete word forms for 0-99
|
|
11
|
+
* - BigInt modulo for efficient segment extraction
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
14
|
import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
@@ -38,26 +39,16 @@ const BELOW_HUNDRED = [
|
|
|
38
39
|
const SCALE_WORDS = ['', 'हज़ार', 'लाख', 'करोड़', 'अरब', 'खरब', 'नील', 'पद्म', 'शंख']
|
|
39
40
|
|
|
40
41
|
// ============================================================================
|
|
41
|
-
// Segment
|
|
42
|
+
// Segment Building
|
|
42
43
|
// ============================================================================
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
let remaining = numStr.slice(0, -3)
|
|
52
|
-
while (remaining.length > 0) {
|
|
53
|
-
segments.unshift(Number(remaining.slice(-2)))
|
|
54
|
-
remaining = remaining.slice(0, -2)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return segments
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function segmentToWords (n) {
|
|
45
|
+
/**
|
|
46
|
+
* Builds words for a 0-999 segment.
|
|
47
|
+
*
|
|
48
|
+
* @param {number} n - Number 0-999
|
|
49
|
+
* @returns {string} Hindi words for the segment
|
|
50
|
+
*/
|
|
51
|
+
function buildSegment (n) {
|
|
61
52
|
if (n === 0) return ''
|
|
62
53
|
if (n < 100) return BELOW_HUNDRED[n]
|
|
63
54
|
|
|
@@ -74,25 +65,59 @@ function segmentToWords (n) {
|
|
|
74
65
|
// Conversion Functions
|
|
75
66
|
// ============================================================================
|
|
76
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Converts a non-negative integer to Hindi words.
|
|
70
|
+
*
|
|
71
|
+
* Uses BigInt modulo for segment extraction (faster than string slicing).
|
|
72
|
+
* South Asian 3-2-2 grouping: first 3 digits, then groups of 2.
|
|
73
|
+
*
|
|
74
|
+
* @param {bigint} n - Non-negative integer to convert
|
|
75
|
+
* @returns {string} Hindi words
|
|
76
|
+
*/
|
|
77
77
|
function integerToWords (n) {
|
|
78
78
|
if (n === 0n) return ZERO
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
// Fast path: numbers < 1000
|
|
81
|
+
if (n < 1000n) {
|
|
82
|
+
return buildSegment(Number(n))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Extract segments using BigInt modulo
|
|
86
|
+
// First segment is 3 digits (thousands), rest are 2 digits (lakhs, crores, etc.)
|
|
87
|
+
// Segments stored least-significant first
|
|
88
|
+
const segments = []
|
|
83
89
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
90
|
+
// First segment: last 3 digits
|
|
91
|
+
segments.push(Number(n % 1000n))
|
|
92
|
+
let temp = n / 1000n
|
|
93
|
+
|
|
94
|
+
// Remaining segments: 2 digits each (lakh = 100k, crore = 10M, etc.)
|
|
95
|
+
while (temp > 0n) {
|
|
96
|
+
segments.push(Number(temp % 100n))
|
|
97
|
+
temp = temp / 100n
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Build result string (process from most-significant to least)
|
|
101
|
+
const words = []
|
|
102
|
+
for (let i = segments.length - 1; i >= 0; i--) {
|
|
103
|
+
const segment = segments[i]
|
|
104
|
+
if (segment === 0) continue
|
|
105
|
+
|
|
106
|
+
if (i === 0) {
|
|
107
|
+
// First segment (units place) can be 0-999
|
|
108
|
+
words.push(buildSegment(segment))
|
|
109
|
+
} else {
|
|
110
|
+
// Other segments are 0-99
|
|
111
|
+
words.push(BELOW_HUNDRED[segment])
|
|
112
|
+
}
|
|
87
113
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
words.push(SCALE_WORDS[scaleIndex])
|
|
114
|
+
// Add scale word if not the units segment
|
|
115
|
+
if (i > 0 && SCALE_WORDS[i]) {
|
|
116
|
+
words.push(SCALE_WORDS[i])
|
|
92
117
|
}
|
|
93
118
|
}
|
|
94
119
|
|
|
95
|
-
return words.join(' ')
|
|
120
|
+
return words.join(' ')
|
|
96
121
|
}
|
|
97
122
|
|
|
98
123
|
function decimalPartToWords (decimalPart) {
|
package/lib/languages/hr.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Croatian language converter - Functional Implementation
|
|
3
3
|
*
|
|
4
|
-
* Self-contained
|
|
4
|
+
* Self-contained module with its own input validation, ready for subpath exports.
|
|
5
5
|
*
|
|
6
6
|
* Key features:
|
|
7
7
|
* - Three-form pluralization (one/few/many)
|
|
@@ -14,7 +14,38 @@ import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
|
14
14
|
import { validateOptions } from '../utils/validate-options.js'
|
|
15
15
|
|
|
16
16
|
// ============================================================================
|
|
17
|
-
//
|
|
17
|
+
// Vocabulary
|
|
18
|
+
// ============================================================================
|
|
19
|
+
|
|
20
|
+
const ONES_MASC = ['', 'jedan', 'dva', 'tri', 'četiri', 'pet', 'šest', 'sedam', 'osam', 'devet']
|
|
21
|
+
const ONES_FEM = ['', 'jedna', 'dvije', 'tri', 'četiri', 'pet', 'šest', 'sedam', 'osam', 'devet']
|
|
22
|
+
|
|
23
|
+
const TEENS = ['deset', 'jedanaest', 'dvanaest', 'trinaest', 'četrnaest', 'petnaest', 'šesnaest', 'sedamnaest', 'osamnaest', 'devetnaest']
|
|
24
|
+
const TENS = ['', '', 'dvadeset', 'trideset', 'četrdeset', 'pedeset', 'šezdeset', 'sedamdeset', 'osamdeset', 'devedeset']
|
|
25
|
+
|
|
26
|
+
// Croatian has irregular hundreds
|
|
27
|
+
const HUNDREDS = ['', 'sto', 'dvjesto', 'tristo', 'četiristo', 'petsto', 'šesto', 'sedamsto', 'osamsto', 'devetsto']
|
|
28
|
+
|
|
29
|
+
const ZERO = 'nula'
|
|
30
|
+
const NEGATIVE = 'minus'
|
|
31
|
+
const DECIMAL_SEP = 'zarez'
|
|
32
|
+
|
|
33
|
+
// Scale words: [singular, few, many]
|
|
34
|
+
// Thousands (index 0) are feminine, rest are masculine
|
|
35
|
+
const SCALE_FORMS = [
|
|
36
|
+
['tisuća', 'tisuće', 'tisuća'],
|
|
37
|
+
['milijun', 'milijuna', 'milijuna'],
|
|
38
|
+
['milijarda', 'milijarde', 'milijarda'],
|
|
39
|
+
['bilijun', 'bilijuna', 'bilijuna'],
|
|
40
|
+
['bilijarda', 'bilijarde', 'bilijarda'],
|
|
41
|
+
['trilijun', 'trilijuna', 'trilijuna'],
|
|
42
|
+
['trilijarda', 'trilijarde', 'trilijarda'],
|
|
43
|
+
['kvadrilijun', 'kvadrilijuna', 'kvadrilijuna'],
|
|
44
|
+
['kvadrilijarda', 'kvadrilijarde', 'kvadrilijarda']
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
// ============================================================================
|
|
48
|
+
// Segment Building
|
|
18
49
|
// ============================================================================
|
|
19
50
|
|
|
20
51
|
function pluralize (n, forms) {
|
|
@@ -31,19 +62,7 @@ function pluralize (n, forms) {
|
|
|
31
62
|
return forms[2]
|
|
32
63
|
}
|
|
33
64
|
|
|
34
|
-
function
|
|
35
|
-
const masc = new Array(1000)
|
|
36
|
-
const fem = new Array(1000)
|
|
37
|
-
|
|
38
|
-
for (let i = 0; i < 1000; i++) {
|
|
39
|
-
masc[i] = buildSegment(i, onesMasc, teens, tens, hundreds)
|
|
40
|
-
fem[i] = buildSegment(i, onesFem, teens, tens, hundreds)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return { masc, fem }
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function buildSegment (n, ones, teens, tens, hundreds) {
|
|
65
|
+
function buildSegmentMasc (n) {
|
|
47
66
|
if (n === 0) return ''
|
|
48
67
|
|
|
49
68
|
const onesDigit = n % 10
|
|
@@ -53,58 +72,47 @@ function buildSegment (n, ones, teens, tens, hundreds) {
|
|
|
53
72
|
const parts = []
|
|
54
73
|
|
|
55
74
|
if (hundredsDigit > 0) {
|
|
56
|
-
parts.push(
|
|
75
|
+
parts.push(HUNDREDS[hundredsDigit])
|
|
57
76
|
}
|
|
58
77
|
|
|
59
78
|
if (tensDigit > 1) {
|
|
60
|
-
parts.push(
|
|
79
|
+
parts.push(TENS[tensDigit])
|
|
61
80
|
}
|
|
62
81
|
|
|
63
82
|
if (tensDigit === 1) {
|
|
64
|
-
parts.push(
|
|
83
|
+
parts.push(TEENS[onesDigit])
|
|
65
84
|
} else if (onesDigit > 0) {
|
|
66
|
-
parts.push(
|
|
85
|
+
parts.push(ONES_MASC[onesDigit])
|
|
67
86
|
}
|
|
68
87
|
|
|
69
88
|
return parts.join(' ')
|
|
70
89
|
}
|
|
71
90
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
// ============================================================================
|
|
75
|
-
|
|
76
|
-
const ONES_MASC = ['', 'jedan', 'dva', 'tri', 'četiri', 'pet', 'šest', 'sedam', 'osam', 'devet']
|
|
77
|
-
const ONES_FEM = ['', 'jedna', 'dvije', 'tri', 'četiri', 'pet', 'šest', 'sedam', 'osam', 'devet']
|
|
91
|
+
function buildSegmentFem (n) {
|
|
92
|
+
if (n === 0) return ''
|
|
78
93
|
|
|
79
|
-
const
|
|
80
|
-
const
|
|
94
|
+
const onesDigit = n % 10
|
|
95
|
+
const tensDigit = Math.floor(n / 10) % 10
|
|
96
|
+
const hundredsDigit = Math.floor(n / 100)
|
|
81
97
|
|
|
82
|
-
|
|
83
|
-
const HUNDREDS = ['', 'sto', 'dvjesto', 'tristo', 'četiristo', 'petsto', 'šesto', 'sedamsto', 'osamsto', 'devetsto']
|
|
98
|
+
const parts = []
|
|
84
99
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
100
|
+
if (hundredsDigit > 0) {
|
|
101
|
+
parts.push(HUNDREDS[hundredsDigit])
|
|
102
|
+
}
|
|
88
103
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
['tisuća', 'tisuće', 'tisuća'],
|
|
93
|
-
['milijun', 'milijuna', 'milijuna'],
|
|
94
|
-
['milijarda', 'milijarde', 'milijarda'],
|
|
95
|
-
['bilijun', 'bilijuna', 'bilijuna'],
|
|
96
|
-
['bilijarda', 'bilijarde', 'bilijarda'],
|
|
97
|
-
['trilijun', 'trilijuna', 'trilijuna'],
|
|
98
|
-
['trilijarda', 'trilijarde', 'trilijarda'],
|
|
99
|
-
['kvadrilijun', 'kvadrilijuna', 'kvadrilijuna'],
|
|
100
|
-
['kvadrilijarda', 'kvadrilijarde', 'kvadrilijarda']
|
|
101
|
-
]
|
|
104
|
+
if (tensDigit > 1) {
|
|
105
|
+
parts.push(TENS[tensDigit])
|
|
106
|
+
}
|
|
102
107
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
108
|
+
if (tensDigit === 1) {
|
|
109
|
+
parts.push(TEENS[onesDigit])
|
|
110
|
+
} else if (onesDigit > 0) {
|
|
111
|
+
parts.push(ONES_FEM[onesDigit])
|
|
112
|
+
}
|
|
106
113
|
|
|
107
|
-
|
|
114
|
+
return parts.join(' ')
|
|
115
|
+
}
|
|
108
116
|
|
|
109
117
|
// ============================================================================
|
|
110
118
|
// Conversion Functions
|
|
@@ -114,8 +122,7 @@ function integerToWords (n, options = {}) {
|
|
|
114
122
|
if (n === 0n) return ZERO
|
|
115
123
|
|
|
116
124
|
if (n < 1000n) {
|
|
117
|
-
|
|
118
|
-
return segments[Number(n)]
|
|
125
|
+
return options.gender === 'feminine' ? buildSegmentFem(Number(n)) : buildSegmentMasc(Number(n))
|
|
119
126
|
}
|
|
120
127
|
|
|
121
128
|
return buildLargeNumberWords(n, options)
|
|
@@ -147,15 +154,14 @@ function buildLargeNumberWords (n, options) {
|
|
|
147
154
|
|
|
148
155
|
if (segment !== 0) {
|
|
149
156
|
if (scaleIndex === 0) {
|
|
150
|
-
|
|
151
|
-
parts.push(segmentWords[segment])
|
|
157
|
+
parts.push(options.gender === 'feminine' ? buildSegmentFem(segment) : buildSegmentMasc(segment))
|
|
152
158
|
} else {
|
|
153
159
|
const scaleForms = SCALE_FORMS[scaleIndex - 1]
|
|
154
160
|
const scaleWord = pluralize(segment, scaleForms)
|
|
155
161
|
// Thousands (scaleIndex=1) are feminine, others masculine
|
|
156
162
|
const isFeminine = scaleIndex === 1
|
|
157
|
-
const
|
|
158
|
-
parts.push(
|
|
163
|
+
const segmentWord = isFeminine ? buildSegmentFem(segment) : buildSegmentMasc(segment)
|
|
164
|
+
parts.push(segmentWord + ' ' + scaleWord)
|
|
159
165
|
}
|
|
160
166
|
}
|
|
161
167
|
|