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,206 +1,276 @@
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 converter with segment-based decomposition.
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
12
+ *
13
+ * Optimization: Precomputed segment lookup tables for 0-999.
11
14
  */
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
15
 
31
- teensWords = {
32
- 0: 'עשר',
33
- 1: 'אחת עשרה',
34
- 2: 'שתים עשרה',
35
- 3: 'שלש עשרה',
36
- 4: 'ארבע עשרה',
37
- 5: 'חמש עשרה',
38
- 6: 'שש עשרה',
39
- 7: 'שבע עשרה',
40
- 8: 'שמונה עשרה',
41
- 9: 'תשע עשרה'
42
- }
16
+ import { parseNumericValue } from '../utils/parse-numeric.js'
17
+ import { validateOptions } from '../utils/validate-options.js'
43
18
 
44
- twentiesWords = {
45
- 2: 'עשרים',
46
- 3: 'שלשים',
47
- 4: 'ארבעים',
48
- 5: 'חמישים',
49
- 6: 'ששים',
50
- 7: 'שבעים',
51
- 8: 'שמונים',
52
- 9: 'תשעים'
53
- }
19
+ // ============================================================================
20
+ // Vocabulary (arrays for indexed access - faster than object property lookup)
21
+ // ============================================================================
54
22
 
55
- hundredsWords = {
56
- 1: 'מאה',
57
- 2: 'מאתיים',
58
- 3: 'מאות'
59
- }
23
+ // Feminine forms (default in Modern Hebrew) - index 0 unused
24
+ const ONES = ['', 'אחת', 'שתים', 'שלש', 'ארבע', 'חמש', 'שש', 'שבע', 'שמונה', 'תשע']
25
+ const TEENS = ['עשר', 'אחת עשרה', 'שתים עשרה', 'שלש עשרה', 'ארבע עשרה', 'חמש עשרה', 'שש עשרה', 'שבע עשרה', 'שמונה עשרה', 'תשע עשרה']
26
+ const TENS = ['', '', 'עשרים', 'שלשים', 'ארבעים', 'חמישים', 'ששים', 'שבעים', 'שמונים', 'תשעים']
27
+ const HUNDREDS = ['', 'מאה', 'מאתיים', 'שלש מאות', 'ארבע מאות', 'חמש מאות', 'שש מאות', 'שבע מאות', 'שמונה מאות', 'תשע מאות']
60
28
 
61
- pluralForms = {
62
- 1: 'אלף',
63
- 2: 'אלפיים',
64
- 3: 'שלשת אלפים',
65
- 4: 'ארבעת אלפים',
66
- 5: 'חמשת אלפים',
67
- 6: 'ששת אלפים',
68
- 7: 'שבעת אלפים',
69
- 8: 'שמונת אלפים',
70
- 9: 'תשעת אלפים'
71
- }
29
+ // Special forms for 1-9 thousand (index 0 unused)
30
+ const THOUSANDS_SPECIAL = ['', 'אלף', 'אלפיים', 'שלשת אלפים', 'ארבעת אלפים', 'חמשת אלפים', 'ששת אלפים', 'שבעת אלפים', 'שמונת אלפים', 'תשעת אלפים']
31
+
32
+ // Scale words (index 1 = thousands, 2 = millions, etc.)
33
+ const SCALE = ['', 'אלף', 'מיליון', 'מיליארד', 'טריליון', 'קוודרליון', 'קווינטיליון']
34
+ const SCALE_PLURAL = ['', 'אלפים', 'מיליונים', 'מיליארדים', 'טריליונים', 'קוודרליונים', 'קווינטיליונים']
35
+
36
+ const ZERO = 'אפס'
37
+ const NEGATIVE = 'מינוס'
38
+ const DECIMAL_SEP = 'נקודה'
72
39
 
73
- scale = {
74
- 1: 'אלף', // thousand (singular)
75
- 2: 'מיליון', // million
76
- 3: 'מיליארד', // billion
77
- 4: 'טריליון', // trillion
78
- 5: 'קוודרליון', // quadrillion
79
- 6: 'קווינטיליון' // quintillion
40
+ // ============================================================================
41
+ // Precomputed Lookup Tables (built once at module load)
42
+ // ============================================================================
43
+
44
+ /**
45
+ * Builds segment word for scale segments (thousands, millions, etc.).
46
+ * "ו" is added before tens and ones when following hundreds.
47
+ */
48
+ function buildScaleSegment (n, andWord) {
49
+ if (n === 0) return ''
50
+
51
+ const ones = n % 10
52
+ const tens = Math.floor(n / 10) % 10
53
+ const hundreds = Math.floor(n / 100)
54
+
55
+ let result = ''
56
+
57
+ // Hundreds
58
+ if (hundreds > 0) {
59
+ result = HUNDREDS[hundreds]
80
60
  }
81
61
 
82
- scalePlural = {
83
- 1: 'אלפים', // thousands
84
- 2: 'מיליונים', // millions
85
- 3: 'מיליארדים', // billions
86
- 4: 'טריליונים', // trillions
87
- 5: 'קוודרליונים', // quadrillions
88
- 6: 'קווינטיליונים' // quintillions
62
+ // Tens and ones
63
+ if (tens === 1) {
64
+ // Teens (10-19)
65
+ const teenWord = TEENS[ones]
66
+ if (result) {
67
+ result += ' ' + andWord + teenWord
68
+ } else {
69
+ result = teenWord
70
+ }
71
+ } else {
72
+ // Tens (20-90)
73
+ if (tens >= 2) {
74
+ if (result) {
75
+ result += ' ' + andWord + TENS[tens]
76
+ } else {
77
+ result = TENS[tens]
78
+ }
79
+ }
80
+
81
+ // Ones
82
+ if (ones > 0) {
83
+ if (result) {
84
+ result += ' ' + andWord + ONES[ones]
85
+ } else {
86
+ result = ONES[ones]
87
+ }
88
+ }
89
89
  }
90
90
 
91
- constructor (options = {}) {
92
- super(options)
91
+ return result
92
+ }
93
+
94
+ /**
95
+ * Builds segment word for units segment (no scale word).
96
+ * "ו" is only added before the final ones digit.
97
+ */
98
+ function buildUnitsSegment (n, andWord) {
99
+ if (n === 0) return ''
100
+
101
+ const ones = n % 10
102
+ const tens = Math.floor(n / 10) % 10
103
+ const hundreds = Math.floor(n / 100)
104
+
105
+ let result = ''
93
106
 
94
- this.setOptions({
95
- andWord: 'ו'
96
- }, options)
107
+ // Hundreds
108
+ if (hundreds > 0) {
109
+ result = HUNDREDS[hundreds]
97
110
  }
98
111
 
99
- /** Converts integer part to Hebrew words with special handling for thousands. */
100
- integerToWords (integerPart) {
101
- if (integerPart === 0n) {
102
- return this.zeroWord
112
+ // Tens (no conjunction)
113
+ if (tens === 1) {
114
+ // Teens (10-19)
115
+ if (result) {
116
+ result += ' ' + TEENS[ones]
117
+ } else {
118
+ result = TEENS[ones]
103
119
  }
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
120
+ } else {
121
+ if (tens >= 2) {
122
+ if (result) {
123
+ result += ' ' + TENS[tens]
124
+ } else {
125
+ result = TENS[tens]
111
126
  }
127
+ }
112
128
 
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
- }
129
+ // Ones - conjunction only here
130
+ if (ones > 0) {
131
+ if (result) {
132
+ result += ' ' + andWord + ONES[ones]
133
+ } else {
134
+ result = ONES[ones]
135
+ }
136
+ }
137
+ }
129
138
 
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
- }
139
+ return result
140
+ }
136
141
 
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
- }
142
+ // Precompute all 1000 segment words with default conjunction
143
+ const SCALE_SEGMENTS = new Array(1000)
144
+ const UNITS_SEGMENTS = new Array(1000)
145
+ for (let i = 0; i < 1000; i++) {
146
+ SCALE_SEGMENTS[i] = buildScaleSegment(i, 'ו')
147
+ UNITS_SEGMENTS[i] = buildUnitsSegment(i, 'ו')
148
+ }
155
149
 
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
- }
150
+ // ============================================================================
151
+ // Conversion Functions
152
+ // ============================================================================
176
153
 
177
- words.push(chunkWords.join(' '))
178
- continue
179
- }
154
+ /**
155
+ * Converts a non-negative integer to Hebrew words.
156
+ *
157
+ * @param {bigint} n - Non-negative integer to convert
158
+ * @param {Object} options - Conversion options
159
+ * @returns {string} Hebrew words
160
+ */
161
+ function integerToWords (n, options) {
162
+ if (n === 0n) return ZERO
163
+
164
+ const andWord = options.andWord ?? 'ו'
165
+ const usePrecomputed = andWord === 'ו'
166
+
167
+ // Fast path: numbers < 1000 (direct lookup)
168
+ if (n < 1000n) {
169
+ return usePrecomputed ? UNITS_SEGMENTS[Number(n)] : buildUnitsSegment(Number(n), andWord)
170
+ }
171
+
172
+ // Extract segments using BigInt modulo
173
+ const segments = []
174
+ let temp = n
175
+ while (temp > 0n) {
176
+ segments.push(Number(temp % 1000n))
177
+ temp = temp / 1000n
178
+ }
179
+
180
+ // Build result string directly
181
+ let result = ''
182
+
183
+ for (let i = segments.length - 1; i >= 0; i--) {
184
+ const segment = segments[i]
185
+ if (segment === 0) continue
180
186
 
181
- if (n3 > 0n) {
182
- if (n3 <= 2n) {
183
- words.push(this.hundredsWords[n3])
187
+ if (i === 0) {
188
+ // Units segment (no scale word)
189
+ const segmentWord = usePrecomputed ? UNITS_SEGMENTS[segment] : buildUnitsSegment(segment, andWord)
190
+ if (result) {
191
+ // Add "ו" before single-digit units when following scale words
192
+ if (segment <= 9) {
193
+ result += ' ' + andWord + segmentWord
184
194
  } else {
185
- words.push(this.onesWords[n3] + ' ' + this.hundredsWords[3])
195
+ result += ' ' + segmentWord
186
196
  }
197
+ } else {
198
+ result = segmentWord
187
199
  }
188
-
189
- if (n2 > 1n) {
190
- words.push(this.twentiesWords[n2])
200
+ } else if (i === 1) {
201
+ // Thousands - special handling for 1-9
202
+ if (segment <= 9) {
203
+ if (result) result += ' '
204
+ result += THOUSANDS_SPECIAL[segment]
205
+ } else {
206
+ const segmentWord = usePrecomputed ? SCALE_SEGMENTS[segment] : buildScaleSegment(segment, andWord)
207
+ if (result) result += ' '
208
+ result += segmentWord + ' ' + SCALE[1]
191
209
  }
192
-
193
- if (n2 === 1n) {
194
- words.push(this.teensWords[n1])
195
- } else if (n1 > 0n) {
196
- words.push(this.onesWords[n1])
210
+ } else {
211
+ // Millions and above
212
+ if (segment === 1) {
213
+ if (result) result += ' '
214
+ result += SCALE[i]
215
+ } else {
216
+ const segmentWord = usePrecomputed ? SCALE_SEGMENTS[segment] : buildScaleSegment(segment, andWord)
217
+ if (result) result += ' '
218
+ result += segmentWord + ' ' + SCALE_PLURAL[i]
197
219
  }
198
220
  }
221
+ }
199
222
 
200
- if (words.length > 1) {
201
- words[words.length - 1] = this.options.andWord + words.at(-1)
202
- }
223
+ return result
224
+ }
225
+
226
+ /**
227
+ * Converts decimal digits to Hebrew words (digit by digit).
228
+ *
229
+ * @param {string} decimalPart - Decimal digits (without the point)
230
+ * @returns {string} Hebrew words for decimal part
231
+ */
232
+ function decimalPartToWords (decimalPart) {
233
+ let result = ''
234
+
235
+ for (let i = 0; i < decimalPart.length; i++) {
236
+ const d = parseInt(decimalPart[i], 10)
237
+ if (result) result += ' '
238
+ result += d === 0 ? ZERO : ONES[d]
239
+ }
240
+
241
+ return result
242
+ }
243
+
244
+ /**
245
+ * Converts a numeric value to Modern Hebrew words.
246
+ *
247
+ * @param {number | string | bigint} value - The numeric value to convert
248
+ * @param {Object} [options] - Optional configuration
249
+ * @param {('masculine'|'feminine')} [options.gender='masculine'] - Grammatical gender
250
+ * @param {string} [options.andWord] - Custom conjunction word
251
+ * @returns {string} The number in Modern Hebrew words
252
+ */
253
+ function toWords (value, options) {
254
+ options = validateOptions(options)
255
+ const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
256
+
257
+ let result = ''
203
258
 
204
- return words.join(' ')
259
+ if (isNegative) {
260
+ result = NEGATIVE + ' '
205
261
  }
262
+
263
+ result += integerToWords(integerPart, options)
264
+
265
+ if (decimalPart) {
266
+ result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart)
267
+ }
268
+
269
+ return result
206
270
  }
271
+
272
+ // ============================================================================
273
+ // Exports
274
+ // ============================================================================
275
+
276
+ 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;