n2words 1.23.1 → 2.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 (322) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +317 -59
  3. package/dist/ArabicConverter.js +3 -0
  4. package/dist/ArabicConverter.js.map +1 -0
  5. package/dist/AzerbaijaniConverter.js +3 -0
  6. package/dist/AzerbaijaniConverter.js.map +1 -0
  7. package/dist/BanglaConverter.js +3 -0
  8. package/dist/BanglaConverter.js.map +1 -0
  9. package/dist/BiblicalHebrewConverter.js +3 -0
  10. package/dist/BiblicalHebrewConverter.js.map +1 -0
  11. package/dist/CroatianConverter.js +3 -0
  12. package/dist/CroatianConverter.js.map +1 -0
  13. package/dist/CzechConverter.js +3 -0
  14. package/dist/CzechConverter.js.map +1 -0
  15. package/dist/DanishConverter.js +3 -0
  16. package/dist/DanishConverter.js.map +1 -0
  17. package/dist/DutchConverter.js +3 -0
  18. package/dist/DutchConverter.js.map +1 -0
  19. package/dist/EnglishConverter.js +3 -0
  20. package/dist/EnglishConverter.js.map +1 -0
  21. package/dist/FilipinoConverter.js +3 -0
  22. package/dist/FilipinoConverter.js.map +1 -0
  23. package/dist/FrenchBelgiumConverter.js +3 -0
  24. package/dist/FrenchBelgiumConverter.js.map +1 -0
  25. package/dist/FrenchConverter.js +3 -0
  26. package/dist/FrenchConverter.js.map +1 -0
  27. package/dist/GermanConverter.js +3 -0
  28. package/dist/GermanConverter.js.map +1 -0
  29. package/dist/GreekConverter.js +3 -0
  30. package/dist/GreekConverter.js.map +1 -0
  31. package/dist/GujaratiConverter.js +3 -0
  32. package/dist/GujaratiConverter.js.map +1 -0
  33. package/dist/HebrewConverter.js +3 -0
  34. package/dist/HebrewConverter.js.map +1 -0
  35. package/dist/HindiConverter.js +3 -0
  36. package/dist/HindiConverter.js.map +1 -0
  37. package/dist/HungarianConverter.js +3 -0
  38. package/dist/HungarianConverter.js.map +1 -0
  39. package/dist/IndonesianConverter.js +3 -0
  40. package/dist/IndonesianConverter.js.map +1 -0
  41. package/dist/ItalianConverter.js +3 -0
  42. package/dist/ItalianConverter.js.map +1 -0
  43. package/dist/JapaneseConverter.js +3 -0
  44. package/dist/JapaneseConverter.js.map +1 -0
  45. package/dist/KannadaConverter.js +3 -0
  46. package/dist/KannadaConverter.js.map +1 -0
  47. package/dist/KoreanConverter.js +3 -0
  48. package/dist/KoreanConverter.js.map +1 -0
  49. package/dist/LatvianConverter.js +3 -0
  50. package/dist/LatvianConverter.js.map +1 -0
  51. package/dist/LithuanianConverter.js +3 -0
  52. package/dist/LithuanianConverter.js.map +1 -0
  53. package/dist/MalayConverter.js +3 -0
  54. package/dist/MalayConverter.js.map +1 -0
  55. package/dist/MarathiConverter.js +3 -0
  56. package/dist/MarathiConverter.js.map +1 -0
  57. package/dist/NorwegianBokmalConverter.js +3 -0
  58. package/dist/NorwegianBokmalConverter.js.map +1 -0
  59. package/dist/PersianConverter.js +3 -0
  60. package/dist/PersianConverter.js.map +1 -0
  61. package/dist/PolishConverter.js +3 -0
  62. package/dist/PolishConverter.js.map +1 -0
  63. package/dist/PortugueseConverter.js +3 -0
  64. package/dist/PortugueseConverter.js.map +1 -0
  65. package/dist/PunjabiConverter.js +3 -0
  66. package/dist/PunjabiConverter.js.map +1 -0
  67. package/dist/RomanianConverter.js +3 -0
  68. package/dist/RomanianConverter.js.map +1 -0
  69. package/dist/RussianConverter.js +3 -0
  70. package/dist/RussianConverter.js.map +1 -0
  71. package/dist/SerbianCyrillicConverter.js +3 -0
  72. package/dist/SerbianCyrillicConverter.js.map +1 -0
  73. package/dist/SerbianLatinConverter.js +3 -0
  74. package/dist/SerbianLatinConverter.js.map +1 -0
  75. package/dist/SimplifiedChineseConverter.js +3 -0
  76. package/dist/SimplifiedChineseConverter.js.map +1 -0
  77. package/dist/SpanishConverter.js +3 -0
  78. package/dist/SpanishConverter.js.map +1 -0
  79. package/dist/SwahiliConverter.js +3 -0
  80. package/dist/SwahiliConverter.js.map +1 -0
  81. package/dist/SwedishConverter.js +3 -0
  82. package/dist/SwedishConverter.js.map +1 -0
  83. package/dist/TamilConverter.js +3 -0
  84. package/dist/TamilConverter.js.map +1 -0
  85. package/dist/TeluguConverter.js +3 -0
  86. package/dist/TeluguConverter.js.map +1 -0
  87. package/dist/ThaiConverter.js +3 -0
  88. package/dist/ThaiConverter.js.map +1 -0
  89. package/dist/TraditionalChineseConverter.js +3 -0
  90. package/dist/TraditionalChineseConverter.js.map +1 -0
  91. package/dist/TurkishConverter.js +3 -0
  92. package/dist/TurkishConverter.js.map +1 -0
  93. package/dist/UkrainianConverter.js +3 -0
  94. package/dist/UkrainianConverter.js.map +1 -0
  95. package/dist/UrduConverter.js +3 -0
  96. package/dist/UrduConverter.js.map +1 -0
  97. package/dist/VietnameseConverter.js +3 -0
  98. package/dist/VietnameseConverter.js.map +1 -0
  99. package/dist/n2words.js +3 -2
  100. package/dist/n2words.js.map +1 -1
  101. package/lib/classes/abstract-language.d.ts +158 -34
  102. package/lib/classes/abstract-language.js +223 -115
  103. package/lib/classes/greedy-scale-language.d.ts +109 -0
  104. package/lib/classes/greedy-scale-language.js +201 -0
  105. package/lib/classes/slavic-language.d.ts +148 -0
  106. package/lib/classes/slavic-language.js +281 -0
  107. package/lib/classes/south-asian-language.d.ts +70 -0
  108. package/lib/classes/south-asian-language.js +154 -0
  109. package/lib/classes/turkic-language.d.ts +26 -0
  110. package/lib/classes/turkic-language.js +59 -0
  111. package/lib/languages/ar.d.ts +30 -0
  112. package/lib/languages/ar.js +159 -0
  113. package/lib/languages/az.d.ts +12 -0
  114. package/lib/languages/az.js +42 -0
  115. package/lib/languages/bn.d.ts +11 -0
  116. package/lib/languages/bn.js +131 -0
  117. package/lib/languages/cs.d.ts +88 -0
  118. package/lib/languages/cs.js +143 -0
  119. package/lib/languages/da.d.ts +15 -0
  120. package/lib/languages/da.js +120 -0
  121. package/lib/languages/de.d.ts +14 -0
  122. package/lib/languages/de.js +101 -0
  123. package/lib/languages/el.d.ts +14 -0
  124. package/lib/languages/el.js +90 -0
  125. package/lib/languages/en.d.ts +16 -0
  126. package/lib/languages/en.js +86 -0
  127. package/lib/languages/es.d.ts +15 -0
  128. package/lib/languages/es.js +121 -0
  129. package/lib/languages/fa.d.ts +47 -0
  130. package/lib/languages/fa.js +144 -0
  131. package/lib/languages/fil.d.ts +16 -0
  132. package/lib/languages/fil.js +121 -0
  133. package/lib/languages/fr-BE.d.ts +11 -0
  134. package/lib/languages/fr-BE.js +25 -0
  135. package/lib/languages/fr.d.ts +15 -0
  136. package/lib/languages/fr.js +106 -0
  137. package/lib/languages/gu.d.ts +11 -0
  138. package/lib/languages/gu.js +132 -0
  139. package/lib/languages/hbo.d.ts +113 -0
  140. package/lib/languages/hbo.js +251 -0
  141. package/lib/languages/he.d.ts +80 -0
  142. package/lib/languages/he.js +206 -0
  143. package/lib/languages/hi.d.ts +11 -0
  144. package/lib/languages/hi.js +131 -0
  145. package/lib/languages/hr.d.ts +80 -0
  146. package/lib/languages/hr.js +113 -0
  147. package/lib/languages/hu.d.ts +22 -0
  148. package/lib/languages/hu.js +137 -0
  149. package/lib/languages/id.d.ts +37 -0
  150. package/lib/languages/id.js +159 -0
  151. package/lib/languages/it.d.ts +37 -0
  152. package/lib/languages/it.js +132 -0
  153. package/lib/languages/ja.d.ts +17 -0
  154. package/lib/languages/ja.js +137 -0
  155. package/lib/languages/kn.d.ts +11 -0
  156. package/lib/languages/kn.js +42 -0
  157. package/lib/languages/ko.d.ts +14 -0
  158. package/lib/languages/ko.js +55 -0
  159. package/lib/{i18n/pl.d.ts → languages/lt.d.ts} +18 -15
  160. package/lib/languages/lt.js +136 -0
  161. package/lib/{i18n/lt.d.ts → languages/lv.d.ts} +16 -14
  162. package/lib/languages/lv.js +130 -0
  163. package/lib/languages/mr.d.ts +11 -0
  164. package/lib/languages/mr.js +132 -0
  165. package/lib/languages/ms.d.ts +31 -0
  166. package/lib/languages/ms.js +150 -0
  167. package/lib/languages/nb.d.ts +12 -0
  168. package/lib/languages/nb.js +100 -0
  169. package/lib/languages/nl.d.ts +16 -0
  170. package/lib/languages/nl.js +155 -0
  171. package/lib/languages/pa.d.ts +11 -0
  172. package/lib/languages/pa.js +131 -0
  173. package/lib/{i18n/uk.d.ts → languages/pl.d.ts} +16 -14
  174. package/lib/languages/pl.js +110 -0
  175. package/lib/languages/pt.d.ts +29 -0
  176. package/lib/languages/pt.js +112 -0
  177. package/lib/languages/ro.d.ts +158 -0
  178. package/lib/languages/ro.js +273 -0
  179. package/lib/languages/ru.d.ts +85 -0
  180. package/lib/languages/ru.js +96 -0
  181. package/lib/languages/sr-Cyrl.d.ts +80 -0
  182. package/lib/languages/sr-Cyrl.js +113 -0
  183. package/lib/{i18n/cz.d.ts → languages/sr-Latn.d.ts} +26 -14
  184. package/lib/languages/sr-Latn.js +113 -0
  185. package/lib/languages/sv.d.ts +14 -0
  186. package/lib/languages/sv.js +90 -0
  187. package/lib/languages/sw.d.ts +39 -0
  188. package/lib/languages/sw.js +126 -0
  189. package/lib/languages/ta.d.ts +20 -0
  190. package/lib/languages/ta.js +226 -0
  191. package/lib/languages/te.d.ts +22 -0
  192. package/lib/languages/te.js +219 -0
  193. package/lib/languages/th.d.ts +17 -0
  194. package/lib/languages/th.js +117 -0
  195. package/lib/languages/tr.d.ts +12 -0
  196. package/lib/languages/tr.js +56 -0
  197. package/lib/languages/uk.d.ts +85 -0
  198. package/lib/{i18n → languages}/uk.js +33 -32
  199. package/lib/languages/ur.d.ts +11 -0
  200. package/lib/languages/ur.js +131 -0
  201. package/lib/{i18n → languages}/vi.d.ts +15 -13
  202. package/lib/languages/vi.js +147 -0
  203. package/lib/languages/zh-Hans.d.ts +21 -0
  204. package/lib/languages/zh-Hans.js +111 -0
  205. package/lib/languages/zh-Hant.d.ts +21 -0
  206. package/lib/languages/zh-Hant.js +111 -0
  207. package/lib/n2words.d.ts +207 -7
  208. package/lib/n2words.js +535 -81
  209. package/package.json +126 -79
  210. package/dist/ar.js +0 -2
  211. package/dist/ar.js.map +0 -1
  212. package/dist/az.js +0 -2
  213. package/dist/az.js.map +0 -1
  214. package/dist/cz.js +0 -2
  215. package/dist/cz.js.map +0 -1
  216. package/dist/de.js +0 -2
  217. package/dist/de.js.map +0 -1
  218. package/dist/dk.js +0 -2
  219. package/dist/dk.js.map +0 -1
  220. package/dist/en.js +0 -2
  221. package/dist/en.js.map +0 -1
  222. package/dist/es.js +0 -2
  223. package/dist/es.js.map +0 -1
  224. package/dist/fa.js +0 -2
  225. package/dist/fa.js.map +0 -1
  226. package/dist/fr-BE.js +0 -2
  227. package/dist/fr-BE.js.map +0 -1
  228. package/dist/fr.js +0 -2
  229. package/dist/fr.js.map +0 -1
  230. package/dist/he.js +0 -2
  231. package/dist/he.js.map +0 -1
  232. package/dist/hr.js +0 -2
  233. package/dist/hr.js.map +0 -1
  234. package/dist/hu.js +0 -2
  235. package/dist/hu.js.map +0 -1
  236. package/dist/id.js +0 -2
  237. package/dist/id.js.map +0 -1
  238. package/dist/it.js +0 -2
  239. package/dist/it.js.map +0 -1
  240. package/dist/ko.js +0 -2
  241. package/dist/ko.js.map +0 -1
  242. package/dist/lt.js +0 -2
  243. package/dist/lt.js.map +0 -1
  244. package/dist/lv.js +0 -2
  245. package/dist/lv.js.map +0 -1
  246. package/dist/n2words.d.ts +0 -2
  247. package/dist/nl.js +0 -2
  248. package/dist/nl.js.map +0 -1
  249. package/dist/no.js +0 -2
  250. package/dist/no.js.map +0 -1
  251. package/dist/pl.js +0 -2
  252. package/dist/pl.js.map +0 -1
  253. package/dist/pt.js +0 -2
  254. package/dist/pt.js.map +0 -1
  255. package/dist/ro.js +0 -2
  256. package/dist/ro.js.map +0 -1
  257. package/dist/ru.js +0 -2
  258. package/dist/ru.js.map +0 -1
  259. package/dist/sr.js +0 -2
  260. package/dist/sr.js.map +0 -1
  261. package/dist/tr.js +0 -2
  262. package/dist/tr.js.map +0 -1
  263. package/dist/uk.js +0 -2
  264. package/dist/uk.js.map +0 -1
  265. package/dist/vi.js +0 -2
  266. package/dist/vi.js.map +0 -1
  267. package/dist/zh.js +0 -2
  268. package/dist/zh.js.map +0 -1
  269. package/lib/classes/base-language.d.ts +0 -58
  270. package/lib/classes/base-language.js +0 -172
  271. package/lib/i18n/ar.d.ts +0 -41
  272. package/lib/i18n/ar.js +0 -209
  273. package/lib/i18n/az.d.ts +0 -15
  274. package/lib/i18n/az.js +0 -66
  275. package/lib/i18n/cz.js +0 -135
  276. package/lib/i18n/de.d.ts +0 -17
  277. package/lib/i18n/de.js +0 -103
  278. package/lib/i18n/dk.d.ts +0 -14
  279. package/lib/i18n/dk.js +0 -110
  280. package/lib/i18n/en.d.ts +0 -22
  281. package/lib/i18n/en.js +0 -86
  282. package/lib/i18n/es.d.ts +0 -16
  283. package/lib/i18n/es.js +0 -110
  284. package/lib/i18n/fa.d.ts +0 -54
  285. package/lib/i18n/fa.js +0 -106
  286. package/lib/i18n/fr-BE.d.ts +0 -11
  287. package/lib/i18n/fr-BE.js +0 -20
  288. package/lib/i18n/fr.d.ts +0 -15
  289. package/lib/i18n/fr.js +0 -99
  290. package/lib/i18n/he.d.ts +0 -61
  291. package/lib/i18n/he.js +0 -132
  292. package/lib/i18n/hr.d.ts +0 -68
  293. package/lib/i18n/hr.js +0 -129
  294. package/lib/i18n/hu.d.ts +0 -17
  295. package/lib/i18n/hu.js +0 -135
  296. package/lib/i18n/id.d.ts +0 -43
  297. package/lib/i18n/id.js +0 -156
  298. package/lib/i18n/it.d.ts +0 -29
  299. package/lib/i18n/it.js +0 -137
  300. package/lib/i18n/ko.d.ts +0 -15
  301. package/lib/i18n/ko.js +0 -56
  302. package/lib/i18n/lt.js +0 -138
  303. package/lib/i18n/lv.d.ts +0 -57
  304. package/lib/i18n/lv.js +0 -120
  305. package/lib/i18n/nl.d.ts +0 -20
  306. package/lib/i18n/nl.js +0 -125
  307. package/lib/i18n/no.d.ts +0 -15
  308. package/lib/i18n/no.js +0 -77
  309. package/lib/i18n/pl.js +0 -126
  310. package/lib/i18n/pt.d.ts +0 -26
  311. package/lib/i18n/pt.js +0 -118
  312. package/lib/i18n/ro.d.ts +0 -109
  313. package/lib/i18n/ro.js +0 -360
  314. package/lib/i18n/ru.d.ts +0 -30
  315. package/lib/i18n/ru.js +0 -198
  316. package/lib/i18n/sr.d.ts +0 -56
  317. package/lib/i18n/sr.js +0 -127
  318. package/lib/i18n/tr.d.ts +0 -15
  319. package/lib/i18n/tr.js +0 -64
  320. package/lib/i18n/vi.js +0 -151
  321. package/lib/i18n/zh.d.ts +0 -18
  322. package/lib/i18n/zh.js +0 -78
package/lib/n2words.js CHANGED
@@ -1,87 +1,541 @@
1
1
  /**
2
+ * n2words - Convert numbers to words in multiple languages
3
+ *
4
+ * This file is the main entry point for the n2words library.
5
+ * It exports converter functions for all supported languages.
6
+ *
7
+ * ## For Contributors
8
+ *
9
+ * When adding a new language, this file must be updated in THREE sections:
10
+ * 1. Language Imports - Add import statement (alphabetically sorted)
11
+ * 2. Language Converters - Create converter with makeConverter() (alphabetically sorted)
12
+ * 3. Exports - Add to export list (alphabetically sorted)
13
+ *
14
+ * Use the scaffolding tool to automate this process:
15
+ * npm run lang:add <language-code>
16
+ *
17
+ * ## Public API Structure
18
+ *
19
+ * Each language exports a converter function:
20
+ * - Name: `{LanguageName}Converter` (e.g., EnglishConverter, SpanishConverter)
21
+ * - Signature: `(value: NumericValue, options?: Options) => string`
22
+ * - Input: number, bigint, or string (numeric strings only)
23
+ * - Output: Words representing the number in the target language
24
+ *
25
+ * Languages without options use signature: `(value: NumericValue) => string`
26
+ * Languages with options define a typedef (e.g., ArabicOptions) and use: `(value: NumericValue, options?: ArabicOptions) => string`
27
+ *
2
28
  * @module n2words
3
29
  */
4
30
 
5
- import n2wordsAR from './i18n/ar.js';
6
- import n2wordsAZ from './i18n/az.js';
7
- import n2wordsCZ from './i18n/cz.js';
8
- import n2wordsDE from './i18n/de.js';
9
- import n2wordsDK from './i18n/dk.js';
10
- import n2wordsEN from './i18n/en.js';
11
- import n2wordsES from './i18n/es.js';
12
- import n2wordsFA from './i18n/fa.js';
13
- import n2wordsFR from './i18n/fr.js';
14
- import n2wordsFRBE from './i18n/fr-BE.js';
15
- import n2wordsHE from './i18n/he.js';
16
- import n2wordsHR from './i18n/hr.js';
17
- import n2wordsHU from './i18n/hu.js';
18
- import n2wordsID from './i18n/id.js';
19
- import n2wordsIT from './i18n/it.js';
20
- import n2wordsKO from './i18n/ko.js';
21
- import n2wordsLT from './i18n/lt.js';
22
- import n2wordsLV from './i18n/lv.js';
23
- import n2wordsNL from './i18n/nl.js';
24
- import n2wordsNO from './i18n/no.js';
25
- import n2wordsPL from './i18n/pl.js';
26
- import n2wordsPT from './i18n/pt.js';
27
- import n2wordsRO from './i18n/ro.js';
28
- import n2wordsRU from './i18n/ru.js';
29
- import n2wordsSR from './i18n/sr.js';
30
- import n2wordsTR from './i18n/tr.js';
31
- import n2wordsUK from './i18n/uk.js';
32
- import n2wordsVI from './i18n/vi.js';
33
- import n2wordsZH from './i18n/zh.js';
34
-
35
- const dict = {
36
- 'ar': n2wordsAR,
37
- 'az': n2wordsAZ,
38
- 'cz': n2wordsCZ,
39
- 'de': n2wordsDE,
40
- 'dk': n2wordsDK,
41
- 'en': n2wordsEN, // default
42
- 'es': n2wordsES,
43
- 'fa': n2wordsFA,
44
- 'fr': n2wordsFR,
45
- 'fr-BE': n2wordsFRBE,
46
- 'he': n2wordsHE, // currently only for numbers < 10000
47
- 'hr': n2wordsHR,
48
- 'hu': n2wordsHU,
49
- 'id': n2wordsID,
50
- 'it': n2wordsIT,
51
- 'ko': n2wordsKO,
52
- 'lt': n2wordsLT,
53
- 'lv': n2wordsLV,
54
- 'nl': n2wordsNL,
55
- 'no': n2wordsNO,
56
- 'pl': n2wordsPL,
57
- 'pt': n2wordsPT,
58
- 'ro': n2wordsRO,
59
- 'ru': n2wordsRU,
60
- 'sr': n2wordsSR,
61
- 'tr': n2wordsTR,
62
- 'uk': n2wordsUK,
63
- 'vi': n2wordsVI,
64
- 'zh': n2wordsZH,
65
- };
66
-
67
- /**
68
- * Converts a number to written form.
69
- * @param {number|string|bigint} value The number to convert.
70
- * @param {object} [options] User options.
71
- * @returns {string} Value in written format.
72
- * TODO [2024-06] Migrate to object destructing for parameters
73
- */
74
- // eslint-disable-next-line unicorn/no-object-as-default-parameter
75
- function floatToCardinal(value, options = { lang: 'en' }) {
76
- const function_ = dict[options.lang];
77
- if (function_ != undefined) return function_(value, options);
78
-
79
- const fallbackLang = options.lang.split('-') // 'en-UK' -> ['en', 'UK']
80
- .map((_, index, array) => array.slice(0, array.length - index).join('-')) // ['en-UK', 'en']
81
- .find(l => dict[l] != undefined);
82
- if (fallbackLang != undefined) return dict[fallbackLang](value, options);
83
-
84
- throw new Error('Unsupported language: ' + value + '.');
31
+ // ============================================================================
32
+ // Language Imports
33
+ // ============================================================================
34
+
35
+ import { Arabic } from './languages/ar.js'
36
+ import { Azerbaijani } from './languages/az.js'
37
+ import { Bangla } from './languages/bn.js'
38
+ import { Czech } from './languages/cs.js'
39
+ import { Danish } from './languages/da.js'
40
+ import { German } from './languages/de.js'
41
+ import { Greek } from './languages/el.js'
42
+ import { English } from './languages/en.js'
43
+ import { Spanish } from './languages/es.js'
44
+ import { Persian } from './languages/fa.js'
45
+ import { Filipino } from './languages/fil.js'
46
+ import { French } from './languages/fr.js'
47
+ import { FrenchBelgium } from './languages/fr-BE.js'
48
+ import { Gujarati } from './languages/gu.js'
49
+ import { Hebrew } from './languages/he.js'
50
+ import { BiblicalHebrew } from './languages/hbo.js'
51
+ import { Hindi } from './languages/hi.js'
52
+ import { Croatian } from './languages/hr.js'
53
+ import { Hungarian } from './languages/hu.js'
54
+ import { Indonesian } from './languages/id.js'
55
+ import { Italian } from './languages/it.js'
56
+ import { Japanese } from './languages/ja.js'
57
+ import { Kannada } from './languages/kn.js'
58
+ import { Korean } from './languages/ko.js'
59
+ import { Lithuanian } from './languages/lt.js'
60
+ import { Latvian } from './languages/lv.js'
61
+ import { Marathi } from './languages/mr.js'
62
+ import { Malay } from './languages/ms.js'
63
+ import { Dutch } from './languages/nl.js'
64
+ import { NorwegianBokmal } from './languages/nb.js'
65
+ import { Punjabi } from './languages/pa.js'
66
+ import { Polish } from './languages/pl.js'
67
+ import { Portuguese } from './languages/pt.js'
68
+ import { Romanian } from './languages/ro.js'
69
+ import { Russian } from './languages/ru.js'
70
+ import { SerbianCyrillic } from './languages/sr-Cyrl.js'
71
+ import { SerbianLatin } from './languages/sr-Latn.js'
72
+ import { Swedish } from './languages/sv.js'
73
+ import { Swahili } from './languages/sw.js'
74
+ import { Tamil } from './languages/ta.js'
75
+ import { Telugu } from './languages/te.js'
76
+ import { Thai } from './languages/th.js'
77
+ import { Turkish } from './languages/tr.js'
78
+ import { Ukrainian } from './languages/uk.js'
79
+ import { Urdu } from './languages/ur.js'
80
+ import { Vietnamese } from './languages/vi.js'
81
+ import { SimplifiedChinese } from './languages/zh-Hans.js'
82
+ import { TraditionalChinese } from './languages/zh-Hant.js'
83
+
84
+ // ============================================================================
85
+ // Type Definitions
86
+ // ============================================================================
87
+ //
88
+ // This section defines TypeScript-compatible JSDoc types for:
89
+ // - NumericValue: The input types accepted by all converters
90
+ // - {Language}Options: Optional configuration for languages that support it
91
+ //
92
+ // Keep options typedefs alphabetically sorted for maintainability.
93
+ // ============================================================================
94
+
95
+ /**
96
+ * Numeric value that can be converted to words.
97
+ * Accepts number, bigint, or numeric string representations.
98
+ * @typedef {number | bigint | string} NumericValue
99
+ */
100
+
101
+ /**
102
+ * @typedef {Object} ArabicOptions
103
+ * @property {string} [negativeWord] Word for negative numbers
104
+ * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms
105
+ */
106
+
107
+ /**
108
+ * @typedef {Object} BiblicalHebrewOptions
109
+ * @property {string} [andWord='ו'] Conjunction character (typically 'ו' for and)
110
+ * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms
111
+ */
112
+
113
+ /**
114
+ * @typedef {Object} CroatianOptions
115
+ * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms
116
+ */
117
+
118
+ /**
119
+ * @typedef {Object} CzechOptions
120
+ * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms
121
+ */
122
+
123
+ /**
124
+ * @typedef {Object} DanishOptions
125
+ * @property {boolean} [ordFlag=false] Enable ordinal number conversion
126
+ */
127
+
128
+ /**
129
+ * @typedef {Object} DutchOptions
130
+ * @property {boolean} [includeOptionalAnd=false] Include optional "en" separator
131
+ * @property {boolean} [noHundredPairing=false] Disable hundred-pairing (e.g., "twelve hundred" becomes "one thousand two hundred")
132
+ * @property {boolean} [accentOne=true] Use accented "één" for one
133
+ */
134
+
135
+ /**
136
+ * @typedef {Object} FrenchOptions
137
+ * @property {boolean} [withHyphenSeparator=false] Use hyphens (true) instead of spaces (false) in compounds
138
+ */
139
+
140
+ /**
141
+ * @typedef {Object} FrenchBelgiumOptions
142
+ * @property {boolean} [withHyphenSeparator=false] Use hyphens (true) instead of spaces (false) in compounds
143
+ */
144
+
145
+ /**
146
+ * @typedef {Object} HebrewOptions
147
+ * @property {string} [andWord='ו'] Conjunction character (typically 'ו' for and)
148
+ */
149
+
150
+ /**
151
+ * @typedef {Object} LatvianOptions
152
+ * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms
153
+ */
154
+
155
+ /**
156
+ * @typedef {Object} LithuanianOptions
157
+ * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms
158
+ */
159
+
160
+ /**
161
+ * @typedef {Object} PolishOptions
162
+ * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms
163
+ */
164
+
165
+ /**
166
+ * @typedef {Object} RomanianOptions
167
+ * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms
168
+ */
169
+
170
+ /**
171
+ * @typedef {Object} RussianOptions
172
+ * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms
173
+ */
174
+
175
+ /**
176
+ * @typedef {Object} SerbianCyrillicOptions
177
+ * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms
178
+ */
179
+
180
+ /**
181
+ * @typedef {Object} SerbianLatinOptions
182
+ * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms
183
+ */
184
+
185
+ /**
186
+ * @typedef {Object} SimplifiedChineseOptions
187
+ * @property {boolean} [formal=true] Use formal/financial numerals (壹贰叁) vs. common numerals (一二三)
188
+ */
189
+
190
+ /**
191
+ * @typedef {Object} SpanishOptions
192
+ * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms
193
+ */
194
+
195
+ /**
196
+ * @typedef {Object} TraditionalChineseOptions
197
+ * @property {boolean} [formal=true] Use formal/financial numerals (壹貳參) vs. common numerals (一二三)
198
+ */
199
+
200
+ /**
201
+ * @typedef {Object} TurkishOptions
202
+ * @property {boolean} [dropSpaces=false] Remove spaces between words if true
203
+ */
204
+
205
+ /**
206
+ * @typedef {Object} UkrainianOptions
207
+ * @property {('masculine'|'feminine')} [gender='masculine'] Grammatical gender for number forms
208
+ */
209
+
210
+ // ============================================================================
211
+ // Converter Factory
212
+ // ============================================================================
213
+ //
214
+ // makeConverter() is a factory function that creates converter functions from
215
+ // language classes. It provides a consistent functional API for all languages:
216
+ //
217
+ // const result = EnglishConverter(42) // "forty-two"
218
+ // const result = ArabicConverter(1, {gender: 'feminine'}) // "واحدة"
219
+ //
220
+ // This design:
221
+ // - Hides class instantiation details from public API
222
+ // - Ensures each conversion uses a fresh instance
223
+ // - Maintains immutability (no shared state between conversions)
224
+ // ============================================================================
225
+
226
+ /**
227
+ * Creates a converter function for a language class.
228
+ *
229
+ * This factory handles all input validation and normalization at the public API
230
+ * boundary, then delegates to the language class with pre-processed data.
231
+ *
232
+ * @template {Object} [TOptions={}]
233
+ * @param {new (options?: TOptions) => { toWords: (isNegative: boolean, integerPart: bigint, decimalPart?: string) => string }} LanguageClass - Language class constructor
234
+ * @returns {(value: NumericValue, options?: TOptions) => string} Converter function
235
+ */
236
+ function makeConverter (LanguageClass) {
237
+ /**
238
+ * @param {NumericValue} value
239
+ * @param {TOptions} [options]
240
+ * @returns {string}
241
+ */
242
+ return function convertToWords (value, options) {
243
+ if (options !== undefined && !isPlainObject(options)) {
244
+ throw new TypeError('options must be a plain object if provided')
245
+ }
246
+
247
+ const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
248
+ return new LanguageClass(options).toWords(isNegative, integerPart, decimalPart)
249
+ }
250
+ }
251
+
252
+ // ============================================================================
253
+ // Input Parsing Utilities
254
+ // ============================================================================
255
+
256
+ /**
257
+ * @typedef {Object} ParsedNumericValue
258
+ * @property {boolean} isNegative - Whether the value is negative
259
+ * @property {bigint} integerPart - The absolute integer part
260
+ * @property {string} [decimalPart] - The decimal digits (without the point)
261
+ */
262
+
263
+ /**
264
+ * Parses and validates a numeric value into its components.
265
+ * Handles number, string, and bigint inputs uniformly.
266
+ *
267
+ * @param {NumericValue} value The value to parse
268
+ * @returns {ParsedNumericValue} The parsed components
269
+ * @throws {TypeError} If value is not a valid numeric type
270
+ * @throws {Error} If value is not a valid number format
271
+ */
272
+ function parseNumericValue (value) {
273
+ const type = typeof value
274
+
275
+ // BigInt: simplest case - no decimals, no scientific notation
276
+ if (type === 'bigint') {
277
+ return value < 0n
278
+ ? { isNegative: true, integerPart: -value }
279
+ : { isNegative: false, integerPart: value }
280
+ }
281
+
282
+ // Reject invalid types early
283
+ if (type !== 'number' && type !== 'string') {
284
+ throw new TypeError(
285
+ `Invalid value type: expected number, string, or bigint, received ${type}`
286
+ )
287
+ }
288
+
289
+ // Convert to normalized string
290
+ const str = type === 'number'
291
+ ? numberToString(value)
292
+ : stringToNormalizedForm(value)
293
+
294
+ return parseNumericString(str)
295
+ }
296
+
297
+ /**
298
+ * Converts a JavaScript number to a decimal string.
299
+ * Handles special cases: Infinity, NaN, and scientific notation.
300
+ *
301
+ * @param {number} value The number to convert
302
+ * @returns {string} Decimal string representation
303
+ * @throws {Error} If value is not finite
304
+ */
305
+ function numberToString (value) {
306
+ if (!Number.isFinite(value)) {
307
+ throw new Error('Number must be finite (NaN and Infinity are not supported)')
308
+ }
309
+
310
+ const str = value.toString()
311
+
312
+ // Expand scientific notation (used for values >= 1e21 or < 1e-6)
313
+ if (str.includes('e') || str.includes('E')) {
314
+ return expandScientificNotation(str)
315
+ }
316
+
317
+ return str
318
+ }
319
+
320
+ /**
321
+ * Validates and normalizes a string numeric input.
322
+ *
323
+ * @param {string} value The string to validate
324
+ * @returns {string} Trimmed and validated string
325
+ * @throws {Error} If string is empty or not a valid number format
326
+ */
327
+ function stringToNormalizedForm (value) {
328
+ const trimmed = value.trim()
329
+
330
+ if (trimmed.length === 0) {
331
+ throw new Error(`Invalid number format: "${value}"`)
332
+ }
333
+
334
+ // Validate by attempting conversion (handles edge cases like "1e21", "-.5", etc.)
335
+ if (Number.isNaN(Number(trimmed))) {
336
+ throw new Error(`Invalid number format: "${value}"`)
337
+ }
338
+
339
+ // Expand scientific notation if present
340
+ if (trimmed.includes('e') || trimmed.includes('E')) {
341
+ return expandScientificNotation(trimmed)
342
+ }
343
+
344
+ return trimmed
345
+ }
346
+
347
+ /**
348
+ * Parses a normalized numeric string into its components.
349
+ *
350
+ * @param {string} str A normalized decimal string (no scientific notation)
351
+ * @returns {ParsedNumericValue} The parsed components
352
+ */
353
+ function parseNumericString (str) {
354
+ // Extract sign
355
+ const isNegative = str[0] === '-'
356
+ if (isNegative) {
357
+ str = str.slice(1)
358
+ }
359
+
360
+ // Split into integer and decimal parts
361
+ const dotIndex = str.indexOf('.')
362
+ if (dotIndex === -1) {
363
+ return { isNegative, integerPart: BigInt(str) }
364
+ }
365
+
366
+ const integerStr = str.slice(0, dotIndex) || '0'
367
+ const decimalPart = str.slice(dotIndex + 1)
368
+
369
+ return { isNegative, integerPart: BigInt(integerStr), decimalPart }
85
370
  }
86
371
 
87
- export default floatToCardinal;
372
+ /**
373
+ * Expands scientific notation to decimal form.
374
+ * JavaScript uses scientific notation for values >= 1e21 or < 1e-6.
375
+ *
376
+ * @param {string} str String possibly in scientific notation (e.g., "1e+21")
377
+ * @returns {string} Decimal form (e.g., "1000000000000000000000")
378
+ */
379
+ function expandScientificNotation (str) {
380
+ const [mantissa, expStr] = str.toLowerCase().split('e')
381
+ const exp = parseInt(expStr, 10)
382
+
383
+ // Extract digits and determine original decimal position
384
+ const dotIndex = mantissa.indexOf('.')
385
+ const digits = dotIndex === -1
386
+ ? mantissa
387
+ : mantissa.slice(0, dotIndex) + mantissa.slice(dotIndex + 1)
388
+ const integerLength = dotIndex === -1 ? mantissa.length : dotIndex
389
+
390
+ // Calculate new decimal position after applying exponent
391
+ const newDotPosition = integerLength + exp
392
+
393
+ if (newDotPosition >= digits.length) {
394
+ // Pure integer: pad with trailing zeros
395
+ return digits + '0'.repeat(newDotPosition - digits.length)
396
+ }
397
+
398
+ if (newDotPosition <= 0) {
399
+ // Pure decimal: pad with leading zeros after decimal point
400
+ return '0.' + '0'.repeat(-newDotPosition) + digits
401
+ }
402
+
403
+ // Mixed: insert decimal point at new position
404
+ return digits.slice(0, newDotPosition) + '.' + digits.slice(newDotPosition)
405
+ }
406
+
407
+ /**
408
+ * Checks if a value is a plain object (not null, array, or other object types).
409
+ *
410
+ * @param {*} value Value to check
411
+ * @returns {boolean} True if value is a plain object
412
+ */
413
+ function isPlainObject (value) {
414
+ if (value === null || typeof value !== 'object') return false
415
+ const proto = Object.getPrototypeOf(value)
416
+ return proto === Object.prototype || proto === null
417
+ }
418
+
419
+ // ============================================================================
420
+ // Language Converters
421
+ // ============================================================================
422
+ //
423
+ // Each converter is created using makeConverter() with explicit type annotations.
424
+ //
425
+ // Pattern for languages WITHOUT options:
426
+ // const LanguageConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Language))
427
+ //
428
+ // Pattern for languages WITH options:
429
+ // const LanguageConverter = /** @type {(value: NumericValue, options?: LanguageOptions) => string} */ (makeConverter(Language))
430
+ //
431
+ // IMPORTANT: Keep converters alphabetically sorted by converter name.
432
+ // ============================================================================
433
+
434
+ const ArabicConverter = /** @type {(value: NumericValue, options?: ArabicOptions) => string} */ (makeConverter(Arabic))
435
+ const AzerbaijaniConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Azerbaijani))
436
+ const BanglaConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Bangla))
437
+ const BiblicalHebrewConverter = /** @type {(value: NumericValue, options?: BiblicalHebrewOptions) => string} */ (makeConverter(BiblicalHebrew))
438
+ const CroatianConverter = /** @type {(value: NumericValue, options?: CroatianOptions) => string} */ (makeConverter(Croatian))
439
+ const CzechConverter = /** @type {(value: NumericValue, options?: CzechOptions) => string} */ (makeConverter(Czech))
440
+ const DanishConverter = /** @type {(value: NumericValue, options?: DanishOptions) => string} */ (makeConverter(Danish))
441
+ const DutchConverter = /** @type {(value: NumericValue, options?: DutchOptions) => string} */ (makeConverter(Dutch))
442
+ const EnglishConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(English))
443
+ const FilipinoConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Filipino))
444
+ const FrenchConverter = /** @type {(value: NumericValue, options?: FrenchOptions) => string} */ (makeConverter(French))
445
+ const FrenchBelgiumConverter = /** @type {(value: NumericValue, options?: FrenchBelgiumOptions) => string} */ (makeConverter(FrenchBelgium))
446
+ const GermanConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(German))
447
+ const GreekConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Greek))
448
+ const GujaratiConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Gujarati))
449
+ const HebrewConverter = /** @type {(value: NumericValue, options?: HebrewOptions) => string} */ (makeConverter(Hebrew))
450
+ const HindiConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Hindi))
451
+ const HungarianConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Hungarian))
452
+ const IndonesianConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Indonesian))
453
+ const ItalianConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Italian))
454
+ const JapaneseConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Japanese))
455
+ const KannadaConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Kannada))
456
+ const KoreanConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Korean))
457
+ const LatvianConverter = /** @type {(value: NumericValue, options?: LatvianOptions) => string} */ (makeConverter(Latvian))
458
+ const LithuanianConverter = /** @type {(value: NumericValue, options?: LithuanianOptions) => string} */ (makeConverter(Lithuanian))
459
+ const MalayConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Malay))
460
+ const MarathiConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Marathi))
461
+ const NorwegianBokmalConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(NorwegianBokmal))
462
+ const PersianConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Persian))
463
+ const PolishConverter = /** @type {(value: NumericValue, options?: PolishOptions) => string} */ (makeConverter(Polish))
464
+ const PortugueseConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Portuguese))
465
+ const PunjabiConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Punjabi))
466
+ const RomanianConverter = /** @type {(value: NumericValue, options?: RomanianOptions) => string} */ (makeConverter(Romanian))
467
+ const RussianConverter = /** @type {(value: NumericValue, options?: RussianOptions) => string} */ (makeConverter(Russian))
468
+ const SerbianCyrillicConverter = /** @type {(value: NumericValue, options?: SerbianCyrillicOptions) => string} */ (makeConverter(SerbianCyrillic))
469
+ const SerbianLatinConverter = /** @type {(value: NumericValue, options?: SerbianLatinOptions) => string} */ (makeConverter(SerbianLatin))
470
+ const SimplifiedChineseConverter = /** @type {(value: NumericValue, options?: SimplifiedChineseOptions) => string} */ (makeConverter(SimplifiedChinese))
471
+ const SpanishConverter = /** @type {(value: NumericValue, options?: SpanishOptions) => string} */ (makeConverter(Spanish))
472
+ const SwahiliConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Swahili))
473
+ const SwedishConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Swedish))
474
+ const TamilConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Tamil))
475
+ const TeluguConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Telugu))
476
+ const ThaiConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Thai))
477
+ const TraditionalChineseConverter = /** @type {(value: NumericValue, options?: TraditionalChineseOptions) => string} */ (makeConverter(TraditionalChinese))
478
+ const TurkishConverter = /** @type {(value: NumericValue, options?: TurkishOptions) => string} */ (makeConverter(Turkish))
479
+ const UkrainianConverter = /** @type {(value: NumericValue, options?: UkrainianOptions) => string} */ (makeConverter(Ukrainian))
480
+ const UrduConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Urdu))
481
+ const VietnameseConverter = /** @type {(value: NumericValue) => string} */ (makeConverter(Vietnamese))
482
+
483
+ // ============================================================================
484
+ // Exports
485
+ // ============================================================================
486
+ //
487
+ // All converter functions are exported for public use.
488
+ //
489
+ // IMPORTANT: Keep exports alphabetically sorted for maintainability.
490
+ // ============================================================================
491
+
492
+ export {
493
+ ArabicConverter,
494
+ AzerbaijaniConverter,
495
+ BanglaConverter,
496
+ BiblicalHebrewConverter,
497
+ CroatianConverter,
498
+ CzechConverter,
499
+ DanishConverter,
500
+ DutchConverter,
501
+ EnglishConverter,
502
+ FilipinoConverter,
503
+ FrenchConverter,
504
+ FrenchBelgiumConverter,
505
+ GermanConverter,
506
+ GreekConverter,
507
+ GujaratiConverter,
508
+ HebrewConverter,
509
+ HindiConverter,
510
+ HungarianConverter,
511
+ IndonesianConverter,
512
+ ItalianConverter,
513
+ JapaneseConverter,
514
+ KannadaConverter,
515
+ KoreanConverter,
516
+ LatvianConverter,
517
+ LithuanianConverter,
518
+ MalayConverter,
519
+ MarathiConverter,
520
+ NorwegianBokmalConverter,
521
+ PersianConverter,
522
+ PolishConverter,
523
+ PortugueseConverter,
524
+ PunjabiConverter,
525
+ RomanianConverter,
526
+ RussianConverter,
527
+ SerbianCyrillicConverter,
528
+ SerbianLatinConverter,
529
+ SimplifiedChineseConverter,
530
+ SpanishConverter,
531
+ SwahiliConverter,
532
+ SwedishConverter,
533
+ TamilConverter,
534
+ TeluguConverter,
535
+ ThaiConverter,
536
+ TraditionalChineseConverter,
537
+ TurkishConverter,
538
+ UkrainianConverter,
539
+ UrduConverter,
540
+ VietnameseConverter
541
+ }