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,251 +1,300 @@
1
- import { SlavicLanguage } from '../classes/slavic-language.js'
2
-
3
1
  /**
4
- * Biblical Hebrew language converter.
2
+ * Biblical Hebrew language converter - Functional Implementation
3
+ *
4
+ * Self-contained converter with segment-based decomposition.
5
+ *
6
+ * Key features:
7
+ * - Gender agreement (masculine default, feminine via option)
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
5
12
  *
6
- * Supports:
7
- * - Three-form pluralization (one/few/many)
8
- * - Gender agreement (masculine/feminine)
9
- * - Optional "ו" (and) conjunction control
13
+ * Optimization: Precomputed segment lookup tables for both genders.
10
14
  */
11
- export class BiblicalHebrew extends SlavicLanguage {
12
- negativeWord = 'מינוס'
13
- decimalSeparatorWord = 'נקודה'
14
- zeroWord = 'אפס'
15
- usePerDigitDecimals = true
16
-
17
- // Biblical Hebrew (masculine forms as default - historically accurate)
18
- onesWords = {
19
- 1: 'אחד',
20
- 2: 'שניים',
21
- 3: 'שלשה',
22
- 4: 'ארבעה',
23
- 5: 'חמשה',
24
- 6: 'ששה',
25
- 7: 'שבעה',
26
- 8: 'שמונה',
27
- 9: 'תשעה'
28
- }
29
15
 
30
- teensWords = {
31
- 0: 'עשרה',
32
- 1: 'אחד עשר',
33
- 2: 'שנים עשר',
34
- 3: 'שלשה עשר',
35
- 4: 'ארבעה עשר',
36
- 5: 'חמשה עשר',
37
- 6: 'ששה עשר',
38
- 7: 'שבעה עשר',
39
- 8: 'שמונה עשר',
40
- 9: 'תשעה עשר'
41
- }
16
+ import { parseNumericValue } from '../utils/parse-numeric.js'
17
+ import { validateOptions } from '../utils/validate-options.js'
42
18
 
43
- twentiesWords = {
44
- 2: 'עשרים',
45
- 3: 'שלשים',
46
- 4: 'ארבעים',
47
- 5: 'חמישים',
48
- 6: 'ששים',
49
- 7: 'שבעים',
50
- 8: 'שמונים',
51
- 9: 'תשעים'
52
- }
19
+ // ============================================================================
20
+ // Vocabulary (arrays for indexed access - faster than object property lookup)
21
+ // ============================================================================
53
22
 
54
- hundredsWords = {
55
- 1: 'מאה',
56
- 2: 'מאתיים',
57
- 3: 'מאות'
58
- }
23
+ // Masculine forms (default in Biblical Hebrew) - index 0 unused
24
+ const ONES_MASC = ['', 'אחד', 'שניים', 'שלשה', 'ארבעה', 'חמשה', 'ששה', 'שבעה', 'שמונה', 'תשעה']
25
+ const TEENS_MASC = ['עשרה', 'אחד עשר', 'שנים עשר', 'שלשה עשר', 'ארבעה עשר', 'חמשה עשר', 'ששה עשר', 'שבעה עשר', 'שמונה עשר', 'תשעה עשר']
26
+ const THOUSANDS_MASC = ['', 'אלף', 'אלפיים', 'שלשה אלפים', 'ארבעה אלפים', 'חמשה אלפים', 'ששה אלפים', 'שבעה אלפים', 'שמונה אלפים', 'תשעה אלפים']
59
27
 
60
- pluralForms = {
61
- 1: 'אלף',
62
- 2: 'אלפיים',
63
- 3: 'שלשה אלפים',
64
- 4: 'ארבעה אלפים',
65
- 5: 'חמשה אלפים',
66
- 6: 'ששה אלפים',
67
- 7: 'שבעה אלפים',
68
- 8: 'שמונה אלפים',
69
- 9: 'תשעה אלפים'
70
- }
28
+ // Feminine forms - index 0 unused
29
+ const ONES_FEM = ['', 'אחת', 'שתים', 'שלש', 'ארבע', 'חמש', 'שש', 'שבע', 'שמונה', 'תשע']
30
+ const TEENS_FEM = ['עשר', 'אחת עשרה', 'שתים עשרה', 'שלש עשרה', 'ארבע עשרה', 'חמש עשרה', 'שש עשרה', 'שבע עשרה', 'שמונה עשרה', 'תשע עשרה']
31
+ const THOUSANDS_FEM = ['', 'אלף', 'אלפיים', 'שלשת אלפים', 'ארבעת אלפים', 'חמשת אלפים', 'ששת אלפים', 'שבעת אלפים', 'שמונת אלפים', 'תשעת אלפים']
71
32
 
72
- // Feminine forms for thousands (when feminine=true is specified)
73
- femininePluralForms = {
74
- 1: 'אלף',
75
- 2: 'אלפיים',
76
- 3: 'שלשת אלפים',
77
- 4: 'ארבעת אלפים',
78
- 5: 'חמשת אלפים',
79
- 6: 'ששת אלפים',
80
- 7: 'שבעת אלפים',
81
- 8: 'שמונת אלפים',
82
- 9: 'תשעת אלפים'
83
- }
33
+ // Shared vocabulary
34
+ const TENS = ['', '', 'עשרים', 'שלשים', 'ארבעים', 'חמישים', 'ששים', 'שבעים', 'שמונים', 'תשעים']
35
+ const HUNDREDS = ['', 'מאה', 'מאתיים', 'שלשה מאות', 'ארבעה מאות', 'חמשה מאות', 'ששה מאות', 'שבעה מאות', 'שמונה מאות', 'תשעה מאות']
36
+ const HUNDREDS_FEM = ['', 'מאה', 'מאתיים', 'שלש מאות', 'ארבע מאות', 'חמש מאות', 'שש מאות', 'שבע מאות', 'שמונה מאות', 'תשע מאות']
84
37
 
85
- scale = {
86
- 1: 'אלף', // thousand (singular)
87
- 2: 'מיליון', // million
88
- 3: 'מיליארד', // billion
89
- 4: 'טריליון', // trillion
90
- 5: 'קוודרליון', // quadrillion
91
- 6: 'קווינטיליון' // quintillion
92
- }
38
+ // Scale words (index 1 = thousands, 2 = millions, etc.)
39
+ const SCALE = ['', 'אלף', 'מיליון', 'מיליארד', 'טריליון', 'קוודרליון', 'קווינטיליון']
40
+ const SCALE_PLURAL = ['', 'אלפים', 'מיליונים', 'מיליארדים', 'טריליונים', 'קוודרליונים', 'קווינטיליונים']
93
41
 
94
- scalePlural = {
95
- 1: 'אלפים', // thousands
96
- 2: 'מיליונים', // millions
97
- 3: 'מיליארדים', // billions
98
- 4: 'טריליונים', // trillions
99
- 5: 'קוודרליונים', // quadrillions
100
- 6: 'קווינטיליונים' // quintillions
101
- }
42
+ const ZERO = 'אפס'
43
+ const NEGATIVE = 'מינוס'
44
+ const DECIMAL_SEP = 'נקודה'
45
+
46
+ // ============================================================================
47
+ // Precomputed Lookup Tables (built once at module load)
48
+ // ============================================================================
49
+
50
+ /**
51
+ * Builds segment word for scale segments (thousands, millions, etc.).
52
+ * "ו" is added before tens and ones when following hundreds.
53
+ */
54
+ function buildScaleSegment (n, andWord, ONES, TEENS, HUNDREDS_ARR) {
55
+ if (n === 0) return ''
102
56
 
103
- // Feminine forms (for when gender='feminine' is specified)
104
- onesFeminineWords = {
105
- 1: 'אחת',
106
- 2: 'שתים',
107
- 3: 'שלש',
108
- 4: 'ארבע',
109
- 5: 'חמש',
110
- 6: 'שש',
111
- 7: 'שבע',
112
- 8: 'שמונה',
113
- 9: 'תשע'
57
+ const ones = n % 10
58
+ const tens = Math.floor(n / 10) % 10
59
+ const hundreds = Math.floor(n / 100)
60
+
61
+ let result = ''
62
+
63
+ // Hundreds
64
+ if (hundreds > 0) {
65
+ result = HUNDREDS_ARR[hundreds]
114
66
  }
115
67
 
116
- teensFeminineWords = {
117
- 0: 'עשר',
118
- 1: 'אחת עשרה',
119
- 2: 'שתים עשרה',
120
- 3: 'שלש עשרה',
121
- 4: 'ארבע עשרה',
122
- 5: 'חמש עשרה',
123
- 6: 'שש עשרה',
124
- 7: 'שבע עשרה',
125
- 8: 'שמונה עשרה',
126
- 9: 'תשע עשרה'
68
+ // Tens and ones
69
+ if (tens === 1) {
70
+ // Teens (10-19)
71
+ const teenWord = TEENS[ones]
72
+ if (result) {
73
+ result += ' ' + andWord + teenWord
74
+ } else {
75
+ result = teenWord
76
+ }
77
+ } else {
78
+ // Tens (20-90)
79
+ if (tens >= 2) {
80
+ if (result) {
81
+ result += ' ' + andWord + TENS[tens]
82
+ } else {
83
+ result = TENS[tens]
84
+ }
85
+ }
86
+
87
+ // Ones
88
+ if (ones > 0) {
89
+ if (result) {
90
+ result += ' ' + andWord + ONES[ones]
91
+ } else {
92
+ result = ONES[ones]
93
+ }
94
+ }
127
95
  }
128
96
 
129
- constructor (options = {}) {
130
- super(options)
97
+ return result
98
+ }
99
+
100
+ /**
101
+ * Builds segment word for units segment (no scale word).
102
+ * "ו" is only added before the final ones digit.
103
+ */
104
+ function buildUnitsSegment (n, andWord, ONES, TEENS, HUNDREDS_ARR) {
105
+ if (n === 0) return ''
131
106
 
132
- this.setOptions({
133
- andWord: 'ו',
134
- gender: 'masculine'
135
- }, options)
107
+ const ones = n % 10
108
+ const tens = Math.floor(n / 10) % 10
109
+ const hundreds = Math.floor(n / 100)
136
110
 
137
- if (this.options.gender === 'feminine') {
138
- this.onesWords = this.onesFeminineWords
139
- this.teensWords = this.teensFeminineWords
140
- this.pluralForms = this.femininePluralForms
141
- }
111
+ let result = ''
112
+
113
+ // Hundreds
114
+ if (hundreds > 0) {
115
+ result = HUNDREDS_ARR[hundreds]
142
116
  }
143
117
 
144
- /** Converts integer part with Biblical Hebrew three-form pluralization. */
145
- integerToWords (integerPart) {
146
- if (integerPart === 0n) {
147
- return this.zeroWord
118
+ // Tens (no conjunction)
119
+ if (tens === 1) {
120
+ // Teens (10-19)
121
+ if (result) {
122
+ result += ' ' + TEENS[ones]
123
+ } else {
124
+ result = TEENS[ones]
148
125
  }
149
- const words = []
150
- const segments = this.splitToSegments(integerPart.toString(), 3)
151
- let index = segments.length
152
- for (const x of segments) {
153
- index = index - 1
154
- if (x === 0n) {
155
- continue
126
+ } else {
127
+ if (tens >= 2) {
128
+ if (result) {
129
+ result += ' ' + TENS[tens]
130
+ } else {
131
+ result = TENS[tens]
156
132
  }
133
+ }
157
134
 
158
- const [n1, n2, n3] = this.extractDigits(x)
159
-
160
- if (index > 0) {
161
- // For thousands and above, handle the full chunk value
162
- const chunkWords = []
163
- let hasHundreds = false
164
-
165
- // Process hundreds in this chunk
166
- if (n3 > 0n) {
167
- hasHundreds = true
168
- if (n3 <= 2n) {
169
- chunkWords.push(this.hundredsWords[n3])
170
- } else {
171
- chunkWords.push(this.onesWords[n3] + ' ' + this.hundredsWords[3])
172
- }
173
- }
135
+ // Ones - conjunction only here
136
+ if (ones > 0) {
137
+ if (result) {
138
+ result += ' ' + andWord + ONES[ones]
139
+ } else {
140
+ result = ONES[ones]
141
+ }
142
+ }
143
+ }
174
144
 
175
- // Process tens in this chunk
176
- if (n2 > 1n) {
177
- // Add conjunction if there were hundreds before
178
- const tensWord = this.twentiesWords[n2]
179
- chunkWords.push(hasHundreds ? this.options.andWord + tensWord : tensWord)
180
- }
145
+ return result
146
+ }
181
147
 
182
- // Process ones in this chunk
183
- if (n2 === 1n) {
184
- // Add conjunction if there were hundreds before
185
- const onesWord = this.teensWords[n1]
186
- chunkWords.push(hasHundreds ? this.options.andWord + onesWord : onesWord)
187
- } else if (n1 > 0n) {
188
- // For "one million", "one billion", etc., don't add the word "one"
189
- if (x === 1n && index > 1) {
190
- // Skip adding "one" for millions/billions/etc.
191
- } else if (x <= 9n && chunkWords.length === 0 && index === 1) {
192
- // Use special forms for 1-9 thousand
193
- chunkWords.push(this.pluralForms[n1])
194
- } else {
195
- const onesWord = this.onesWords[n1]
196
- // Add conjunction if there were hundreds or tens before
197
- chunkWords.push((hasHundreds || n2 > 0n) ? this.options.andWord + onesWord : onesWord)
198
- }
199
- }
148
+ // Precompute all 1000 segment words for masculine (default) with default conjunction
149
+ const SCALE_SEGMENTS_MASC = new Array(1000)
150
+ const UNITS_SEGMENTS_MASC = new Array(1000)
151
+ const SCALE_SEGMENTS_FEM = new Array(1000)
152
+ const UNITS_SEGMENTS_FEM = new Array(1000)
200
153
 
201
- // Add scale word (thousand, million, billion, etc.)
202
- if (x > 9n || index > 1) {
203
- // For numbers > 9 or higher scales, use appropriate scale word
204
- if (x === 1n) {
205
- // Singular form (e.g., "one thousand", "one million")
206
- chunkWords.push(this.scale[index])
207
- } else if (x === 2n && index === 1) {
208
- // Special dual form for "two thousand" (already in thousands[2])
209
- return [this.pluralForms[2], ...words].join(' ')
210
- } else if (x === 2n) {
211
- // For two million, two billion, etc. - use plural form
212
- chunkWords.push(this.scalePlural[index])
213
- } else if (index === 1) {
214
- // For thousands (10+), always use singular "אלף"
215
- chunkWords.push(this.scale[index])
216
- } else {
217
- // For millions/billions/etc. use plural form
218
- chunkWords.push(this.scalePlural[index])
219
- }
220
- }
154
+ for (let i = 0; i < 1000; i++) {
155
+ SCALE_SEGMENTS_MASC[i] = buildScaleSegment(i, 'ו', ONES_MASC, TEENS_MASC, HUNDREDS)
156
+ UNITS_SEGMENTS_MASC[i] = buildUnitsSegment(i, 'ו', ONES_MASC, TEENS_MASC, HUNDREDS)
157
+ SCALE_SEGMENTS_FEM[i] = buildScaleSegment(i, 'ו', ONES_FEM, TEENS_FEM, HUNDREDS_FEM)
158
+ UNITS_SEGMENTS_FEM[i] = buildUnitsSegment(i, 'ו', ONES_FEM, TEENS_FEM, HUNDREDS_FEM)
159
+ }
221
160
 
222
- words.push(chunkWords.join(' '))
223
- continue
224
- }
161
+ // ============================================================================
162
+ // Conversion Functions
163
+ // ============================================================================
164
+
165
+ /**
166
+ * Converts a non-negative integer to Biblical Hebrew words.
167
+ *
168
+ * @param {bigint} n - Non-negative integer to convert
169
+ * @param {Object} options - Conversion options
170
+ * @returns {string} Biblical Hebrew words
171
+ */
172
+ function integerToWords (n, options) {
173
+ if (n === 0n) return ZERO
174
+
175
+ const andWord = options.andWord ?? 'ו'
176
+ const gender = options.gender || 'masculine'
177
+ const isFeminine = gender === 'feminine'
178
+ const usePrecomputed = andWord === 'ו'
179
+
180
+ // Select vocabulary based on gender
181
+ const ONES = isFeminine ? ONES_FEM : ONES_MASC
182
+ const TEENS = isFeminine ? TEENS_FEM : TEENS_MASC
183
+ const THOUSANDS_SPECIAL = isFeminine ? THOUSANDS_FEM : THOUSANDS_MASC
184
+ const HUNDREDS_ARR = isFeminine ? HUNDREDS_FEM : HUNDREDS
185
+ const SCALE_SEGS = isFeminine ? SCALE_SEGMENTS_FEM : SCALE_SEGMENTS_MASC
186
+ const UNITS_SEGS = isFeminine ? UNITS_SEGMENTS_FEM : UNITS_SEGMENTS_MASC
187
+
188
+ // Fast path: numbers < 1000 (direct lookup)
189
+ if (n < 1000n) {
190
+ return usePrecomputed ? UNITS_SEGS[Number(n)] : buildUnitsSegment(Number(n), andWord, ONES, TEENS, HUNDREDS_ARR)
191
+ }
225
192
 
226
- if (n3 > 0n) {
227
- if (n3 <= 2n) {
228
- words.push(this.hundredsWords[n3])
193
+ // Extract segments using BigInt modulo
194
+ const segments = []
195
+ let temp = n
196
+ while (temp > 0n) {
197
+ segments.push(Number(temp % 1000n))
198
+ temp = temp / 1000n
199
+ }
200
+
201
+ // Build result string directly
202
+ let result = ''
203
+
204
+ for (let i = segments.length - 1; i >= 0; i--) {
205
+ const segment = segments[i]
206
+ if (segment === 0) continue
207
+
208
+ if (i === 0) {
209
+ // Units segment (no scale word)
210
+ const segmentWord = usePrecomputed ? UNITS_SEGS[segment] : buildUnitsSegment(segment, andWord, ONES, TEENS, HUNDREDS_ARR)
211
+ if (result) {
212
+ // Add "ו" before single-digit units when following scale words
213
+ if (segment <= 9) {
214
+ result += ' ' + andWord + segmentWord
229
215
  } else {
230
- words.push(this.onesWords[n3] + ' ' + this.hundredsWords[3])
216
+ result += ' ' + segmentWord
231
217
  }
218
+ } else {
219
+ result = segmentWord
232
220
  }
233
-
234
- if (n2 > 1n) {
235
- words.push(this.twentiesWords[n2])
221
+ } else if (i === 1) {
222
+ // Thousands - special handling for 1-9
223
+ if (segment <= 9) {
224
+ if (result) result += ' '
225
+ result += THOUSANDS_SPECIAL[segment]
226
+ } else {
227
+ const segmentWord = usePrecomputed ? SCALE_SEGS[segment] : buildScaleSegment(segment, andWord, ONES, TEENS, HUNDREDS_ARR)
228
+ if (result) result += ' '
229
+ result += segmentWord + ' ' + SCALE[1]
236
230
  }
237
-
238
- if (n2 === 1n) {
239
- words.push(this.teensWords[n1])
240
- } else if (n1 > 0n) {
241
- words.push(this.onesWords[n1])
231
+ } else {
232
+ // Millions and above
233
+ if (segment === 1) {
234
+ if (result) result += ' '
235
+ result += SCALE[i]
236
+ } else {
237
+ const segmentWord = usePrecomputed ? SCALE_SEGS[segment] : buildScaleSegment(segment, andWord, ONES, TEENS, HUNDREDS_ARR)
238
+ if (result) result += ' '
239
+ result += segmentWord + ' ' + SCALE_PLURAL[i]
242
240
  }
243
241
  }
242
+ }
244
243
 
245
- if (words.length > 1) {
246
- words[words.length - 1] = this.options.andWord + words.at(-1)
247
- }
244
+ return result
245
+ }
248
246
 
249
- return words.join(' ')
247
+ /**
248
+ * Converts decimal digits to Biblical Hebrew words (digit by digit).
249
+ *
250
+ * @param {string} decimalPart - Decimal digits (without the point)
251
+ * @param {Object} options - Conversion options
252
+ * @returns {string} Biblical Hebrew words for decimal part
253
+ */
254
+ function decimalPartToWords (decimalPart, options) {
255
+ const gender = options.gender || 'masculine'
256
+ const ONES = gender === 'feminine' ? ONES_FEM : ONES_MASC
257
+
258
+ let result = ''
259
+ for (let i = 0; i < decimalPart.length; i++) {
260
+ const d = parseInt(decimalPart[i], 10)
261
+ if (result) result += ' '
262
+ result += d === 0 ? ZERO : ONES[d]
250
263
  }
264
+
265
+ return result
251
266
  }
267
+
268
+ /**
269
+ * Converts a numeric value to Biblical Hebrew words.
270
+ *
271
+ * @param {number | string | bigint} value - The numeric value to convert
272
+ * @param {Object} [options] - Optional configuration
273
+ * @param {('masculine'|'feminine')} [options.gender='masculine'] - Grammatical gender
274
+ * @param {string} [options.andWord] - Custom conjunction word
275
+ * @returns {string} The number in Biblical Hebrew words
276
+ */
277
+ function toWords (value, options) {
278
+ options = validateOptions(options)
279
+ const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
280
+
281
+ let result = ''
282
+
283
+ if (isNegative) {
284
+ result = NEGATIVE + ' '
285
+ }
286
+
287
+ result += integerToWords(integerPart, options)
288
+
289
+ if (decimalPart) {
290
+ result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart, options)
291
+ }
292
+
293
+ return result
294
+ }
295
+
296
+ // ============================================================================
297
+ // Exports
298
+ // ============================================================================
299
+
300
+ export { toWords }
@@ -1,80 +1,13 @@
1
1
  /**
2
- * Modern Hebrew language converter.
2
+ * Converts a numeric value to Modern Hebrew words.
3
3
  *
4
- * Supports:
5
- * - Right-to-left text orientation
6
- * - Feminine grammatical forms (default in Modern Hebrew)
7
- * - Three-form pluralization (singular/few/many)
8
- * - Optional "ve" (ו) conjunction via options
4
+ * @param {number | string | bigint} value - The numeric value to convert
5
+ * @param {Object} [options] - Optional configuration
6
+ * @param {('masculine'|'feminine')} [options.gender='masculine'] - Grammatical gender
7
+ * @param {string} [options.andWord] - Custom conjunction word
8
+ * @returns {string} The number in Modern Hebrew words
9
9
  */
10
- export class Hebrew extends SlavicLanguage {
11
- constructor(options?: {});
12
- onesWords: {
13
- 1: string;
14
- 2: string;
15
- 3: string;
16
- 4: string;
17
- 5: string;
18
- 6: string;
19
- 7: string;
20
- 8: string;
21
- 9: string;
22
- };
23
- teensWords: {
24
- 0: string;
25
- 1: string;
26
- 2: string;
27
- 3: string;
28
- 4: string;
29
- 5: string;
30
- 6: string;
31
- 7: string;
32
- 8: string;
33
- 9: string;
34
- };
35
- twentiesWords: {
36
- 2: string;
37
- 3: string;
38
- 4: string;
39
- 5: string;
40
- 6: string;
41
- 7: string;
42
- 8: string;
43
- 9: string;
44
- };
45
- hundredsWords: {
46
- 1: string;
47
- 2: string;
48
- 3: string;
49
- };
50
- pluralForms: {
51
- 1: string;
52
- 2: string;
53
- 3: string;
54
- 4: string;
55
- 5: string;
56
- 6: string;
57
- 7: string;
58
- 8: string;
59
- 9: string;
60
- };
61
- scale: {
62
- 1: string;
63
- 2: string;
64
- 3: string;
65
- 4: string;
66
- 5: string;
67
- 6: string;
68
- };
69
- scalePlural: {
70
- 1: string;
71
- 2: string;
72
- 3: string;
73
- 4: string;
74
- 5: string;
75
- 6: string;
76
- };
77
- /** Converts integer part to Hebrew words with special handling for thousands. */
78
- integerToWords(integerPart: any): string;
79
- }
80
- import { SlavicLanguage } from '../classes/slavic-language.js';
10
+ export function toWords(value: number | string | bigint, options?: {
11
+ gender?: "masculine" | "feminine" | undefined;
12
+ andWord?: string | undefined;
13
+ }): string;