n2words 2.0.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.
Files changed (327) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +86 -188
  3. package/dist/languages/am-Latn.js +3 -0
  4. package/dist/languages/am-Latn.js.map +1 -0
  5. package/dist/languages/am.js +3 -0
  6. package/dist/languages/am.js.map +1 -0
  7. package/dist/languages/ar.js +3 -0
  8. package/dist/languages/ar.js.map +1 -0
  9. package/dist/languages/az.js +3 -0
  10. package/dist/languages/az.js.map +1 -0
  11. package/dist/languages/bn.js +3 -0
  12. package/dist/languages/bn.js.map +1 -0
  13. package/dist/languages/cs.js +3 -0
  14. package/dist/languages/cs.js.map +1 -0
  15. package/dist/languages/da.js +3 -0
  16. package/dist/languages/da.js.map +1 -0
  17. package/dist/languages/de.js +3 -0
  18. package/dist/languages/de.js.map +1 -0
  19. package/dist/languages/el.js +3 -0
  20. package/dist/languages/el.js.map +1 -0
  21. package/dist/languages/en.js +3 -0
  22. package/dist/languages/en.js.map +1 -0
  23. package/dist/languages/es.js +3 -0
  24. package/dist/languages/es.js.map +1 -0
  25. package/dist/languages/fa.js +3 -0
  26. package/dist/languages/fa.js.map +1 -0
  27. package/dist/languages/fi.js +3 -0
  28. package/dist/languages/fi.js.map +1 -0
  29. package/dist/languages/fil.js +3 -0
  30. package/dist/languages/fil.js.map +1 -0
  31. package/dist/languages/fr-BE.js +3 -0
  32. package/dist/languages/fr-BE.js.map +1 -0
  33. package/dist/languages/fr.js +3 -0
  34. package/dist/languages/fr.js.map +1 -0
  35. package/dist/languages/gu.js +3 -0
  36. package/dist/languages/gu.js.map +1 -0
  37. package/dist/languages/ha.js +3 -0
  38. package/dist/languages/ha.js.map +1 -0
  39. package/dist/languages/hbo.js +3 -0
  40. package/dist/languages/hbo.js.map +1 -0
  41. package/dist/languages/he.js +3 -0
  42. package/dist/languages/he.js.map +1 -0
  43. package/dist/languages/hi.js +3 -0
  44. package/dist/languages/hi.js.map +1 -0
  45. package/dist/languages/hr.js +3 -0
  46. package/dist/languages/hr.js.map +1 -0
  47. package/dist/languages/hu.js +3 -0
  48. package/dist/languages/hu.js.map +1 -0
  49. package/dist/languages/id.js +3 -0
  50. package/dist/languages/id.js.map +1 -0
  51. package/dist/languages/it.js +3 -0
  52. package/dist/languages/it.js.map +1 -0
  53. package/dist/languages/ja.js +3 -0
  54. package/dist/languages/ja.js.map +1 -0
  55. package/dist/languages/kn.js +3 -0
  56. package/dist/languages/kn.js.map +1 -0
  57. package/dist/languages/ko.js +3 -0
  58. package/dist/languages/ko.js.map +1 -0
  59. package/dist/languages/lt.js +3 -0
  60. package/dist/languages/lt.js.map +1 -0
  61. package/dist/languages/lv.js +3 -0
  62. package/dist/languages/lv.js.map +1 -0
  63. package/dist/languages/mr.js +3 -0
  64. package/dist/languages/mr.js.map +1 -0
  65. package/dist/languages/ms.js +3 -0
  66. package/dist/languages/ms.js.map +1 -0
  67. package/dist/languages/nb.js +3 -0
  68. package/dist/languages/nb.js.map +1 -0
  69. package/dist/languages/nl.js +3 -0
  70. package/dist/languages/nl.js.map +1 -0
  71. package/dist/languages/pa.js +3 -0
  72. package/dist/languages/pa.js.map +1 -0
  73. package/dist/languages/pl.js +3 -0
  74. package/dist/languages/pl.js.map +1 -0
  75. package/dist/languages/pt.js +3 -0
  76. package/dist/languages/pt.js.map +1 -0
  77. package/dist/languages/ro.js +3 -0
  78. package/dist/languages/ro.js.map +1 -0
  79. package/dist/languages/ru.js +3 -0
  80. package/dist/languages/ru.js.map +1 -0
  81. package/dist/languages/sr-Cyrl.js +3 -0
  82. package/dist/languages/sr-Cyrl.js.map +1 -0
  83. package/dist/languages/sr-Latn.js +3 -0
  84. package/dist/languages/sr-Latn.js.map +1 -0
  85. package/dist/languages/sv.js +3 -0
  86. package/dist/languages/sv.js.map +1 -0
  87. package/dist/languages/sw.js +3 -0
  88. package/dist/languages/sw.js.map +1 -0
  89. package/dist/languages/ta.js +3 -0
  90. package/dist/languages/ta.js.map +1 -0
  91. package/dist/languages/te.js +3 -0
  92. package/dist/languages/te.js.map +1 -0
  93. package/dist/languages/th.js +3 -0
  94. package/dist/languages/th.js.map +1 -0
  95. package/dist/languages/tr.js +3 -0
  96. package/dist/languages/tr.js.map +1 -0
  97. package/dist/languages/uk.js +3 -0
  98. package/dist/languages/uk.js.map +1 -0
  99. package/dist/languages/ur.js +3 -0
  100. package/dist/languages/ur.js.map +1 -0
  101. package/dist/languages/vi.js +3 -0
  102. package/dist/languages/vi.js.map +1 -0
  103. package/dist/languages/zh-Hans.js +3 -0
  104. package/dist/languages/zh-Hans.js.map +1 -0
  105. package/dist/languages/zh-Hant.js +3 -0
  106. package/dist/languages/zh-Hant.js.map +1 -0
  107. package/dist/n2words.js +2 -2
  108. package/dist/n2words.js.map +1 -1
  109. package/lib/languages/am-Latn.d.ts +7 -0
  110. package/lib/languages/am-Latn.js +164 -0
  111. package/lib/languages/am.d.ts +7 -0
  112. package/lib/languages/am.js +164 -0
  113. package/lib/languages/ar.d.ts +14 -27
  114. package/lib/languages/ar.js +175 -129
  115. package/lib/languages/az.d.ts +4 -9
  116. package/lib/languages/az.js +171 -37
  117. package/lib/languages/bn.d.ts +4 -8
  118. package/lib/languages/bn.js +138 -124
  119. package/lib/languages/cs.d.ts +15 -85
  120. package/lib/languages/cs.js +310 -114
  121. package/lib/languages/da.d.ts +11 -12
  122. package/lib/languages/da.js +276 -101
  123. package/lib/languages/de.d.ts +14 -11
  124. package/lib/languages/de.js +317 -86
  125. package/lib/languages/el.d.ts +11 -11
  126. package/lib/languages/el.js +231 -78
  127. package/lib/languages/en.d.ts +14 -13
  128. package/lib/languages/en.js +242 -72
  129. package/lib/languages/es.d.ts +18 -12
  130. package/lib/languages/es.js +317 -103
  131. package/lib/languages/fa.d.ts +4 -44
  132. package/lib/languages/fa.js +112 -122
  133. package/lib/languages/fi.d.ts +14 -0
  134. package/lib/languages/fi.js +245 -0
  135. package/lib/languages/fil.d.ts +4 -13
  136. package/lib/languages/fil.js +207 -106
  137. package/lib/languages/fr-BE.d.ts +8 -8
  138. package/lib/languages/fr-BE.js +294 -19
  139. package/lib/languages/fr.d.ts +18 -12
  140. package/lib/languages/fr.js +352 -89
  141. package/lib/languages/gu.d.ts +4 -8
  142. package/lib/languages/gu.js +130 -125
  143. package/lib/languages/ha.d.ts +7 -0
  144. package/lib/languages/ha.js +230 -0
  145. package/lib/languages/hbo.d.ts +10 -110
  146. package/lib/languages/hbo.js +263 -214
  147. package/lib/languages/he.d.ts +10 -77
  148. package/lib/languages/he.js +242 -172
  149. package/lib/languages/hi.d.ts +4 -8
  150. package/lib/languages/hi.js +138 -124
  151. package/lib/languages/hr.d.ts +8 -77
  152. package/lib/languages/hr.js +194 -89
  153. package/lib/languages/hu.d.ts +4 -19
  154. package/lib/languages/hu.js +198 -119
  155. package/lib/languages/id.d.ts +4 -34
  156. package/lib/languages/id.js +171 -129
  157. package/lib/languages/it.d.ts +16 -34
  158. package/lib/languages/it.js +339 -94
  159. package/lib/languages/ja.d.ts +14 -14
  160. package/lib/languages/ja.js +233 -111
  161. package/lib/languages/kn.d.ts +4 -8
  162. package/lib/languages/kn.js +130 -35
  163. package/lib/languages/ko.d.ts +11 -11
  164. package/lib/languages/ko.js +257 -49
  165. package/lib/languages/lt.d.ts +15 -67
  166. package/lib/languages/lt.js +296 -122
  167. package/lib/languages/lv.d.ts +15 -67
  168. package/lib/languages/lv.js +297 -106
  169. package/lib/languages/mr.d.ts +4 -8
  170. package/lib/languages/mr.js +130 -125
  171. package/lib/languages/ms.d.ts +4 -28
  172. package/lib/languages/ms.js +171 -116
  173. package/lib/languages/nb.d.ts +11 -9
  174. package/lib/languages/nb.js +282 -87
  175. package/lib/languages/nl.d.ts +23 -13
  176. package/lib/languages/nl.js +317 -133
  177. package/lib/languages/pa.d.ts +4 -8
  178. package/lib/languages/pa.js +156 -124
  179. package/lib/languages/pl.d.ts +19 -77
  180. package/lib/languages/pl.js +307 -87
  181. package/lib/languages/pt.d.ts +14 -26
  182. package/lib/languages/pt.js +286 -92
  183. package/lib/languages/ro.d.ts +15 -155
  184. package/lib/languages/ro.js +219 -235
  185. package/lib/languages/ru.d.ts +8 -82
  186. package/lib/languages/ru.js +222 -78
  187. package/lib/languages/sr-Cyrl.d.ts +8 -77
  188. package/lib/languages/sr-Cyrl.js +191 -89
  189. package/lib/languages/sr-Latn.d.ts +8 -77
  190. package/lib/languages/sr-Latn.js +191 -89
  191. package/lib/languages/sv.d.ts +11 -11
  192. package/lib/languages/sv.js +288 -74
  193. package/lib/languages/sw.d.ts +4 -36
  194. package/lib/languages/sw.js +133 -106
  195. package/lib/languages/ta.d.ts +4 -17
  196. package/lib/languages/ta.js +129 -201
  197. package/lib/languages/te.d.ts +4 -19
  198. package/lib/languages/te.js +141 -196
  199. package/lib/languages/th.d.ts +4 -14
  200. package/lib/languages/th.js +135 -91
  201. package/lib/languages/tr.d.ts +15 -9
  202. package/lib/languages/tr.js +256 -49
  203. package/lib/languages/uk.d.ts +8 -82
  204. package/lib/languages/uk.js +200 -78
  205. package/lib/languages/ur.d.ts +4 -8
  206. package/lib/languages/ur.js +156 -124
  207. package/lib/languages/vi.d.ts +14 -69
  208. package/lib/languages/vi.js +294 -125
  209. package/lib/languages/zh-Hans.d.ts +8 -18
  210. package/lib/languages/zh-Hans.js +163 -92
  211. package/lib/languages/zh-Hant.d.ts +8 -18
  212. package/lib/languages/zh-Hant.js +181 -90
  213. package/lib/n2words.d.ts +53 -209
  214. package/lib/n2words.js +111 -530
  215. package/lib/utils/is-plain-object.d.ts +13 -0
  216. package/lib/utils/is-plain-object.js +17 -0
  217. package/lib/utils/parse-numeric.d.ts +17 -0
  218. package/lib/utils/parse-numeric.js +108 -0
  219. package/lib/utils/validate-options.d.ts +8 -0
  220. package/lib/utils/validate-options.js +16 -0
  221. package/package.json +26 -14
  222. package/dist/ArabicConverter.js +0 -3
  223. package/dist/ArabicConverter.js.map +0 -1
  224. package/dist/AzerbaijaniConverter.js +0 -3
  225. package/dist/AzerbaijaniConverter.js.map +0 -1
  226. package/dist/BanglaConverter.js +0 -3
  227. package/dist/BanglaConverter.js.map +0 -1
  228. package/dist/BiblicalHebrewConverter.js +0 -3
  229. package/dist/BiblicalHebrewConverter.js.map +0 -1
  230. package/dist/CroatianConverter.js +0 -3
  231. package/dist/CroatianConverter.js.map +0 -1
  232. package/dist/CzechConverter.js +0 -3
  233. package/dist/CzechConverter.js.map +0 -1
  234. package/dist/DanishConverter.js +0 -3
  235. package/dist/DanishConverter.js.map +0 -1
  236. package/dist/DutchConverter.js +0 -3
  237. package/dist/DutchConverter.js.map +0 -1
  238. package/dist/EnglishConverter.js +0 -3
  239. package/dist/EnglishConverter.js.map +0 -1
  240. package/dist/FilipinoConverter.js +0 -3
  241. package/dist/FilipinoConverter.js.map +0 -1
  242. package/dist/FrenchBelgiumConverter.js +0 -3
  243. package/dist/FrenchBelgiumConverter.js.map +0 -1
  244. package/dist/FrenchConverter.js +0 -3
  245. package/dist/FrenchConverter.js.map +0 -1
  246. package/dist/GermanConverter.js +0 -3
  247. package/dist/GermanConverter.js.map +0 -1
  248. package/dist/GreekConverter.js +0 -3
  249. package/dist/GreekConverter.js.map +0 -1
  250. package/dist/GujaratiConverter.js +0 -3
  251. package/dist/GujaratiConverter.js.map +0 -1
  252. package/dist/HebrewConverter.js +0 -3
  253. package/dist/HebrewConverter.js.map +0 -1
  254. package/dist/HindiConverter.js +0 -3
  255. package/dist/HindiConverter.js.map +0 -1
  256. package/dist/HungarianConverter.js +0 -3
  257. package/dist/HungarianConverter.js.map +0 -1
  258. package/dist/IndonesianConverter.js +0 -3
  259. package/dist/IndonesianConverter.js.map +0 -1
  260. package/dist/ItalianConverter.js +0 -3
  261. package/dist/ItalianConverter.js.map +0 -1
  262. package/dist/JapaneseConverter.js +0 -3
  263. package/dist/JapaneseConverter.js.map +0 -1
  264. package/dist/KannadaConverter.js +0 -3
  265. package/dist/KannadaConverter.js.map +0 -1
  266. package/dist/KoreanConverter.js +0 -3
  267. package/dist/KoreanConverter.js.map +0 -1
  268. package/dist/LatvianConverter.js +0 -3
  269. package/dist/LatvianConverter.js.map +0 -1
  270. package/dist/LithuanianConverter.js +0 -3
  271. package/dist/LithuanianConverter.js.map +0 -1
  272. package/dist/MalayConverter.js +0 -3
  273. package/dist/MalayConverter.js.map +0 -1
  274. package/dist/MarathiConverter.js +0 -3
  275. package/dist/MarathiConverter.js.map +0 -1
  276. package/dist/NorwegianBokmalConverter.js +0 -3
  277. package/dist/NorwegianBokmalConverter.js.map +0 -1
  278. package/dist/PersianConverter.js +0 -3
  279. package/dist/PersianConverter.js.map +0 -1
  280. package/dist/PolishConverter.js +0 -3
  281. package/dist/PolishConverter.js.map +0 -1
  282. package/dist/PortugueseConverter.js +0 -3
  283. package/dist/PortugueseConverter.js.map +0 -1
  284. package/dist/PunjabiConverter.js +0 -3
  285. package/dist/PunjabiConverter.js.map +0 -1
  286. package/dist/RomanianConverter.js +0 -3
  287. package/dist/RomanianConverter.js.map +0 -1
  288. package/dist/RussianConverter.js +0 -3
  289. package/dist/RussianConverter.js.map +0 -1
  290. package/dist/SerbianCyrillicConverter.js +0 -3
  291. package/dist/SerbianCyrillicConverter.js.map +0 -1
  292. package/dist/SerbianLatinConverter.js +0 -3
  293. package/dist/SerbianLatinConverter.js.map +0 -1
  294. package/dist/SimplifiedChineseConverter.js +0 -3
  295. package/dist/SimplifiedChineseConverter.js.map +0 -1
  296. package/dist/SpanishConverter.js +0 -3
  297. package/dist/SpanishConverter.js.map +0 -1
  298. package/dist/SwahiliConverter.js +0 -3
  299. package/dist/SwahiliConverter.js.map +0 -1
  300. package/dist/SwedishConverter.js +0 -3
  301. package/dist/SwedishConverter.js.map +0 -1
  302. package/dist/TamilConverter.js +0 -3
  303. package/dist/TamilConverter.js.map +0 -1
  304. package/dist/TeluguConverter.js +0 -3
  305. package/dist/TeluguConverter.js.map +0 -1
  306. package/dist/ThaiConverter.js +0 -3
  307. package/dist/ThaiConverter.js.map +0 -1
  308. package/dist/TraditionalChineseConverter.js +0 -3
  309. package/dist/TraditionalChineseConverter.js.map +0 -1
  310. package/dist/TurkishConverter.js +0 -3
  311. package/dist/TurkishConverter.js.map +0 -1
  312. package/dist/UkrainianConverter.js +0 -3
  313. package/dist/UkrainianConverter.js.map +0 -1
  314. package/dist/UrduConverter.js +0 -3
  315. package/dist/UrduConverter.js.map +0 -1
  316. package/dist/VietnameseConverter.js +0 -3
  317. package/dist/VietnameseConverter.js.map +0 -1
  318. package/lib/classes/abstract-language.d.ts +0 -178
  319. package/lib/classes/abstract-language.js +0 -268
  320. package/lib/classes/greedy-scale-language.d.ts +0 -109
  321. package/lib/classes/greedy-scale-language.js +0 -201
  322. package/lib/classes/slavic-language.d.ts +0 -148
  323. package/lib/classes/slavic-language.js +0 -281
  324. package/lib/classes/south-asian-language.d.ts +0 -70
  325. package/lib/classes/south-asian-language.js +0 -154
  326. package/lib/classes/turkic-language.d.ts +0 -26
  327. package/lib/classes/turkic-language.js +0 -59
@@ -1,132 +1,137 @@
1
- import { SouthAsianLanguage } from '../classes/south-asian-language.js'
2
-
3
1
  /**
4
- * Marathi language converter.
2
+ * Marathi language converter - Functional Implementation
3
+ *
4
+ * Self-contained converter for South Asian numbering.
5
5
  *
6
- * Supports:
6
+ * Key features:
7
7
  * - Indian numbering system (हजार, लाख, कोटी)
8
8
  * - Devanagari script
9
+ * - 3-2-2 grouping pattern (last 3 digits, then groups of 2)
9
10
  * - Complete word forms for 0-99
11
+ * - Per-digit decimal reading
10
12
  */
11
- export class Marathi extends SouthAsianLanguage {
12
- negativeWord = 'उणे'
13
- decimalSeparatorWord = 'दशांश'
14
- zeroWord = 'शून्य'
15
- hundredWord = 'शंभर'
16
- usePerDigitDecimals = true
17
-
18
- belowHundredWords = [
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
- scaleWords = [
122
- '',
123
- 'हजार',
124
- 'लाख',
125
- 'कोटी',
126
- 'अब्ज',
127
- 'खर्व',
128
- 'निखर्व',
129
- 'महापद्म',
130
- 'शंकू'
131
- ]
13
+
14
+ import { parseNumericValue } from '../utils/parse-numeric.js'
15
+
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
132
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(' ')
107
+ }
108
+
109
+ /**
110
+ * Converts a numeric value to Marathi words.
111
+ *
112
+ * @param {number | string | bigint} value - The numeric value to convert
113
+ * @returns {string} The number in Marathi words
114
+ */
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
131
+ }
132
+
133
+ // ============================================================================
134
+ // Exports
135
+ // ============================================================================
136
+
137
+ export { toWords }
@@ -1,31 +1,7 @@
1
1
  /**
2
- * Malay (Bahasa Melayu) language converter.
2
+ * Converts a numeric value to Malay words.
3
3
  *
4
- * Supports:
5
- * - "Se-" prefix for singular units (seratus, seribu, sejuta)
6
- * - Regular patterns (puluh for tens, ratus for hundreds)
7
- * - Space-separated number components
4
+ * @param {number | string | bigint} value - The numeric value to convert
5
+ * @returns {string} The number in Malay words
8
6
  */
9
- export class Malay extends AbstractLanguage {
10
- /**
11
- * Word forms for digits 0-9.
12
- * @type {Object.<number, string[]>}
13
- */
14
- digitWords: {
15
- [x: number]: string[];
16
- };
17
- /**
18
- * Scale magnitude words keyed by exponent (10^n).
19
- * @type {Object.<number, string>}
20
- */
21
- scaleWords: {
22
- [x: number]: string;
23
- };
24
- splitBy3(number: any): any[][];
25
- spell(blocks: any): any[];
26
- getHundreds(number: any): string[];
27
- getTens(number: any): string[];
28
- join(wordBlocks: any): string;
29
- integerToWords(integerPart: any): string;
30
- }
31
- import { AbstractLanguage } from '../classes/abstract-language.js';
7
+ export function toWords(value: number | string | bigint): string;
@@ -1,150 +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
- * Supports:
7
- * - "Se-" prefix for singular units (seratus, seribu, sejuta)
6
+ * Key features:
7
+ * - "Se-" prefix for ALL singular scale units (seratus, seribu, sejuta, sebilion)
8
8
  * - Regular patterns (puluh for tens, ratus for hundreds)
9
- * - Space-separated number components
9
+ * - Teens with "belas" suffix
10
+ * - Note: "lapan" (8) differs from Indonesian "delapan"
10
11
  */
11
- export class Malay extends AbstractLanguage {
12
- negativeWord = 'minus'
13
- decimalSeparatorWord = 'perpuluhan'
14
- zeroWord = 'sifar'
15
-
16
- /**
17
- * Word forms for digits 0-9.
18
- * @type {Object.<number, string[]>}
19
- */
20
- digitWords = {
21
- 0: [],
22
- 1: ['satu'],
23
- 2: ['dua'],
24
- 3: ['tiga'],
25
- 4: ['empat'],
26
- 5: ['lima'],
27
- 6: ['enam'],
28
- 7: ['tujuh'],
29
- 8: ['lapan'],
30
- 9: ['sembilan']
12
+
13
+ import { parseNumericValue } from '../utils/parse-numeric.js'
14
+
15
+ // ============================================================================
16
+ // Vocabulary
17
+ // ============================================================================
18
+
19
+ const ONES = ['', 'satu', 'dua', 'tiga', 'empat', 'lima', 'enam', 'tujuh', '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']
22
+
23
+ const HUNDRED_WORD = 'ratus'
24
+ const THOUSAND_WORD = 'ribu'
25
+ const SCALE_WORDS = ['juta', 'bilion', 'trilion']
26
+
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 = []
43
+
44
+ // Hundreds: seratus (100) or N ratus (200-900)
45
+ if (hundredsDigit > 0) {
46
+ if (hundredsDigit === 1) {
47
+ parts.push('se' + HUNDRED_WORD)
48
+ } else {
49
+ parts.push(ONES[hundredsDigit] + ' ' + HUNDRED_WORD)
50
+ }
31
51
  }
32
52
 
33
- /**
34
- * Scale magnitude words keyed by exponent (10^n).
35
- * @type {Object.<number, string>}
36
- */
37
- scaleWords = {
38
- 3: 'ribu',
39
- 6: 'juta',
40
- 9: 'bilion',
41
- 12: 'trilion'
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])
42
66
  }
43
67
 
44
- splitBy3 (number) {
45
- const blocks = []
46
- const stringNumber = number.toString()
47
- const length = stringNumber.length
48
- let firstBlock
68
+ return parts.join(' ')
69
+ }
49
70
 
50
- if (length < 3) {
51
- blocks.push([stringNumber])
52
- } else {
53
- const firstBlockLength = length % 3
71
+ const SEGMENTS = new Array(1000)
72
+ for (let i = 0; i < 1000; i++) {
73
+ SEGMENTS[i] = buildSegment(i)
74
+ }
54
75
 
55
- if (firstBlockLength > 0) {
56
- firstBlock = [stringNumber.slice(0, firstBlockLength)]
57
- blocks.push(firstBlock)
58
- }
76
+ // ============================================================================
77
+ // Conversion Functions
78
+ // ============================================================================
59
79
 
60
- for (let index = firstBlockLength; index < length; index += 3) {
61
- const nextBlock = [stringNumber.slice(index, index + 3)]
62
- blocks.push(nextBlock)
63
- }
64
- }
65
- return blocks
80
+ function integerToWords (n) {
81
+ if (n === 0n) return ZERO
82
+
83
+ if (n < 1000n) {
84
+ return SEGMENTS[Number(n)]
66
85
  }
67
86
 
68
- spell (blocks) {
69
- let wordBlocks = []
70
- let spelling
71
- const firstBlock = blocks[0]
72
- if (firstBlock[0].length === 1) {
73
- spelling = firstBlock[0] === '0' ? ['sifar'] : this.digitWords[Math.trunc(firstBlock[0])]
74
- } else if (firstBlock[0].length === 2) {
75
- spelling = this.getTens(firstBlock[0])
87
+ if (n < 1_000_000n) {
88
+ const thousands = Number(n / 1000n)
89
+ const remainder = Number(n % 1000n)
90
+
91
+ let result
92
+ if (thousands === 1) {
93
+ result = 'se' + THOUSAND_WORD
76
94
  } else {
77
- spelling = [...this.getHundreds(firstBlock[0][0]), ...this.getTens(firstBlock[0].slice(1, 3))]
95
+ result = SEGMENTS[thousands] + ' ' + THOUSAND_WORD
78
96
  }
79
- wordBlocks = [...wordBlocks, [firstBlock[0], spelling]]
80
- for (let index = 1; index < blocks.length; index++) {
81
- let block = blocks[index]
82
- spelling = [...this.getHundreds(block[0][0]), ...this.getTens(block[0].slice(1, 3))]
83
- block = [...block, spelling]
84
- wordBlocks = [...wordBlocks, block]
97
+
98
+ if (remainder > 0) {
99
+ result += ' ' + SEGMENTS[remainder]
85
100
  }
86
- return wordBlocks
101
+
102
+ return result
87
103
  }
88
104
 
89
- getHundreds (number) { // 'ratus'
90
- if (number === '1') {
91
- return ['seratus']
92
- } else if (number === '0') {
93
- return []
94
- } else {
95
- return [...this.digitWords[Math.trunc(number)], 'ratus']
96
- }
105
+ return buildLargeNumberWords(n)
106
+ }
107
+
108
+ function buildLargeNumberWords (n) {
109
+ const numStr = n.toString()
110
+ const len = numStr.length
111
+
112
+ const segments = []
113
+ const segmentSize = 3
114
+
115
+ const remainderLen = len % segmentSize
116
+ let pos = 0
117
+ if (remainderLen > 0) {
118
+ segments.push(Number(numStr.slice(0, remainderLen)))
119
+ pos = remainderLen
120
+ }
121
+ while (pos < len) {
122
+ segments.push(Number(numStr.slice(pos, pos + segmentSize)))
123
+ pos += segmentSize
97
124
  }
98
125
 
99
- getTens (number) { // 'puluh' and 'belas'
100
- if (number[0] === '1') {
101
- if (number[1] === '0') {
102
- return ['sepuluh']
103
- } else if (number[1] === '1') {
104
- return ['sebelas']
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
+ }
105
149
  }
106
- return [...this.digitWords[Math.trunc(number[1])], 'belas']
107
150
  }
108
151
 
109
- if (number[0] === '0') {
110
- return this.digitWords[Math.trunc(number[1])]
111
- }
112
-
113
- return [...this.digitWords[Math.trunc(number[0])], 'puluh', ...this.digitWords[Math.trunc(number[1])]]
152
+ scaleIndex--
114
153
  }
115
154
 
116
- join (wordBlocks) {
117
- const wordList = []
118
- const length = wordBlocks.length - 1
155
+ return parts.join(' ')
156
+ }
157
+
158
+ function decimalPartToWords (decimalPart) {
159
+ let result = ''
119
160
 
120
- for (let index = 0; index <= length; index++) {
121
- const words = wordBlocks[index][1]
122
- const isLast = index === length
123
- const scaleWord = isLast ? null : this.scaleWords[(length - index) * 3]
161
+ let i = 0
162
+ while (i < decimalPart.length && decimalPart[i] === '0') {
163
+ if (result) result += ' '
164
+ result += ZERO
165
+ i++
166
+ }
124
167
 
125
- if (!isLast && words.length === 1 && words[0] === 'satu') {
126
- // Use se- prefix for singular scale units: seribu, sejuta, sebilion, setrilion
127
- wordList.push('se' + scaleWord)
128
- continue
129
- }
168
+ const remainder = decimalPart.slice(i)
169
+ if (remainder) {
170
+ if (result) result += ' '
171
+ result += integerToWords(BigInt(remainder))
172
+ }
130
173
 
131
- // Add current block words
132
- for (const w of words) wordList.push(w)
174
+ return result
175
+ }
133
176
 
134
- // Append scale word if applicable and current block contributed words
135
- if (!isLast && words.length > 0) {
136
- wordList.push(scaleWord)
137
- }
138
- }
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 = ''
139
187
 
140
- return wordList.join(' ')
188
+ if (isNegative) {
189
+ result = NEGATIVE + ' '
141
190
  }
142
191
 
143
- integerToWords (integerPart) {
144
- return this.join(
145
- this.spell(
146
- this.splitBy3(integerPart)
147
- )
148
- ).trim()
192
+ result += integerToWords(integerPart)
193
+
194
+ if (decimalPart) {
195
+ result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart)
149
196
  }
197
+
198
+ return result
150
199
  }
200
+
201
+ // ============================================================================
202
+ // Exports
203
+ // ============================================================================
204
+
205
+ export { toWords }
@@ -1,12 +1,14 @@
1
1
  /**
2
- * Norwegian Bokmål language converter.
2
+ * Converts a numeric value to Norwegian Bokmål words.
3
3
  *
4
- * Supports:
5
- * - Hyphenation for compound numbers (tjue-en)
6
- * - "og" (and) for hundreds combinations
7
- * - Implicit '1' omission before tens and magnitudes
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'
8
13
  */
9
- export class NorwegianBokmal extends GreedyScaleLanguage {
10
- scaleWords: (string | bigint)[][];
11
- }
12
- import { GreedyScaleLanguage } from '../classes/greedy-scale-language.js';
14
+ export function toWords(value: number | string | bigint): string;