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/sr-Latn-RS.js
CHANGED
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
import { parseCardinalValue } from './utils/parse-cardinal.js'
|
|
15
15
|
import { parseCurrencyValue } from './utils/parse-currency.js'
|
|
16
16
|
import { parseOrdinalValue } from './utils/parse-ordinal.js'
|
|
17
|
-
import {
|
|
17
|
+
import { checkMax } from './utils/check-max.js'
|
|
18
|
+
import { western } from './utils/scale.js'
|
|
19
|
+
import { resolveOptions } from './utils/resolve-options.js'
|
|
18
20
|
|
|
19
21
|
// ============================================================================
|
|
20
22
|
// Vocabulary
|
|
@@ -56,7 +58,7 @@ const ORDINAL_SCALES = [
|
|
|
56
58
|
'trilioniti',
|
|
57
59
|
'trilijarditi',
|
|
58
60
|
'kvadrilioniti',
|
|
59
|
-
'kvadrilijarditi'
|
|
61
|
+
'kvadrilijarditi',
|
|
60
62
|
]
|
|
61
63
|
|
|
62
64
|
// ============================================================================
|
|
@@ -79,14 +81,27 @@ const SCALE_FORMS = [
|
|
|
79
81
|
['trilion', 'triliona', 'triliona'],
|
|
80
82
|
['trilijarda', 'trilijarde', 'trilijarda'],
|
|
81
83
|
['kvadrilion', 'kvadriliona', 'kvadriliona'],
|
|
82
|
-
['kvadrilijarda', 'kvadrilijarde', 'kvadrilijarda']
|
|
84
|
+
['kvadrilijarda', 'kvadrilijarde', 'kvadrilijarda'],
|
|
83
85
|
]
|
|
84
86
|
|
|
87
|
+
// Supported magnitude ceilings (checked at the public entry points). Both the
|
|
88
|
+
// cardinal SCALE_FORMS and the ORDINAL_SCALES tables cover units + N scale
|
|
89
|
+
// groups, so values must stay below 10^((length + 1) * 3) = 10^30.
|
|
90
|
+
export const cardinalMax = western(SCALE_FORMS.length)
|
|
91
|
+
export const ordinalMax = western(ORDINAL_SCALES.length)
|
|
92
|
+
export const currencyMax = western(SCALE_FORMS.length)
|
|
93
|
+
|
|
85
94
|
// ============================================================================
|
|
86
95
|
// Segment Building
|
|
87
96
|
// ============================================================================
|
|
88
97
|
|
|
89
|
-
|
|
98
|
+
/**
|
|
99
|
+
* Selects the correct plural form based on Serbian grammar rules.
|
|
100
|
+
* @param {number | bigint} n - The count
|
|
101
|
+
* @param {string[]} forms - Plural forms [one, few, many]
|
|
102
|
+
* @returns {string} The selected plural form
|
|
103
|
+
*/
|
|
104
|
+
function pluralize(n, forms) {
|
|
90
105
|
const num = typeof n === 'bigint' ? Number(n) : n
|
|
91
106
|
const lastDigit = num % 10
|
|
92
107
|
const lastTwoDigits = num % 100
|
|
@@ -100,7 +115,12 @@ function pluralize (n, forms) {
|
|
|
100
115
|
return forms[2]
|
|
101
116
|
}
|
|
102
117
|
|
|
103
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Builds the masculine word form for a 0-999 segment.
|
|
120
|
+
* @param {number} n - Segment value 0-999
|
|
121
|
+
* @returns {string} The segment words
|
|
122
|
+
*/
|
|
123
|
+
function buildSegmentMasc(n) {
|
|
104
124
|
if (n === 0) return ''
|
|
105
125
|
|
|
106
126
|
const onesDigit = n % 10
|
|
@@ -119,14 +139,20 @@ function buildSegmentMasc (n) {
|
|
|
119
139
|
|
|
120
140
|
if (tensDigit === 1) {
|
|
121
141
|
parts.push(TEENS[onesDigit])
|
|
122
|
-
}
|
|
142
|
+
}
|
|
143
|
+
else if (onesDigit > 0) {
|
|
123
144
|
parts.push(ONES_MASC[onesDigit])
|
|
124
145
|
}
|
|
125
146
|
|
|
126
147
|
return parts.join(' ')
|
|
127
148
|
}
|
|
128
149
|
|
|
129
|
-
|
|
150
|
+
/**
|
|
151
|
+
* Builds the feminine word form for a 0-999 segment.
|
|
152
|
+
* @param {number} n - Segment value 0-999
|
|
153
|
+
* @returns {string} The segment words
|
|
154
|
+
*/
|
|
155
|
+
function buildSegmentFem(n) {
|
|
130
156
|
if (n === 0) return ''
|
|
131
157
|
|
|
132
158
|
const onesDigit = n % 10
|
|
@@ -145,7 +171,8 @@ function buildSegmentFem (n) {
|
|
|
145
171
|
|
|
146
172
|
if (tensDigit === 1) {
|
|
147
173
|
parts.push(TEENS[onesDigit])
|
|
148
|
-
}
|
|
174
|
+
}
|
|
175
|
+
else if (onesDigit > 0) {
|
|
149
176
|
parts.push(ONES_FEM[onesDigit])
|
|
150
177
|
}
|
|
151
178
|
|
|
@@ -156,7 +183,13 @@ function buildSegmentFem (n) {
|
|
|
156
183
|
// Conversion Functions
|
|
157
184
|
// ============================================================================
|
|
158
185
|
|
|
159
|
-
|
|
186
|
+
/**
|
|
187
|
+
* Converts a non-negative integer to Serbian words.
|
|
188
|
+
* @param {bigint} n - The integer to convert
|
|
189
|
+
* @param {('masculine'|'feminine')} gender - Grammatical gender
|
|
190
|
+
* @returns {string} The integer in Serbian words
|
|
191
|
+
*/
|
|
192
|
+
function integerToWords(n, gender) {
|
|
160
193
|
if (n === 0n) return ZERO
|
|
161
194
|
|
|
162
195
|
if (n < 1000n) {
|
|
@@ -166,7 +199,13 @@ function integerToWords (n, gender) {
|
|
|
166
199
|
return buildLargeNumberWords(n, gender)
|
|
167
200
|
}
|
|
168
201
|
|
|
169
|
-
|
|
202
|
+
/**
|
|
203
|
+
* Builds words for numbers >= 1000 using scale decomposition.
|
|
204
|
+
* @param {bigint} n - The integer to convert (>= 1000)
|
|
205
|
+
* @param {('masculine'|'feminine')} gender - Grammatical gender
|
|
206
|
+
* @returns {string} The number in Serbian words
|
|
207
|
+
*/
|
|
208
|
+
function buildLargeNumberWords(n, gender) {
|
|
170
209
|
const numStr = n.toString()
|
|
171
210
|
const len = numStr.length
|
|
172
211
|
|
|
@@ -193,7 +232,8 @@ function buildLargeNumberWords (n, gender) {
|
|
|
193
232
|
if (segment !== 0) {
|
|
194
233
|
if (scaleIndex === 0) {
|
|
195
234
|
parts.push(gender === 'feminine' ? buildSegmentFem(segment) : buildSegmentMasc(segment))
|
|
196
|
-
}
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
197
237
|
const scaleForms = SCALE_FORMS[scaleIndex - 1]
|
|
198
238
|
const scaleWord = pluralize(segment, scaleForms)
|
|
199
239
|
// Thousands (scaleIndex=1) are feminine, others masculine
|
|
@@ -209,7 +249,13 @@ function buildLargeNumberWords (n, gender) {
|
|
|
209
249
|
return parts.join(' ')
|
|
210
250
|
}
|
|
211
251
|
|
|
212
|
-
|
|
252
|
+
/**
|
|
253
|
+
* Converts the decimal-part digit string to Serbian words.
|
|
254
|
+
* @param {string} decimalPart - The fractional digits as a string
|
|
255
|
+
* @param {('masculine'|'feminine')} gender - Grammatical gender
|
|
256
|
+
* @returns {string} The decimal part in Serbian words
|
|
257
|
+
*/
|
|
258
|
+
function decimalPartToWords(decimalPart, gender) {
|
|
213
259
|
let result = ''
|
|
214
260
|
let i = 0
|
|
215
261
|
|
|
@@ -228,20 +274,31 @@ function decimalPartToWords (decimalPart, gender) {
|
|
|
228
274
|
return result
|
|
229
275
|
}
|
|
230
276
|
|
|
277
|
+
/**
|
|
278
|
+
* @typedef {object} CardinalOptions
|
|
279
|
+
* @property {('masculine'|'feminine')} [gender] - Grammatical gender
|
|
280
|
+
*/
|
|
281
|
+
|
|
282
|
+
/** @type {Required<CardinalOptions>} */
|
|
283
|
+
export const cardinalDefaults = { gender: 'masculine' }
|
|
284
|
+
|
|
285
|
+
/** @type {{ gender: ReadonlyArray<Required<CardinalOptions>['gender']> }} */
|
|
286
|
+
export const cardinalValues = { gender: ['masculine', 'feminine'] }
|
|
287
|
+
|
|
231
288
|
/**
|
|
232
289
|
* Converts a numeric value to Serbian (Latin) words.
|
|
233
|
-
*
|
|
234
290
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
235
|
-
* @param {
|
|
236
|
-
* @param {('masculine'|'feminine')} [options.gender='masculine'] - Grammatical gender
|
|
291
|
+
* @param {CardinalOptions} [options] - Optional configuration
|
|
237
292
|
* @returns {string} The number in Serbian Latin words
|
|
238
293
|
*/
|
|
239
|
-
function toCardinal
|
|
240
|
-
options = validateOptions(options)
|
|
294
|
+
function toCardinal(value, options) {
|
|
241
295
|
const { isNegative, integerPart, decimalPart } = parseCardinalValue(value)
|
|
296
|
+
// Both the integer part and the decimal's significant digits are spelled via
|
|
297
|
+
// the scale builder, so both must clear the ceiling.
|
|
298
|
+
checkMax(integerPart, cardinalMax, decimalPart)
|
|
242
299
|
|
|
243
300
|
// Apply option defaults
|
|
244
|
-
const { gender
|
|
301
|
+
const { gender } = resolveOptions(options, cardinalDefaults, cardinalValues)
|
|
245
302
|
|
|
246
303
|
let result = ''
|
|
247
304
|
|
|
@@ -265,11 +322,10 @@ function toCardinal (value, options) {
|
|
|
265
322
|
/**
|
|
266
323
|
* Builds ordinal for a 0-99 segment when it's the final (ordinal) part.
|
|
267
324
|
* Returns ordinal form: "prvi", "dvadeset prvi", etc.
|
|
268
|
-
*
|
|
269
325
|
* @param {number} n - Number 0-99
|
|
270
326
|
* @returns {string} Ordinal words
|
|
271
327
|
*/
|
|
272
|
-
function buildOrdinalTensOnes
|
|
328
|
+
function buildOrdinalTensOnes(n) {
|
|
273
329
|
if (n === 0) return ''
|
|
274
330
|
|
|
275
331
|
const onesDigit = n % 10
|
|
@@ -300,11 +356,10 @@ function buildOrdinalTensOnes (n) {
|
|
|
300
356
|
*
|
|
301
357
|
* In Serbian ordinals, only the LAST component becomes ordinal.
|
|
302
358
|
* E.g., 121 = "sto dvadeset prvi" (one hundred twenty first)
|
|
303
|
-
*
|
|
304
359
|
* @param {bigint} n - Positive integer to convert
|
|
305
360
|
* @returns {string} Ordinal Serbian words
|
|
306
361
|
*/
|
|
307
|
-
function integerToOrdinal
|
|
362
|
+
function integerToOrdinal(n) {
|
|
308
363
|
// Fast path: numbers < 100
|
|
309
364
|
if (n < 100n) {
|
|
310
365
|
return buildOrdinalTensOnes(Number(n))
|
|
@@ -352,11 +407,10 @@ function integerToOrdinal (n) {
|
|
|
352
407
|
/**
|
|
353
408
|
* Builds ordinal words for numbers >= 1,000,000.
|
|
354
409
|
* All segments except the final one are cardinal; final segment is ordinal.
|
|
355
|
-
*
|
|
356
410
|
* @param {bigint} n - Number >= 1,000,000
|
|
357
411
|
* @returns {string} Ordinal Serbian words
|
|
358
412
|
*/
|
|
359
|
-
function buildLargeOrdinal
|
|
413
|
+
function buildLargeOrdinal(n) {
|
|
360
414
|
const numStr = n.toString()
|
|
361
415
|
const len = numStr.length
|
|
362
416
|
|
|
@@ -394,22 +448,26 @@ function buildLargeOrdinal (n) {
|
|
|
394
448
|
// Units position (no scale)
|
|
395
449
|
if (isLastNonZero) {
|
|
396
450
|
parts.push(integerToOrdinal(BigInt(segment)))
|
|
397
|
-
}
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
398
453
|
parts.push(buildSegmentMasc(segment))
|
|
399
454
|
}
|
|
400
|
-
}
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
401
457
|
// Has scale word
|
|
402
458
|
if (isLastNonZero) {
|
|
403
459
|
// This scale position is the final ordinal
|
|
404
460
|
if (segment === 1) {
|
|
405
461
|
parts.push(ORDINAL_SCALES[scaleIndex - 1])
|
|
406
|
-
}
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
407
464
|
// Use cardinal segment + ordinal scale
|
|
408
465
|
const isFeminine = scaleIndex === 1 // thousands are feminine
|
|
409
466
|
const segmentWord = isFeminine ? buildSegmentFem(segment) : buildSegmentMasc(segment)
|
|
410
467
|
parts.push(segmentWord + ' ' + ORDINAL_SCALES[scaleIndex - 1])
|
|
411
468
|
}
|
|
412
|
-
}
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
413
471
|
// Not the final segment: use cardinal
|
|
414
472
|
const scaleForms = SCALE_FORMS[scaleIndex - 1]
|
|
415
473
|
const scaleWord = pluralize(segment, scaleForms)
|
|
@@ -428,12 +486,10 @@ function buildLargeOrdinal (n) {
|
|
|
428
486
|
|
|
429
487
|
/**
|
|
430
488
|
* Converts a numeric value to Serbian ordinal words (masculine nominative).
|
|
431
|
-
*
|
|
432
489
|
* @param {number | string | bigint} value - The numeric value to convert (must be a positive integer)
|
|
433
490
|
* @returns {string} The number as ordinal words (e.g., "prvi", "četrdeset drugi")
|
|
434
491
|
* @throws {TypeError} If value is not a valid numeric type
|
|
435
492
|
* @throws {RangeError} If value is negative, zero, or has a decimal part
|
|
436
|
-
*
|
|
437
493
|
* @example
|
|
438
494
|
* toOrdinal(1) // 'prvi'
|
|
439
495
|
* toOrdinal(2) // 'drugi'
|
|
@@ -443,8 +499,9 @@ function buildLargeOrdinal (n) {
|
|
|
443
499
|
* toOrdinal(100) // 'stoti'
|
|
444
500
|
* toOrdinal(1000) // 'hiljaditi'
|
|
445
501
|
*/
|
|
446
|
-
function toOrdinal
|
|
502
|
+
function toOrdinal(value) {
|
|
447
503
|
const integerPart = parseOrdinalValue(value)
|
|
504
|
+
checkMax(integerPart, ordinalMax)
|
|
448
505
|
return integerToOrdinal(integerPart)
|
|
449
506
|
}
|
|
450
507
|
|
|
@@ -452,16 +509,21 @@ function toOrdinal (value) {
|
|
|
452
509
|
// CURRENCY: toCurrency(value, options?)
|
|
453
510
|
// ============================================================================
|
|
454
511
|
|
|
512
|
+
/**
|
|
513
|
+
* @typedef {object} CurrencyOptions
|
|
514
|
+
* @property {boolean} [and] - Use "i" between dinars and para
|
|
515
|
+
*/
|
|
516
|
+
|
|
517
|
+
/** @type {Required<CurrencyOptions>} */
|
|
518
|
+
export const currencyDefaults = { and: true }
|
|
519
|
+
|
|
455
520
|
/**
|
|
456
521
|
* Converts a numeric value to Serbian currency words (Serbian Dinar).
|
|
457
|
-
*
|
|
458
522
|
* @param {number | string | bigint} value - The currency amount to convert
|
|
459
|
-
* @param {
|
|
460
|
-
* @param {boolean} [options.and=true] - Use "i" between dinars and para
|
|
523
|
+
* @param {CurrencyOptions} [options] - Optional configuration
|
|
461
524
|
* @returns {string} The amount in Serbian currency words
|
|
462
525
|
* @throws {TypeError} If value is not a valid numeric type
|
|
463
526
|
* @throws {Error} If value is not a valid number format
|
|
464
|
-
*
|
|
465
527
|
* @example
|
|
466
528
|
* toCurrency(42.50) // 'četrdeset dva dinara i pedeset para'
|
|
467
529
|
* toCurrency(1) // 'jedan dinar'
|
|
@@ -469,10 +531,10 @@ function toOrdinal (value) {
|
|
|
469
531
|
* toCurrency(0.01) // 'jedna para'
|
|
470
532
|
* toCurrency(42.50, { and: false }) // 'četrdeset dva dinara pedeset para'
|
|
471
533
|
*/
|
|
472
|
-
function toCurrency
|
|
473
|
-
options = validateOptions(options)
|
|
534
|
+
function toCurrency(value, options) {
|
|
474
535
|
const { isNegative, dollars: dinars, cents: para } = parseCurrencyValue(value)
|
|
475
|
-
|
|
536
|
+
checkMax(dinars, currencyMax)
|
|
537
|
+
const { and: useAnd } = resolveOptions(options, currencyDefaults)
|
|
476
538
|
|
|
477
539
|
// Build result
|
|
478
540
|
let result = ''
|
package/src/sv-SE.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 Swedish words.
|
|
3
|
-
*
|
|
4
6
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
5
7
|
* @returns {string} The number in Swedish 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(42) // 'fyrtio-två'
|
|
11
12
|
* toCardinal(101) // 'hundra och ett'
|
|
@@ -14,12 +15,10 @@
|
|
|
14
15
|
export function toCardinal(value: number | string | bigint): string;
|
|
15
16
|
/**
|
|
16
17
|
* Converts a numeric value to Swedish ordinal words.
|
|
17
|
-
*
|
|
18
18
|
* @param {number | string | bigint} value - The numeric value to convert (positive integer)
|
|
19
19
|
* @returns {string} The number as ordinal words
|
|
20
20
|
* @throws {TypeError} If value is not a valid numeric type
|
|
21
21
|
* @throws {RangeError} If value is negative, zero, or has a decimal part
|
|
22
|
-
*
|
|
23
22
|
* @example
|
|
24
23
|
* toOrdinal(1) // 'första'
|
|
25
24
|
* toOrdinal(2) // 'andra'
|
|
@@ -30,12 +29,10 @@ export function toOrdinal(value: number | string | bigint): string;
|
|
|
30
29
|
* Converts a numeric value to Swedish currency words (Swedish Krona).
|
|
31
30
|
*
|
|
32
31
|
* Uses krona/kronor and öre (100 öre = 1 krona).
|
|
33
|
-
*
|
|
34
32
|
* @param {number | string | bigint} value - The currency amount to convert
|
|
35
33
|
* @returns {string} The amount in Swedish currency words
|
|
36
34
|
* @throws {TypeError} If value is not a valid numeric type
|
|
37
35
|
* @throws {Error} If value is not a valid number format
|
|
38
|
-
*
|
|
39
36
|
* @example
|
|
40
37
|
* toCurrency(1) // 'en krona'
|
|
41
38
|
* toCurrency(42) // 'fyrtio-två kronor'
|
package/src/sv-SE.js
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
import { parseCardinalValue } from './utils/parse-cardinal.js'
|
|
15
15
|
import { parseCurrencyValue } from './utils/parse-currency.js'
|
|
16
16
|
import { parseOrdinalValue } from './utils/parse-ordinal.js'
|
|
17
|
+
import { checkMax } from './utils/check-max.js'
|
|
18
|
+
import { western } from './utils/scale.js'
|
|
17
19
|
|
|
18
20
|
// ============================================================================
|
|
19
21
|
// Vocabulary (module-level constants)
|
|
@@ -33,12 +35,22 @@ const DECIMAL_SEP = 'komma'
|
|
|
33
35
|
// Scale words (long scale with -ard forms)
|
|
34
36
|
const SCALES = ['tusen', 'miljon', 'miljard', 'biljon', 'biljard', 'triljon', 'triljard', 'kvadriljon']
|
|
35
37
|
|
|
38
|
+
// Supported magnitude ceiling (checked at the public entry points). SCALES is
|
|
39
|
+
// indexed [scaleIndex - 1] from 'tusen' (10^3), so segments are [units, then
|
|
40
|
+
// one per SCALES entry] -> ceiling 10^((SCALES.length + 1) * 3) = 10^27.
|
|
41
|
+
// Ordinal (cardinal + suffix) and currency build on the cardinal, and the
|
|
42
|
+
// decimal is spelled via integerToWords, so all share it.
|
|
43
|
+
export const cardinalMax = western(SCALES.length)
|
|
44
|
+
export const ordinalMax = western(SCALES.length)
|
|
45
|
+
export const currencyMax = western(SCALES.length)
|
|
46
|
+
|
|
36
47
|
// ============================================================================
|
|
37
48
|
// Ordinal Vocabulary
|
|
38
49
|
// ============================================================================
|
|
39
50
|
|
|
40
51
|
// Swedish ordinals: 1st-2nd use -a (första, andra), then -de suffix
|
|
41
52
|
// Numbers ending in 1, 2 (except 11, 12) use special forms
|
|
53
|
+
/** @type {Record<number, string>} */
|
|
42
54
|
const ORDINAL_ONES = {
|
|
43
55
|
1: 'första',
|
|
44
56
|
2: 'andra',
|
|
@@ -51,7 +63,7 @@ const ORDINAL_ONES = {
|
|
|
51
63
|
9: 'nionde',
|
|
52
64
|
10: 'tionde',
|
|
53
65
|
11: 'elfte',
|
|
54
|
-
12: 'tolfte'
|
|
66
|
+
12: 'tolfte',
|
|
55
67
|
}
|
|
56
68
|
|
|
57
69
|
// ============================================================================
|
|
@@ -69,8 +81,10 @@ const ORE = 'öre' // same singular and plural
|
|
|
69
81
|
/**
|
|
70
82
|
* Builds segment word for 0-999.
|
|
71
83
|
* Returns object with word and metadata for "och" logic.
|
|
84
|
+
* @param {number} n - Integer in range 0-999
|
|
85
|
+
* @returns {{word: string, hasHundred: boolean, lessThan100: boolean}} Segment word with "och" metadata
|
|
72
86
|
*/
|
|
73
|
-
function buildSegment
|
|
87
|
+
function buildSegment(n) {
|
|
74
88
|
if (n === 0) return { word: '', hasHundred: false, lessThan100: false }
|
|
75
89
|
|
|
76
90
|
const ones = n % 10
|
|
@@ -85,7 +99,8 @@ function buildSegment (n) {
|
|
|
85
99
|
hasHundred = true
|
|
86
100
|
if (hundreds === 1) {
|
|
87
101
|
parts.push(HUNDRED)
|
|
88
|
-
}
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
89
104
|
parts.push(ONES[hundreds] + ' ' + HUNDRED)
|
|
90
105
|
}
|
|
91
106
|
}
|
|
@@ -94,22 +109,27 @@ function buildSegment (n) {
|
|
|
94
109
|
let tensOnesWord = ''
|
|
95
110
|
if (tens === 1) {
|
|
96
111
|
tensOnesWord = TEENS[ones]
|
|
97
|
-
}
|
|
112
|
+
}
|
|
113
|
+
else if (tens >= 2) {
|
|
98
114
|
if (ones > 0) {
|
|
99
115
|
tensOnesWord = TENS[tens] + '-' + ONES[ones]
|
|
100
|
-
}
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
101
118
|
tensOnesWord = TENS[tens]
|
|
102
119
|
}
|
|
103
|
-
}
|
|
120
|
+
}
|
|
121
|
+
else if (ones > 0) {
|
|
104
122
|
tensOnesWord = ONES[ones]
|
|
105
123
|
}
|
|
106
124
|
|
|
107
125
|
// Combine with "och" after hundreds if there's a remainder
|
|
108
126
|
if (hasHundred && tensOnesWord) {
|
|
109
127
|
return { word: parts[0] + ' och ' + tensOnesWord, hasHundred: true, lessThan100: false }
|
|
110
|
-
}
|
|
128
|
+
}
|
|
129
|
+
else if (hasHundred) {
|
|
111
130
|
return { word: parts[0], hasHundred: true, lessThan100: false }
|
|
112
|
-
}
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
113
133
|
return { word: tensOnesWord, hasHundred: false, lessThan100: true }
|
|
114
134
|
}
|
|
115
135
|
}
|
|
@@ -120,11 +140,10 @@ function buildSegment (n) {
|
|
|
120
140
|
|
|
121
141
|
/**
|
|
122
142
|
* Converts a non-negative integer to Swedish words.
|
|
123
|
-
*
|
|
124
143
|
* @param {bigint} n - Non-negative integer to convert
|
|
125
144
|
* @returns {string} Swedish words
|
|
126
145
|
*/
|
|
127
|
-
function integerToWords
|
|
146
|
+
function integerToWords(n) {
|
|
128
147
|
if (n === 0n) return ZERO
|
|
129
148
|
|
|
130
149
|
// Fast path: numbers < 1000
|
|
@@ -145,7 +164,8 @@ function integerToWords (n) {
|
|
|
145
164
|
// Insert "och" if remainder < 100 (doesn't have hundred)
|
|
146
165
|
if (remainderResult.lessThan100) {
|
|
147
166
|
result += ' och ' + remainderResult.word
|
|
148
|
-
}
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
149
169
|
result += ' ' + remainderResult.word
|
|
150
170
|
}
|
|
151
171
|
}
|
|
@@ -159,11 +179,10 @@ function integerToWords (n) {
|
|
|
159
179
|
|
|
160
180
|
/**
|
|
161
181
|
* Builds words for numbers >= 1,000,000.
|
|
162
|
-
*
|
|
163
182
|
* @param {bigint} n - Number >= 1,000,000
|
|
164
183
|
* @returns {string} Swedish words
|
|
165
184
|
*/
|
|
166
|
-
function buildLargeNumberWords
|
|
185
|
+
function buildLargeNumberWords(n) {
|
|
167
186
|
const numStr = n.toString()
|
|
168
187
|
const len = numStr.length
|
|
169
188
|
|
|
@@ -197,9 +216,10 @@ function buildLargeNumberWords (n) {
|
|
|
197
216
|
parts.push({
|
|
198
217
|
word: segmentResult.word,
|
|
199
218
|
hasHundred: segmentResult.hasHundred,
|
|
200
|
-
isScale: false
|
|
219
|
+
isScale: false,
|
|
201
220
|
})
|
|
202
|
-
}
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
203
223
|
// Segment with scale word
|
|
204
224
|
const scaleWord = SCALES[scaleIndex - 1]
|
|
205
225
|
|
|
@@ -208,10 +228,12 @@ function buildLargeNumberWords (n) {
|
|
|
208
228
|
// Omit "ett" before tusen, use "en" before million+
|
|
209
229
|
if (scaleIndex === 1) {
|
|
210
230
|
segmentWord = '' // Just "tusen"
|
|
211
|
-
}
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
212
233
|
segmentWord = 'en' // "en miljon"
|
|
213
234
|
}
|
|
214
|
-
}
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
215
237
|
segmentWord = segmentResult.word
|
|
216
238
|
}
|
|
217
239
|
|
|
@@ -232,11 +254,10 @@ function buildLargeNumberWords (n) {
|
|
|
232
254
|
/**
|
|
233
255
|
* Joins parts with Swedish "och" rules.
|
|
234
256
|
* Insert "och" before final segment if it follows a scale word and doesn't have "hundra".
|
|
235
|
-
*
|
|
236
|
-
* @param {Array} parts - Parts with metadata
|
|
257
|
+
* @param {Array<{word: string, hasHundred: boolean, isScale: boolean}>} parts - Parts with metadata
|
|
237
258
|
* @returns {string} Joined string
|
|
238
259
|
*/
|
|
239
|
-
function joinSwedishParts
|
|
260
|
+
function joinSwedishParts(parts) {
|
|
240
261
|
if (parts.length === 0) return ZERO
|
|
241
262
|
if (parts.length === 1) return parts[0].word
|
|
242
263
|
|
|
@@ -262,11 +283,10 @@ function joinSwedishParts (parts) {
|
|
|
262
283
|
|
|
263
284
|
/**
|
|
264
285
|
* Converts decimal digits to Swedish words.
|
|
265
|
-
*
|
|
266
286
|
* @param {string} decimalPart - Decimal digits (without the point)
|
|
267
287
|
* @returns {string} Swedish words for decimal part
|
|
268
288
|
*/
|
|
269
|
-
function decimalPartToWords
|
|
289
|
+
function decimalPartToWords(decimalPart) {
|
|
270
290
|
let result = ''
|
|
271
291
|
|
|
272
292
|
// Handle leading zeros
|
|
@@ -289,19 +309,20 @@ function decimalPartToWords (decimalPart) {
|
|
|
289
309
|
|
|
290
310
|
/**
|
|
291
311
|
* Converts a numeric value to Swedish words.
|
|
292
|
-
*
|
|
293
312
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
294
313
|
* @returns {string} The number in Swedish words
|
|
295
314
|
* @throws {TypeError} If value is not a valid numeric type
|
|
296
315
|
* @throws {Error} If value is not a valid number format
|
|
297
|
-
*
|
|
298
316
|
* @example
|
|
299
317
|
* toCardinal(42) // 'fyrtio-två'
|
|
300
318
|
* toCardinal(101) // 'hundra och ett'
|
|
301
319
|
* toCardinal(1000000) // 'en miljon'
|
|
302
320
|
*/
|
|
303
|
-
function toCardinal
|
|
321
|
+
function toCardinal(value) {
|
|
304
322
|
const { isNegative, integerPart, decimalPart } = parseCardinalValue(value)
|
|
323
|
+
// Both the integer part and the decimal's significant digits are spelled via
|
|
324
|
+
// the scale builder, so both must clear the ceiling.
|
|
325
|
+
checkMax(integerPart, cardinalMax, decimalPart)
|
|
305
326
|
|
|
306
327
|
let result = ''
|
|
307
328
|
|
|
@@ -327,11 +348,10 @@ function toCardinal (value) {
|
|
|
327
348
|
*
|
|
328
349
|
* Swedish ordinals: första (1st), andra (2nd), tredje (3rd), etc.
|
|
329
350
|
* Most use cardinal + de suffix, with special forms 1-12.
|
|
330
|
-
*
|
|
331
351
|
* @param {bigint} n - Positive integer to convert
|
|
332
352
|
* @returns {string} Swedish ordinal words
|
|
333
353
|
*/
|
|
334
|
-
function integerToOrdinal
|
|
354
|
+
function integerToOrdinal(n) {
|
|
335
355
|
// Special forms for 1-12
|
|
336
356
|
if (n >= 1n && n <= 12n) {
|
|
337
357
|
return ORDINAL_ONES[Number(n)]
|
|
@@ -348,19 +368,18 @@ function integerToOrdinal (n) {
|
|
|
348
368
|
|
|
349
369
|
/**
|
|
350
370
|
* Converts a numeric value to Swedish ordinal words.
|
|
351
|
-
*
|
|
352
371
|
* @param {number | string | bigint} value - The numeric value to convert (positive integer)
|
|
353
372
|
* @returns {string} The number as ordinal words
|
|
354
373
|
* @throws {TypeError} If value is not a valid numeric type
|
|
355
374
|
* @throws {RangeError} If value is negative, zero, or has a decimal part
|
|
356
|
-
*
|
|
357
375
|
* @example
|
|
358
376
|
* toOrdinal(1) // 'första'
|
|
359
377
|
* toOrdinal(2) // 'andra'
|
|
360
378
|
* toOrdinal(21) // 'tjugo-ettde'
|
|
361
379
|
*/
|
|
362
|
-
function toOrdinal
|
|
380
|
+
function toOrdinal(value) {
|
|
363
381
|
const integerPart = parseOrdinalValue(value)
|
|
382
|
+
checkMax(integerPart, ordinalMax)
|
|
364
383
|
return integerToOrdinal(integerPart)
|
|
365
384
|
}
|
|
366
385
|
|
|
@@ -372,19 +391,18 @@ function toOrdinal (value) {
|
|
|
372
391
|
* Converts a numeric value to Swedish currency words (Swedish Krona).
|
|
373
392
|
*
|
|
374
393
|
* Uses krona/kronor and öre (100 öre = 1 krona).
|
|
375
|
-
*
|
|
376
394
|
* @param {number | string | bigint} value - The currency amount to convert
|
|
377
395
|
* @returns {string} The amount in Swedish currency words
|
|
378
396
|
* @throws {TypeError} If value is not a valid numeric type
|
|
379
397
|
* @throws {Error} If value is not a valid number format
|
|
380
|
-
*
|
|
381
398
|
* @example
|
|
382
399
|
* toCurrency(1) // 'en krona'
|
|
383
400
|
* toCurrency(42) // 'fyrtio-två kronor'
|
|
384
401
|
* toCurrency(1.50) // 'en krona och femtio öre'
|
|
385
402
|
*/
|
|
386
|
-
function toCurrency
|
|
403
|
+
function toCurrency(value) {
|
|
387
404
|
const { isNegative, dollars: kronor, cents: ore } = parseCurrencyValue(value)
|
|
405
|
+
checkMax(kronor, currencyMax)
|
|
388
406
|
|
|
389
407
|
let result = ''
|
|
390
408
|
if (isNegative) {
|
|
@@ -396,7 +414,8 @@ function toCurrency (value) {
|
|
|
396
414
|
// Use "en" for 1 krona (not "ett")
|
|
397
415
|
if (kronor === 1n) {
|
|
398
416
|
result += 'en ' + KRONA
|
|
399
|
-
}
|
|
417
|
+
}
|
|
418
|
+
else {
|
|
400
419
|
result += integerToWords(kronor) + ' ' + KRONOR
|
|
401
420
|
}
|
|
402
421
|
}
|
package/src/sw-KE.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 Swahili words.
|
|
3
|
-
*
|
|
4
6
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
5
7
|
* @returns {string} The number in Swahili words
|
|
6
8
|
*/
|
|
7
9
|
export function toCardinal(value: number | string | bigint): string;
|
|
8
10
|
/**
|
|
9
11
|
* Converts a numeric value to Swahili 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) // 'wa kwanza'
|
|
18
18
|
* toOrdinal(2) // 'wa pili'
|
|
@@ -23,12 +23,10 @@ export function toOrdinal(value: number | string | bigint): string;
|
|
|
23
23
|
* Converts a numeric value to Swahili currency words (Kenyan Shilling).
|
|
24
24
|
*
|
|
25
25
|
* Uses shilingi and senti (100 senti = 1 shilingi).
|
|
26
|
-
*
|
|
27
26
|
* @param {number | string | bigint} value - The currency amount to convert
|
|
28
27
|
* @returns {string} The amount in Swahili currency words
|
|
29
28
|
* @throws {TypeError} If value is not a valid numeric type
|
|
30
29
|
* @throws {Error} If value is not a valid number format
|
|
31
|
-
*
|
|
32
30
|
* @example
|
|
33
31
|
* toCurrency(42) // 'shilingi arobaini na mbili'
|
|
34
32
|
* toCurrency(1.50) // 'shilingi moja na senti hamsini'
|