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.
- package/CHANGELOG.md +49 -0
- package/README.md +183 -156
- package/dist/languages/am-Latn.js +3 -0
- package/dist/languages/am-Latn.js.map +1 -0
- package/dist/languages/am.js +3 -0
- package/dist/languages/am.js.map +1 -0
- package/dist/languages/ar.js +3 -2
- package/dist/languages/ar.js.map +1 -1
- package/dist/languages/az.js +3 -2
- package/dist/languages/az.js.map +1 -1
- package/dist/languages/bn.js +3 -2
- package/dist/languages/bn.js.map +1 -1
- package/dist/languages/cs.js +3 -2
- package/dist/languages/cs.js.map +1 -1
- package/dist/languages/da.js +3 -2
- package/dist/languages/da.js.map +1 -1
- package/dist/languages/de.js +3 -2
- package/dist/languages/de.js.map +1 -1
- package/dist/languages/el.js +3 -2
- package/dist/languages/el.js.map +1 -1
- package/dist/languages/en.js +3 -2
- package/dist/languages/en.js.map +1 -1
- package/dist/languages/es.js +3 -2
- package/dist/languages/es.js.map +1 -1
- package/dist/languages/fa.js +3 -2
- package/dist/languages/fa.js.map +1 -1
- package/dist/languages/fi.js +3 -0
- package/dist/languages/fi.js.map +1 -0
- package/dist/languages/fil.js +3 -2
- package/dist/languages/fil.js.map +1 -1
- package/dist/languages/fr-BE.js +3 -2
- package/dist/languages/fr-BE.js.map +1 -1
- package/dist/languages/fr.js +3 -2
- package/dist/languages/fr.js.map +1 -1
- package/dist/languages/gu.js +3 -2
- package/dist/languages/gu.js.map +1 -1
- package/dist/languages/ha.js +3 -0
- package/dist/languages/ha.js.map +1 -0
- package/dist/languages/hbo.js +3 -0
- package/dist/languages/hbo.js.map +1 -0
- package/dist/languages/he.js +3 -2
- package/dist/languages/he.js.map +1 -1
- package/dist/languages/hi.js +3 -2
- package/dist/languages/hi.js.map +1 -1
- package/dist/languages/hr.js +3 -2
- package/dist/languages/hr.js.map +1 -1
- package/dist/languages/hu.js +3 -2
- package/dist/languages/hu.js.map +1 -1
- package/dist/languages/id.js +3 -2
- package/dist/languages/id.js.map +1 -1
- package/dist/languages/it.js +3 -2
- package/dist/languages/it.js.map +1 -1
- package/dist/languages/ja.js +3 -2
- package/dist/languages/ja.js.map +1 -1
- package/dist/languages/kn.js +3 -2
- package/dist/languages/kn.js.map +1 -1
- package/dist/languages/ko.js +3 -2
- package/dist/languages/ko.js.map +1 -1
- package/dist/languages/lt.js +3 -2
- package/dist/languages/lt.js.map +1 -1
- package/dist/languages/lv.js +3 -2
- package/dist/languages/lv.js.map +1 -1
- package/dist/languages/mr.js +3 -2
- package/dist/languages/mr.js.map +1 -1
- package/dist/languages/ms.js +3 -2
- package/dist/languages/ms.js.map +1 -1
- package/dist/languages/nb.js +3 -2
- package/dist/languages/nb.js.map +1 -1
- package/dist/languages/nl.js +3 -2
- package/dist/languages/nl.js.map +1 -1
- package/dist/languages/pa.js +3 -0
- package/dist/languages/pa.js.map +1 -0
- package/dist/languages/pl.js +3 -2
- package/dist/languages/pl.js.map +1 -1
- package/dist/languages/pt.js +3 -2
- package/dist/languages/pt.js.map +1 -1
- package/dist/languages/ro.js +3 -2
- package/dist/languages/ro.js.map +1 -1
- package/dist/languages/ru.js +3 -2
- package/dist/languages/ru.js.map +1 -1
- package/dist/languages/sr-Cyrl.js +3 -0
- package/dist/languages/sr-Cyrl.js.map +1 -0
- package/dist/languages/sr-Latn.js +3 -2
- package/dist/languages/sr-Latn.js.map +1 -1
- package/dist/languages/sv.js +3 -2
- package/dist/languages/sv.js.map +1 -1
- package/dist/languages/sw.js +3 -2
- package/dist/languages/sw.js.map +1 -1
- package/dist/languages/ta.js +3 -2
- package/dist/languages/ta.js.map +1 -1
- package/dist/languages/te.js +3 -2
- package/dist/languages/te.js.map +1 -1
- package/dist/languages/th.js +3 -2
- package/dist/languages/th.js.map +1 -1
- package/dist/languages/tr.js +3 -2
- package/dist/languages/tr.js.map +1 -1
- package/dist/languages/uk.js +3 -2
- package/dist/languages/uk.js.map +1 -1
- package/dist/languages/ur.js +3 -2
- package/dist/languages/ur.js.map +1 -1
- package/dist/languages/vi.js +3 -2
- package/dist/languages/vi.js.map +1 -1
- package/dist/languages/zh-Hans.js +3 -2
- package/dist/languages/zh-Hans.js.map +1 -1
- package/dist/languages/zh-Hant.js +3 -0
- package/dist/languages/zh-Hant.js.map +1 -0
- package/dist/n2words.js +3 -2
- package/dist/n2words.js.map +1 -1
- package/lib/languages/am-Latn.d.ts +7 -0
- package/lib/languages/am-Latn.js +164 -0
- package/lib/languages/am.d.ts +7 -0
- package/lib/languages/am.js +164 -0
- package/lib/languages/ar.d.ts +17 -0
- package/lib/languages/ar.js +171 -209
- package/lib/languages/az.d.ts +7 -0
- package/lib/languages/az.js +167 -49
- package/lib/languages/bn.d.ts +7 -0
- package/lib/languages/bn.js +142 -123
- package/lib/languages/cs.d.ts +18 -0
- package/lib/languages/cs.js +303 -176
- package/lib/languages/da.d.ts +14 -0
- package/lib/languages/da.js +267 -139
- package/lib/languages/de.d.ts +17 -0
- package/lib/languages/de.js +310 -113
- package/lib/languages/el.d.ts +14 -0
- package/lib/languages/el.js +225 -98
- package/lib/languages/en.d.ts +17 -0
- package/lib/languages/en.js +235 -102
- package/lib/languages/es.d.ts +21 -0
- package/lib/languages/es.js +307 -125
- package/lib/languages/fa.d.ts +7 -0
- package/lib/languages/fa.js +115 -108
- package/lib/languages/fi.d.ts +14 -0
- package/lib/languages/fi.js +245 -0
- package/lib/languages/fil.d.ts +7 -0
- package/lib/languages/fil.js +199 -139
- package/lib/languages/fr-BE.d.ts +11 -0
- package/lib/languages/fr-BE.js +287 -48
- package/lib/languages/fr.d.ts +21 -0
- package/lib/languages/fr.js +343 -119
- package/lib/languages/gu.d.ts +7 -0
- package/lib/languages/gu.js +125 -144
- package/lib/languages/ha.d.ts +7 -0
- package/lib/languages/ha.js +230 -0
- package/lib/languages/hbo.d.ts +13 -0
- package/lib/languages/hbo.js +300 -0
- package/lib/languages/he.d.ts +13 -0
- package/lib/languages/he.js +230 -283
- package/lib/languages/hi.d.ts +7 -0
- package/lib/languages/hi.js +142 -123
- package/lib/languages/hr.d.ts +11 -0
- package/lib/languages/hr.js +190 -129
- package/lib/languages/hu.d.ts +7 -0
- package/lib/languages/hu.js +194 -133
- package/lib/languages/id.d.ts +7 -0
- package/lib/languages/id.js +167 -140
- package/lib/languages/it.d.ts +19 -0
- package/lib/languages/it.js +337 -108
- package/lib/languages/ja.d.ts +17 -0
- package/lib/languages/ja.js +224 -155
- package/lib/languages/kn.d.ts +7 -0
- package/lib/languages/kn.js +128 -62
- package/lib/languages/ko.d.ts +14 -0
- package/lib/languages/ko.js +250 -70
- package/lib/languages/lt.d.ts +18 -0
- package/lib/languages/lt.js +287 -148
- package/lib/languages/lv.d.ts +18 -0
- package/lib/languages/lv.js +291 -123
- package/lib/languages/mr.d.ts +7 -0
- package/lib/languages/mr.js +125 -144
- package/lib/languages/ms.d.ts +7 -0
- package/lib/languages/ms.js +171 -112
- package/lib/languages/nb.d.ts +14 -0
- package/lib/languages/nb.js +275 -100
- package/lib/languages/nl.d.ts +26 -0
- package/lib/languages/nl.js +307 -174
- package/lib/languages/pa.d.ts +7 -0
- package/lib/languages/pa.js +163 -0
- package/lib/languages/pl.d.ts +22 -0
- package/lib/languages/pl.js +299 -158
- package/lib/languages/pt.d.ts +17 -0
- package/lib/languages/pt.js +279 -120
- package/lib/languages/ro.d.ts +18 -0
- package/lib/languages/ro.js +214 -337
- package/lib/languages/ru.d.ts +11 -0
- package/lib/languages/ru.js +219 -95
- package/lib/languages/sr-Cyrl.d.ts +11 -0
- package/lib/languages/sr-Cyrl.js +215 -0
- package/lib/languages/sr-Latn.d.ts +11 -0
- package/lib/languages/sr-Latn.js +190 -132
- package/lib/languages/sv.d.ts +14 -0
- package/lib/languages/sv.js +280 -103
- package/lib/languages/sw.d.ts +7 -0
- package/lib/languages/sw.js +135 -103
- package/lib/languages/ta.d.ts +7 -0
- package/lib/languages/ta.js +133 -205
- package/lib/languages/te.d.ts +7 -0
- package/lib/languages/te.js +148 -213
- package/lib/languages/th.d.ts +7 -0
- package/lib/languages/th.js +139 -101
- package/lib/languages/tr.d.ts +18 -0
- package/lib/languages/tr.js +246 -66
- package/lib/languages/uk.d.ts +11 -0
- package/lib/languages/uk.js +197 -101
- package/lib/languages/ur.d.ts +7 -0
- package/lib/languages/ur.js +160 -123
- package/lib/languages/vi.d.ts +17 -0
- package/lib/languages/vi.js +287 -164
- package/lib/languages/zh-Hans.d.ts +11 -0
- package/lib/languages/zh-Hans.js +159 -142
- package/lib/languages/zh-Hant.d.ts +11 -0
- package/lib/languages/zh-Hant.js +202 -0
- package/lib/n2words.d.ts +53 -0
- package/lib/n2words.js +91 -227
- package/lib/utils/is-plain-object.d.ts +13 -0
- package/lib/utils/is-plain-object.js +17 -0
- package/lib/utils/parse-numeric.d.ts +17 -0
- package/lib/utils/parse-numeric.js +108 -0
- package/lib/utils/validate-options.d.ts +8 -0
- package/lib/utils/validate-options.js +16 -0
- package/package.json +118 -67
- package/dist/languages/pa-Guru.js +0 -2
- package/dist/languages/pa-Guru.js.map +0 -1
- package/lib/classes/abstract-language.js +0 -261
- package/lib/classes/greedy-scale-language.js +0 -195
- package/lib/classes/slavic-language.js +0 -251
- package/lib/classes/south-asian-language.js +0 -161
- package/lib/classes/turkic-language.js +0 -63
- package/lib/languages/pa-Guru.js +0 -126
- package/typings/classes/abstract-language.d.ts +0 -144
- package/typings/classes/greedy-scale-language.d.ts +0 -148
- package/typings/classes/slavic-language.d.ts +0 -145
- package/typings/classes/south-asian-language.d.ts +0 -101
- package/typings/classes/turkic-language.d.ts +0 -42
- package/typings/languages/ar.d.ts +0 -93
- package/typings/languages/az.d.ts +0 -25
- package/typings/languages/bn.d.ts +0 -1
- package/typings/languages/cs.d.ts +0 -120
- package/typings/languages/da.d.ts +0 -53
- package/typings/languages/de.d.ts +0 -26
- package/typings/languages/el.d.ts +0 -11
- package/typings/languages/en.d.ts +0 -30
- package/typings/languages/es.d.ts +0 -43
- package/typings/languages/fa.d.ts +0 -81
- package/typings/languages/fil.d.ts +0 -12
- package/typings/languages/fr-BE.d.ts +0 -41
- package/typings/languages/fr.d.ts +0 -43
- package/typings/languages/gu.d.ts +0 -12
- package/typings/languages/he.d.ts +0 -197
- package/typings/languages/hi.d.ts +0 -1
- package/typings/languages/hr.d.ts +0 -110
- package/typings/languages/hu.d.ts +0 -37
- package/typings/languages/id.d.ts +0 -69
- package/typings/languages/it.d.ts +0 -51
- package/typings/languages/ja.d.ts +0 -58
- package/typings/languages/kn.d.ts +0 -11
- package/typings/languages/ko.d.ts +0 -25
- package/typings/languages/lt.d.ts +0 -110
- package/typings/languages/lv.d.ts +0 -99
- package/typings/languages/mr.d.ts +0 -12
- package/typings/languages/ms.d.ts +0 -37
- package/typings/languages/nb.d.ts +0 -27
- package/typings/languages/nl.d.ts +0 -65
- package/typings/languages/pa-Guru.d.ts +0 -1
- package/typings/languages/pl.d.ts +0 -116
- package/typings/languages/pt.d.ts +0 -39
- package/typings/languages/ro.d.ts +0 -229
- package/typings/languages/ru.d.ts +0 -108
- package/typings/languages/sr-Latn.d.ts +0 -98
- package/typings/languages/sv.d.ts +0 -30
- package/typings/languages/sw.d.ts +0 -1
- package/typings/languages/ta.d.ts +0 -1
- package/typings/languages/te.d.ts +0 -1
- package/typings/languages/th.d.ts +0 -1
- package/typings/languages/tr.d.ts +0 -46
- package/typings/languages/uk.d.ts +0 -117
- package/typings/languages/ur.d.ts +0 -1
- package/typings/languages/vi.d.ts +0 -116
- package/typings/languages/zh-Hans.d.ts +0 -57
- package/typings/n2words.d.ts +0 -177
package/lib/languages/he.js
CHANGED
|
@@ -1,329 +1,276 @@
|
|
|
1
|
-
import SlavicLanguage from '../classes/slavic-language.js'
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
28
|
-
* -
|
|
29
|
-
* -
|
|
30
|
-
* -
|
|
31
|
-
* -
|
|
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
|
-
*
|
|
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
|
-
|
|
55
|
-
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
|
|
85
|
-
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
152
|
-
1: 'מאה',
|
|
153
|
-
2: 'מאתיים',
|
|
154
|
-
3: 'מאות'
|
|
155
|
-
}
|
|
55
|
+
let result = ''
|
|
156
56
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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
|
-
|
|
211
|
-
|
|
212
|
-
|
|
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
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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
|
-
|
|
224
|
-
|
|
225
|
-
if (
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
-
|
|
241
|
-
|
|
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
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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
|
-
|
|
288
|
-
|
|
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
|
-
|
|
292
|
-
|
|
293
|
-
|
|
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
|
-
|
|
195
|
+
result += ' ' + segmentWord
|
|
296
196
|
}
|
|
197
|
+
} else {
|
|
198
|
+
result = segmentWord
|
|
297
199
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
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
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
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
|
-
|
|
311
|
-
|
|
312
|
-
}
|
|
223
|
+
return result
|
|
224
|
+
}
|
|
313
225
|
|
|
314
|
-
|
|
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
|
|
245
|
+
* Converts a numeric value to Modern Hebrew words.
|
|
320
246
|
*
|
|
321
|
-
* @param {number|string|bigint} value The
|
|
322
|
-
* @param {
|
|
323
|
-
* @
|
|
324
|
-
* @
|
|
325
|
-
* @
|
|
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
|
-
|
|
328
|
-
|
|
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 }
|