n2words 1.24.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (280) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +183 -156
  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 -2
  8. package/dist/languages/ar.js.map +1 -1
  9. package/dist/languages/az.js +3 -2
  10. package/dist/languages/az.js.map +1 -1
  11. package/dist/languages/bn.js +3 -2
  12. package/dist/languages/bn.js.map +1 -1
  13. package/dist/languages/cs.js +3 -2
  14. package/dist/languages/cs.js.map +1 -1
  15. package/dist/languages/da.js +3 -2
  16. package/dist/languages/da.js.map +1 -1
  17. package/dist/languages/de.js +3 -2
  18. package/dist/languages/de.js.map +1 -1
  19. package/dist/languages/el.js +3 -2
  20. package/dist/languages/el.js.map +1 -1
  21. package/dist/languages/en.js +3 -2
  22. package/dist/languages/en.js.map +1 -1
  23. package/dist/languages/es.js +3 -2
  24. package/dist/languages/es.js.map +1 -1
  25. package/dist/languages/fa.js +3 -2
  26. package/dist/languages/fa.js.map +1 -1
  27. package/dist/languages/fi.js +3 -0
  28. package/dist/languages/fi.js.map +1 -0
  29. package/dist/languages/fil.js +3 -2
  30. package/dist/languages/fil.js.map +1 -1
  31. package/dist/languages/fr-BE.js +3 -2
  32. package/dist/languages/fr-BE.js.map +1 -1
  33. package/dist/languages/fr.js +3 -2
  34. package/dist/languages/fr.js.map +1 -1
  35. package/dist/languages/gu.js +3 -2
  36. package/dist/languages/gu.js.map +1 -1
  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 -2
  42. package/dist/languages/he.js.map +1 -1
  43. package/dist/languages/hi.js +3 -2
  44. package/dist/languages/hi.js.map +1 -1
  45. package/dist/languages/hr.js +3 -2
  46. package/dist/languages/hr.js.map +1 -1
  47. package/dist/languages/hu.js +3 -2
  48. package/dist/languages/hu.js.map +1 -1
  49. package/dist/languages/id.js +3 -2
  50. package/dist/languages/id.js.map +1 -1
  51. package/dist/languages/it.js +3 -2
  52. package/dist/languages/it.js.map +1 -1
  53. package/dist/languages/ja.js +3 -2
  54. package/dist/languages/ja.js.map +1 -1
  55. package/dist/languages/kn.js +3 -2
  56. package/dist/languages/kn.js.map +1 -1
  57. package/dist/languages/ko.js +3 -2
  58. package/dist/languages/ko.js.map +1 -1
  59. package/dist/languages/lt.js +3 -2
  60. package/dist/languages/lt.js.map +1 -1
  61. package/dist/languages/lv.js +3 -2
  62. package/dist/languages/lv.js.map +1 -1
  63. package/dist/languages/mr.js +3 -2
  64. package/dist/languages/mr.js.map +1 -1
  65. package/dist/languages/ms.js +3 -2
  66. package/dist/languages/ms.js.map +1 -1
  67. package/dist/languages/nb.js +3 -2
  68. package/dist/languages/nb.js.map +1 -1
  69. package/dist/languages/nl.js +3 -2
  70. package/dist/languages/nl.js.map +1 -1
  71. package/dist/languages/pa.js +3 -0
  72. package/dist/languages/pa.js.map +1 -0
  73. package/dist/languages/pl.js +3 -2
  74. package/dist/languages/pl.js.map +1 -1
  75. package/dist/languages/pt.js +3 -2
  76. package/dist/languages/pt.js.map +1 -1
  77. package/dist/languages/ro.js +3 -2
  78. package/dist/languages/ro.js.map +1 -1
  79. package/dist/languages/ru.js +3 -2
  80. package/dist/languages/ru.js.map +1 -1
  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 -2
  84. package/dist/languages/sr-Latn.js.map +1 -1
  85. package/dist/languages/sv.js +3 -2
  86. package/dist/languages/sv.js.map +1 -1
  87. package/dist/languages/sw.js +3 -2
  88. package/dist/languages/sw.js.map +1 -1
  89. package/dist/languages/ta.js +3 -2
  90. package/dist/languages/ta.js.map +1 -1
  91. package/dist/languages/te.js +3 -2
  92. package/dist/languages/te.js.map +1 -1
  93. package/dist/languages/th.js +3 -2
  94. package/dist/languages/th.js.map +1 -1
  95. package/dist/languages/tr.js +3 -2
  96. package/dist/languages/tr.js.map +1 -1
  97. package/dist/languages/uk.js +3 -2
  98. package/dist/languages/uk.js.map +1 -1
  99. package/dist/languages/ur.js +3 -2
  100. package/dist/languages/ur.js.map +1 -1
  101. package/dist/languages/vi.js +3 -2
  102. package/dist/languages/vi.js.map +1 -1
  103. package/dist/languages/zh-Hans.js +3 -2
  104. package/dist/languages/zh-Hans.js.map +1 -1
  105. package/dist/languages/zh-Hant.js +3 -0
  106. package/dist/languages/zh-Hant.js.map +1 -0
  107. package/dist/n2words.js +3 -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 +17 -0
  114. package/lib/languages/ar.js +171 -209
  115. package/lib/languages/az.d.ts +7 -0
  116. package/lib/languages/az.js +167 -49
  117. package/lib/languages/bn.d.ts +7 -0
  118. package/lib/languages/bn.js +142 -123
  119. package/lib/languages/cs.d.ts +18 -0
  120. package/lib/languages/cs.js +303 -176
  121. package/lib/languages/da.d.ts +14 -0
  122. package/lib/languages/da.js +267 -139
  123. package/lib/languages/de.d.ts +17 -0
  124. package/lib/languages/de.js +310 -113
  125. package/lib/languages/el.d.ts +14 -0
  126. package/lib/languages/el.js +225 -98
  127. package/lib/languages/en.d.ts +17 -0
  128. package/lib/languages/en.js +235 -102
  129. package/lib/languages/es.d.ts +21 -0
  130. package/lib/languages/es.js +307 -125
  131. package/lib/languages/fa.d.ts +7 -0
  132. package/lib/languages/fa.js +115 -108
  133. package/lib/languages/fi.d.ts +14 -0
  134. package/lib/languages/fi.js +245 -0
  135. package/lib/languages/fil.d.ts +7 -0
  136. package/lib/languages/fil.js +199 -139
  137. package/lib/languages/fr-BE.d.ts +11 -0
  138. package/lib/languages/fr-BE.js +287 -48
  139. package/lib/languages/fr.d.ts +21 -0
  140. package/lib/languages/fr.js +343 -119
  141. package/lib/languages/gu.d.ts +7 -0
  142. package/lib/languages/gu.js +125 -144
  143. package/lib/languages/ha.d.ts +7 -0
  144. package/lib/languages/ha.js +230 -0
  145. package/lib/languages/hbo.d.ts +13 -0
  146. package/lib/languages/hbo.js +300 -0
  147. package/lib/languages/he.d.ts +13 -0
  148. package/lib/languages/he.js +230 -283
  149. package/lib/languages/hi.d.ts +7 -0
  150. package/lib/languages/hi.js +142 -123
  151. package/lib/languages/hr.d.ts +11 -0
  152. package/lib/languages/hr.js +190 -129
  153. package/lib/languages/hu.d.ts +7 -0
  154. package/lib/languages/hu.js +194 -133
  155. package/lib/languages/id.d.ts +7 -0
  156. package/lib/languages/id.js +167 -140
  157. package/lib/languages/it.d.ts +19 -0
  158. package/lib/languages/it.js +337 -108
  159. package/lib/languages/ja.d.ts +17 -0
  160. package/lib/languages/ja.js +224 -155
  161. package/lib/languages/kn.d.ts +7 -0
  162. package/lib/languages/kn.js +128 -62
  163. package/lib/languages/ko.d.ts +14 -0
  164. package/lib/languages/ko.js +250 -70
  165. package/lib/languages/lt.d.ts +18 -0
  166. package/lib/languages/lt.js +287 -148
  167. package/lib/languages/lv.d.ts +18 -0
  168. package/lib/languages/lv.js +291 -123
  169. package/lib/languages/mr.d.ts +7 -0
  170. package/lib/languages/mr.js +125 -144
  171. package/lib/languages/ms.d.ts +7 -0
  172. package/lib/languages/ms.js +171 -112
  173. package/lib/languages/nb.d.ts +14 -0
  174. package/lib/languages/nb.js +275 -100
  175. package/lib/languages/nl.d.ts +26 -0
  176. package/lib/languages/nl.js +307 -174
  177. package/lib/languages/pa.d.ts +7 -0
  178. package/lib/languages/pa.js +163 -0
  179. package/lib/languages/pl.d.ts +22 -0
  180. package/lib/languages/pl.js +299 -158
  181. package/lib/languages/pt.d.ts +17 -0
  182. package/lib/languages/pt.js +279 -120
  183. package/lib/languages/ro.d.ts +18 -0
  184. package/lib/languages/ro.js +214 -337
  185. package/lib/languages/ru.d.ts +11 -0
  186. package/lib/languages/ru.js +219 -95
  187. package/lib/languages/sr-Cyrl.d.ts +11 -0
  188. package/lib/languages/sr-Cyrl.js +215 -0
  189. package/lib/languages/sr-Latn.d.ts +11 -0
  190. package/lib/languages/sr-Latn.js +190 -132
  191. package/lib/languages/sv.d.ts +14 -0
  192. package/lib/languages/sv.js +280 -103
  193. package/lib/languages/sw.d.ts +7 -0
  194. package/lib/languages/sw.js +135 -103
  195. package/lib/languages/ta.d.ts +7 -0
  196. package/lib/languages/ta.js +133 -205
  197. package/lib/languages/te.d.ts +7 -0
  198. package/lib/languages/te.js +148 -213
  199. package/lib/languages/th.d.ts +7 -0
  200. package/lib/languages/th.js +139 -101
  201. package/lib/languages/tr.d.ts +18 -0
  202. package/lib/languages/tr.js +246 -66
  203. package/lib/languages/uk.d.ts +11 -0
  204. package/lib/languages/uk.js +197 -101
  205. package/lib/languages/ur.d.ts +7 -0
  206. package/lib/languages/ur.js +160 -123
  207. package/lib/languages/vi.d.ts +17 -0
  208. package/lib/languages/vi.js +287 -164
  209. package/lib/languages/zh-Hans.d.ts +11 -0
  210. package/lib/languages/zh-Hans.js +159 -142
  211. package/lib/languages/zh-Hant.d.ts +11 -0
  212. package/lib/languages/zh-Hant.js +202 -0
  213. package/lib/n2words.d.ts +53 -0
  214. package/lib/n2words.js +91 -227
  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 +118 -67
  222. package/dist/languages/pa-Guru.js +0 -2
  223. package/dist/languages/pa-Guru.js.map +0 -1
  224. package/lib/classes/abstract-language.js +0 -261
  225. package/lib/classes/greedy-scale-language.js +0 -195
  226. package/lib/classes/slavic-language.js +0 -251
  227. package/lib/classes/south-asian-language.js +0 -161
  228. package/lib/classes/turkic-language.js +0 -63
  229. package/lib/languages/pa-Guru.js +0 -126
  230. package/typings/classes/abstract-language.d.ts +0 -144
  231. package/typings/classes/greedy-scale-language.d.ts +0 -148
  232. package/typings/classes/slavic-language.d.ts +0 -145
  233. package/typings/classes/south-asian-language.d.ts +0 -101
  234. package/typings/classes/turkic-language.d.ts +0 -42
  235. package/typings/languages/ar.d.ts +0 -93
  236. package/typings/languages/az.d.ts +0 -25
  237. package/typings/languages/bn.d.ts +0 -1
  238. package/typings/languages/cs.d.ts +0 -120
  239. package/typings/languages/da.d.ts +0 -53
  240. package/typings/languages/de.d.ts +0 -26
  241. package/typings/languages/el.d.ts +0 -11
  242. package/typings/languages/en.d.ts +0 -30
  243. package/typings/languages/es.d.ts +0 -43
  244. package/typings/languages/fa.d.ts +0 -81
  245. package/typings/languages/fil.d.ts +0 -12
  246. package/typings/languages/fr-BE.d.ts +0 -41
  247. package/typings/languages/fr.d.ts +0 -43
  248. package/typings/languages/gu.d.ts +0 -12
  249. package/typings/languages/he.d.ts +0 -197
  250. package/typings/languages/hi.d.ts +0 -1
  251. package/typings/languages/hr.d.ts +0 -110
  252. package/typings/languages/hu.d.ts +0 -37
  253. package/typings/languages/id.d.ts +0 -69
  254. package/typings/languages/it.d.ts +0 -51
  255. package/typings/languages/ja.d.ts +0 -58
  256. package/typings/languages/kn.d.ts +0 -11
  257. package/typings/languages/ko.d.ts +0 -25
  258. package/typings/languages/lt.d.ts +0 -110
  259. package/typings/languages/lv.d.ts +0 -99
  260. package/typings/languages/mr.d.ts +0 -12
  261. package/typings/languages/ms.d.ts +0 -37
  262. package/typings/languages/nb.d.ts +0 -27
  263. package/typings/languages/nl.d.ts +0 -65
  264. package/typings/languages/pa-Guru.d.ts +0 -1
  265. package/typings/languages/pl.d.ts +0 -116
  266. package/typings/languages/pt.d.ts +0 -39
  267. package/typings/languages/ro.d.ts +0 -229
  268. package/typings/languages/ru.d.ts +0 -108
  269. package/typings/languages/sr-Latn.d.ts +0 -98
  270. package/typings/languages/sv.d.ts +0 -30
  271. package/typings/languages/sw.d.ts +0 -1
  272. package/typings/languages/ta.d.ts +0 -1
  273. package/typings/languages/te.d.ts +0 -1
  274. package/typings/languages/th.d.ts +0 -1
  275. package/typings/languages/tr.d.ts +0 -46
  276. package/typings/languages/uk.d.ts +0 -117
  277. package/typings/languages/ur.d.ts +0 -1
  278. package/typings/languages/vi.d.ts +0 -116
  279. package/typings/languages/zh-Hans.d.ts +0 -57
  280. package/typings/n2words.d.ts +0 -177
@@ -1,329 +1,276 @@
1
- import SlavicLanguage from '../classes/slavic-language.js'
2
-
3
1
  /**
4
- * @typedef {Object} HebrewOptions
5
- * @property {string} [and='ו'] Conjunction character (typically 'ו' for and).
6
- * @property {boolean} [biblical=false] Use biblical scale words instead of modern ones.
7
- * @property {boolean} [feminine=false] Use feminine forms for numbers.
8
- */
9
-
10
- /**
11
- * Hebrew language converter.
12
- *
13
- * Implements Hebrew number words using the Slavic language pattern:
14
- * - Hebrew alphabet and right-to-left text
15
- * - Hebrew number words (אחת, שתים, שלוש, ארבע...)
16
- * - Feminine number forms (default in Hebrew)
17
- * - Optional "ve" (ו, "and") conjunction between number groups
2
+ * Modern Hebrew language converter - Functional Implementation
18
3
  *
19
- * Key Features:
20
- * - Three-form pluralization system shared across Slavic languages
21
- * * Form 1 (singular): 1 (e.g., "אלף")
22
- * * Form 2 (few): 2-4, 22-24, 32-34... excluding teens (e.g., "אלפים")
23
- * * Form 3 (many): all other numbers (e.g., "אלף")
24
- * - Chunk-based decomposition (splits into groups of 3 digits: ones, thousands, millions, etc.)
25
- * - Large number handling via thousands[] array with indexed [singular, few, many] forms
4
+ * Self-contained converter with segment-based decomposition.
26
5
  *
27
- * Features:
28
- * - Right-to-left text orientation
29
- * - Feminine grammatical gender for numbers
30
- * - Three-form pluralization (similar to Slavic pattern)
31
- * - Conjunction control via "and" option
6
+ * Key features:
7
+ * - Feminine grammatical forms (default in Modern Hebrew)
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
32
12
  *
33
- * Inherits from SlavicLanguage for complex pluralization algorithms.
13
+ * Optimization: Precomputed segment lookup tables for 0-999.
34
14
  */
35
- export class Hebrew extends SlavicLanguage {
36
- negativeWord = 'מינוס'
37
- decimalSeparatorWord = 'נקודה'
38
- zeroWord = 'אפס'
39
- convertDecimalsPerDigit = true
40
-
41
- // Modern Hebrew (feminine forms)
42
- ones = {
43
- 1: 'אחת',
44
- 2: 'שתים',
45
- 3: 'שלש',
46
- 4: 'ארבע',
47
- 5: 'חמש',
48
- 6: 'שש',
49
- 7: 'שבע',
50
- 8: 'שמונה',
51
- 9: 'תשע'
52
- }
53
15
 
54
- tens = {
55
- 0: 'עשר',
56
- 1: 'אחת עשרה',
57
- 2: 'שתים עשרה',
58
- 3: 'שלש עשרה',
59
- 4: 'ארבע עשרה',
60
- 5: 'חמש עשרה',
61
- 6: 'שש עשרה',
62
- 7: 'שבע עשרה',
63
- 8: 'שמונה עשרה',
64
- 9: 'תשע עשרה'
65
- }
16
+ import { parseNumericValue } from '../utils/parse-numeric.js'
17
+ import { validateOptions } from '../utils/validate-options.js'
66
18
 
67
- twenties = {
68
- 2: 'עשרים',
69
- 3: 'שלשים',
70
- 4: 'ארבעים',
71
- 5: 'חמישים',
72
- 6: 'ששים',
73
- 7: 'שבעים',
74
- 8: 'שמונים',
75
- 9: 'תשעים'
76
- }
19
+ // ============================================================================
20
+ // Vocabulary (arrays for indexed access - faster than object property lookup)
21
+ // ============================================================================
77
22
 
78
- hundreds = {
79
- 1: 'מאה',
80
- 2: 'מאתיים',
81
- 3: 'מאות'
82
- }
23
+ // Feminine forms (default in Modern Hebrew) - index 0 unused
24
+ const ONES = ['', 'אחת', 'שתים', 'שלש', 'ארבע', 'חמש', 'שש', 'שבע', 'שמונה', 'תשע']
25
+ const TEENS = ['עשר', 'אחת עשרה', 'שתים עשרה', 'שלש עשרה', 'ארבע עשרה', 'חמש עשרה', 'שש עשרה', 'שבע עשרה', 'שמונה עשרה', 'תשע עשרה']
26
+ const TENS = ['', '', 'עשרים', 'שלשים', 'ארבעים', 'חמישים', 'ששים', 'שבעים', 'שמונים', 'תשעים']
27
+ const HUNDREDS = ['', 'מאה', 'מאתיים', 'שלש מאות', 'ארבע מאות', 'חמש מאות', 'שש מאות', 'שבע מאות', 'שמונה מאות', 'תשע מאות']
83
28
 
84
- thousands = {
85
- 1: 'אלף',
86
- 2: 'אלפיים',
87
- 3: 'שלשת אלפים',
88
- 4: 'ארבעת אלפים',
89
- 5: 'חמשת אלפים',
90
- 6: 'ששת אלפים',
91
- 7: 'שבעת אלפים',
92
- 8: 'שמונת אלפים',
93
- 9: 'תשעת אלפים'
94
- }
29
+ // Special forms for 1-9 thousand (index 0 unused)
30
+ const THOUSANDS_SPECIAL = ['', 'אלף', 'אלפיים', 'שלשת אלפים', 'ארבעת אלפים', 'חמשת אלפים', 'ששת אלפים', 'שבעת אלפים', 'שמונת אלפים', 'תשעת אלפים']
95
31
 
96
- scale = {
97
- 1: 'אלף', // thousand (singular)
98
- 2: 'מיליון', // million
99
- 3: 'מיליארד', // billion
100
- 4: 'טריליון', // trillion
101
- 5: 'קוודרליון', // quadrillion
102
- 6: 'קווינטיליון' // quintillion
103
- }
32
+ // Scale words (index 1 = thousands, 2 = millions, etc.)
33
+ const SCALE = ['', 'אלף', 'מיליון', 'מיליארד', 'טריליון', 'קוודרליון', 'קווינטיליון']
34
+ const SCALE_PLURAL = ['', 'אלפים', 'מיליונים', 'מיליארדים', 'טריליונים', 'קוודרליונים', 'קווינטיליונים']
104
35
 
105
- scalePlural = {
106
- 1: 'אלפים', // thousands
107
- 2: 'מיליונים', // millions
108
- 3: 'מיליארדים', // billions
109
- 4: 'טריליונים', // trillions
110
- 5: 'קוודרליונים', // quadrillions
111
- 6: 'קווינטיליונים' // quintillions
112
- }
36
+ const ZERO = 'אפס'
37
+ const NEGATIVE = 'מינוס'
38
+ const DECIMAL_SEP = 'נקודה'
113
39
 
114
- // Biblical Hebrew (masculine forms)
115
- biblicalOnes = {
116
- 1: 'אחד',
117
- 2: 'שניים',
118
- 3: 'שלשה',
119
- 4: 'ארבעה',
120
- 5: 'חמשה',
121
- 6: 'ששה',
122
- 7: 'שבעה',
123
- 8: 'שמונה',
124
- 9: 'תשעה'
125
- }
40
+ // ============================================================================
41
+ // Precomputed Lookup Tables (built once at module load)
42
+ // ============================================================================
126
43
 
127
- biblicalTens = {
128
- 0: 'עשרה',
129
- 1: 'אחד עשר',
130
- 2: 'שנים עשר',
131
- 3: 'שלשה עשר',
132
- 4: 'ארבעה עשר',
133
- 5: 'חמשה עשר',
134
- 6: 'ששה עשר',
135
- 7: 'שבעה עשר',
136
- 8: 'שמונה עשר',
137
- 9: 'תשעה עשר'
138
- }
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 ''
139
50
 
140
- biblicalTwenties = {
141
- 2: 'עשרים',
142
- 3: 'שלשים',
143
- 4: 'ארבעים',
144
- 5: 'חמישים',
145
- 6: 'ששים',
146
- 7: 'שבעים',
147
- 8: 'שמונים',
148
- 9: 'תשעים'
149
- }
51
+ const ones = n % 10
52
+ const tens = Math.floor(n / 10) % 10
53
+ const hundreds = Math.floor(n / 100)
150
54
 
151
- biblicalHundreds = {
152
- 1: 'מאה',
153
- 2: 'מאתיים',
154
- 3: 'מאות'
155
- }
55
+ let result = ''
156
56
 
157
- biblicalThousands = {
158
- 1: 'אלף',
159
- 2: 'אלפיים',
160
- 3: 'שלשת אלפים',
161
- 4: 'ארבעת אלפים',
162
- 5: 'חמשת אלפים',
163
- 6: 'ששת אלפים',
164
- 7: 'שבעת אלפים',
165
- 8: 'שמונת אלפים',
166
- 9: 'תשעת אלפים'
57
+ // Hundreds
58
+ if (hundreds > 0) {
59
+ result = HUNDREDS[hundreds]
167
60
  }
168
61
 
169
- biblicalScale = {
170
- 1: 'אלף',
171
- 2: 'מיליון',
172
- 3: 'מיליארד',
173
- 4: 'טריליון',
174
- 5: 'קוודרליון',
175
- 6: 'קווינטיליון'
176
- }
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
+ }
177
80
 
178
- biblicalScalePlural = {
179
- 1: 'אלפים',
180
- 2: 'מיליונים',
181
- 3: 'מיליארדים',
182
- 4: 'טריליונים',
183
- 5: 'קוודרליונים',
184
- 6: 'קווינטיליונים'
81
+ // Ones
82
+ if (ones > 0) {
83
+ if (result) {
84
+ result += ' ' + andWord + ONES[ones]
85
+ } else {
86
+ result = ONES[ones]
87
+ }
88
+ }
185
89
  }
186
90
 
187
- /**
188
- * Initializes the Hebrew converter with language-specific options.
189
- *
190
- * @param {HebrewOptions} [options={}] Configuration options.
191
- */
192
- constructor ({ and = 'ו', biblical = false, feminine = false } = {}) {
193
- super({ feminine })
194
-
195
- this.and = and
196
- this.feminine = feminine
197
-
198
- this.biblical = biblical
199
- if (this.biblical) {
200
- this.ones = this.biblicalOnes
201
- this.tens = this.biblicalTens
202
- this.twenties = this.biblicalTwenties
203
- this.hundreds = this.biblicalHundreds
204
- this.thousands = this.biblicalThousands
205
- this.scale = this.biblicalScale
206
- this.scalePlural = this.biblicalScalePlural
207
- }
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 = ''
106
+
107
+ // Hundreds
108
+ if (hundreds > 0) {
109
+ result = HUNDREDS[hundreds]
208
110
  }
209
111
 
210
- convertWholePart (number) {
211
- if (number === 0n) {
212
- 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]
213
119
  }
214
- const words = []
215
- const chunks = this.splitByX(number.toString(), 3)
216
- let index = chunks.length
217
- for (const x of chunks) {
218
- index = index - 1
219
- if (x === 0n) {
220
- continue
120
+ } else {
121
+ if (tens >= 2) {
122
+ if (result) {
123
+ result += ' ' + TENS[tens]
124
+ } else {
125
+ result = TENS[tens]
221
126
  }
127
+ }
222
128
 
223
- const [n1, n2, n3] = this.getDigits(x)
224
-
225
- if (index > 0) {
226
- // For thousands and above, handle the full chunk value
227
- const chunkWords = []
228
- let hasHundreds = false
229
-
230
- // Process hundreds in this chunk
231
- if (n3 > 0n) {
232
- hasHundreds = true
233
- if (n3 <= 2n) {
234
- chunkWords.push(this.hundreds[n3])
235
- } else {
236
- chunkWords.push(this.ones[n3] + ' ' + this.hundreds[3])
237
- }
238
- }
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
+ }
239
138
 
240
- // Process tens in this chunk
241
- if (n2 > 1n) {
242
- // Add conjunction if there were hundreds before
243
- const tensWord = this.twenties[n2]
244
- chunkWords.push(hasHundreds ? this.and + tensWord : tensWord)
245
- }
139
+ return result
140
+ }
246
141
 
247
- // Process ones in this chunk
248
- if (n2 === 1n) {
249
- // Add conjunction if there were hundreds before
250
- const onesWord = this.tens[n1]
251
- chunkWords.push(hasHundreds ? this.and + onesWord : onesWord)
252
- } else if (n1 > 0n) {
253
- // For "one million", "one billion", etc., don't add the word "one"
254
- if (x === 1n && index > 1) {
255
- // Skip adding "one" for millions/billions/etc.
256
- } else if (x <= 9n && chunkWords.length === 0 && index === 1) {
257
- // Use special forms for 1-9 thousand
258
- chunkWords.push(this.thousands[n1])
259
- } else {
260
- const onesWord = this.ones[n1]
261
- // Add conjunction if there were hundreds or tens before
262
- chunkWords.push((hasHundreds || n2 > 0n) ? this.and + onesWord : onesWord)
263
- }
264
- }
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
+ }
265
149
 
266
- // Add scale word (thousand, million, billion, etc.)
267
- if (x > 9n || index > 1) {
268
- // For numbers > 9 or higher scales, use appropriate scale word
269
- if (x === 1n) {
270
- // Singular form (e.g., "one thousand", "one million")
271
- chunkWords.push(this.scale[index])
272
- } else if (x === 2n && index === 1) {
273
- // Special dual form for "two thousand" (already in thousands[2])
274
- return [this.thousands[2], ...words].join(' ')
275
- } else if (x === 2n) {
276
- // For two million, two billion, etc. - use plural form
277
- chunkWords.push(this.scalePlural[index])
278
- } else if (index === 1) {
279
- // For thousands (10+), always use singular "אלף"
280
- chunkWords.push(this.scale[index])
281
- } else {
282
- // For millions/billions/etc. use plural form
283
- chunkWords.push(this.scalePlural[index])
284
- }
285
- }
150
+ // ============================================================================
151
+ // Conversion Functions
152
+ // ============================================================================
286
153
 
287
- words.push(chunkWords.join(' '))
288
- continue
289
- }
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 === 'ו'
290
166
 
291
- if (n3 > 0n) {
292
- if (n3 <= 2n) {
293
- words.push(this.hundreds[n3])
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
186
+
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
294
194
  } else {
295
- words.push(this.ones[n3] + ' ' + this.hundreds[3])
195
+ result += ' ' + segmentWord
296
196
  }
197
+ } else {
198
+ result = segmentWord
297
199
  }
298
-
299
- if (n2 > 1n) {
300
- words.push(this.twenties[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]
301
209
  }
302
-
303
- if (n2 === 1n) {
304
- words.push(this.tens[n1])
305
- } else if (n1 > 0n) {
306
- words.push(this.ones[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]
307
219
  }
308
220
  }
221
+ }
309
222
 
310
- if (words.length > 1) {
311
- words[words.length - 1] = this.and + words.at(-1)
312
- }
223
+ return result
224
+ }
313
225
 
314
- return words.join(' ')
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]
315
239
  }
240
+
241
+ return result
316
242
  }
317
243
 
318
244
  /**
319
- * Converts a number to Hebrew cardinal (written) form.
245
+ * Converts a numeric value to Modern Hebrew words.
320
246
  *
321
- * @param {number|string|bigint} value The number to convert.
322
- * @param {HebrewOptions} [options={}] Configuration options.
323
- * @returns {string} The number expressed in Hebrew words.
324
- * @throws {TypeError} If value is NaN or invalid type.
325
- * @throws {Error} If value is an invalid number string.
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
326
252
  */
327
- export default function convertToWords (value, options = {}) {
328
- return new Hebrew(options).convertToWords(value)
253
+ function toWords (value, options) {
254
+ options = validateOptions(options)
255
+ const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
256
+
257
+ let result = ''
258
+
259
+ if (isNegative) {
260
+ result = NEGATIVE + ' '
261
+ }
262
+
263
+ result += integerToWords(integerPart, options)
264
+
265
+ if (decimalPart) {
266
+ result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart)
267
+ }
268
+
269
+ return result
329
270
  }
271
+
272
+ // ============================================================================
273
+ // Exports
274
+ // ============================================================================
275
+
276
+ export { toWords }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Converts a numeric value to Hindi words.
3
+ *
4
+ * @param {number | string | bigint} value - The numeric value to convert
5
+ * @returns {string} The number in Hindi words
6
+ */
7
+ export function toWords(value: number | string | bigint): string;