n2words 5.0.0 → 5.1.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 +128 -42
- 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 +31 -22
- 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 +100 -38
- package/src/sr-Latn-RS.d.ts +35 -15
- package/src/sr-Latn-RS.js +100 -38
- 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/hr-HR.js
CHANGED
|
@@ -13,7 +13,9 @@
|
|
|
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 {
|
|
16
|
+
import { checkMax } from './utils/check-max.js'
|
|
17
|
+
import { western } from './utils/scale.js'
|
|
18
|
+
import { resolveOptions } from './utils/resolve-options.js'
|
|
17
19
|
|
|
18
20
|
// ============================================================================
|
|
19
21
|
// Vocabulary
|
|
@@ -71,14 +73,20 @@ const SCALE_FORMS = [
|
|
|
71
73
|
['trilijun', 'trilijuna', 'trilijuna'],
|
|
72
74
|
['trilijarda', 'trilijarde', 'trilijarda'],
|
|
73
75
|
['kvadrilijun', 'kvadrilijuna', 'kvadrilijuna'],
|
|
74
|
-
['kvadrilijarda', 'kvadrilijarde', 'kvadrilijarda']
|
|
76
|
+
['kvadrilijarda', 'kvadrilijarde', 'kvadrilijarda'],
|
|
75
77
|
]
|
|
76
78
|
|
|
77
79
|
// ============================================================================
|
|
78
80
|
// Segment Building
|
|
79
81
|
// ============================================================================
|
|
80
82
|
|
|
81
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Selects the correct plural form for a count.
|
|
85
|
+
* @param {number | bigint} n - The count
|
|
86
|
+
* @param {string[]} forms - The [one, few, many] plural forms
|
|
87
|
+
* @returns {string} The selected plural form
|
|
88
|
+
*/
|
|
89
|
+
function pluralize(n, forms) {
|
|
82
90
|
const num = typeof n === 'bigint' ? Number(n) : n
|
|
83
91
|
const lastDigit = num % 10
|
|
84
92
|
const lastTwoDigits = num % 100
|
|
@@ -92,7 +100,12 @@ function pluralize (n, forms) {
|
|
|
92
100
|
return forms[2]
|
|
93
101
|
}
|
|
94
102
|
|
|
95
|
-
|
|
103
|
+
/**
|
|
104
|
+
* Builds the masculine words for a 0-999 segment.
|
|
105
|
+
* @param {number} n - Number 0-999
|
|
106
|
+
* @returns {string} The segment words
|
|
107
|
+
*/
|
|
108
|
+
function buildSegmentMasc(n) {
|
|
96
109
|
if (n === 0) return ''
|
|
97
110
|
|
|
98
111
|
const onesDigit = n % 10
|
|
@@ -111,14 +124,20 @@ function buildSegmentMasc (n) {
|
|
|
111
124
|
|
|
112
125
|
if (tensDigit === 1) {
|
|
113
126
|
parts.push(TEENS[onesDigit])
|
|
114
|
-
}
|
|
127
|
+
}
|
|
128
|
+
else if (onesDigit > 0) {
|
|
115
129
|
parts.push(ONES_MASC[onesDigit])
|
|
116
130
|
}
|
|
117
131
|
|
|
118
132
|
return parts.join(' ')
|
|
119
133
|
}
|
|
120
134
|
|
|
121
|
-
|
|
135
|
+
/**
|
|
136
|
+
* Builds the feminine words for a 0-999 segment.
|
|
137
|
+
* @param {number} n - Number 0-999
|
|
138
|
+
* @returns {string} The segment words
|
|
139
|
+
*/
|
|
140
|
+
function buildSegmentFem(n) {
|
|
122
141
|
if (n === 0) return ''
|
|
123
142
|
|
|
124
143
|
const onesDigit = n % 10
|
|
@@ -137,7 +156,8 @@ function buildSegmentFem (n) {
|
|
|
137
156
|
|
|
138
157
|
if (tensDigit === 1) {
|
|
139
158
|
parts.push(TEENS[onesDigit])
|
|
140
|
-
}
|
|
159
|
+
}
|
|
160
|
+
else if (onesDigit > 0) {
|
|
141
161
|
parts.push(ONES_FEM[onesDigit])
|
|
142
162
|
}
|
|
143
163
|
|
|
@@ -148,7 +168,13 @@ function buildSegmentFem (n) {
|
|
|
148
168
|
// Conversion Functions
|
|
149
169
|
// ============================================================================
|
|
150
170
|
|
|
151
|
-
|
|
171
|
+
/**
|
|
172
|
+
* Converts a non-negative integer to Croatian words.
|
|
173
|
+
* @param {bigint} n - Non-negative integer to convert
|
|
174
|
+
* @param {('masculine'|'feminine')} gender - Grammatical gender
|
|
175
|
+
* @returns {string} The number in Croatian words
|
|
176
|
+
*/
|
|
177
|
+
function integerToWords(n, gender) {
|
|
152
178
|
if (n === 0n) return ZERO
|
|
153
179
|
|
|
154
180
|
if (n < 1000n) {
|
|
@@ -158,7 +184,13 @@ function integerToWords (n, gender) {
|
|
|
158
184
|
return buildLargeNumberWords(n, gender)
|
|
159
185
|
}
|
|
160
186
|
|
|
161
|
-
|
|
187
|
+
/**
|
|
188
|
+
* Builds words for numbers >= 1000.
|
|
189
|
+
* @param {bigint} n - Number >= 1000
|
|
190
|
+
* @param {('masculine'|'feminine')} gender - Grammatical gender
|
|
191
|
+
* @returns {string} The number in Croatian words
|
|
192
|
+
*/
|
|
193
|
+
function buildLargeNumberWords(n, gender) {
|
|
162
194
|
const numStr = n.toString()
|
|
163
195
|
const len = numStr.length
|
|
164
196
|
|
|
@@ -185,7 +217,8 @@ function buildLargeNumberWords (n, gender) {
|
|
|
185
217
|
if (segment !== 0) {
|
|
186
218
|
if (scaleIndex === 0) {
|
|
187
219
|
parts.push(gender === 'feminine' ? buildSegmentFem(segment) : buildSegmentMasc(segment))
|
|
188
|
-
}
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
189
222
|
const scaleForms = SCALE_FORMS[scaleIndex - 1]
|
|
190
223
|
const scaleWord = pluralize(segment, scaleForms)
|
|
191
224
|
// Thousands (scaleIndex=1) are feminine, others masculine
|
|
@@ -201,7 +234,13 @@ function buildLargeNumberWords (n, gender) {
|
|
|
201
234
|
return parts.join(' ')
|
|
202
235
|
}
|
|
203
236
|
|
|
204
|
-
|
|
237
|
+
/**
|
|
238
|
+
* Converts the decimal-part digit string to Croatian words.
|
|
239
|
+
* @param {string} decimalPart - The decimal digits as a string
|
|
240
|
+
* @param {('masculine'|'feminine')} gender - Grammatical gender
|
|
241
|
+
* @returns {string} The decimal part in Croatian words
|
|
242
|
+
*/
|
|
243
|
+
function decimalPartToWords(decimalPart, gender) {
|
|
205
244
|
let result = ''
|
|
206
245
|
let i = 0
|
|
207
246
|
|
|
@@ -220,20 +259,38 @@ function decimalPartToWords (decimalPart, gender) {
|
|
|
220
259
|
return result
|
|
221
260
|
}
|
|
222
261
|
|
|
262
|
+
// Supported magnitude ceilings (checked at the public entry points). Both
|
|
263
|
+
// tables are indexed [scaleIndex - 1] (units separate), so the ceiling is
|
|
264
|
+
// 10^((length + 1) * 3): cardinal/currency 10^30, ordinal 10^15.
|
|
265
|
+
export const cardinalMax = western(SCALE_FORMS.length)
|
|
266
|
+
export const ordinalMax = western(ORDINAL_SCALES.length)
|
|
267
|
+
export const currencyMax = western(SCALE_FORMS.length)
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* @typedef {object} CardinalOptions
|
|
271
|
+
* @property {('masculine'|'feminine')} [gender] - Grammatical gender
|
|
272
|
+
*/
|
|
273
|
+
|
|
274
|
+
/** @type {Required<CardinalOptions>} */
|
|
275
|
+
export const cardinalDefaults = { gender: 'masculine' }
|
|
276
|
+
|
|
277
|
+
/** @type {{ gender: ReadonlyArray<Required<CardinalOptions>['gender']> }} */
|
|
278
|
+
export const cardinalValues = { gender: ['masculine', 'feminine'] }
|
|
279
|
+
|
|
223
280
|
/**
|
|
224
281
|
* Converts a numeric value to Croatian words.
|
|
225
|
-
*
|
|
226
282
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
227
|
-
* @param {
|
|
228
|
-
* @param {('masculine'|'feminine')} [options.gender='masculine'] - Grammatical gender
|
|
283
|
+
* @param {CardinalOptions} [options] - Optional configuration
|
|
229
284
|
* @returns {string} The number in Croatian words
|
|
230
285
|
*/
|
|
231
|
-
function toCardinal
|
|
232
|
-
options = validateOptions(options)
|
|
286
|
+
function toCardinal(value, options) {
|
|
233
287
|
const { isNegative, integerPart, decimalPart } = parseCardinalValue(value)
|
|
288
|
+
// Both the integer part and the decimal's significant digits are spelled via
|
|
289
|
+
// the scale builder, so both must clear the ceiling.
|
|
290
|
+
checkMax(integerPart, cardinalMax, decimalPart)
|
|
234
291
|
|
|
235
292
|
// Apply option defaults
|
|
236
|
-
const { gender
|
|
293
|
+
const { gender } = resolveOptions(options, cardinalDefaults, cardinalValues)
|
|
237
294
|
|
|
238
295
|
let result = ''
|
|
239
296
|
|
|
@@ -256,11 +313,10 @@ function toCardinal (value, options) {
|
|
|
256
313
|
|
|
257
314
|
/**
|
|
258
315
|
* Builds ordinal for a 0-99 segment when it's the final (ordinal) part.
|
|
259
|
-
*
|
|
260
316
|
* @param {number} n - Number 0-99
|
|
261
317
|
* @returns {string} Ordinal words
|
|
262
318
|
*/
|
|
263
|
-
function buildOrdinalTensOnes
|
|
319
|
+
function buildOrdinalTensOnes(n) {
|
|
264
320
|
if (n === 0) return ''
|
|
265
321
|
|
|
266
322
|
const onesDigit = n % 10
|
|
@@ -283,11 +339,10 @@ function buildOrdinalTensOnes (n) {
|
|
|
283
339
|
|
|
284
340
|
/**
|
|
285
341
|
* Converts a positive integer to Croatian ordinal words (masculine nominative).
|
|
286
|
-
*
|
|
287
342
|
* @param {bigint} n - Positive integer to convert
|
|
288
343
|
* @returns {string} Ordinal Croatian words
|
|
289
344
|
*/
|
|
290
|
-
function integerToOrdinal
|
|
345
|
+
function integerToOrdinal(n) {
|
|
291
346
|
if (n < 100n) {
|
|
292
347
|
return buildOrdinalTensOnes(Number(n))
|
|
293
348
|
}
|
|
@@ -325,11 +380,10 @@ function integerToOrdinal (n) {
|
|
|
325
380
|
|
|
326
381
|
/**
|
|
327
382
|
* Builds ordinal words for numbers >= 1,000,000.
|
|
328
|
-
*
|
|
329
383
|
* @param {bigint} n - Number >= 1,000,000
|
|
330
384
|
* @returns {string} Ordinal Croatian words
|
|
331
385
|
*/
|
|
332
|
-
function buildLargeOrdinal
|
|
386
|
+
function buildLargeOrdinal(n) {
|
|
333
387
|
const numStr = n.toString()
|
|
334
388
|
const len = numStr.length
|
|
335
389
|
|
|
@@ -364,19 +418,23 @@ function buildLargeOrdinal (n) {
|
|
|
364
418
|
if (scaleIndex === 0) {
|
|
365
419
|
if (isLastNonZero) {
|
|
366
420
|
parts.push(integerToOrdinal(BigInt(segment)))
|
|
367
|
-
}
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
368
423
|
parts.push(buildSegmentMasc(segment))
|
|
369
424
|
}
|
|
370
|
-
}
|
|
425
|
+
}
|
|
426
|
+
else {
|
|
371
427
|
if (isLastNonZero) {
|
|
372
428
|
if (segment === 1) {
|
|
373
429
|
parts.push(ORDINAL_SCALES[scaleIndex - 1])
|
|
374
|
-
}
|
|
430
|
+
}
|
|
431
|
+
else {
|
|
375
432
|
const isFeminine = scaleIndex === 1
|
|
376
433
|
const segmentWord = isFeminine ? buildSegmentFem(segment) : buildSegmentMasc(segment)
|
|
377
434
|
parts.push(segmentWord + ' ' + ORDINAL_SCALES[scaleIndex - 1])
|
|
378
435
|
}
|
|
379
|
-
}
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
380
438
|
const scaleForms = SCALE_FORMS[scaleIndex - 1]
|
|
381
439
|
const scaleWord = pluralize(segment, scaleForms)
|
|
382
440
|
const isFeminine = scaleIndex === 1
|
|
@@ -394,12 +452,10 @@ function buildLargeOrdinal (n) {
|
|
|
394
452
|
|
|
395
453
|
/**
|
|
396
454
|
* Converts a numeric value to Croatian ordinal words (masculine nominative).
|
|
397
|
-
*
|
|
398
455
|
* @param {number | string | bigint} value - The numeric value to convert (must be a positive integer)
|
|
399
456
|
* @returns {string} The number as ordinal words
|
|
400
457
|
* @throws {TypeError} If value is not a valid numeric type
|
|
401
458
|
* @throws {RangeError} If value is negative, zero, or has a decimal part
|
|
402
|
-
*
|
|
403
459
|
* @example
|
|
404
460
|
* toOrdinal(1) // 'prvi'
|
|
405
461
|
* toOrdinal(2) // 'drugi'
|
|
@@ -407,8 +463,9 @@ function buildLargeOrdinal (n) {
|
|
|
407
463
|
* toOrdinal(100) // 'stoti'
|
|
408
464
|
* toOrdinal(1000) // 'tisućiti'
|
|
409
465
|
*/
|
|
410
|
-
function toOrdinal
|
|
466
|
+
function toOrdinal(value) {
|
|
411
467
|
const integerPart = parseOrdinalValue(value)
|
|
468
|
+
checkMax(integerPart, ordinalMax)
|
|
412
469
|
return integerToOrdinal(integerPart)
|
|
413
470
|
}
|
|
414
471
|
|
|
@@ -418,20 +475,19 @@ function toOrdinal (value) {
|
|
|
418
475
|
|
|
419
476
|
/**
|
|
420
477
|
* Converts a numeric value to Croatian currency words (Euro).
|
|
421
|
-
*
|
|
422
478
|
* @param {number | string | bigint} value - The currency amount to convert
|
|
423
479
|
* @returns {string} The amount in Croatian currency words
|
|
424
480
|
* @throws {TypeError} If value is not a valid numeric type
|
|
425
481
|
* @throws {Error} If value is not a valid number format
|
|
426
|
-
*
|
|
427
482
|
* @example
|
|
428
483
|
* toCurrency(42) // 'četrdeset dva eura'
|
|
429
484
|
* toCurrency(1) // 'jedan euro'
|
|
430
485
|
* toCurrency(1.50) // 'jedan euro pedeset centi'
|
|
431
486
|
* toCurrency(-5) // 'minus pet eura'
|
|
432
487
|
*/
|
|
433
|
-
function toCurrency
|
|
488
|
+
function toCurrency(value) {
|
|
434
489
|
const { isNegative, dollars: euros, cents } = parseCurrencyValue(value)
|
|
490
|
+
checkMax(euros, currencyMax)
|
|
435
491
|
|
|
436
492
|
let result = ''
|
|
437
493
|
if (isNegative) {
|
package/src/hu-HU.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
+
export const cardinalMax: null;
|
|
2
|
+
export const ordinalMax: null;
|
|
3
|
+
export const currencyMax: null;
|
|
1
4
|
/**
|
|
2
5
|
* Converts a numeric value to Hungarian words.
|
|
3
|
-
*
|
|
4
6
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
5
7
|
* @returns {string} The number in Hungarian words
|
|
6
8
|
*/
|
|
7
9
|
export function toCardinal(value: number | string | bigint): string;
|
|
8
10
|
/**
|
|
9
11
|
* Converts a numeric value to Hungarian ordinal words.
|
|
10
|
-
*
|
|
11
12
|
* @param {number | string | bigint} value - The numeric value to convert (positive integer)
|
|
12
13
|
* @returns {string} The number as ordinal words
|
|
13
14
|
* @throws {TypeError} If value is not a valid numeric type
|
|
14
15
|
* @throws {RangeError} If value is negative, zero, or has a decimal part
|
|
15
|
-
*
|
|
16
16
|
* @example
|
|
17
17
|
* toOrdinal(1) // 'első'
|
|
18
18
|
* toOrdinal(2) // 'második'
|
|
@@ -24,12 +24,10 @@ export function toOrdinal(value: number | string | bigint): string;
|
|
|
24
24
|
*
|
|
25
25
|
* Uses forint (no plural form needed in Hungarian).
|
|
26
26
|
* Fillér (1/100) is rarely used but included for completeness.
|
|
27
|
-
*
|
|
28
27
|
* @param {number | string | bigint} value - The currency amount to convert
|
|
29
28
|
* @returns {string} The amount in Hungarian currency words
|
|
30
29
|
* @throws {TypeError} If value is not a valid numeric type
|
|
31
30
|
* @throws {Error} If value is not a valid number format
|
|
32
|
-
*
|
|
33
31
|
* @example
|
|
34
32
|
* toCurrency(42) // 'negyvenkettő forint'
|
|
35
33
|
* toCurrency(1.50) // 'egy forint ötven fillér'
|
package/src/hu-HU.js
CHANGED
|
@@ -13,6 +13,12 @@
|
|
|
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 { UNBOUNDED } from './utils/scale.js'
|
|
17
|
+
|
|
18
|
+
// No fixed scale ceiling — the speller composes every magnitude.
|
|
19
|
+
export const cardinalMax = UNBOUNDED
|
|
20
|
+
export const ordinalMax = UNBOUNDED
|
|
21
|
+
export const currencyMax = UNBOUNDED
|
|
16
22
|
|
|
17
23
|
// ============================================================================
|
|
18
24
|
// Vocabulary
|
|
@@ -66,7 +72,7 @@ const WORDS = new Map([
|
|
|
66
72
|
[3n, 'három'],
|
|
67
73
|
[2n, 'kettő'],
|
|
68
74
|
[1n, 'egy'],
|
|
69
|
-
[0n, 'nulla']
|
|
75
|
+
[0n, 'nulla'],
|
|
70
76
|
])
|
|
71
77
|
|
|
72
78
|
const ZERO = 'nulla'
|
|
@@ -79,6 +85,7 @@ const DECIMAL_SEP = 'egész'
|
|
|
79
85
|
|
|
80
86
|
// Hungarian ordinals: special forms 1-10, then cardinal + -dik/-ik suffix
|
|
81
87
|
// Vowel harmony determines -dik vs -ik
|
|
88
|
+
/** @type {Record<number, string>} */
|
|
82
89
|
const ORDINAL_SPECIAL = {
|
|
83
90
|
1: 'első',
|
|
84
91
|
2: 'második',
|
|
@@ -99,7 +106,7 @@ const ORDINAL_SPECIAL = {
|
|
|
99
106
|
80: 'nyolcvanadik',
|
|
100
107
|
90: 'kilencvenedik',
|
|
101
108
|
100: 'századik',
|
|
102
|
-
1000: 'ezredik'
|
|
109
|
+
1000: 'ezredik',
|
|
103
110
|
}
|
|
104
111
|
|
|
105
112
|
// ============================================================================
|
|
@@ -113,20 +120,32 @@ const FILLER = 'fillér' // subunit (rarely used, same singular and plural)
|
|
|
113
120
|
// Conversion Functions
|
|
114
121
|
// ============================================================================
|
|
115
122
|
|
|
116
|
-
|
|
123
|
+
/**
|
|
124
|
+
* @param {bigint} value The scale or vocabulary key to look up
|
|
125
|
+
* @returns {string | undefined} The Hungarian word for the key, or undefined if absent
|
|
126
|
+
*/
|
|
127
|
+
function wordForScale(value) {
|
|
117
128
|
return WORDS.get(value)
|
|
118
129
|
}
|
|
119
130
|
|
|
120
|
-
|
|
131
|
+
/**
|
|
132
|
+
* @param {bigint} n The integer (under 100) to convert
|
|
133
|
+
* @returns {string} The number in Hungarian words
|
|
134
|
+
*/
|
|
135
|
+
function tensToCardinal(n) {
|
|
121
136
|
if (WORDS.has(n)) {
|
|
122
|
-
return WORDS.get(n)
|
|
137
|
+
return /** @type {string} */ (WORDS.get(n))
|
|
123
138
|
}
|
|
124
139
|
const tens = n / 10n
|
|
125
140
|
const units = n % 10n
|
|
126
141
|
return wordForScale(tens * 10n) + integerToWordsInner(units)
|
|
127
142
|
}
|
|
128
143
|
|
|
129
|
-
|
|
144
|
+
/**
|
|
145
|
+
* @param {bigint} n The integer (under 1000) to convert
|
|
146
|
+
* @returns {string} The number in Hungarian words
|
|
147
|
+
*/
|
|
148
|
+
function hundredsToCardinal(n) {
|
|
130
149
|
const hundreds = n / 100n
|
|
131
150
|
let prefix = 'száz'
|
|
132
151
|
if (hundreds !== 1n) {
|
|
@@ -136,7 +155,11 @@ function hundredsToCardinal (n) {
|
|
|
136
155
|
return prefix + postfix
|
|
137
156
|
}
|
|
138
157
|
|
|
139
|
-
|
|
158
|
+
/**
|
|
159
|
+
* @param {bigint} n The integer (under one million) to convert
|
|
160
|
+
* @returns {string} The number in Hungarian words
|
|
161
|
+
*/
|
|
162
|
+
function thousandsToCardinal(n) {
|
|
140
163
|
const thousands = n / 1000n
|
|
141
164
|
let prefix = 'ezer'
|
|
142
165
|
if (thousands !== 1n) {
|
|
@@ -156,10 +179,14 @@ const SCALES = [
|
|
|
156
179
|
1_000_000_000_000_000n,
|
|
157
180
|
1_000_000_000_000n,
|
|
158
181
|
1_000_000_000n,
|
|
159
|
-
1_000_000n
|
|
182
|
+
1_000_000n,
|
|
160
183
|
]
|
|
161
184
|
|
|
162
|
-
|
|
185
|
+
/**
|
|
186
|
+
* @param {bigint} n The integer (one million or greater) to convert
|
|
187
|
+
* @returns {string} The number in Hungarian words
|
|
188
|
+
*/
|
|
189
|
+
function bigNumberToCardinal(n) {
|
|
163
190
|
// Find appropriate scale using BigInt comparison (avoids toString)
|
|
164
191
|
let exp = 1_000_000n
|
|
165
192
|
for (const scale of SCALES) {
|
|
@@ -175,7 +202,12 @@ function bigNumberToCardinal (n) {
|
|
|
175
202
|
return prefix + wordForScale(exp) + postfix
|
|
176
203
|
}
|
|
177
204
|
|
|
178
|
-
|
|
205
|
+
/**
|
|
206
|
+
* @param {bigint} n The integer to convert
|
|
207
|
+
* @param {string} [zeroWord] The word to use for zero (empty string in compound contexts)
|
|
208
|
+
* @returns {string} The number in Hungarian words
|
|
209
|
+
*/
|
|
210
|
+
function integerToWordsInner(n, zeroWord = ZERO) {
|
|
179
211
|
// Normalize to BigInt for consistent comparisons
|
|
180
212
|
if (typeof n !== 'bigint') n = BigInt(n)
|
|
181
213
|
|
|
@@ -186,7 +218,7 @@ function integerToWordsInner (n, zeroWord = ZERO) {
|
|
|
186
218
|
return 'két'
|
|
187
219
|
}
|
|
188
220
|
if (n < 30n) {
|
|
189
|
-
return wordForScale(n)
|
|
221
|
+
return /** @type {string} */ (wordForScale(n))
|
|
190
222
|
}
|
|
191
223
|
if (n < 100n) {
|
|
192
224
|
return tensToCardinal(n)
|
|
@@ -200,11 +232,19 @@ function integerToWordsInner (n, zeroWord = ZERO) {
|
|
|
200
232
|
return bigNumberToCardinal(n)
|
|
201
233
|
}
|
|
202
234
|
|
|
203
|
-
|
|
235
|
+
/**
|
|
236
|
+
* @param {bigint} n The integer to convert
|
|
237
|
+
* @returns {string} The number in Hungarian words
|
|
238
|
+
*/
|
|
239
|
+
function integerToWords(n) {
|
|
204
240
|
return integerToWordsInner(n, ZERO)
|
|
205
241
|
}
|
|
206
242
|
|
|
207
|
-
|
|
243
|
+
/**
|
|
244
|
+
* @param {string} decimalPart The decimal digits (after the separator) to convert
|
|
245
|
+
* @returns {string} The decimal digits in Hungarian words
|
|
246
|
+
*/
|
|
247
|
+
function decimalPartToWords(decimalPart) {
|
|
208
248
|
let result = ''
|
|
209
249
|
let i = 0
|
|
210
250
|
|
|
@@ -225,11 +265,10 @@ function decimalPartToWords (decimalPart) {
|
|
|
225
265
|
|
|
226
266
|
/**
|
|
227
267
|
* Converts a numeric value to Hungarian words.
|
|
228
|
-
*
|
|
229
268
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
230
269
|
* @returns {string} The number in Hungarian words
|
|
231
270
|
*/
|
|
232
|
-
function toCardinal
|
|
271
|
+
function toCardinal(value) {
|
|
233
272
|
const { isNegative, integerPart, decimalPart } = parseCardinalValue(value)
|
|
234
273
|
|
|
235
274
|
let result = ''
|
|
@@ -256,11 +295,10 @@ function toCardinal (value) {
|
|
|
256
295
|
*
|
|
257
296
|
* Hungarian ordinals: első (1st), második (2nd), harmadik (3rd), etc.
|
|
258
297
|
* 1-10 have special forms, others use cardinal + -dik/-edik/-adik/-ödik suffix.
|
|
259
|
-
*
|
|
260
298
|
* @param {bigint} n - Positive integer to convert
|
|
261
299
|
* @returns {string} Hungarian ordinal words
|
|
262
300
|
*/
|
|
263
|
-
function integerToOrdinal
|
|
301
|
+
function integerToOrdinal(n) {
|
|
264
302
|
const num = Number(n)
|
|
265
303
|
|
|
266
304
|
// Exact special forms
|
|
@@ -307,18 +345,16 @@ function integerToOrdinal (n) {
|
|
|
307
345
|
|
|
308
346
|
/**
|
|
309
347
|
* Converts a numeric value to Hungarian ordinal words.
|
|
310
|
-
*
|
|
311
348
|
* @param {number | string | bigint} value - The numeric value to convert (positive integer)
|
|
312
349
|
* @returns {string} The number as ordinal words
|
|
313
350
|
* @throws {TypeError} If value is not a valid numeric type
|
|
314
351
|
* @throws {RangeError} If value is negative, zero, or has a decimal part
|
|
315
|
-
*
|
|
316
352
|
* @example
|
|
317
353
|
* toOrdinal(1) // 'első'
|
|
318
354
|
* toOrdinal(2) // 'második'
|
|
319
355
|
* toOrdinal(21) // 'huszonegyedik'
|
|
320
356
|
*/
|
|
321
|
-
function toOrdinal
|
|
357
|
+
function toOrdinal(value) {
|
|
322
358
|
const integerPart = parseOrdinalValue(value)
|
|
323
359
|
return integerToOrdinal(integerPart)
|
|
324
360
|
}
|
|
@@ -332,18 +368,16 @@ function toOrdinal (value) {
|
|
|
332
368
|
*
|
|
333
369
|
* Uses forint (no plural form needed in Hungarian).
|
|
334
370
|
* Fillér (1/100) is rarely used but included for completeness.
|
|
335
|
-
*
|
|
336
371
|
* @param {number | string | bigint} value - The currency amount to convert
|
|
337
372
|
* @returns {string} The amount in Hungarian currency words
|
|
338
373
|
* @throws {TypeError} If value is not a valid numeric type
|
|
339
374
|
* @throws {Error} If value is not a valid number format
|
|
340
|
-
*
|
|
341
375
|
* @example
|
|
342
376
|
* toCurrency(42) // 'negyvenkettő forint'
|
|
343
377
|
* toCurrency(1.50) // 'egy forint ötven fillér'
|
|
344
378
|
* toCurrency(-5) // 'mínusz öt forint'
|
|
345
379
|
*/
|
|
346
|
-
function toCurrency
|
|
380
|
+
function toCurrency(value) {
|
|
347
381
|
const { isNegative, dollars: forint, cents: filler } = parseCurrencyValue(value)
|
|
348
382
|
|
|
349
383
|
let result = ''
|
package/src/id-ID.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
+
export const cardinalMax: bigint;
|
|
2
|
+
export const ordinalMax: bigint;
|
|
3
|
+
export const currencyMax: bigint;
|
|
1
4
|
/**
|
|
2
5
|
* Converts a numeric value to Indonesian words.
|
|
3
|
-
*
|
|
4
6
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
5
7
|
* @returns {string} The number in Indonesian words
|
|
6
8
|
*/
|
|
7
9
|
export function toCardinal(value: number | string | bigint): string;
|
|
8
10
|
/**
|
|
9
11
|
* Converts a numeric value to Indonesian ordinal words.
|
|
10
|
-
*
|
|
11
12
|
* @param {number | string | bigint} value - The numeric value to convert (positive integer)
|
|
12
13
|
* @returns {string} The number as ordinal words
|
|
13
14
|
* @throws {TypeError} If value is not a valid numeric type
|
|
14
15
|
* @throws {RangeError} If value is negative, zero, or has a decimal part
|
|
15
|
-
*
|
|
16
16
|
* @example
|
|
17
17
|
* toOrdinal(1) // 'pertama'
|
|
18
18
|
* toOrdinal(2) // 'kedua'
|
|
@@ -24,12 +24,10 @@ export function toOrdinal(value: number | string | bigint): string;
|
|
|
24
24
|
*
|
|
25
25
|
* Indonesian Rupiah has no subunit in modern usage (sen are historical).
|
|
26
26
|
* Amounts are rounded to whole rupiah.
|
|
27
|
-
*
|
|
28
27
|
* @param {number | string | bigint} value - The currency amount to convert
|
|
29
28
|
* @returns {string} The amount in Indonesian currency words
|
|
30
29
|
* @throws {TypeError} If value is not a valid numeric type
|
|
31
30
|
* @throws {Error} If value is not a valid number format
|
|
32
|
-
*
|
|
33
31
|
* @example
|
|
34
32
|
* toCurrency(42) // 'empat puluh dua rupiah'
|
|
35
33
|
* toCurrency(1000) // 'seribu rupiah'
|