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/hi.js
CHANGED
|
@@ -1,126 +1,145 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
'उनचास',
|
|
59
|
-
'पचास',
|
|
60
|
-
'इक्यावन',
|
|
61
|
-
'बावन',
|
|
62
|
-
'तिरपन',
|
|
63
|
-
'चौवन',
|
|
64
|
-
'पचपन',
|
|
65
|
-
'छप्पन',
|
|
66
|
-
'सत्तावन',
|
|
67
|
-
'अट्ठावन',
|
|
68
|
-
'उनसठ',
|
|
69
|
-
'साठ',
|
|
70
|
-
'इकसठ',
|
|
71
|
-
'बासठ',
|
|
72
|
-
'तिरसठ',
|
|
73
|
-
'चौंसठ',
|
|
74
|
-
'पैंसठ',
|
|
75
|
-
'छियासठ',
|
|
76
|
-
'सड़सठ',
|
|
77
|
-
'अड़सठ',
|
|
78
|
-
'उनहत्तर',
|
|
79
|
-
'सत्तर',
|
|
80
|
-
'इकहत्तर',
|
|
81
|
-
'बहत्तर',
|
|
82
|
-
'तिहत्तर',
|
|
83
|
-
'चौहत्तर',
|
|
84
|
-
'पचहत्तर',
|
|
85
|
-
'छिहत्तर',
|
|
86
|
-
'सतहत्तर',
|
|
87
|
-
'अठहत्तर',
|
|
88
|
-
'उन्यासी',
|
|
89
|
-
'अस्सी',
|
|
90
|
-
'इक्यासी',
|
|
91
|
-
'बयासी',
|
|
92
|
-
'तिरासी',
|
|
93
|
-
'चौरासी',
|
|
94
|
-
'पचासी',
|
|
95
|
-
'छियासी',
|
|
96
|
-
'सत्तासी',
|
|
97
|
-
'अट्ठासी',
|
|
98
|
-
'नवासी',
|
|
99
|
-
'नब्बे',
|
|
100
|
-
'इक्यानवे',
|
|
101
|
-
'बानवे',
|
|
102
|
-
'तिरानवे',
|
|
103
|
-
'चौरानवे',
|
|
104
|
-
'पचानवे',
|
|
105
|
-
'छियानवे',
|
|
106
|
-
'सत्तानवे',
|
|
107
|
-
'अट्ठानवे',
|
|
108
|
-
'निन्यानवे'
|
|
109
|
-
]
|
|
110
|
-
|
|
111
|
-
scaleWords = [
|
|
112
|
-
'',
|
|
113
|
-
'हज़ार',
|
|
114
|
-
'लाख',
|
|
115
|
-
'करोड़',
|
|
116
|
-
'अरब',
|
|
117
|
-
'खरब',
|
|
118
|
-
'नील',
|
|
119
|
-
'पद्म',
|
|
120
|
-
'शंख'
|
|
121
|
-
]
|
|
1
|
+
/**
|
|
2
|
+
* Hindi language converter - Functional Implementation
|
|
3
|
+
*
|
|
4
|
+
* Self-contained converter for South Asian numbering.
|
|
5
|
+
*
|
|
6
|
+
* Key features:
|
|
7
|
+
* - Indian numbering system (हज़ार, लाख, करोड़)
|
|
8
|
+
* - Devanagari script
|
|
9
|
+
* - 3-2-2 grouping pattern (last 3 digits, then groups of 2)
|
|
10
|
+
* - Complete word forms for 0-99
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
14
|
+
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// Vocabulary
|
|
17
|
+
// ============================================================================
|
|
18
|
+
|
|
19
|
+
const ZERO = 'शून्य'
|
|
20
|
+
const NEGATIVE = 'माइनस'
|
|
21
|
+
const DECIMAL_SEP = 'दशमलव'
|
|
22
|
+
const HUNDRED = 'सौ'
|
|
23
|
+
|
|
24
|
+
const BELOW_HUNDRED = [
|
|
25
|
+
'शून्य', 'एक', 'दो', 'तीन', 'चार', 'पाँच', 'छह', 'सात', 'आठ', 'नौ',
|
|
26
|
+
'दस', 'ग्यारह', 'बारह', 'तेरह', 'चौदह', 'पंद्रह', 'सोलह', 'सत्रह', 'अठारह', 'उन्नीस',
|
|
27
|
+
'बीस', 'इक्कीस', 'बाईस', 'तेईस', 'चौबीस', 'पच्चीस', 'छब्बीस', 'सत्ताईस', 'अट्ठाईस', 'उनतीस',
|
|
28
|
+
'तीस', 'इकतीस', 'बत्तीस', 'तैंतीस', 'चौंतीस', 'पैंतीस', 'छत्तीस', 'सैंतीस', 'अड़तीस', 'उनतालीस',
|
|
29
|
+
'चालीस', 'इकतालीस', 'बयालीस', 'तेतालीस', 'चवालीस', 'पैंतालीस', 'छियालीस', 'सैंतालीस', 'अड़तालीस', 'उनचास',
|
|
30
|
+
'पचास', 'इक्यावन', 'बावन', 'तिरपन', 'चौवन', 'पचपन', 'छप्पन', 'सत्तावन', 'अट्ठावन', 'उनसठ',
|
|
31
|
+
'साठ', 'इकसठ', 'बासठ', 'तिरसठ', 'चौंसठ', 'पैंसठ', 'छियासठ', 'सड़सठ', 'अड़सठ', 'उनहत्तर',
|
|
32
|
+
'सत्तर', 'इकहत्तर', 'बहत्तर', 'तिहत्तर', 'चौहत्तर', 'पचहत्तर', 'छिहत्तर', 'सतहत्तर', 'अठहत्तर', 'उन्यासी',
|
|
33
|
+
'अस्सी', 'इक्यासी', 'बयासी', 'तिरासी', 'चौरासी', 'पचासी', 'छियासी', 'सत्तासी', 'अट्ठासी', 'नवासी',
|
|
34
|
+
'नब्बे', 'इक्यानवे', 'बानवे', 'तिरानवे', 'चौरानवे', 'पचानवे', 'छियानवे', 'सत्तानवे', 'अट्ठानवे', 'निन्यानवे'
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
// Scale words: index 0 = units (empty), 1 = thousand, 2 = lakh, 3 = crore, etc.
|
|
38
|
+
const SCALE_WORDS = ['', 'हज़ार', 'लाख', 'करोड़', 'अरब', 'खरब', 'नील', 'पद्म', 'शंख']
|
|
39
|
+
|
|
40
|
+
// ============================================================================
|
|
41
|
+
// Segment Splitting (inlined for performance)
|
|
42
|
+
// ============================================================================
|
|
43
|
+
|
|
44
|
+
function groupByThreeThenTwos (n) {
|
|
45
|
+
const numStr = n.toString()
|
|
46
|
+
if (numStr.length <= 3) return [Number(numStr)]
|
|
47
|
+
|
|
48
|
+
const segments = []
|
|
49
|
+
segments.unshift(Number(numStr.slice(-3)))
|
|
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
|
|
122
58
|
}
|
|
123
59
|
|
|
124
|
-
|
|
125
|
-
|
|
60
|
+
function segmentToWords (n) {
|
|
61
|
+
if (n === 0) return ''
|
|
62
|
+
if (n < 100) return BELOW_HUNDRED[n]
|
|
63
|
+
|
|
64
|
+
const hundreds = Math.trunc(n / 100)
|
|
65
|
+
const remainder = n % 100
|
|
66
|
+
|
|
67
|
+
if (remainder === 0) {
|
|
68
|
+
return BELOW_HUNDRED[hundreds] + ' ' + HUNDRED
|
|
69
|
+
}
|
|
70
|
+
return BELOW_HUNDRED[hundreds] + ' ' + HUNDRED + ' ' + BELOW_HUNDRED[remainder]
|
|
126
71
|
}
|
|
72
|
+
|
|
73
|
+
// ============================================================================
|
|
74
|
+
// Conversion Functions
|
|
75
|
+
// ============================================================================
|
|
76
|
+
|
|
77
|
+
function integerToWords (n) {
|
|
78
|
+
if (n === 0n) return ZERO
|
|
79
|
+
|
|
80
|
+
const segments = groupByThreeThenTwos(n)
|
|
81
|
+
const segmentCount = segments.length
|
|
82
|
+
const words = []
|
|
83
|
+
|
|
84
|
+
for (let i = 0; i < segmentCount; i++) {
|
|
85
|
+
const segmentValue = segments[i]
|
|
86
|
+
if (segmentValue === 0) continue
|
|
87
|
+
|
|
88
|
+
const scaleIndex = segmentCount - i - 1
|
|
89
|
+
words.push(segmentToWords(segmentValue))
|
|
90
|
+
if (scaleIndex > 0 && SCALE_WORDS[scaleIndex]) {
|
|
91
|
+
words.push(SCALE_WORDS[scaleIndex])
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return words.join(' ').trim()
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function decimalPartToWords (decimalPart) {
|
|
99
|
+
let result = ''
|
|
100
|
+
let i = 0
|
|
101
|
+
|
|
102
|
+
while (i < decimalPart.length && decimalPart[i] === '0') {
|
|
103
|
+
if (result) result += ' '
|
|
104
|
+
result += ZERO
|
|
105
|
+
i++
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const remainder = decimalPart.slice(i)
|
|
109
|
+
if (remainder) {
|
|
110
|
+
if (result) result += ' '
|
|
111
|
+
result += integerToWords(BigInt(remainder))
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return result
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Converts a numeric value to Hindi words.
|
|
119
|
+
*
|
|
120
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
121
|
+
* @returns {string} The number in Hindi words
|
|
122
|
+
*/
|
|
123
|
+
function toWords (value) {
|
|
124
|
+
const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
|
|
125
|
+
|
|
126
|
+
let result = ''
|
|
127
|
+
|
|
128
|
+
if (isNegative) {
|
|
129
|
+
result = NEGATIVE + ' '
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
result += integerToWords(integerPart)
|
|
133
|
+
|
|
134
|
+
if (decimalPart) {
|
|
135
|
+
result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return result
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ============================================================================
|
|
142
|
+
// Exports
|
|
143
|
+
// ============================================================================
|
|
144
|
+
|
|
145
|
+
export { toWords }
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a numeric value to Croatian words.
|
|
3
|
+
*
|
|
4
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
5
|
+
* @param {Object} [options] - Optional configuration
|
|
6
|
+
* @param {('masculine'|'feminine')} [options.gender='masculine'] - Grammatical gender
|
|
7
|
+
* @returns {string} The number in Croatian words
|
|
8
|
+
*/
|
|
9
|
+
export function toWords(value: number | string | bigint, options?: {
|
|
10
|
+
gender?: "masculine" | "feminine" | undefined;
|
|
11
|
+
}): string;
|
package/lib/languages/hr.js
CHANGED
|
@@ -1,157 +1,218 @@
|
|
|
1
|
-
import SlavicLanguage from '../classes/slavic-language.js'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @typedef {Object} SlavicOptions
|
|
5
|
-
* @property {boolean} [feminine=false] Use feminine forms for numbers.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
1
|
/**
|
|
9
|
-
* Croatian language converter
|
|
2
|
+
* Croatian language converter - Functional Implementation
|
|
10
3
|
*
|
|
11
|
-
*
|
|
12
|
-
* - Croatian number words (jedan/jedna, dva/dvije, tri, četiri...)
|
|
13
|
-
* - Gender-aware forms (masculine/feminine)
|
|
14
|
-
* - Slavic three-form pluralization (tisuća/tisuće/tisuća)
|
|
15
|
-
* - Croatian-specific declension endings
|
|
4
|
+
* Self-contained converter using shared Slavic utilities.
|
|
16
5
|
*
|
|
17
|
-
* Key
|
|
18
|
-
* - Three-form pluralization
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* - Chunk-based decomposition (splits into groups of 3 digits: ones, thousands, millions, etc.)
|
|
23
|
-
* - Large number handling via thousands[] array with indexed [singular, few, many] forms
|
|
24
|
-
* - Gender-specific number forms for 1 and 2 (masculine/feminine dual forms)
|
|
25
|
-
*
|
|
26
|
-
* Features:
|
|
27
|
-
* - Dual gender forms for 1 and 2 (jedan/jedna, dva/dvije)
|
|
28
|
-
* - Latin script orthography
|
|
29
|
-
* - Similar structure to Serbian
|
|
30
|
-
*
|
|
31
|
-
* Inherits from SlavicLanguage for complex pluralization algorithms.
|
|
6
|
+
* Key features:
|
|
7
|
+
* - Three-form pluralization (one/few/many)
|
|
8
|
+
* - Gender: thousands are feminine, millions+ are masculine
|
|
9
|
+
* - Irregular hundreds (dvjesto, tristo, etc.)
|
|
10
|
+
* - Long scale naming with -ard forms
|
|
32
11
|
*/
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
12
|
+
|
|
13
|
+
import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
14
|
+
import { validateOptions } from '../utils/validate-options.js'
|
|
15
|
+
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Slavic Utilities (inlined for performance)
|
|
18
|
+
// ============================================================================
|
|
19
|
+
|
|
20
|
+
function pluralize (n, forms) {
|
|
21
|
+
const num = typeof n === 'bigint' ? Number(n) : n
|
|
22
|
+
const lastDigit = num % 10
|
|
23
|
+
const lastTwoDigits = num % 100
|
|
24
|
+
|
|
25
|
+
if (lastTwoDigits >= 11 && lastTwoDigits <= 19) {
|
|
26
|
+
return forms[2]
|
|
47
27
|
}
|
|
48
28
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
29
|
+
if (lastDigit === 1) return forms[0]
|
|
30
|
+
if (lastDigit >= 2 && lastDigit <= 4) return forms[1]
|
|
31
|
+
return forms[2]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function buildAllSegments (onesMasc, onesFem, teens, tens, hundreds) {
|
|
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)
|
|
60
41
|
}
|
|
61
42
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
43
|
+
return { masc, fem }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function buildSegment (n, ones, teens, tens, hundreds) {
|
|
47
|
+
if (n === 0) return ''
|
|
48
|
+
|
|
49
|
+
const onesDigit = n % 10
|
|
50
|
+
const tensDigit = Math.floor(n / 10) % 10
|
|
51
|
+
const hundredsDigit = Math.floor(n / 100)
|
|
52
|
+
|
|
53
|
+
const parts = []
|
|
54
|
+
|
|
55
|
+
if (hundredsDigit > 0) {
|
|
56
|
+
parts.push(hundreds[hundredsDigit])
|
|
71
57
|
}
|
|
72
58
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
2: 'dvjesto',
|
|
76
|
-
3: 'tristo',
|
|
77
|
-
4: 'četiristo',
|
|
78
|
-
5: 'petsto',
|
|
79
|
-
6: 'šesto',
|
|
80
|
-
7: 'sedamsto',
|
|
81
|
-
8: 'osamsto',
|
|
82
|
-
9: 'devetsto'
|
|
59
|
+
if (tensDigit > 1) {
|
|
60
|
+
parts.push(tens[tensDigit])
|
|
83
61
|
}
|
|
84
62
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
3: ['milijarda', 'milijarde', 'milijarda', false], // 10 ^ 9
|
|
90
|
-
4: ['bilijun', 'bilijuna', 'bilijuna', false], // 10 ^ 12
|
|
91
|
-
5: ['bilijarda', 'bilijarde', 'bilijarda', false], // 10 ^ 15
|
|
92
|
-
6: ['trilijun', 'trilijuna', 'trilijuna', false], // 10 ^ 18
|
|
93
|
-
7: ['trilijarda', 'trilijarde', 'trilijarda', false], // 10 ^ 21
|
|
94
|
-
8: ['kvadrilijun', 'kvadrilijuna', 'kvadrilijuna', false], // 10 ^ 24
|
|
95
|
-
9: ['kvadrilijarda', 'kvadrilijarde', 'kvadrilijarda', false], // 10 ^ 27
|
|
96
|
-
10: ['kvintilijun', 'kvintilijuna', 'kvintilijuna', false] // 10 ^ 30
|
|
63
|
+
if (tensDigit === 1) {
|
|
64
|
+
parts.push(teens[onesDigit])
|
|
65
|
+
} else if (onesDigit > 0) {
|
|
66
|
+
parts.push(ones[onesDigit])
|
|
97
67
|
}
|
|
98
68
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
69
|
+
return parts.join(' ')
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ============================================================================
|
|
73
|
+
// Vocabulary
|
|
74
|
+
// ============================================================================
|
|
102
75
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
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']
|
|
106
78
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
79
|
+
const TEENS = ['deset', 'jedanaest', 'dvanaest', 'trinaest', 'četrnaest', 'petnaest', 'šesnaest', 'sedamnaest', 'osamnaest', 'devetnaest']
|
|
80
|
+
const TENS = ['', '', 'dvadeset', 'trideset', 'četrdeset', 'pedeset', 'šezdeset', 'sedamdeset', 'osamdeset', 'devedeset']
|
|
110
81
|
|
|
111
|
-
|
|
82
|
+
// Croatian has irregular hundreds
|
|
83
|
+
const HUNDREDS = ['', 'sto', 'dvjesto', 'tristo', 'četiristo', 'petsto', 'šesto', 'sedamsto', 'osamsto', 'devetsto']
|
|
84
|
+
|
|
85
|
+
const ZERO = 'nula'
|
|
86
|
+
const NEGATIVE = 'minus'
|
|
87
|
+
const DECIMAL_SEP = 'zarez'
|
|
88
|
+
|
|
89
|
+
// Scale words: [singular, few, many]
|
|
90
|
+
// Thousands (index 0) are feminine, rest are masculine
|
|
91
|
+
const SCALE_FORMS = [
|
|
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
|
+
]
|
|
102
|
+
|
|
103
|
+
// ============================================================================
|
|
104
|
+
// Precomputed Lookup Tables
|
|
105
|
+
// ============================================================================
|
|
106
|
+
|
|
107
|
+
const { masc: SEGMENTS_MASC, fem: SEGMENTS_FEM } = buildAllSegments(ONES_MASC, ONES_FEM, TEENS, TENS, HUNDREDS)
|
|
108
|
+
|
|
109
|
+
// ============================================================================
|
|
110
|
+
// Conversion Functions
|
|
111
|
+
// ============================================================================
|
|
112
|
+
|
|
113
|
+
function integerToWords (n, options = {}) {
|
|
114
|
+
if (n === 0n) return ZERO
|
|
115
|
+
|
|
116
|
+
if (n < 1000n) {
|
|
117
|
+
const segments = options.gender === 'feminine' ? SEGMENTS_FEM : SEGMENTS_MASC
|
|
118
|
+
return segments[Number(n)]
|
|
112
119
|
}
|
|
113
120
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
121
|
+
return buildLargeNumberWords(n, options)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function buildLargeNumberWords (n, options) {
|
|
125
|
+
const numStr = n.toString()
|
|
126
|
+
const len = numStr.length
|
|
127
|
+
|
|
128
|
+
const segments = []
|
|
129
|
+
const segmentSize = 3
|
|
130
|
+
|
|
131
|
+
const remainderLen = len % segmentSize
|
|
132
|
+
let pos = 0
|
|
133
|
+
if (remainderLen > 0) {
|
|
134
|
+
segments.push(Number(numStr.slice(0, remainderLen)))
|
|
135
|
+
pos = remainderLen
|
|
136
|
+
}
|
|
137
|
+
while (pos < len) {
|
|
138
|
+
segments.push(Number(numStr.slice(pos, pos + segmentSize)))
|
|
139
|
+
pos += segmentSize
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const parts = []
|
|
143
|
+
let scaleIndex = segments.length - 1
|
|
144
|
+
|
|
145
|
+
for (let i = 0; i < segments.length; i++) {
|
|
146
|
+
const segment = segments[i]
|
|
147
|
+
|
|
148
|
+
if (segment !== 0) {
|
|
149
|
+
if (scaleIndex === 0) {
|
|
150
|
+
const segmentWords = options.gender === 'feminine' ? SEGMENTS_FEM : SEGMENTS_MASC
|
|
151
|
+
parts.push(segmentWords[segment])
|
|
152
|
+
} else {
|
|
153
|
+
const scaleForms = SCALE_FORMS[scaleIndex - 1]
|
|
154
|
+
const scaleWord = pluralize(segment, scaleForms)
|
|
155
|
+
// Thousands (scaleIndex=1) are feminine, others masculine
|
|
156
|
+
const isFeminine = scaleIndex === 1
|
|
157
|
+
const segmentWords = isFeminine ? SEGMENTS_FEM : SEGMENTS_MASC
|
|
158
|
+
parts.push(segmentWords[segment] + ' ' + scaleWord)
|
|
139
159
|
}
|
|
140
160
|
}
|
|
141
|
-
|
|
161
|
+
|
|
162
|
+
scaleIndex--
|
|
142
163
|
}
|
|
164
|
+
|
|
165
|
+
return parts.join(' ')
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function decimalPartToWords (decimalPart, options) {
|
|
169
|
+
let result = ''
|
|
170
|
+
let i = 0
|
|
171
|
+
|
|
172
|
+
while (i < decimalPart.length && decimalPart[i] === '0') {
|
|
173
|
+
if (result) result += ' '
|
|
174
|
+
result += ZERO
|
|
175
|
+
i++
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const remainder = decimalPart.slice(i)
|
|
179
|
+
if (remainder) {
|
|
180
|
+
if (result) result += ' '
|
|
181
|
+
result += integerToWords(BigInt(remainder), options)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return result
|
|
143
185
|
}
|
|
144
186
|
|
|
145
187
|
/**
|
|
146
|
-
* Converts a
|
|
188
|
+
* Converts a numeric value to Croatian words.
|
|
147
189
|
*
|
|
148
|
-
* @param {number|string|bigint} value The
|
|
149
|
-
* @param {Object} [options
|
|
150
|
-
* @param {
|
|
151
|
-
* @returns {string} The number
|
|
152
|
-
* @throws {TypeError} If value is NaN or invalid type.
|
|
153
|
-
* @throws {Error} If value is an invalid number string.
|
|
190
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
191
|
+
* @param {Object} [options] - Optional configuration
|
|
192
|
+
* @param {('masculine'|'feminine')} [options.gender='masculine'] - Grammatical gender
|
|
193
|
+
* @returns {string} The number in Croatian words
|
|
154
194
|
*/
|
|
155
|
-
|
|
156
|
-
|
|
195
|
+
function toWords (value, options) {
|
|
196
|
+
options = validateOptions(options)
|
|
197
|
+
const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
|
|
198
|
+
|
|
199
|
+
let result = ''
|
|
200
|
+
|
|
201
|
+
if (isNegative) {
|
|
202
|
+
result = NEGATIVE + ' '
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
result += integerToWords(integerPart, options)
|
|
206
|
+
|
|
207
|
+
if (decimalPart) {
|
|
208
|
+
result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart, options)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return result
|
|
157
212
|
}
|
|
213
|
+
|
|
214
|
+
// ============================================================================
|
|
215
|
+
// Exports
|
|
216
|
+
// ============================================================================
|
|
217
|
+
|
|
218
|
+
export { toWords }
|