n2words 2.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (335) hide show
  1. package/CHANGELOG.md +64 -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/ka.js +3 -0
  56. package/dist/languages/ka.js.map +1 -0
  57. package/dist/languages/kn.js +3 -0
  58. package/dist/languages/kn.js.map +1 -0
  59. package/dist/languages/ko.js +3 -0
  60. package/dist/languages/ko.js.map +1 -0
  61. package/dist/languages/lt.js +3 -0
  62. package/dist/languages/lt.js.map +1 -0
  63. package/dist/languages/lv.js +3 -0
  64. package/dist/languages/lv.js.map +1 -0
  65. package/dist/languages/mr.js +3 -0
  66. package/dist/languages/mr.js.map +1 -0
  67. package/dist/languages/ms.js +3 -0
  68. package/dist/languages/ms.js.map +1 -0
  69. package/dist/languages/nb.js +3 -0
  70. package/dist/languages/nb.js.map +1 -0
  71. package/dist/languages/nl.js +3 -0
  72. package/dist/languages/nl.js.map +1 -0
  73. package/dist/languages/pa.js +3 -0
  74. package/dist/languages/pa.js.map +1 -0
  75. package/dist/languages/pl.js +3 -0
  76. package/dist/languages/pl.js.map +1 -0
  77. package/dist/languages/pt.js +3 -0
  78. package/dist/languages/pt.js.map +1 -0
  79. package/dist/languages/ro.js +3 -0
  80. package/dist/languages/ro.js.map +1 -0
  81. package/dist/languages/ru.js +3 -0
  82. package/dist/languages/ru.js.map +1 -0
  83. package/dist/languages/sr-Cyrl.js +3 -0
  84. package/dist/languages/sr-Cyrl.js.map +1 -0
  85. package/dist/languages/sr-Latn.js +3 -0
  86. package/dist/languages/sr-Latn.js.map +1 -0
  87. package/dist/languages/sv.js +3 -0
  88. package/dist/languages/sv.js.map +1 -0
  89. package/dist/languages/sw.js +3 -0
  90. package/dist/languages/sw.js.map +1 -0
  91. package/dist/languages/ta.js +3 -0
  92. package/dist/languages/ta.js.map +1 -0
  93. package/dist/languages/te.js +3 -0
  94. package/dist/languages/te.js.map +1 -0
  95. package/dist/languages/th.js +3 -0
  96. package/dist/languages/th.js.map +1 -0
  97. package/dist/languages/tr.js +3 -0
  98. package/dist/languages/tr.js.map +1 -0
  99. package/dist/languages/uk.js +3 -0
  100. package/dist/languages/uk.js.map +1 -0
  101. package/dist/languages/ur.js +3 -0
  102. package/dist/languages/ur.js.map +1 -0
  103. package/dist/languages/vi.js +3 -0
  104. package/dist/languages/vi.js.map +1 -0
  105. package/dist/languages/yo.js +3 -0
  106. package/dist/languages/yo.js.map +1 -0
  107. package/dist/languages/zh-Hans.js +3 -0
  108. package/dist/languages/zh-Hans.js.map +1 -0
  109. package/dist/languages/zh-Hant.js +3 -0
  110. package/dist/languages/zh-Hant.js.map +1 -0
  111. package/dist/n2words.js +2 -2
  112. package/dist/n2words.js.map +1 -1
  113. package/lib/languages/am-Latn.d.ts +7 -0
  114. package/lib/languages/am-Latn.js +159 -0
  115. package/lib/languages/am.d.ts +7 -0
  116. package/lib/languages/am.js +159 -0
  117. package/lib/languages/ar.d.ts +14 -27
  118. package/lib/languages/ar.js +175 -129
  119. package/lib/languages/az.d.ts +4 -9
  120. package/lib/languages/az.js +166 -37
  121. package/lib/languages/bn.d.ts +4 -8
  122. package/lib/languages/bn.js +159 -124
  123. package/lib/languages/cs.d.ts +15 -85
  124. package/lib/languages/cs.js +293 -114
  125. package/lib/languages/da.d.ts +11 -12
  126. package/lib/languages/da.js +269 -101
  127. package/lib/languages/de.d.ts +14 -11
  128. package/lib/languages/de.js +305 -86
  129. package/lib/languages/el.d.ts +11 -11
  130. package/lib/languages/el.js +224 -78
  131. package/lib/languages/en.d.ts +14 -13
  132. package/lib/languages/en.js +228 -72
  133. package/lib/languages/es.d.ts +18 -12
  134. package/lib/languages/es.js +297 -103
  135. package/lib/languages/fa.d.ts +4 -44
  136. package/lib/languages/fa.js +112 -122
  137. package/lib/languages/fi.d.ts +14 -0
  138. package/lib/languages/fi.js +238 -0
  139. package/lib/languages/fil.d.ts +4 -13
  140. package/lib/languages/fil.js +196 -106
  141. package/lib/languages/fr-BE.d.ts +8 -8
  142. package/lib/languages/fr-BE.js +285 -19
  143. package/lib/languages/fr.d.ts +18 -12
  144. package/lib/languages/fr.js +339 -89
  145. package/lib/languages/gu.d.ts +4 -8
  146. package/lib/languages/gu.js +143 -125
  147. package/lib/languages/ha.d.ts +7 -0
  148. package/lib/languages/ha.js +225 -0
  149. package/lib/languages/hbo.d.ts +10 -110
  150. package/lib/languages/hbo.js +245 -214
  151. package/lib/languages/he.d.ts +10 -77
  152. package/lib/languages/he.js +231 -172
  153. package/lib/languages/hi.d.ts +4 -8
  154. package/lib/languages/hi.js +163 -124
  155. package/lib/languages/hr.d.ts +8 -77
  156. package/lib/languages/hr.js +200 -89
  157. package/lib/languages/hu.d.ts +4 -19
  158. package/lib/languages/hu.js +198 -119
  159. package/lib/languages/id.d.ts +4 -34
  160. package/lib/languages/id.js +166 -129
  161. package/lib/languages/it.d.ts +16 -34
  162. package/lib/languages/it.js +307 -97
  163. package/lib/languages/ja.d.ts +14 -14
  164. package/lib/languages/ja.js +221 -111
  165. package/lib/languages/ka.d.ts +17 -0
  166. package/lib/languages/ka.js +291 -0
  167. package/lib/languages/kn.d.ts +4 -8
  168. package/lib/languages/kn.js +143 -35
  169. package/lib/languages/ko.d.ts +11 -11
  170. package/lib/languages/ko.js +250 -49
  171. package/lib/languages/lt.d.ts +15 -67
  172. package/lib/languages/lt.js +287 -122
  173. package/lib/languages/lv.d.ts +15 -67
  174. package/lib/languages/lv.js +288 -106
  175. package/lib/languages/mr.d.ts +4 -8
  176. package/lib/languages/mr.js +143 -125
  177. package/lib/languages/ms.d.ts +4 -28
  178. package/lib/languages/ms.js +166 -116
  179. package/lib/languages/nb.d.ts +11 -9
  180. package/lib/languages/nb.js +272 -87
  181. package/lib/languages/nl.d.ts +23 -13
  182. package/lib/languages/nl.js +299 -133
  183. package/lib/languages/pa.d.ts +4 -8
  184. package/lib/languages/pa.js +151 -124
  185. package/lib/languages/pl.d.ts +19 -77
  186. package/lib/languages/pl.js +294 -87
  187. package/lib/languages/pt.d.ts +14 -26
  188. package/lib/languages/pt.js +272 -92
  189. package/lib/languages/ro.d.ts +15 -155
  190. package/lib/languages/ro.js +219 -235
  191. package/lib/languages/ru.d.ts +8 -82
  192. package/lib/languages/ru.js +239 -90
  193. package/lib/languages/sr-Cyrl.d.ts +8 -77
  194. package/lib/languages/sr-Cyrl.js +197 -89
  195. package/lib/languages/sr-Latn.d.ts +8 -77
  196. package/lib/languages/sr-Latn.js +197 -89
  197. package/lib/languages/sv.d.ts +11 -11
  198. package/lib/languages/sv.js +278 -74
  199. package/lib/languages/sw.d.ts +4 -36
  200. package/lib/languages/sw.js +133 -106
  201. package/lib/languages/ta.d.ts +4 -17
  202. package/lib/languages/ta.js +143 -202
  203. package/lib/languages/te.d.ts +4 -19
  204. package/lib/languages/te.js +133 -196
  205. package/lib/languages/th.d.ts +4 -14
  206. package/lib/languages/th.js +135 -91
  207. package/lib/languages/tr.d.ts +15 -9
  208. package/lib/languages/tr.js +245 -49
  209. package/lib/languages/uk.d.ts +8 -82
  210. package/lib/languages/uk.js +206 -78
  211. package/lib/languages/ur.d.ts +4 -8
  212. package/lib/languages/ur.js +151 -124
  213. package/lib/languages/vi.d.ts +14 -69
  214. package/lib/languages/vi.js +278 -129
  215. package/lib/languages/yo.d.ts +7 -0
  216. package/lib/languages/yo.js +303 -0
  217. package/lib/languages/zh-Hans.d.ts +8 -18
  218. package/lib/languages/zh-Hans.js +163 -92
  219. package/lib/languages/zh-Hant.d.ts +8 -18
  220. package/lib/languages/zh-Hant.js +181 -90
  221. package/lib/n2words.d.ts +55 -209
  222. package/lib/n2words.js +115 -530
  223. package/lib/utils/is-plain-object.d.ts +13 -0
  224. package/lib/utils/is-plain-object.js +17 -0
  225. package/lib/utils/parse-numeric.d.ts +17 -0
  226. package/lib/utils/parse-numeric.js +108 -0
  227. package/lib/utils/validate-options.d.ts +8 -0
  228. package/lib/utils/validate-options.js +16 -0
  229. package/package.json +26 -14
  230. package/dist/ArabicConverter.js +0 -3
  231. package/dist/ArabicConverter.js.map +0 -1
  232. package/dist/AzerbaijaniConverter.js +0 -3
  233. package/dist/AzerbaijaniConverter.js.map +0 -1
  234. package/dist/BanglaConverter.js +0 -3
  235. package/dist/BanglaConverter.js.map +0 -1
  236. package/dist/BiblicalHebrewConverter.js +0 -3
  237. package/dist/BiblicalHebrewConverter.js.map +0 -1
  238. package/dist/CroatianConverter.js +0 -3
  239. package/dist/CroatianConverter.js.map +0 -1
  240. package/dist/CzechConverter.js +0 -3
  241. package/dist/CzechConverter.js.map +0 -1
  242. package/dist/DanishConverter.js +0 -3
  243. package/dist/DanishConverter.js.map +0 -1
  244. package/dist/DutchConverter.js +0 -3
  245. package/dist/DutchConverter.js.map +0 -1
  246. package/dist/EnglishConverter.js +0 -3
  247. package/dist/EnglishConverter.js.map +0 -1
  248. package/dist/FilipinoConverter.js +0 -3
  249. package/dist/FilipinoConverter.js.map +0 -1
  250. package/dist/FrenchBelgiumConverter.js +0 -3
  251. package/dist/FrenchBelgiumConverter.js.map +0 -1
  252. package/dist/FrenchConverter.js +0 -3
  253. package/dist/FrenchConverter.js.map +0 -1
  254. package/dist/GermanConverter.js +0 -3
  255. package/dist/GermanConverter.js.map +0 -1
  256. package/dist/GreekConverter.js +0 -3
  257. package/dist/GreekConverter.js.map +0 -1
  258. package/dist/GujaratiConverter.js +0 -3
  259. package/dist/GujaratiConverter.js.map +0 -1
  260. package/dist/HebrewConverter.js +0 -3
  261. package/dist/HebrewConverter.js.map +0 -1
  262. package/dist/HindiConverter.js +0 -3
  263. package/dist/HindiConverter.js.map +0 -1
  264. package/dist/HungarianConverter.js +0 -3
  265. package/dist/HungarianConverter.js.map +0 -1
  266. package/dist/IndonesianConverter.js +0 -3
  267. package/dist/IndonesianConverter.js.map +0 -1
  268. package/dist/ItalianConverter.js +0 -3
  269. package/dist/ItalianConverter.js.map +0 -1
  270. package/dist/JapaneseConverter.js +0 -3
  271. package/dist/JapaneseConverter.js.map +0 -1
  272. package/dist/KannadaConverter.js +0 -3
  273. package/dist/KannadaConverter.js.map +0 -1
  274. package/dist/KoreanConverter.js +0 -3
  275. package/dist/KoreanConverter.js.map +0 -1
  276. package/dist/LatvianConverter.js +0 -3
  277. package/dist/LatvianConverter.js.map +0 -1
  278. package/dist/LithuanianConverter.js +0 -3
  279. package/dist/LithuanianConverter.js.map +0 -1
  280. package/dist/MalayConverter.js +0 -3
  281. package/dist/MalayConverter.js.map +0 -1
  282. package/dist/MarathiConverter.js +0 -3
  283. package/dist/MarathiConverter.js.map +0 -1
  284. package/dist/NorwegianBokmalConverter.js +0 -3
  285. package/dist/NorwegianBokmalConverter.js.map +0 -1
  286. package/dist/PersianConverter.js +0 -3
  287. package/dist/PersianConverter.js.map +0 -1
  288. package/dist/PolishConverter.js +0 -3
  289. package/dist/PolishConverter.js.map +0 -1
  290. package/dist/PortugueseConverter.js +0 -3
  291. package/dist/PortugueseConverter.js.map +0 -1
  292. package/dist/PunjabiConverter.js +0 -3
  293. package/dist/PunjabiConverter.js.map +0 -1
  294. package/dist/RomanianConverter.js +0 -3
  295. package/dist/RomanianConverter.js.map +0 -1
  296. package/dist/RussianConverter.js +0 -3
  297. package/dist/RussianConverter.js.map +0 -1
  298. package/dist/SerbianCyrillicConverter.js +0 -3
  299. package/dist/SerbianCyrillicConverter.js.map +0 -1
  300. package/dist/SerbianLatinConverter.js +0 -3
  301. package/dist/SerbianLatinConverter.js.map +0 -1
  302. package/dist/SimplifiedChineseConverter.js +0 -3
  303. package/dist/SimplifiedChineseConverter.js.map +0 -1
  304. package/dist/SpanishConverter.js +0 -3
  305. package/dist/SpanishConverter.js.map +0 -1
  306. package/dist/SwahiliConverter.js +0 -3
  307. package/dist/SwahiliConverter.js.map +0 -1
  308. package/dist/SwedishConverter.js +0 -3
  309. package/dist/SwedishConverter.js.map +0 -1
  310. package/dist/TamilConverter.js +0 -3
  311. package/dist/TamilConverter.js.map +0 -1
  312. package/dist/TeluguConverter.js +0 -3
  313. package/dist/TeluguConverter.js.map +0 -1
  314. package/dist/ThaiConverter.js +0 -3
  315. package/dist/ThaiConverter.js.map +0 -1
  316. package/dist/TraditionalChineseConverter.js +0 -3
  317. package/dist/TraditionalChineseConverter.js.map +0 -1
  318. package/dist/TurkishConverter.js +0 -3
  319. package/dist/TurkishConverter.js.map +0 -1
  320. package/dist/UkrainianConverter.js +0 -3
  321. package/dist/UkrainianConverter.js.map +0 -1
  322. package/dist/UrduConverter.js +0 -3
  323. package/dist/UrduConverter.js.map +0 -1
  324. package/dist/VietnameseConverter.js +0 -3
  325. package/dist/VietnameseConverter.js.map +0 -1
  326. package/lib/classes/abstract-language.d.ts +0 -178
  327. package/lib/classes/abstract-language.js +0 -268
  328. package/lib/classes/greedy-scale-language.d.ts +0 -109
  329. package/lib/classes/greedy-scale-language.js +0 -201
  330. package/lib/classes/slavic-language.d.ts +0 -148
  331. package/lib/classes/slavic-language.js +0 -281
  332. package/lib/classes/south-asian-language.d.ts +0 -70
  333. package/lib/classes/south-asian-language.js +0 -154
  334. package/lib/classes/turkic-language.d.ts +0 -26
  335. package/lib/classes/turkic-language.js +0 -59
@@ -1,206 +1,265 @@
1
- import { SlavicLanguage } from '../classes/slavic-language.js'
2
-
3
1
  /**
4
- * Modern Hebrew language converter.
2
+ * Modern Hebrew language converter - Functional Implementation
3
+ *
4
+ * Self-contained module with its own input validation, ready for subpath exports.
5
5
  *
6
- * Supports:
7
- * - Right-to-left text orientation
6
+ * Key features:
8
7
  * - Feminine grammatical forms (default in Modern Hebrew)
9
- * - Three-form pluralization (singular/few/many)
10
- * - Optional "ve" (ו) conjunction via options
8
+ * - Dual forms for 2, 200, 2000
9
+ * - Special 1-9 thousands construct state
10
+ * - "ו" (ve) conjunction rules vary by position
11
+ * - Per-digit decimal reading
11
12
  */
12
- export class Hebrew extends SlavicLanguage {
13
- negativeWord = 'מינוס'
14
- decimalSeparatorWord = 'נקודה'
15
- zeroWord = 'אפס'
16
- usePerDigitDecimals = true
17
-
18
- // Feminine forms (default in Modern Hebrew)
19
- onesWords = {
20
- 1: 'אחת',
21
- 2: 'שתים',
22
- 3: 'שלש',
23
- 4: 'ארבע',
24
- 5: 'חמש',
25
- 6: 'שש',
26
- 7: 'שבע',
27
- 8: 'שמונה',
28
- 9: 'תשע'
29
- }
30
13
 
31
- teensWords = {
32
- 0: 'עשר',
33
- 1: 'אחת עשרה',
34
- 2: 'שתים עשרה',
35
- 3: 'שלש עשרה',
36
- 4: 'ארבע עשרה',
37
- 5: 'חמש עשרה',
38
- 6: 'שש עשרה',
39
- 7: 'שבע עשרה',
40
- 8: 'שמונה עשרה',
41
- 9: 'תשע עשרה'
42
- }
14
+ import { parseNumericValue } from '../utils/parse-numeric.js'
15
+ import { validateOptions } from '../utils/validate-options.js'
43
16
 
44
- twentiesWords = {
45
- 2: 'עשרים',
46
- 3: 'שלשים',
47
- 4: 'ארבעים',
48
- 5: 'חמישים',
49
- 6: 'ששים',
50
- 7: 'שבעים',
51
- 8: 'שמונים',
52
- 9: 'תשעים'
53
- }
17
+ // ============================================================================
18
+ // Vocabulary (arrays for indexed access - faster than object property lookup)
19
+ // ============================================================================
54
20
 
55
- hundredsWords = {
56
- 1: 'מאה',
57
- 2: 'מאתיים',
58
- 3: 'מאות'
59
- }
21
+ // Feminine forms (default in Modern Hebrew) - index 0 unused
22
+ const ONES = ['', 'אחת', 'שתים', 'שלש', 'ארבע', 'חמש', 'שש', 'שבע', 'שמונה', 'תשע']
23
+ const TEENS = ['עשר', 'אחת עשרה', 'שתים עשרה', 'שלש עשרה', 'ארבע עשרה', 'חמש עשרה', 'שש עשרה', 'שבע עשרה', 'שמונה עשרה', 'תשע עשרה']
24
+ const TENS = ['', '', 'עשרים', 'שלשים', 'ארבעים', 'חמישים', 'ששים', 'שבעים', 'שמונים', 'תשעים']
25
+ const HUNDREDS = ['', 'מאה', 'מאתיים', 'שלש מאות', 'ארבע מאות', 'חמש מאות', 'שש מאות', 'שבע מאות', 'שמונה מאות', 'תשע מאות']
60
26
 
61
- pluralForms = {
62
- 1: 'אלף',
63
- 2: 'אלפיים',
64
- 3: 'שלשת אלפים',
65
- 4: 'ארבעת אלפים',
66
- 5: 'חמשת אלפים',
67
- 6: 'ששת אלפים',
68
- 7: 'שבעת אלפים',
69
- 8: 'שמונת אלפים',
70
- 9: 'תשעת אלפים'
71
- }
27
+ // Special forms for 1-9 thousand (index 0 unused)
28
+ const THOUSANDS_SPECIAL = ['', 'אלף', 'אלפיים', 'שלשת אלפים', 'ארבעת אלפים', 'חמשת אלפים', 'ששת אלפים', 'שבעת אלפים', 'שמונת אלפים', 'תשעת אלפים']
29
+
30
+ // Scale words (index 1 = thousands, 2 = millions, etc.)
31
+ const SCALE = ['', 'אלף', 'מיליון', 'מיליארד', 'טריליון', 'קוודרליון', 'קווינטיליון']
32
+ const SCALE_PLURAL = ['', 'אלפים', 'מיליונים', 'מיליארדים', 'טריליונים', 'קוודרליונים', 'קווינטיליונים']
33
+
34
+ const ZERO = 'אפס'
35
+ const NEGATIVE = 'מינוס'
36
+ const DECIMAL_SEP = 'נקודה'
72
37
 
73
- scale = {
74
- 1: 'אלף', // thousand (singular)
75
- 2: 'מיליון', // million
76
- 3: 'מיליארד', // billion
77
- 4: 'טריליון', // trillion
78
- 5: 'קוודרליון', // quadrillion
79
- 6: 'קווינטיליון' // quintillion
38
+ // ============================================================================
39
+ // Segment Building
40
+ // ============================================================================
41
+
42
+ /**
43
+ * Builds segment word for scale segments (thousands, millions, etc.).
44
+ * "ו" is added before tens and ones when following hundreds.
45
+ */
46
+ function buildScaleSegment (n, andWord) {
47
+ if (n === 0) return ''
48
+
49
+ const ones = n % 10
50
+ const tens = Math.floor(n / 10) % 10
51
+ const hundreds = Math.floor(n / 100)
52
+
53
+ let result = ''
54
+
55
+ // Hundreds
56
+ if (hundreds > 0) {
57
+ result = HUNDREDS[hundreds]
80
58
  }
81
59
 
82
- scalePlural = {
83
- 1: 'אלפים', // thousands
84
- 2: 'מיליונים', // millions
85
- 3: 'מיליארדים', // billions
86
- 4: 'טריליונים', // trillions
87
- 5: 'קוודרליונים', // quadrillions
88
- 6: 'קווינטיליונים' // quintillions
60
+ // Tens and ones
61
+ if (tens === 1) {
62
+ // Teens (10-19)
63
+ const teenWord = TEENS[ones]
64
+ if (result) {
65
+ result += ' ' + andWord + teenWord
66
+ } else {
67
+ result = teenWord
68
+ }
69
+ } else {
70
+ // Tens (20-90)
71
+ if (tens >= 2) {
72
+ if (result) {
73
+ result += ' ' + andWord + TENS[tens]
74
+ } else {
75
+ result = TENS[tens]
76
+ }
77
+ }
78
+
79
+ // Ones
80
+ if (ones > 0) {
81
+ if (result) {
82
+ result += ' ' + andWord + ONES[ones]
83
+ } else {
84
+ result = ONES[ones]
85
+ }
86
+ }
89
87
  }
90
88
 
91
- constructor (options = {}) {
92
- super(options)
89
+ return result
90
+ }
91
+
92
+ /**
93
+ * Builds segment word for units segment (no scale word).
94
+ * "ו" is only added before the final ones digit.
95
+ */
96
+ function buildUnitsSegment (n, andWord) {
97
+ if (n === 0) return ''
98
+
99
+ const ones = n % 10
100
+ const tens = Math.floor(n / 10) % 10
101
+ const hundreds = Math.floor(n / 100)
102
+
103
+ let result = ''
93
104
 
94
- this.setOptions({
95
- andWord: 'ו'
96
- }, options)
105
+ // Hundreds
106
+ if (hundreds > 0) {
107
+ result = HUNDREDS[hundreds]
97
108
  }
98
109
 
99
- /** Converts integer part to Hebrew words with special handling for thousands. */
100
- integerToWords (integerPart) {
101
- if (integerPart === 0n) {
102
- return this.zeroWord
110
+ // Tens (no conjunction)
111
+ if (tens === 1) {
112
+ // Teens (10-19)
113
+ if (result) {
114
+ result += ' ' + TEENS[ones]
115
+ } else {
116
+ result = TEENS[ones]
103
117
  }
104
- const words = []
105
- const segments = this.splitToSegments(integerPart.toString(), 3)
106
- let index = segments.length
107
- for (const x of segments) {
108
- index = index - 1
109
- if (x === 0n) {
110
- continue
118
+ } else {
119
+ if (tens >= 2) {
120
+ if (result) {
121
+ result += ' ' + TENS[tens]
122
+ } else {
123
+ result = TENS[tens]
111
124
  }
125
+ }
112
126
 
113
- const [n1, n2, n3] = this.extractDigits(x)
114
-
115
- if (index > 0) {
116
- // For thousands and above, handle the full chunk value
117
- const chunkWords = []
118
- let hasHundreds = false
119
-
120
- // Process hundreds in this chunk
121
- if (n3 > 0n) {
122
- hasHundreds = true
123
- if (n3 <= 2n) {
124
- chunkWords.push(this.hundredsWords[n3])
125
- } else {
126
- chunkWords.push(this.onesWords[n3] + ' ' + this.hundredsWords[3])
127
- }
128
- }
127
+ // Ones - conjunction only here
128
+ if (ones > 0) {
129
+ if (result) {
130
+ result += ' ' + andWord + ONES[ones]
131
+ } else {
132
+ result = ONES[ones]
133
+ }
134
+ }
135
+ }
129
136
 
130
- // Process tens in this chunk
131
- if (n2 > 1n) {
132
- // Add conjunction if there were hundreds before
133
- const tensWord = this.twentiesWords[n2]
134
- chunkWords.push(hasHundreds ? this.options.andWord + tensWord : tensWord)
135
- }
137
+ return result
138
+ }
136
139
 
137
- // Process ones in this chunk
138
- if (n2 === 1n) {
139
- // Add conjunction if there were hundreds before
140
- const onesWord = this.teensWords[n1]
141
- chunkWords.push(hasHundreds ? this.options.andWord + onesWord : onesWord)
142
- } else if (n1 > 0n) {
143
- // For "one million", "one billion", etc., don't add the word "one"
144
- if (x === 1n && index > 1) {
145
- // Skip adding "one" for millions/billions/etc.
146
- } else if (x <= 9n && chunkWords.length === 0 && index === 1) {
147
- // Use special forms for 1-9 thousand
148
- chunkWords.push(this.pluralForms[n1])
149
- } else {
150
- const onesWord = this.onesWords[n1]
151
- // Add conjunction if there were hundreds or tens before
152
- chunkWords.push((hasHundreds || n2 > 0n) ? this.options.andWord + onesWord : onesWord)
153
- }
154
- }
140
+ // ============================================================================
141
+ // Conversion Functions
142
+ // ============================================================================
155
143
 
156
- // Add scale word (thousand, million, billion, etc.)
157
- if (x > 9n || index > 1) {
158
- // For numbers > 9 or higher scales, use appropriate scale word
159
- if (x === 1n) {
160
- // Singular form (e.g., "one thousand", "one million")
161
- chunkWords.push(this.scale[index])
162
- } else if (x === 2n && index === 1) {
163
- // Special dual form for "two thousand" (already in thousands[2])
164
- return [this.pluralForms[2], ...words].join(' ')
165
- } else if (x === 2n) {
166
- // For two million, two billion, etc. - use plural form
167
- chunkWords.push(this.scalePlural[index])
168
- } else if (index === 1) {
169
- // For thousands (10+), always use singular "אלף"
170
- chunkWords.push(this.scale[index])
171
- } else {
172
- // For millions/billions/etc. use plural form
173
- chunkWords.push(this.scalePlural[index])
174
- }
175
- }
144
+ /**
145
+ * Converts a non-negative integer to Hebrew words.
146
+ *
147
+ * @param {bigint} n - Non-negative integer to convert
148
+ * @param {Object} options - Conversion options
149
+ * @returns {string} Hebrew words
150
+ */
151
+ function integerToWords (n, options) {
152
+ if (n === 0n) return ZERO
176
153
 
177
- words.push(chunkWords.join(' '))
178
- continue
179
- }
154
+ const andWord = options.andWord ?? 'ו'
155
+
156
+ // Fast path: numbers < 1000
157
+ if (n < 1000n) {
158
+ return buildUnitsSegment(Number(n), andWord)
159
+ }
160
+
161
+ // Extract segments using BigInt modulo
162
+ const segments = []
163
+ let temp = n
164
+ while (temp > 0n) {
165
+ segments.push(Number(temp % 1000n))
166
+ temp = temp / 1000n
167
+ }
180
168
 
181
- if (n3 > 0n) {
182
- if (n3 <= 2n) {
183
- words.push(this.hundredsWords[n3])
169
+ // Build result string directly
170
+ let result = ''
171
+
172
+ for (let i = segments.length - 1; i >= 0; i--) {
173
+ const segment = segments[i]
174
+ if (segment === 0) continue
175
+
176
+ if (i === 0) {
177
+ // Units segment (no scale word)
178
+ const segmentWord = buildUnitsSegment(segment, andWord)
179
+ if (result) {
180
+ // Add "ו" before single-digit units when following scale words
181
+ if (segment <= 9) {
182
+ result += ' ' + andWord + segmentWord
184
183
  } else {
185
- words.push(this.onesWords[n3] + ' ' + this.hundredsWords[3])
184
+ result += ' ' + segmentWord
186
185
  }
186
+ } else {
187
+ result = segmentWord
187
188
  }
188
-
189
- if (n2 > 1n) {
190
- words.push(this.twentiesWords[n2])
189
+ } else if (i === 1) {
190
+ // Thousands - special handling for 1-9
191
+ if (segment <= 9) {
192
+ if (result) result += ' '
193
+ result += THOUSANDS_SPECIAL[segment]
194
+ } else {
195
+ const segmentWord = buildScaleSegment(segment, andWord)
196
+ if (result) result += ' '
197
+ result += segmentWord + ' ' + SCALE[1]
191
198
  }
192
-
193
- if (n2 === 1n) {
194
- words.push(this.teensWords[n1])
195
- } else if (n1 > 0n) {
196
- words.push(this.onesWords[n1])
199
+ } else {
200
+ // Millions and above
201
+ if (segment === 1) {
202
+ if (result) result += ' '
203
+ result += SCALE[i]
204
+ } else {
205
+ const segmentWord = buildScaleSegment(segment, andWord)
206
+ if (result) result += ' '
207
+ result += segmentWord + ' ' + SCALE_PLURAL[i]
197
208
  }
198
209
  }
210
+ }
199
211
 
200
- if (words.length > 1) {
201
- words[words.length - 1] = this.options.andWord + words.at(-1)
202
- }
212
+ return result
213
+ }
203
214
 
204
- return words.join(' ')
215
+ /**
216
+ * Converts decimal digits to Hebrew words (digit by digit).
217
+ *
218
+ * @param {string} decimalPart - Decimal digits (without the point)
219
+ * @returns {string} Hebrew words for decimal part
220
+ */
221
+ function decimalPartToWords (decimalPart) {
222
+ let result = ''
223
+
224
+ for (let i = 0; i < decimalPart.length; i++) {
225
+ const d = parseInt(decimalPart[i], 10)
226
+ if (result) result += ' '
227
+ result += d === 0 ? ZERO : ONES[d]
205
228
  }
229
+
230
+ return result
206
231
  }
232
+
233
+ /**
234
+ * Converts a numeric value to Modern Hebrew words.
235
+ *
236
+ * @param {number | string | bigint} value - The numeric value to convert
237
+ * @param {Object} [options] - Optional configuration
238
+ * @param {('masculine'|'feminine')} [options.gender='masculine'] - Grammatical gender
239
+ * @param {string} [options.andWord] - Custom conjunction word
240
+ * @returns {string} The number in Modern Hebrew words
241
+ */
242
+ function toWords (value, options) {
243
+ options = validateOptions(options)
244
+ const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
245
+
246
+ let result = ''
247
+
248
+ if (isNegative) {
249
+ result = NEGATIVE + ' '
250
+ }
251
+
252
+ result += integerToWords(integerPart, options)
253
+
254
+ if (decimalPart) {
255
+ result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart)
256
+ }
257
+
258
+ return result
259
+ }
260
+
261
+ // ============================================================================
262
+ // Exports
263
+ // ============================================================================
264
+
265
+ export { toWords }
@@ -1,11 +1,7 @@
1
1
  /**
2
- * Hindi language converter.
2
+ * Converts a numeric value to Hindi words.
3
3
  *
4
- * Supports:
5
- * - Indian numbering system (हज़ार, लाख, करोड़)
6
- * - Devanagari script
7
- * - Complete word forms for 0-99
4
+ * @param {number | string | bigint} value - The numeric value to convert
5
+ * @returns {string} The number in Hindi words
8
6
  */
9
- export class Hindi extends SouthAsianLanguage {
10
- }
11
- import { SouthAsianLanguage } from '../classes/south-asian-language.js';
7
+ export function toWords(value: number | string | bigint): string;