n2words 5.0.0 → 5.1.1
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 +133 -40
- package/README.md +6 -4
- package/dist/am-ET.js +2 -2
- package/dist/am-ET.umd.js +2 -2
- package/dist/am-Latn-ET.js +2 -2
- package/dist/am-Latn-ET.umd.js +2 -2
- package/dist/ar-SA.js +2 -2
- package/dist/ar-SA.umd.js +2 -2
- package/dist/az-AZ.js +2 -2
- package/dist/az-AZ.umd.js +2 -2
- package/dist/bn-BD.js +2 -2
- package/dist/bn-BD.umd.js +2 -2
- package/dist/cs-CZ.js +2 -2
- package/dist/cs-CZ.umd.js +2 -2
- package/dist/da-DK.js +2 -2
- package/dist/da-DK.umd.js +2 -2
- package/dist/de-DE.js +2 -2
- package/dist/de-DE.umd.js +2 -2
- package/dist/el-GR.js +2 -2
- package/dist/el-GR.umd.js +2 -2
- package/dist/en-AU.js +2 -2
- package/dist/en-AU.umd.js +2 -2
- package/dist/en-BD.js +2 -2
- package/dist/en-BD.umd.js +2 -2
- package/dist/en-CA.js +2 -2
- package/dist/en-CA.umd.js +2 -2
- package/dist/en-GB.js +2 -2
- package/dist/en-GB.umd.js +2 -2
- package/dist/en-GH.js +2 -2
- package/dist/en-GH.umd.js +2 -2
- package/dist/en-IE.js +2 -2
- package/dist/en-IE.umd.js +2 -2
- package/dist/en-IN.js +2 -2
- package/dist/en-IN.umd.js +2 -2
- package/dist/en-KE.js +2 -2
- package/dist/en-KE.umd.js +2 -2
- package/dist/en-MY.js +2 -2
- package/dist/en-MY.umd.js +2 -2
- package/dist/en-NG.js +2 -2
- package/dist/en-NG.umd.js +2 -2
- package/dist/en-NZ.js +2 -2
- package/dist/en-NZ.umd.js +2 -2
- package/dist/en-PH.js +2 -2
- package/dist/en-PH.umd.js +2 -2
- package/dist/en-PK.js +2 -2
- package/dist/en-PK.umd.js +2 -2
- package/dist/en-SG.js +2 -2
- package/dist/en-SG.umd.js +2 -2
- package/dist/en-US.js +2 -2
- package/dist/en-US.umd.js +2 -2
- package/dist/en-ZA.js +2 -2
- package/dist/en-ZA.umd.js +2 -2
- package/dist/es-ES.js +2 -2
- package/dist/es-ES.umd.js +2 -2
- package/dist/es-MX.js +2 -2
- package/dist/es-MX.umd.js +2 -2
- package/dist/es-US.js +2 -2
- package/dist/es-US.umd.js +2 -2
- package/dist/fa-IR.js +2 -2
- package/dist/fa-IR.umd.js +2 -2
- package/dist/fi-FI.js +2 -2
- package/dist/fi-FI.umd.js +2 -2
- package/dist/fil-PH.js +2 -2
- package/dist/fil-PH.umd.js +2 -2
- package/dist/fr-BE.js +2 -2
- package/dist/fr-BE.umd.js +2 -2
- package/dist/fr-FR.js +2 -2
- package/dist/fr-FR.umd.js +2 -2
- package/dist/gu-IN.js +2 -2
- package/dist/gu-IN.umd.js +2 -2
- package/dist/ha-NG.js +2 -2
- package/dist/ha-NG.umd.js +2 -2
- package/dist/hbo-IL.js +2 -2
- package/dist/hbo-IL.umd.js +2 -2
- package/dist/he-IL.js +2 -2
- package/dist/he-IL.umd.js +2 -2
- package/dist/hi-IN.js +2 -2
- package/dist/hi-IN.umd.js +2 -2
- package/dist/hr-HR.js +2 -2
- package/dist/hr-HR.umd.js +2 -2
- package/dist/hu-HU.js +2 -2
- package/dist/hu-HU.umd.js +2 -2
- package/dist/id-ID.js +2 -2
- package/dist/id-ID.umd.js +2 -2
- package/dist/it-IT.js +2 -2
- package/dist/it-IT.umd.js +2 -2
- package/dist/ja-JP.js +2 -2
- package/dist/ja-JP.umd.js +2 -2
- package/dist/ka-GE.js +2 -2
- package/dist/ka-GE.umd.js +2 -2
- package/dist/kn-IN.js +2 -2
- package/dist/kn-IN.umd.js +2 -2
- package/dist/ko-KR.js +2 -2
- package/dist/ko-KR.umd.js +2 -2
- package/dist/lt-LT.js +2 -2
- package/dist/lt-LT.umd.js +2 -2
- package/dist/lv-LV.js +2 -2
- package/dist/lv-LV.umd.js +2 -2
- package/dist/mr-IN.js +2 -2
- package/dist/mr-IN.umd.js +2 -2
- package/dist/ms-MY.js +2 -2
- package/dist/ms-MY.umd.js +2 -2
- package/dist/nb-NO.js +2 -2
- package/dist/nb-NO.umd.js +2 -2
- package/dist/nl-NL.js +2 -2
- package/dist/nl-NL.umd.js +2 -2
- package/dist/pa-IN.js +2 -2
- package/dist/pa-IN.umd.js +2 -2
- package/dist/pl-PL.js +2 -2
- package/dist/pl-PL.umd.js +2 -2
- package/dist/pt-BR.js +2 -2
- package/dist/pt-BR.umd.js +2 -2
- package/dist/pt-PT.js +2 -2
- package/dist/pt-PT.umd.js +2 -2
- package/dist/ro-RO.js +2 -2
- package/dist/ro-RO.umd.js +2 -2
- package/dist/ru-RU.js +2 -2
- package/dist/ru-RU.umd.js +2 -2
- package/dist/sr-Cyrl-RS.js +2 -2
- package/dist/sr-Cyrl-RS.umd.js +2 -2
- package/dist/sr-Latn-RS.js +2 -2
- package/dist/sr-Latn-RS.umd.js +2 -2
- package/dist/sv-SE.js +2 -2
- package/dist/sv-SE.umd.js +2 -2
- package/dist/sw-KE.js +2 -2
- package/dist/sw-KE.umd.js +2 -2
- package/dist/ta-IN.js +2 -2
- package/dist/ta-IN.umd.js +2 -2
- package/dist/te-IN.js +2 -2
- package/dist/te-IN.umd.js +2 -2
- package/dist/th-TH.js +2 -2
- package/dist/th-TH.umd.js +2 -2
- package/dist/tr-TR.js +2 -2
- package/dist/tr-TR.umd.js +2 -2
- package/dist/uk-UA.js +2 -2
- package/dist/uk-UA.umd.js +2 -2
- package/dist/ur-PK.js +2 -2
- package/dist/ur-PK.umd.js +2 -2
- package/dist/vi-VN.js +2 -2
- package/dist/vi-VN.umd.js +2 -2
- package/dist/yo-NG.js +2 -2
- package/dist/yo-NG.umd.js +2 -2
- package/dist/zh-Hans-CN.js +2 -2
- package/dist/zh-Hans-CN.umd.js +2 -2
- package/dist/zh-Hant-TW.js +2 -2
- package/dist/zh-Hant-TW.umd.js +2 -2
- package/package.json +33 -24
- package/src/am-ET.d.ts +3 -5
- package/src/am-ET.js +41 -16
- package/src/am-Latn-ET.d.ts +3 -5
- package/src/am-Latn-ET.js +45 -16
- package/src/ar-SA.d.ts +44 -18
- package/src/ar-SA.js +93 -40
- package/src/az-AZ.d.ts +3 -5
- package/src/az-AZ.js +58 -20
- package/src/bn-BD.d.ts +3 -5
- package/src/bn-BD.js +32 -16
- package/src/cs-CZ.d.ts +3 -6
- package/src/cs-CZ.js +66 -42
- package/src/da-DK.d.ts +3 -6
- package/src/da-DK.js +53 -48
- package/src/de-DE.d.ts +17 -11
- package/src/de-DE.js +88 -57
- package/src/el-GR.d.ts +3 -6
- package/src/el-GR.js +45 -32
- package/src/en-AU.d.ts +17 -11
- package/src/en-AU.js +56 -41
- package/src/en-BD.d.ts +17 -11
- package/src/en-BD.js +60 -41
- package/src/en-CA.d.ts +36 -18
- package/src/en-CA.js +67 -46
- package/src/en-GB.d.ts +17 -11
- package/src/en-GB.js +56 -41
- package/src/en-GH.d.ts +32 -3
- package/src/en-GH.js +104 -26
- package/src/en-IE.d.ts +17 -11
- package/src/en-IE.js +56 -41
- package/src/en-IN.d.ts +17 -11
- package/src/en-IN.js +60 -41
- package/src/en-KE.d.ts +28 -3
- package/src/en-KE.js +93 -26
- package/src/en-MY.d.ts +26 -3
- package/src/en-MY.js +91 -26
- package/src/en-NG.d.ts +17 -11
- package/src/en-NG.js +56 -41
- package/src/en-NZ.d.ts +32 -3
- package/src/en-NZ.js +85 -31
- package/src/en-PH.d.ts +32 -3
- package/src/en-PH.js +97 -26
- package/src/en-PK.d.ts +17 -11
- package/src/en-PK.js +60 -41
- package/src/en-SG.d.ts +28 -3
- package/src/en-SG.js +93 -26
- package/src/en-US.d.ts +36 -18
- package/src/en-US.js +70 -47
- package/src/en-ZA.d.ts +17 -11
- package/src/en-ZA.js +56 -41
- package/src/es-ES.d.ts +53 -21
- package/src/es-ES.js +104 -56
- package/src/es-MX.d.ts +53 -21
- package/src/es-MX.js +104 -56
- package/src/es-US.d.ts +53 -21
- package/src/es-US.js +92 -51
- package/src/fa-IR.d.ts +3 -5
- package/src/fa-IR.js +28 -13
- package/src/fi-FI.d.ts +3 -6
- package/src/fi-FI.js +47 -29
- package/src/fil-PH.d.ts +3 -5
- package/src/fil-PH.js +61 -28
- package/src/fr-BE.d.ts +31 -15
- package/src/fr-BE.js +128 -57
- package/src/fr-FR.d.ts +31 -16
- package/src/fr-FR.js +97 -60
- package/src/gu-IN.d.ts +3 -5
- package/src/gu-IN.js +31 -16
- package/src/ha-NG.d.ts +3 -5
- package/src/ha-NG.js +55 -27
- package/src/hbo-IL.d.ts +26 -12
- package/src/hbo-IL.js +92 -51
- package/src/he-IL.d.ts +17 -10
- package/src/he-IL.js +92 -50
- package/src/hi-IN.d.ts +3 -5
- package/src/hi-IN.js +30 -17
- package/src/hr-HR.d.ts +21 -10
- package/src/hr-HR.js +89 -33
- package/src/hu-HU.d.ts +3 -5
- package/src/hu-HU.js +57 -23
- package/src/id-ID.d.ts +3 -5
- package/src/id-ID.js +56 -23
- package/src/it-IT.d.ts +17 -11
- package/src/it-IT.js +74 -43
- package/src/ja-JP.d.ts +3 -6
- package/src/ja-JP.js +39 -26
- package/src/ka-GE.d.ts +3 -6
- package/src/ka-GE.js +38 -26
- package/src/kn-IN.d.ts +3 -5
- package/src/kn-IN.js +31 -16
- package/src/ko-KR.d.ts +3 -6
- package/src/ko-KR.js +34 -26
- package/src/lt-LT.d.ts +21 -11
- package/src/lt-LT.js +64 -42
- package/src/lv-LV.d.ts +21 -11
- package/src/lv-LV.js +79 -51
- package/src/mr-IN.d.ts +3 -5
- package/src/mr-IN.js +31 -16
- package/src/ms-MY.d.ts +3 -5
- package/src/ms-MY.js +58 -24
- package/src/nb-NO.d.ts +3 -6
- package/src/nb-NO.js +54 -34
- package/src/nl-NL.d.ts +41 -20
- package/src/nl-NL.js +111 -69
- package/src/pa-IN.d.ts +3 -5
- package/src/pa-IN.js +32 -16
- package/src/pl-PL.d.ts +21 -11
- package/src/pl-PL.js +69 -45
- package/src/pt-BR.d.ts +22 -11
- package/src/pt-BR.js +93 -53
- package/src/pt-PT.d.ts +17 -11
- package/src/pt-PT.js +80 -48
- package/src/ro-RO.d.ts +21 -11
- package/src/ro-RO.js +77 -39
- package/src/ru-RU.d.ts +35 -15
- package/src/ru-RU.js +100 -38
- package/src/sr-Cyrl-RS.d.ts +35 -15
- package/src/sr-Cyrl-RS.js +106 -43
- package/src/sr-Latn-RS.d.ts +35 -15
- package/src/sr-Latn-RS.js +106 -43
- package/src/sv-SE.d.ts +3 -6
- package/src/sv-SE.js +53 -34
- package/src/sw-KE.d.ts +3 -5
- package/src/sw-KE.js +50 -20
- package/src/ta-IN.d.ts +3 -5
- package/src/ta-IN.js +29 -17
- package/src/te-IN.d.ts +3 -5
- package/src/te-IN.js +31 -16
- package/src/th-TH.d.ts +3 -5
- package/src/th-TH.js +42 -19
- package/src/tr-TR.d.ts +17 -11
- package/src/tr-TR.js +63 -37
- package/src/uk-UA.d.ts +21 -10
- package/src/uk-UA.js +89 -33
- package/src/ur-PK.d.ts +3 -5
- package/src/ur-PK.js +32 -16
- package/src/utils/check-max.d.ts +26 -0
- package/src/utils/check-max.js +33 -0
- package/src/utils/expand-scientific.d.ts +0 -4
- package/src/utils/expand-scientific.js +7 -9
- package/src/utils/is-plain-object.d.ts +3 -4
- package/src/utils/is-plain-object.js +3 -4
- package/src/utils/parse-cardinal.d.ts +1 -2
- package/src/utils/parse-cardinal.js +12 -9
- package/src/utils/parse-currency.d.ts +1 -2
- package/src/utils/parse-currency.js +9 -11
- package/src/utils/parse-ordinal.d.ts +0 -1
- package/src/utils/parse-ordinal.js +9 -10
- package/src/utils/resolve-options.d.ts +17 -0
- package/src/utils/resolve-options.js +56 -0
- package/src/utils/scale.d.ts +49 -0
- package/src/utils/scale.js +65 -0
- package/src/vi-VN.d.ts +3 -6
- package/src/vi-VN.js +41 -28
- package/src/yo-NG.d.ts +3 -5
- package/src/yo-NG.js +49 -33
- package/src/zh-Hans-CN.d.ts +45 -20
- package/src/zh-Hans-CN.js +84 -31
- package/src/zh-Hant-TW.d.ts +45 -20
- package/src/zh-Hant-TW.js +85 -34
- package/src/utils/validate-options.d.ts +0 -8
- package/src/utils/validate-options.js +0 -16
package/src/de-DE.js
CHANGED
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
import { parseCardinalValue } from './utils/parse-cardinal.js'
|
|
16
16
|
import { parseCurrencyValue } from './utils/parse-currency.js'
|
|
17
17
|
import { parseOrdinalValue } from './utils/parse-ordinal.js'
|
|
18
|
-
import {
|
|
18
|
+
import { checkMax } from './utils/check-max.js'
|
|
19
|
+
import { western } from './utils/scale.js'
|
|
20
|
+
import { resolveOptions } from './utils/resolve-options.js'
|
|
19
21
|
|
|
20
22
|
// ============================================================================
|
|
21
23
|
// Vocabulary (module-level constants)
|
|
@@ -39,6 +41,15 @@ const SCALES = ['tausend', 'Million', 'Milliarde', 'Billion', 'Billiarde', 'Tril
|
|
|
39
41
|
// Pluralized scale words (million+)
|
|
40
42
|
const SCALES_PLURAL = ['tausend', 'Millionen', 'Milliarden', 'Billionen', 'Billiarden', 'Trillionen', 'Trilliarden', 'Quadrillionen', 'Quadrilliarden']
|
|
41
43
|
|
|
44
|
+
// Supported magnitude ceiling (checked at the public entry points). SCALES is
|
|
45
|
+
// indexed [scaleIndex - 1] starting at 'tausend' (10^3), so segments are
|
|
46
|
+
// [units, then one per SCALES entry] -> ceiling 10^((SCALES.length + 1) * 3) =
|
|
47
|
+
// 10^30. Ordinal (cardinal + suffix) and currency build on the cardinal, and
|
|
48
|
+
// the decimal is spelled via integerToWords, so all share the ceiling.
|
|
49
|
+
export const cardinalMax = western(SCALES.length)
|
|
50
|
+
export const ordinalMax = western(SCALES.length)
|
|
51
|
+
export const currencyMax = western(SCALES.length)
|
|
52
|
+
|
|
42
53
|
const HUNDRED = 'hundert'
|
|
43
54
|
const ZERO = 'null'
|
|
44
55
|
const NEGATIVE = 'minus'
|
|
@@ -75,11 +86,10 @@ const CENT = 'Cent'
|
|
|
75
86
|
/**
|
|
76
87
|
* Builds segment word for 0-999 (standalone form, uses "eins").
|
|
77
88
|
* German inverts ones and tens: "einundzwanzig" = one-and-twenty
|
|
78
|
-
*
|
|
79
89
|
* @param {number} n - Number 0-999
|
|
80
90
|
* @returns {string} German words for the segment
|
|
81
91
|
*/
|
|
82
|
-
function buildSegment
|
|
92
|
+
function buildSegment(n) {
|
|
83
93
|
if (n === 0) return ''
|
|
84
94
|
|
|
85
95
|
const ones = n % 10
|
|
@@ -97,14 +107,17 @@ function buildSegment (n) {
|
|
|
97
107
|
if (tens === 1) {
|
|
98
108
|
// Teens
|
|
99
109
|
result += TEENS[ones]
|
|
100
|
-
}
|
|
110
|
+
}
|
|
111
|
+
else if (tens >= 2 && ones > 0) {
|
|
101
112
|
// Inverted: "einundzwanzig" (one-and-twenty)
|
|
102
113
|
// Use "ein" before "und", not "eins"
|
|
103
114
|
result += (ones === 1 ? EIN : ONES[ones]) + 'und' + TENS[tens]
|
|
104
|
-
}
|
|
115
|
+
}
|
|
116
|
+
else if (tens >= 2) {
|
|
105
117
|
// Just tens
|
|
106
118
|
result += TENS[tens]
|
|
107
|
-
}
|
|
119
|
+
}
|
|
120
|
+
else if (ones > 0) {
|
|
108
121
|
// Just ones (no tens, possibly after hundreds)
|
|
109
122
|
// Use "eins" for standalone/after hundreds
|
|
110
123
|
result += ONES[ones]
|
|
@@ -116,11 +129,10 @@ function buildSegment (n) {
|
|
|
116
129
|
/**
|
|
117
130
|
* Builds segment word for use before "tausend".
|
|
118
131
|
* Uses "ein" instead of "eins" for 1.
|
|
119
|
-
*
|
|
120
132
|
* @param {number} n - Number 0-999
|
|
121
133
|
* @returns {string} German words for thousand context
|
|
122
134
|
*/
|
|
123
|
-
function buildSegmentForThousand
|
|
135
|
+
function buildSegmentForThousand(n) {
|
|
124
136
|
if (n === 0) return ''
|
|
125
137
|
if (n === 1) return EIN // "eintausend"
|
|
126
138
|
|
|
@@ -136,13 +148,17 @@ function buildSegmentForThousand (n) {
|
|
|
136
148
|
|
|
137
149
|
if (tens === 1) {
|
|
138
150
|
result += TEENS[ones]
|
|
139
|
-
}
|
|
151
|
+
}
|
|
152
|
+
else if (tens >= 2 && ones > 0) {
|
|
140
153
|
result += (ones === 1 ? EIN : ONES[ones]) + 'und' + TENS[tens]
|
|
141
|
-
}
|
|
154
|
+
}
|
|
155
|
+
else if (tens >= 2) {
|
|
142
156
|
result += TENS[tens]
|
|
143
|
-
}
|
|
157
|
+
}
|
|
158
|
+
else if (ones > 0 && hundreds > 0) {
|
|
144
159
|
result += ONES[ones]
|
|
145
|
-
}
|
|
160
|
+
}
|
|
161
|
+
else if (ones > 0) {
|
|
146
162
|
result += ONES[ones]
|
|
147
163
|
}
|
|
148
164
|
|
|
@@ -155,11 +171,10 @@ function buildSegmentForThousand (n) {
|
|
|
155
171
|
|
|
156
172
|
/**
|
|
157
173
|
* Converts a non-negative integer to German words.
|
|
158
|
-
*
|
|
159
174
|
* @param {bigint} n - Non-negative integer to convert
|
|
160
175
|
* @returns {string} German words
|
|
161
176
|
*/
|
|
162
|
-
function integerToWords
|
|
177
|
+
function integerToWords(n) {
|
|
163
178
|
if (n === 0n) return ZERO
|
|
164
179
|
|
|
165
180
|
// Fast path: numbers < 1000
|
|
@@ -188,11 +203,10 @@ function integerToWords (n) {
|
|
|
188
203
|
|
|
189
204
|
/**
|
|
190
205
|
* Builds words for numbers >= 1,000,000.
|
|
191
|
-
*
|
|
192
206
|
* @param {bigint} n - Number >= 1,000,000
|
|
193
207
|
* @returns {string} German words
|
|
194
208
|
*/
|
|
195
|
-
function buildLargeNumberWords
|
|
209
|
+
function buildLargeNumberWords(n) {
|
|
196
210
|
const numStr = n.toString()
|
|
197
211
|
const len = numStr.length
|
|
198
212
|
|
|
@@ -222,16 +236,19 @@ function buildLargeNumberWords (n) {
|
|
|
222
236
|
if (scaleIndex === 0) {
|
|
223
237
|
// Units segment (no scale word)
|
|
224
238
|
parts.push({ words: buildSegment(segment), isScale: false, scaleLevel: 0 })
|
|
225
|
-
}
|
|
239
|
+
}
|
|
240
|
+
else if (scaleIndex === 1) {
|
|
226
241
|
// Thousands: compound without space
|
|
227
242
|
const segWords = buildSegmentForThousand(segment)
|
|
228
243
|
parts.push({ words: segWords + SCALES[0], isScale: false, scaleLevel: 1 })
|
|
229
|
-
}
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
230
246
|
// Million+ : space around scale word
|
|
231
247
|
let segWords
|
|
232
248
|
if (segment === 1) {
|
|
233
249
|
segWords = 'eine' // "eine Million"
|
|
234
|
-
}
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
235
252
|
segWords = buildSegment(segment)
|
|
236
253
|
}
|
|
237
254
|
const scaleWord = segment === 1 ? SCALES[scaleIndex - 1] : SCALES_PLURAL[scaleIndex - 1]
|
|
@@ -250,11 +267,10 @@ function buildLargeNumberWords (n) {
|
|
|
250
267
|
/**
|
|
251
268
|
* Joins parts with German spacing rules.
|
|
252
269
|
* Spaces only around million+ scale words.
|
|
253
|
-
*
|
|
254
|
-
* @param {Array} parts - Parts with metadata
|
|
270
|
+
* @param {Array<{words: string, isScale: boolean, scaleLevel: number}>} parts - Parts with metadata
|
|
255
271
|
* @returns {string} Joined string
|
|
256
272
|
*/
|
|
257
|
-
function joinGermanParts
|
|
273
|
+
function joinGermanParts(parts) {
|
|
258
274
|
if (parts.length === 0) return ZERO
|
|
259
275
|
|
|
260
276
|
let result = ''
|
|
@@ -281,11 +297,10 @@ function joinGermanParts (parts) {
|
|
|
281
297
|
|
|
282
298
|
/**
|
|
283
299
|
* Converts decimal digits to German words.
|
|
284
|
-
*
|
|
285
300
|
* @param {string} decimalPart - Decimal digits (without the point)
|
|
286
301
|
* @returns {string} German words for decimal part
|
|
287
302
|
*/
|
|
288
|
-
function decimalPartToWords
|
|
303
|
+
function decimalPartToWords(decimalPart) {
|
|
289
304
|
let result = ''
|
|
290
305
|
|
|
291
306
|
// Handle leading zeros
|
|
@@ -311,19 +326,20 @@ function decimalPartToWords (decimalPart) {
|
|
|
311
326
|
*
|
|
312
327
|
* This is the main public API. It accepts any valid numeric input
|
|
313
328
|
* (number, string, or bigint) and handles parsing internally.
|
|
314
|
-
*
|
|
315
329
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
316
330
|
* @returns {string} The number in German words
|
|
317
331
|
* @throws {TypeError} If value is not a valid numeric type
|
|
318
332
|
* @throws {Error} If value is not a valid number format
|
|
319
|
-
*
|
|
320
333
|
* @example
|
|
321
334
|
* toCardinal(21) // 'einundzwanzig'
|
|
322
335
|
* toCardinal(1000) // 'eintausend'
|
|
323
336
|
* toCardinal(1000000) // 'eine Million'
|
|
324
337
|
*/
|
|
325
|
-
function toCardinal
|
|
338
|
+
function toCardinal(value) {
|
|
326
339
|
const { isNegative, integerPart, decimalPart } = parseCardinalValue(value)
|
|
340
|
+
// Both the integer part and the decimal's significant digits are spelled via
|
|
341
|
+
// the scale builder, so both must clear the ceiling.
|
|
342
|
+
checkMax(integerPart, cardinalMax, decimalPart)
|
|
327
343
|
|
|
328
344
|
let result = ''
|
|
329
345
|
|
|
@@ -348,12 +364,11 @@ function toCardinal (value) {
|
|
|
348
364
|
* Builds ordinal segment for 0-999.
|
|
349
365
|
* Only the final component becomes ordinal.
|
|
350
366
|
* Uses -te for 1-19, -ste for 20+.
|
|
351
|
-
*
|
|
352
367
|
* @param {number} n - Number 0-999
|
|
353
368
|
* @param {boolean} isFinal - Whether this is the final segment (gets ordinal suffix)
|
|
354
369
|
* @returns {string} German ordinal words for this segment
|
|
355
370
|
*/
|
|
356
|
-
function buildOrdinalSegment
|
|
371
|
+
function buildOrdinalSegment(n, isFinal) {
|
|
357
372
|
if (n === 0) return ''
|
|
358
373
|
|
|
359
374
|
const ones = n % 10
|
|
@@ -372,28 +387,35 @@ function buildOrdinalSegment (n, isFinal) {
|
|
|
372
387
|
// Teens: 10-19
|
|
373
388
|
if (isFinal) {
|
|
374
389
|
result += ORDINAL_TEENS[ones]
|
|
375
|
-
}
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
376
392
|
result += TEENS[ones]
|
|
377
393
|
}
|
|
378
|
-
}
|
|
394
|
+
}
|
|
395
|
+
else if (tens >= 2 && ones > 0) {
|
|
379
396
|
// Compound: einundzwanzig → einundzwanzigste
|
|
380
397
|
if (isFinal) {
|
|
381
398
|
result += (ones === 1 ? EIN : ONES[ones]) + 'und' + ORDINAL_TENS[tens]
|
|
382
|
-
}
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
383
401
|
result += (ones === 1 ? EIN : ONES[ones]) + 'und' + TENS[tens]
|
|
384
402
|
}
|
|
385
|
-
}
|
|
403
|
+
}
|
|
404
|
+
else if (tens >= 2) {
|
|
386
405
|
// Just tens: zwanzig → zwanzigste
|
|
387
406
|
if (isFinal) {
|
|
388
407
|
result += ORDINAL_TENS[tens]
|
|
389
|
-
}
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
390
410
|
result += TENS[tens]
|
|
391
411
|
}
|
|
392
|
-
}
|
|
412
|
+
}
|
|
413
|
+
else if (ones > 0) {
|
|
393
414
|
// Just ones: eins → erste
|
|
394
415
|
if (isFinal) {
|
|
395
416
|
result += ORDINAL_ONES[ones]
|
|
396
|
-
}
|
|
417
|
+
}
|
|
418
|
+
else {
|
|
397
419
|
result += ONES[ones]
|
|
398
420
|
}
|
|
399
421
|
}
|
|
@@ -408,11 +430,10 @@ function buildOrdinalSegment (n, isFinal) {
|
|
|
408
430
|
|
|
409
431
|
/**
|
|
410
432
|
* Converts integer to German ordinal words.
|
|
411
|
-
*
|
|
412
433
|
* @param {bigint} n - Positive integer
|
|
413
434
|
* @returns {string} German ordinal words
|
|
414
435
|
*/
|
|
415
|
-
function integerToOrdinal
|
|
436
|
+
function integerToOrdinal(n) {
|
|
416
437
|
// Fast path: numbers < 1000
|
|
417
438
|
if (n < 1000n) {
|
|
418
439
|
return buildOrdinalSegment(Number(n), true)
|
|
@@ -438,11 +459,10 @@ function integerToOrdinal (n) {
|
|
|
438
459
|
|
|
439
460
|
/**
|
|
440
461
|
* Builds ordinal words for numbers >= 1,000,000.
|
|
441
|
-
*
|
|
442
462
|
* @param {bigint} n - Number >= 1,000,000
|
|
443
463
|
* @returns {string} German ordinal words
|
|
444
464
|
*/
|
|
445
|
-
function buildLargeOrdinal
|
|
465
|
+
function buildLargeOrdinal(n) {
|
|
446
466
|
const numStr = n.toString()
|
|
447
467
|
const len = numStr.length
|
|
448
468
|
|
|
@@ -482,27 +502,32 @@ function buildLargeOrdinal (n) {
|
|
|
482
502
|
if (scaleIndex === 0) {
|
|
483
503
|
// Units segment
|
|
484
504
|
parts.push({ words: buildOrdinalSegment(segment, true), isScale: false, scaleLevel: 0 })
|
|
485
|
-
}
|
|
505
|
+
}
|
|
506
|
+
else if (scaleIndex === 1) {
|
|
486
507
|
// Thousands
|
|
487
508
|
const segWords = buildSegmentForThousand(segment)
|
|
488
509
|
if (isLowestSegment) {
|
|
489
510
|
parts.push({ words: segWords + SCALES[0] + ORDINAL_SUFFIX, isScale: false, scaleLevel: 1 })
|
|
490
|
-
}
|
|
511
|
+
}
|
|
512
|
+
else {
|
|
491
513
|
parts.push({ words: segWords + SCALES[0], isScale: false, scaleLevel: 1 })
|
|
492
514
|
}
|
|
493
|
-
}
|
|
515
|
+
}
|
|
516
|
+
else {
|
|
494
517
|
// Million+
|
|
495
518
|
let segWords
|
|
496
519
|
if (segment === 1) {
|
|
497
520
|
segWords = 'eine'
|
|
498
|
-
}
|
|
521
|
+
}
|
|
522
|
+
else {
|
|
499
523
|
segWords = buildSegment(segment)
|
|
500
524
|
}
|
|
501
525
|
const scaleWord = segment === 1 ? SCALES[scaleIndex - 1] : SCALES_PLURAL[scaleIndex - 1]
|
|
502
526
|
parts.push({ words: segWords, isScale: false, scaleLevel: scaleIndex })
|
|
503
527
|
if (isLowestSegment) {
|
|
504
528
|
parts.push({ words: scaleWord + ORDINAL_SUFFIX, isScale: true, scaleLevel: scaleIndex })
|
|
505
|
-
}
|
|
529
|
+
}
|
|
530
|
+
else {
|
|
506
531
|
parts.push({ words: scaleWord, isScale: true, scaleLevel: scaleIndex })
|
|
507
532
|
}
|
|
508
533
|
}
|
|
@@ -519,12 +544,10 @@ function buildLargeOrdinal (n) {
|
|
|
519
544
|
*
|
|
520
545
|
* German ordinals add -te for 1-19 and -ste for 20+.
|
|
521
546
|
* Irregular forms: erste (1st), dritte (3rd), siebte (7th), achte (8th).
|
|
522
|
-
*
|
|
523
547
|
* @param {number | string | bigint} value - The numeric value to convert (positive integer)
|
|
524
548
|
* @returns {string} The number as ordinal words
|
|
525
549
|
* @throws {TypeError} If value is not a valid numeric type
|
|
526
550
|
* @throws {RangeError} If value is negative, zero, or has a decimal part
|
|
527
|
-
*
|
|
528
551
|
* @example
|
|
529
552
|
* toOrdinal(1) // 'erste'
|
|
530
553
|
* toOrdinal(2) // 'zweite'
|
|
@@ -533,8 +556,9 @@ function buildLargeOrdinal (n) {
|
|
|
533
556
|
* toOrdinal(100) // 'einhundertste'
|
|
534
557
|
* toOrdinal(1000) // 'eintausendste'
|
|
535
558
|
*/
|
|
536
|
-
function toOrdinal
|
|
559
|
+
function toOrdinal(value) {
|
|
537
560
|
const integerPart = parseOrdinalValue(value)
|
|
561
|
+
checkMax(integerPart, ordinalMax)
|
|
538
562
|
return integerToOrdinal(integerPart)
|
|
539
563
|
}
|
|
540
564
|
|
|
@@ -542,16 +566,21 @@ function toOrdinal (value) {
|
|
|
542
566
|
// CURRENCY: toCurrency(value, options?)
|
|
543
567
|
// ============================================================================
|
|
544
568
|
|
|
569
|
+
/**
|
|
570
|
+
* @typedef {object} CurrencyOptions
|
|
571
|
+
* @property {boolean} [and] - Use "und" between euros and cents
|
|
572
|
+
*/
|
|
573
|
+
|
|
574
|
+
/** @type {Required<CurrencyOptions>} */
|
|
575
|
+
export const currencyDefaults = { and: true }
|
|
576
|
+
|
|
545
577
|
/**
|
|
546
578
|
* Converts a numeric value to German currency words (Euro).
|
|
547
|
-
*
|
|
548
579
|
* @param {number | string | bigint} value - The currency amount to convert
|
|
549
|
-
* @param {
|
|
550
|
-
* @param {boolean} [options.and=true] - Use "und" between euros and cents
|
|
580
|
+
* @param {CurrencyOptions} [options] - Optional configuration
|
|
551
581
|
* @returns {string} The amount in German currency words
|
|
552
582
|
* @throws {TypeError} If value is not a valid numeric type
|
|
553
583
|
* @throws {Error} If value is not a valid number format
|
|
554
|
-
*
|
|
555
584
|
* @example
|
|
556
585
|
* toCurrency(42.50) // 'zweiundvierzig Euro und fünfzig Cent'
|
|
557
586
|
* toCurrency(1) // 'ein Euro'
|
|
@@ -559,10 +588,10 @@ function toOrdinal (value) {
|
|
|
559
588
|
* toCurrency(0.01) // 'ein Cent'
|
|
560
589
|
* toCurrency(42.50, { and: false }) // 'zweiundvierzig Euro fünfzig Cent'
|
|
561
590
|
*/
|
|
562
|
-
function toCurrency
|
|
563
|
-
options = validateOptions(options)
|
|
591
|
+
function toCurrency(value, options) {
|
|
564
592
|
const { isNegative, dollars: euros, cents } = parseCurrencyValue(value)
|
|
565
|
-
|
|
593
|
+
checkMax(euros, currencyMax)
|
|
594
|
+
const { and: useAnd } = resolveOptions(options, currencyDefaults)
|
|
566
595
|
|
|
567
596
|
// Build result
|
|
568
597
|
let result = ''
|
|
@@ -573,7 +602,8 @@ function toCurrency (value, options) {
|
|
|
573
602
|
// Use "ein" instead of "eins" before Euro
|
|
574
603
|
if (euros === 1n) {
|
|
575
604
|
result += EIN
|
|
576
|
-
}
|
|
605
|
+
}
|
|
606
|
+
else {
|
|
577
607
|
result += integerToWords(euros)
|
|
578
608
|
}
|
|
579
609
|
result += ' ' + EURO
|
|
@@ -587,7 +617,8 @@ function toCurrency (value, options) {
|
|
|
587
617
|
// Use "ein" instead of "eins" before Cent
|
|
588
618
|
if (cents === 1n) {
|
|
589
619
|
result += EIN
|
|
590
|
-
}
|
|
620
|
+
}
|
|
621
|
+
else {
|
|
591
622
|
result += integerToWords(cents)
|
|
592
623
|
}
|
|
593
624
|
result += ' ' + CENT
|
package/src/el-GR.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
+
export const cardinalMax: bigint;
|
|
2
|
+
export const ordinalMax: bigint;
|
|
3
|
+
export const currencyMax: bigint;
|
|
1
4
|
/**
|
|
2
5
|
* Converts a numeric value to Greek words.
|
|
3
|
-
*
|
|
4
6
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
5
7
|
* @returns {string} The number in Greek words
|
|
6
8
|
* @throws {TypeError} If value is not a valid numeric type
|
|
7
9
|
* @throws {Error} If value is not a valid number format
|
|
8
|
-
*
|
|
9
10
|
* @example
|
|
10
11
|
* toCardinal(21) // 'είκοσι ένα'
|
|
11
12
|
* toCardinal(1000) // 'χίλια'
|
|
@@ -14,12 +15,10 @@
|
|
|
14
15
|
export function toCardinal(value: number | string | bigint): string;
|
|
15
16
|
/**
|
|
16
17
|
* Converts a numeric value to Greek ordinal words.
|
|
17
|
-
*
|
|
18
18
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
19
19
|
* @returns {string} The ordinal in Greek words
|
|
20
20
|
* @throws {TypeError} If value is not a valid numeric type
|
|
21
21
|
* @throws {Error} If value is not a positive integer
|
|
22
|
-
*
|
|
23
22
|
* @example
|
|
24
23
|
* toOrdinal(1) // 'πρώτος'
|
|
25
24
|
* toOrdinal(21) // 'εικοστός πρώτος'
|
|
@@ -27,12 +26,10 @@ export function toCardinal(value: number | string | bigint): string;
|
|
|
27
26
|
export function toOrdinal(value: number | string | bigint): string;
|
|
28
27
|
/**
|
|
29
28
|
* Converts a numeric value to Greek Euro currency words.
|
|
30
|
-
*
|
|
31
29
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
32
30
|
* @returns {string} The currency in Greek words
|
|
33
31
|
* @throws {TypeError} If value is not a valid numeric type
|
|
34
32
|
* @throws {Error} If value is not a valid number format
|
|
35
|
-
*
|
|
36
33
|
* @example
|
|
37
34
|
* toCurrency(1) // 'ένα ευρώ'
|
|
38
35
|
* toCurrency(2.50) // 'δύο ευρώ πενήντα λεπτά'
|
package/src/el-GR.js
CHANGED
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { parseCardinalValue } from './utils/parse-cardinal.js'
|
|
14
14
|
import { parseCurrencyValue } from './utils/parse-currency.js'
|
|
15
15
|
import { parseOrdinalValue } from './utils/parse-ordinal.js'
|
|
16
|
+
import { checkMax } from './utils/check-max.js'
|
|
17
|
+
import { bounded, western } from './utils/scale.js'
|
|
16
18
|
|
|
17
19
|
// ============================================================================
|
|
18
20
|
// Vocabulary (module-level constants)
|
|
@@ -36,6 +38,11 @@ const DECIMAL_SEP = 'κόμμα'
|
|
|
36
38
|
// Short scale
|
|
37
39
|
const SCALES = ['εκατομμύριο', 'δισεκατομμύριο', 'τρισεκατομμύριο']
|
|
38
40
|
|
|
41
|
+
// Supported magnitude ceiling (checked at the public entry points), derived from the scale table.
|
|
42
|
+
export const cardinalMax = western(SCALES.length + 1)
|
|
43
|
+
export const ordinalMax = bounded(9)
|
|
44
|
+
export const currencyMax = western(SCALES.length + 1)
|
|
45
|
+
|
|
39
46
|
// Ordinal vocabulary
|
|
40
47
|
const ORDINAL_ONES = ['', 'πρώτος', 'δεύτερος', 'τρίτος', 'τέταρτος', 'πέμπτος', 'έκτος', 'έβδομος', 'όγδοος', 'ένατος']
|
|
41
48
|
|
|
@@ -58,8 +65,10 @@ const CENT_FORMS = ['λεπτό', 'λεπτά'] // Singular, plural
|
|
|
58
65
|
|
|
59
66
|
/**
|
|
60
67
|
* Builds segment word for 0-999.
|
|
68
|
+
* @param {number} n - Number 0-999
|
|
69
|
+
* @returns {string} Greek words for the segment
|
|
61
70
|
*/
|
|
62
|
-
function buildSegment
|
|
71
|
+
function buildSegment(n) {
|
|
63
72
|
if (n === 0) return ''
|
|
64
73
|
|
|
65
74
|
const ones = n % 10
|
|
@@ -78,13 +87,17 @@ function buildSegment (n) {
|
|
|
78
87
|
|
|
79
88
|
if (tensOnes === 0) {
|
|
80
89
|
// Just hundreds
|
|
81
|
-
}
|
|
90
|
+
}
|
|
91
|
+
else if (tensOnes < 10) {
|
|
82
92
|
parts.push(ONES[ones])
|
|
83
|
-
}
|
|
93
|
+
}
|
|
94
|
+
else if (tensOnes < 20) {
|
|
84
95
|
parts.push(TEENS[ones])
|
|
85
|
-
}
|
|
96
|
+
}
|
|
97
|
+
else if (ones === 0) {
|
|
86
98
|
parts.push(TENS[tens])
|
|
87
|
-
}
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
88
101
|
parts.push(TENS[tens] + ' ' + ONES[ones])
|
|
89
102
|
}
|
|
90
103
|
|
|
@@ -97,11 +110,10 @@ function buildSegment (n) {
|
|
|
97
110
|
|
|
98
111
|
/**
|
|
99
112
|
* Converts a non-negative integer to Greek words.
|
|
100
|
-
*
|
|
101
113
|
* @param {bigint} n - Non-negative integer to convert
|
|
102
114
|
* @returns {string} Greek words
|
|
103
115
|
*/
|
|
104
|
-
function integerToWords
|
|
116
|
+
function integerToWords(n) {
|
|
105
117
|
if (n === 0n) return ZERO
|
|
106
118
|
|
|
107
119
|
// Fast path: numbers < 1000 (direct lookup)
|
|
@@ -118,7 +130,8 @@ function integerToWords (n) {
|
|
|
118
130
|
let result
|
|
119
131
|
if (thousands === 1) {
|
|
120
132
|
result = THOUSAND
|
|
121
|
-
}
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
122
135
|
result = buildSegment(thousands) + ' ' + THOUSAND
|
|
123
136
|
}
|
|
124
137
|
|
|
@@ -135,11 +148,10 @@ function integerToWords (n) {
|
|
|
135
148
|
|
|
136
149
|
/**
|
|
137
150
|
* Builds words for numbers >= 1,000,000.
|
|
138
|
-
*
|
|
139
151
|
* @param {bigint} n - Number >= 1,000,000
|
|
140
152
|
* @returns {string} Greek words
|
|
141
153
|
*/
|
|
142
|
-
function buildLargeNumberWords
|
|
154
|
+
function buildLargeNumberWords(n) {
|
|
143
155
|
const numStr = n.toString()
|
|
144
156
|
const len = numStr.length
|
|
145
157
|
|
|
@@ -171,19 +183,23 @@ function buildLargeNumberWords (n) {
|
|
|
171
183
|
if (scaleIndex === 0) {
|
|
172
184
|
// Units segment
|
|
173
185
|
parts.push(segmentWord)
|
|
174
|
-
}
|
|
186
|
+
}
|
|
187
|
+
else if (scaleIndex === 1) {
|
|
175
188
|
// Thousands - omit "ένα" before χίλια
|
|
176
189
|
if (segment === 1) {
|
|
177
190
|
parts.push(THOUSAND)
|
|
178
|
-
}
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
179
193
|
parts.push(segmentWord + ' ' + THOUSAND)
|
|
180
194
|
}
|
|
181
|
-
}
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
182
197
|
// Millions+ - omit "ένα" before scale words
|
|
183
198
|
const scaleWord = SCALES[scaleIndex - 2]
|
|
184
199
|
if (segment === 1) {
|
|
185
200
|
parts.push(scaleWord)
|
|
186
|
-
}
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
187
203
|
parts.push(segmentWord + ' ' + scaleWord)
|
|
188
204
|
}
|
|
189
205
|
}
|
|
@@ -197,18 +213,18 @@ function buildLargeNumberWords (n) {
|
|
|
197
213
|
|
|
198
214
|
/**
|
|
199
215
|
* Converts decimal digits to Greek words (per-digit).
|
|
200
|
-
*
|
|
201
216
|
* @param {string} decimalPart - Decimal digits (without the point)
|
|
202
217
|
* @returns {string} Greek words for decimal part
|
|
203
218
|
*/
|
|
204
|
-
function decimalPartToWords
|
|
219
|
+
function decimalPartToWords(decimalPart) {
|
|
205
220
|
const parts = []
|
|
206
221
|
|
|
207
222
|
for (const digit of decimalPart) {
|
|
208
223
|
const d = parseInt(digit, 10)
|
|
209
224
|
if (d === 0) {
|
|
210
225
|
parts.push(ZERO)
|
|
211
|
-
}
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
212
228
|
parts.push(ONES[d])
|
|
213
229
|
}
|
|
214
230
|
}
|
|
@@ -218,19 +234,18 @@ function decimalPartToWords (decimalPart) {
|
|
|
218
234
|
|
|
219
235
|
/**
|
|
220
236
|
* Converts a numeric value to Greek words.
|
|
221
|
-
*
|
|
222
237
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
223
238
|
* @returns {string} The number in Greek words
|
|
224
239
|
* @throws {TypeError} If value is not a valid numeric type
|
|
225
240
|
* @throws {Error} If value is not a valid number format
|
|
226
|
-
*
|
|
227
241
|
* @example
|
|
228
242
|
* toCardinal(21) // 'είκοσι ένα'
|
|
229
243
|
* toCardinal(1000) // 'χίλια'
|
|
230
244
|
* toCardinal('3.14') // 'τρία κόμμα ένα τέσσερα'
|
|
231
245
|
*/
|
|
232
|
-
function toCardinal
|
|
246
|
+
function toCardinal(value) {
|
|
233
247
|
const { isNegative, integerPart, decimalPart } = parseCardinalValue(value)
|
|
248
|
+
checkMax(integerPart, cardinalMax)
|
|
234
249
|
|
|
235
250
|
let result = ''
|
|
236
251
|
|
|
@@ -253,11 +268,10 @@ function toCardinal (value) {
|
|
|
253
268
|
|
|
254
269
|
/**
|
|
255
270
|
* Builds ordinal for tens and ones (0-99).
|
|
256
|
-
*
|
|
257
271
|
* @param {number} n - Number 0-99
|
|
258
272
|
* @returns {string} Ordinal word
|
|
259
273
|
*/
|
|
260
|
-
function buildOrdinalTensOnes
|
|
274
|
+
function buildOrdinalTensOnes(n) {
|
|
261
275
|
if (n === 0) return ''
|
|
262
276
|
if (n < 10) return ORDINAL_ONES[n]
|
|
263
277
|
if (n < 20) return ORDINAL_TEENS[n - 10]
|
|
@@ -273,11 +287,10 @@ function buildOrdinalTensOnes (n) {
|
|
|
273
287
|
|
|
274
288
|
/**
|
|
275
289
|
* Converts a non-negative integer to Greek ordinal words.
|
|
276
|
-
*
|
|
277
290
|
* @param {bigint} n - Non-negative integer to convert
|
|
278
291
|
* @returns {string} Greek ordinal words
|
|
279
292
|
*/
|
|
280
|
-
function integerToOrdinal
|
|
293
|
+
function integerToOrdinal(n) {
|
|
281
294
|
if (n === 0n) return ''
|
|
282
295
|
if (n === 1n) return ORDINAL_ONES[1]
|
|
283
296
|
|
|
@@ -313,7 +326,8 @@ function integerToOrdinal (n) {
|
|
|
313
326
|
let result
|
|
314
327
|
if (thousands === 1) {
|
|
315
328
|
result = THOUSAND
|
|
316
|
-
}
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
317
331
|
result = buildSegment(thousands) + ' ' + THOUSAND
|
|
318
332
|
}
|
|
319
333
|
|
|
@@ -345,7 +359,8 @@ function integerToOrdinal (n) {
|
|
|
345
359
|
let result
|
|
346
360
|
if (millions === 1) {
|
|
347
361
|
result = SCALES[0]
|
|
348
|
-
}
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
349
364
|
result = buildSegment(millions) + ' ' + SCALES[0]
|
|
350
365
|
}
|
|
351
366
|
|
|
@@ -354,18 +369,17 @@ function integerToOrdinal (n) {
|
|
|
354
369
|
|
|
355
370
|
/**
|
|
356
371
|
* Converts a numeric value to Greek ordinal words.
|
|
357
|
-
*
|
|
358
372
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
359
373
|
* @returns {string} The ordinal in Greek words
|
|
360
374
|
* @throws {TypeError} If value is not a valid numeric type
|
|
361
375
|
* @throws {Error} If value is not a positive integer
|
|
362
|
-
*
|
|
363
376
|
* @example
|
|
364
377
|
* toOrdinal(1) // 'πρώτος'
|
|
365
378
|
* toOrdinal(21) // 'εικοστός πρώτος'
|
|
366
379
|
*/
|
|
367
|
-
function toOrdinal
|
|
380
|
+
function toOrdinal(value) {
|
|
368
381
|
const n = parseOrdinalValue(value)
|
|
382
|
+
checkMax(n, ordinalMax)
|
|
369
383
|
return integerToOrdinal(n)
|
|
370
384
|
}
|
|
371
385
|
|
|
@@ -375,18 +389,17 @@ function toOrdinal (value) {
|
|
|
375
389
|
|
|
376
390
|
/**
|
|
377
391
|
* Converts a numeric value to Greek Euro currency words.
|
|
378
|
-
*
|
|
379
392
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
380
393
|
* @returns {string} The currency in Greek words
|
|
381
394
|
* @throws {TypeError} If value is not a valid numeric type
|
|
382
395
|
* @throws {Error} If value is not a valid number format
|
|
383
|
-
*
|
|
384
396
|
* @example
|
|
385
397
|
* toCurrency(1) // 'ένα ευρώ'
|
|
386
398
|
* toCurrency(2.50) // 'δύο ευρώ πενήντα λεπτά'
|
|
387
399
|
*/
|
|
388
|
-
function toCurrency
|
|
400
|
+
function toCurrency(value) {
|
|
389
401
|
const { isNegative, dollars, cents } = parseCurrencyValue(value)
|
|
402
|
+
checkMax(dollars, currencyMax)
|
|
390
403
|
|
|
391
404
|
const parts = []
|
|
392
405
|
|