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/mr.js
CHANGED
|
@@ -1,156 +1,137 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Marathi language
|
|
2
|
+
* Marathi language converter - Functional Implementation
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* Numbers: शून्य (0), एक (1), दोन (2), तीन (3), चार (4), पाच (5)...
|
|
4
|
+
* Self-contained converter for South Asian numbering.
|
|
6
5
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
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
|
+
* - Per-digit decimal reading
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import
|
|
14
|
+
import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
15
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
|
-
'त्र्याऐंशी',
|
|
112
|
-
'चौऱ्याऐंशी',
|
|
113
|
-
'पंच्याऐंशी',
|
|
114
|
-
'शहाऐंशी',
|
|
115
|
-
'सत्याऐंशी',
|
|
116
|
-
'अठ्ठ्याऐंशी',
|
|
117
|
-
'एकोणनव्वद',
|
|
118
|
-
'नव्वद',
|
|
119
|
-
'एक्याण्णव',
|
|
120
|
-
'ब्याण्णव',
|
|
121
|
-
'त्र्याण्णव',
|
|
122
|
-
'चौऱ्याण्णव',
|
|
123
|
-
'पंच्याण्णव',
|
|
124
|
-
'शहाण्णव',
|
|
125
|
-
'सत्याण्णव',
|
|
126
|
-
'अठ्ठ्याण्णव',
|
|
127
|
-
'नव्याण्णव'
|
|
128
|
-
]
|
|
129
|
-
|
|
130
|
-
scaleWords = [
|
|
131
|
-
'',
|
|
132
|
-
'हजार',
|
|
133
|
-
'लाख',
|
|
134
|
-
'कोटी',
|
|
135
|
-
'अब्ज',
|
|
136
|
-
'खर्व',
|
|
137
|
-
'निखर्व',
|
|
138
|
-
'महापद्म',
|
|
139
|
-
'शंकू'
|
|
140
|
-
]
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Vocabulary
|
|
18
|
+
// ============================================================================
|
|
19
|
+
|
|
20
|
+
const ZERO = 'शून्य'
|
|
21
|
+
const NEGATIVE = 'उणे'
|
|
22
|
+
const DECIMAL_SEP = 'दशांश'
|
|
23
|
+
const HUNDRED = 'शंभर'
|
|
24
|
+
|
|
25
|
+
const BELOW_HUNDRED = [
|
|
26
|
+
'शून्य', 'एक', 'दोन', 'तीन', 'चार', 'पाच', 'सहा', 'सात', 'आठ', 'नऊ',
|
|
27
|
+
'दहा', 'अकरा', 'बारा', 'तेरा', 'चौदा', 'पंधरा', 'सोळा', 'सतरा', 'अठरा', 'एकोणीस',
|
|
28
|
+
'वीस', 'एकवीस', 'बावीस', 'तेवीस', 'चोवीस', 'पंचवीस', 'सव्वीस', 'सत्तावीस', 'अठ्ठावीस', 'एकोणतीस',
|
|
29
|
+
'तीस', 'एकतीस', 'बत्तीस', 'तेहेतीस', 'चौतीस', 'पस्तीस', 'छत्तीस', 'सदतीस', 'अडतीस', 'एकोणचाळीस',
|
|
30
|
+
'चाळीस', 'एकेचाळीस', 'बेचाळीस', 'त्रेचाळीस', 'चव्वेचाळीस', 'पंचेचाळीस', 'सेहेचाळीस', 'सत्तेचाळीस', 'अठ्ठेचाळीस', 'एकोणपन्नास',
|
|
31
|
+
'पन्नास', 'एक्काव्वन', 'बावन्न', 'त्रेपन्न', 'चोपन्न', 'पंचाव्वन', 'छप्पन्न', 'सत्तावन्न', 'अठ्ठावन्न', 'एकोणसाठ',
|
|
32
|
+
'साठ', 'एकसष्ठ', 'बासष्ठ', 'त्रेसष्ठ', 'चौसष्ठ', 'पासष्ठ', 'सहासष्ठ', 'सदुसष्ठ', 'अडुसष्ठ', 'एकोणसत्तर',
|
|
33
|
+
'सत्तर', 'एकाहत्तर', 'बाहत्तर', 'त्र्याहत्तर', 'चौऱ्याहत्तर', 'पंच्याहत्तर', 'शहात्तर', 'सत्याहत्तर', 'अठ्ठ्याहत्तर', 'एकोणऐंशी',
|
|
34
|
+
'ऐंशी', 'एक्याऐंशी', 'ब्याऐंशी', 'त्र्याऐंशी', 'चौऱ्याऐंशी', 'पंच्याऐंशी', 'शहाऐंशी', 'सत्याऐंशी', 'अठ्ठ्याऐंशी', 'एकोणनव्वद',
|
|
35
|
+
'नव्वद', 'एक्याण्णव', 'ब्याण्णव', 'त्र्याण्णव', 'चौऱ्याण्णव', 'पंच्याण्णव', 'शहाण्णव', 'सत्याण्णव', 'अठ्ठ्याण्णव', 'नव्याण्णव'
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
// Scale words: index 0 = units (empty), 1 = thousand, 2 = lakh, 3 = crore, etc.
|
|
39
|
+
const SCALE_WORDS = ['', 'हजार', 'लाख', 'कोटी', 'अब्ज', 'खर्व', 'निखर्व', 'महापद्म', 'शंकू']
|
|
40
|
+
|
|
41
|
+
// ============================================================================
|
|
42
|
+
// Segment Splitting (inlined for performance)
|
|
43
|
+
// ============================================================================
|
|
44
|
+
|
|
45
|
+
function groupByThreeThenTwos (n) {
|
|
46
|
+
const numStr = n.toString()
|
|
47
|
+
if (numStr.length <= 3) return [Number(numStr)]
|
|
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) {
|
|
62
|
+
if (n === 0) return ''
|
|
63
|
+
if (n < 100) return BELOW_HUNDRED[n]
|
|
64
|
+
|
|
65
|
+
const hundreds = Math.trunc(n / 100)
|
|
66
|
+
const remainder = n % 100
|
|
67
|
+
|
|
68
|
+
if (remainder === 0) {
|
|
69
|
+
return BELOW_HUNDRED[hundreds] + ' ' + HUNDRED
|
|
70
|
+
}
|
|
71
|
+
return BELOW_HUNDRED[hundreds] + ' ' + HUNDRED + ' ' + BELOW_HUNDRED[remainder]
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ============================================================================
|
|
75
|
+
// Conversion Functions
|
|
76
|
+
// ============================================================================
|
|
77
|
+
|
|
78
|
+
function integerToWords (n) {
|
|
79
|
+
if (n === 0n) return ZERO
|
|
80
|
+
|
|
81
|
+
const segments = groupByThreeThenTwos(n)
|
|
82
|
+
const segmentCount = segments.length
|
|
83
|
+
const words = []
|
|
84
|
+
|
|
85
|
+
for (let i = 0; i < segmentCount; i++) {
|
|
86
|
+
const segmentValue = segments[i]
|
|
87
|
+
if (segmentValue === 0) continue
|
|
88
|
+
|
|
89
|
+
const scaleIndex = segmentCount - i - 1
|
|
90
|
+
words.push(segmentToWords(segmentValue))
|
|
91
|
+
if (scaleIndex > 0 && SCALE_WORDS[scaleIndex]) {
|
|
92
|
+
words.push(SCALE_WORDS[scaleIndex])
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return words.join(' ').trim()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function decimalPartToWords (decimalPart) {
|
|
100
|
+
// Per-digit decimal reading
|
|
101
|
+
const digits = []
|
|
102
|
+
for (const char of decimalPart) {
|
|
103
|
+
const d = parseInt(char, 10)
|
|
104
|
+
digits.push(d === 0 ? ZERO : BELOW_HUNDRED[d])
|
|
105
|
+
}
|
|
106
|
+
return digits.join(' ')
|
|
141
107
|
}
|
|
142
108
|
|
|
143
109
|
/**
|
|
144
|
-
*
|
|
110
|
+
* Converts a numeric value to Marathi words.
|
|
145
111
|
*
|
|
146
|
-
* @param {number|string|bigint} value - The
|
|
147
|
-
* @
|
|
148
|
-
* @returns {string} The Marathi word representation
|
|
149
|
-
* @example
|
|
150
|
-
* convertToWords(42) // 'बेचाळीस'
|
|
151
|
-
* convertToWords(1000) // 'एक हजार'
|
|
152
|
-
* convertToWords(100000) // 'एक लाख'
|
|
112
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
113
|
+
* @returns {string} The number in Marathi words
|
|
153
114
|
*/
|
|
154
|
-
|
|
155
|
-
|
|
115
|
+
function toWords (value) {
|
|
116
|
+
const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
|
|
117
|
+
|
|
118
|
+
let result = ''
|
|
119
|
+
|
|
120
|
+
if (isNegative) {
|
|
121
|
+
result = NEGATIVE + ' '
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
result += integerToWords(integerPart)
|
|
125
|
+
|
|
126
|
+
if (decimalPart) {
|
|
127
|
+
result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return result
|
|
156
131
|
}
|
|
132
|
+
|
|
133
|
+
// ============================================================================
|
|
134
|
+
// Exports
|
|
135
|
+
// ============================================================================
|
|
136
|
+
|
|
137
|
+
export { toWords }
|
package/lib/languages/ms.js
CHANGED
|
@@ -1,146 +1,205 @@
|
|
|
1
|
-
import AbstractLanguage from '../classes/abstract-language.js'
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
|
-
* Malay (Bahasa Melayu) language converter
|
|
2
|
+
* Malay (Bahasa Melayu) language converter - Functional Implementation
|
|
3
|
+
*
|
|
4
|
+
* Self-contained converter with precomputed lookup tables.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
9
|
-
* -
|
|
10
|
-
* -
|
|
6
|
+
* Key features:
|
|
7
|
+
* - "Se-" prefix for ALL singular scale units (seratus, seribu, sejuta, sebilion)
|
|
8
|
+
* - Regular patterns (puluh for tens, ratus for hundreds)
|
|
9
|
+
* - Teens with "belas" suffix
|
|
10
|
+
* - Note: "lapan" (8) differs from Indonesian "delapan"
|
|
11
11
|
*/
|
|
12
|
-
export class Malay extends AbstractLanguage {
|
|
13
|
-
negativeWord = 'minus'
|
|
14
|
-
decimalSeparatorWord = 'perpuluhan'
|
|
15
|
-
zeroWord = 'sifar'
|
|
16
|
-
base = {
|
|
17
|
-
0: [],
|
|
18
|
-
1: ['satu'],
|
|
19
|
-
2: ['dua'],
|
|
20
|
-
3: ['tiga'],
|
|
21
|
-
4: ['empat'],
|
|
22
|
-
5: ['lima'],
|
|
23
|
-
6: ['enam'],
|
|
24
|
-
7: ['tujuh'],
|
|
25
|
-
8: ['lapan'],
|
|
26
|
-
9: ['sembilan']
|
|
27
|
-
}
|
|
28
12
|
|
|
29
|
-
|
|
30
|
-
3: 'ribu',
|
|
31
|
-
6: 'juta',
|
|
32
|
-
9: 'bilion',
|
|
33
|
-
12: 'trilion'
|
|
34
|
-
}
|
|
13
|
+
import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
35
14
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const length = stringNumber.length
|
|
40
|
-
let firstBlock
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// Vocabulary
|
|
17
|
+
// ============================================================================
|
|
41
18
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const firstBlockLength = length % 3
|
|
19
|
+
const ONES = ['', 'satu', 'dua', 'tiga', 'empat', 'lima', 'enam', 'tujuh', 'lapan', 'sembilan']
|
|
20
|
+
const TEENS = ['sepuluh', 'sebelas', 'dua belas', 'tiga belas', 'empat belas', 'lima belas', 'enam belas', 'tujuh belas', 'lapan belas', 'sembilan belas']
|
|
21
|
+
const TENS = ['', '', 'dua puluh', 'tiga puluh', 'empat puluh', 'lima puluh', 'enam puluh', 'tujuh puluh', 'lapan puluh', 'sembilan puluh']
|
|
46
22
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
23
|
+
const HUNDRED_WORD = 'ratus'
|
|
24
|
+
const THOUSAND_WORD = 'ribu'
|
|
25
|
+
const SCALE_WORDS = ['juta', 'bilion', 'trilion']
|
|
51
26
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
27
|
+
const ZERO = 'sifar'
|
|
28
|
+
const NEGATIVE = 'minus'
|
|
29
|
+
const DECIMAL_SEP = 'perpuluhan'
|
|
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 = []
|
|
59
43
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (firstBlock[0].length === 1) {
|
|
65
|
-
spelling = firstBlock[0] === '0' ? ['sifar'] : this.base[Math.trunc(firstBlock[0])]
|
|
66
|
-
} else if (firstBlock[0].length === 2) {
|
|
67
|
-
spelling = this.getTens(firstBlock[0])
|
|
44
|
+
// Hundreds: seratus (100) or N ratus (200-900)
|
|
45
|
+
if (hundredsDigit > 0) {
|
|
46
|
+
if (hundredsDigit === 1) {
|
|
47
|
+
parts.push('se' + HUNDRED_WORD)
|
|
68
48
|
} else {
|
|
69
|
-
|
|
49
|
+
parts.push(ONES[hundredsDigit] + ' ' + HUNDRED_WORD)
|
|
70
50
|
}
|
|
71
|
-
wordBlocks = [...wordBlocks, [firstBlock[0], spelling]]
|
|
72
|
-
for (let index = 1; index < blocks.length; index++) {
|
|
73
|
-
let block = blocks[index]
|
|
74
|
-
spelling = [...this.getHundreds(block[0][0]), ...this.getTens(block[0].slice(1, 3))]
|
|
75
|
-
block = [...block, spelling]
|
|
76
|
-
wordBlocks = [...wordBlocks, block]
|
|
77
|
-
}
|
|
78
|
-
return wordBlocks
|
|
79
51
|
}
|
|
80
52
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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])
|
|
89
66
|
}
|
|
90
67
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
68
|
+
return parts.join(' ')
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const SEGMENTS = new Array(1000)
|
|
72
|
+
for (let i = 0; i < 1000; i++) {
|
|
73
|
+
SEGMENTS[i] = buildSegment(i)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ============================================================================
|
|
77
|
+
// Conversion Functions
|
|
78
|
+
// ============================================================================
|
|
79
|
+
|
|
80
|
+
function integerToWords (n) {
|
|
81
|
+
if (n === 0n) return ZERO
|
|
82
|
+
|
|
83
|
+
if (n < 1000n) {
|
|
84
|
+
return SEGMENTS[Number(n)]
|
|
85
|
+
}
|
|
86
|
+
|
|
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
|
|
94
|
+
} else {
|
|
95
|
+
result = SEGMENTS[thousands] + ' ' + THOUSAND_WORD
|
|
99
96
|
}
|
|
100
97
|
|
|
101
|
-
if (
|
|
102
|
-
|
|
98
|
+
if (remainder > 0) {
|
|
99
|
+
result += ' ' + SEGMENTS[remainder]
|
|
103
100
|
}
|
|
104
101
|
|
|
105
|
-
return
|
|
102
|
+
return result
|
|
106
103
|
}
|
|
107
104
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const length = wordBlocks.length - 1
|
|
105
|
+
return buildLargeNumberWords(n)
|
|
106
|
+
}
|
|
111
107
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const scaleWord = isLast ? null : this.thousands[(length - index) * 3]
|
|
108
|
+
function buildLargeNumberWords (n) {
|
|
109
|
+
const numStr = n.toString()
|
|
110
|
+
const len = numStr.length
|
|
116
111
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
wordList.push('se' + scaleWord)
|
|
120
|
-
continue
|
|
121
|
-
}
|
|
112
|
+
const segments = []
|
|
113
|
+
const segmentSize = 3
|
|
122
114
|
|
|
123
|
-
|
|
124
|
-
|
|
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
|
|
124
|
+
}
|
|
125
125
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
+
// Malay: "se-" prefix for ALL scale words when segment is 1
|
|
143
|
+
const scaleWord = SCALE_WORDS[scaleIndex - 2]
|
|
144
|
+
if (segment === 1) {
|
|
145
|
+
parts.push('se' + scaleWord)
|
|
146
|
+
} else {
|
|
147
|
+
parts.push(SEGMENTS[segment] + ' ' + scaleWord)
|
|
148
|
+
}
|
|
129
149
|
}
|
|
130
150
|
}
|
|
131
151
|
|
|
132
|
-
|
|
152
|
+
scaleIndex--
|
|
133
153
|
}
|
|
134
154
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
155
|
+
return parts.join(' ')
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function decimalPartToWords (decimalPart) {
|
|
159
|
+
let result = ''
|
|
160
|
+
|
|
161
|
+
let i = 0
|
|
162
|
+
while (i < decimalPart.length && decimalPart[i] === '0') {
|
|
163
|
+
if (result) result += ' '
|
|
164
|
+
result += ZERO
|
|
165
|
+
i++
|
|
141
166
|
}
|
|
167
|
+
|
|
168
|
+
const remainder = decimalPart.slice(i)
|
|
169
|
+
if (remainder) {
|
|
170
|
+
if (result) result += ' '
|
|
171
|
+
result += integerToWords(BigInt(remainder))
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return result
|
|
142
175
|
}
|
|
143
176
|
|
|
144
|
-
|
|
145
|
-
|
|
177
|
+
/**
|
|
178
|
+
* Converts a numeric value to Malay words.
|
|
179
|
+
*
|
|
180
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
181
|
+
* @returns {string} The number in Malay words
|
|
182
|
+
*/
|
|
183
|
+
function toWords (value) {
|
|
184
|
+
const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
|
|
185
|
+
|
|
186
|
+
let result = ''
|
|
187
|
+
|
|
188
|
+
if (isNegative) {
|
|
189
|
+
result = NEGATIVE + ' '
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
result += integerToWords(integerPart)
|
|
193
|
+
|
|
194
|
+
if (decimalPart) {
|
|
195
|
+
result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return result
|
|
146
199
|
}
|
|
200
|
+
|
|
201
|
+
// ============================================================================
|
|
202
|
+
// Exports
|
|
203
|
+
// ============================================================================
|
|
204
|
+
|
|
205
|
+
export { toWords }
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a numeric value to Norwegian Bokmål words.
|
|
3
|
+
*
|
|
4
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
5
|
+
* @returns {string} The number in Norwegian words
|
|
6
|
+
* @throws {TypeError} If value is not a valid numeric type
|
|
7
|
+
* @throws {Error} If value is not a valid number format
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* toWords(21) // 'tjue-en'
|
|
11
|
+
* toWords(101) // 'en hundre og en'
|
|
12
|
+
* toWords(1000000) // 'en million'
|
|
13
|
+
*/
|
|
14
|
+
export function toWords(value: number | string | bigint): string;
|