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/pl-PL.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 (module-level constants)
|
|
@@ -31,6 +33,7 @@ const TENS = ['', '', 'dwadzieścia', 'trzydzieści', 'czterdzieści', 'pięćdz
|
|
|
31
33
|
const HUNDREDS = ['', 'sto', 'dwieście', 'trzysta', 'czterysta', 'pięćset', 'sześćset', 'siedemset', 'osiemset', 'dziewięćset']
|
|
32
34
|
|
|
33
35
|
// Scale words: [singular, few (2-4), many (5+)]
|
|
36
|
+
/** @type {Record<number, string[]>} */
|
|
34
37
|
const PLURAL_FORMS = {
|
|
35
38
|
1: ['tysiąc', 'tysiące', 'tysięcy'],
|
|
36
39
|
2: ['milion', 'miliony', 'milionów'],
|
|
@@ -41,7 +44,7 @@ const PLURAL_FORMS = {
|
|
|
41
44
|
7: ['tryliard', 'tryliardy', 'tryliardów'],
|
|
42
45
|
8: ['kwadrylion', 'kwadryliony', 'kwadrylionów'],
|
|
43
46
|
9: ['kwaryliard', 'kwadryliardy', 'kwadryliardów'],
|
|
44
|
-
10: ['kwintylion', 'kwintyliony', 'kwintylionów']
|
|
47
|
+
10: ['kwintylion', 'kwintyliony', 'kwintylionów'],
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
const ZERO = 'zero'
|
|
@@ -86,7 +89,7 @@ const GROSZ_FORMS = ['grosz', 'grosze', 'groszy']
|
|
|
86
89
|
* @param {number} n - Segment value
|
|
87
90
|
* @returns {string} Polish word
|
|
88
91
|
*/
|
|
89
|
-
function buildSegment
|
|
92
|
+
function buildSegment(n) {
|
|
90
93
|
if (n === 0) return ''
|
|
91
94
|
|
|
92
95
|
const ones = n % 10
|
|
@@ -104,7 +107,8 @@ function buildSegment (n) {
|
|
|
104
107
|
if (tens === 1) {
|
|
105
108
|
// Teens (10-19)
|
|
106
109
|
parts.push(TEENS[ones])
|
|
107
|
-
}
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
108
112
|
if (tens >= 2) {
|
|
109
113
|
parts.push(TENS[tens])
|
|
110
114
|
}
|
|
@@ -121,7 +125,7 @@ function buildSegment (n) {
|
|
|
121
125
|
* @param {number} n - Segment value
|
|
122
126
|
* @returns {string} Polish word
|
|
123
127
|
*/
|
|
124
|
-
function buildSegmentFeminine
|
|
128
|
+
function buildSegmentFeminine(n) {
|
|
125
129
|
if (n === 0) return ''
|
|
126
130
|
|
|
127
131
|
const ones = n % 10
|
|
@@ -138,7 +142,8 @@ function buildSegmentFeminine (n) {
|
|
|
138
142
|
// Tens and ones - feminine for ones only
|
|
139
143
|
if (tens === 1) {
|
|
140
144
|
parts.push(TEENS[ones])
|
|
141
|
-
}
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
142
147
|
if (tens >= 2) {
|
|
143
148
|
parts.push(TENS[tens])
|
|
144
149
|
}
|
|
@@ -157,12 +162,11 @@ function buildSegmentFeminine (n) {
|
|
|
157
162
|
/**
|
|
158
163
|
* Polish pluralization: 1 = singular, 2-4 = few, else = many.
|
|
159
164
|
* Special case: 11-19 always use many form.
|
|
160
|
-
*
|
|
161
165
|
* @param {bigint} n - Number to pluralize
|
|
162
166
|
* @param {string[]} forms - [singular, few, many]
|
|
163
167
|
* @returns {string} Correct plural form
|
|
164
168
|
*/
|
|
165
|
-
function pluralize
|
|
169
|
+
function pluralize(n, forms) {
|
|
166
170
|
if (n === 1n) {
|
|
167
171
|
return forms[0]
|
|
168
172
|
}
|
|
@@ -185,12 +189,11 @@ function pluralize (n, forms) {
|
|
|
185
189
|
|
|
186
190
|
/**
|
|
187
191
|
* Converts a non-negative integer to Polish words.
|
|
188
|
-
*
|
|
189
192
|
* @param {bigint} n - Non-negative integer to convert
|
|
190
|
-
* @param {
|
|
193
|
+
* @param {string} gender - Gender for numbers < 1000 ('masculine' or 'feminine')
|
|
191
194
|
* @returns {string} Polish words
|
|
192
195
|
*/
|
|
193
|
-
function integerToWords
|
|
196
|
+
function integerToWords(n, gender) {
|
|
194
197
|
if (n === 0n) return ZERO
|
|
195
198
|
|
|
196
199
|
// Fast path: numbers < 1000
|
|
@@ -209,7 +212,8 @@ function integerToWords (n, gender) {
|
|
|
209
212
|
if (thousands === 1) {
|
|
210
213
|
// Omit "jeden" before tysiąc
|
|
211
214
|
result = scaleWord
|
|
212
|
-
}
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
213
217
|
result = buildSegment(thousands) + ' ' + scaleWord
|
|
214
218
|
}
|
|
215
219
|
|
|
@@ -221,18 +225,16 @@ function integerToWords (n, gender) {
|
|
|
221
225
|
}
|
|
222
226
|
|
|
223
227
|
// For numbers >= 1,000,000, use scale decomposition
|
|
224
|
-
return buildLargeNumberWords(n
|
|
228
|
+
return buildLargeNumberWords(n)
|
|
225
229
|
}
|
|
226
230
|
|
|
227
231
|
/**
|
|
228
232
|
* Builds words for numbers >= 1,000,000.
|
|
229
233
|
* Uses BigInt division for faster segment extraction.
|
|
230
|
-
*
|
|
231
234
|
* @param {bigint} n - Number >= 1,000,000
|
|
232
|
-
* @param {Object} options - Conversion options
|
|
233
235
|
* @returns {string} Polish words
|
|
234
236
|
*/
|
|
235
|
-
function buildLargeNumberWords
|
|
237
|
+
function buildLargeNumberWords(n) {
|
|
236
238
|
// Extract segments using BigInt division (faster than string slicing)
|
|
237
239
|
// Segments stored least-significant first (index 0 = ones, 1 = thousands, etc.)
|
|
238
240
|
const segmentValues = []
|
|
@@ -256,7 +258,8 @@ function buildLargeNumberWords (n, gender) {
|
|
|
256
258
|
if (i === 0) {
|
|
257
259
|
// Units segment
|
|
258
260
|
result += segmentWord
|
|
259
|
-
}
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
260
263
|
// Scale word needed
|
|
261
264
|
const forms = PLURAL_FORMS[i]
|
|
262
265
|
if (forms) {
|
|
@@ -265,7 +268,8 @@ function buildLargeNumberWords (n, gender) {
|
|
|
265
268
|
if (segment === 1n) {
|
|
266
269
|
// Omit "jeden" before scale words
|
|
267
270
|
result += scaleWord
|
|
268
|
-
}
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
269
273
|
result += segmentWord + ' ' + scaleWord
|
|
270
274
|
}
|
|
271
275
|
}
|
|
@@ -277,12 +281,11 @@ function buildLargeNumberWords (n, gender) {
|
|
|
277
281
|
|
|
278
282
|
/**
|
|
279
283
|
* Converts decimal digits to Polish words.
|
|
280
|
-
*
|
|
281
284
|
* @param {string} decimalPart - Decimal digits (without the point)
|
|
282
|
-
* @param {
|
|
285
|
+
* @param {string} gender - Gender for numbers < 1000 ('masculine' or 'feminine')
|
|
283
286
|
* @returns {string} Polish words for decimal part
|
|
284
287
|
*/
|
|
285
|
-
function decimalPartToWords
|
|
288
|
+
function decimalPartToWords(decimalPart, gender) {
|
|
286
289
|
let result = ''
|
|
287
290
|
|
|
288
291
|
// Handle leading zeros
|
|
@@ -303,31 +306,52 @@ function decimalPartToWords (decimalPart, gender) {
|
|
|
303
306
|
return result
|
|
304
307
|
}
|
|
305
308
|
|
|
309
|
+
// Supported magnitude ceilings (checked at the public entry points). PLURAL_FORMS
|
|
310
|
+
// is keyed by scale level (1 = thousands, …), units separate, so cardinal/
|
|
311
|
+
// currency reach 10^((maxScaleKey + 1) * 3) = 10^33; the shorter ORDINAL_SCALES
|
|
312
|
+
// bounds ordinals at 10^((length + 1) * 3) = 10^24. (Past the cardinal ceiling
|
|
313
|
+
// the fraction would spell silently-wrong, so the decimal is guarded too.)
|
|
314
|
+
// Derive from the max numeric key (robust to gaps / non-scale keys).
|
|
315
|
+
const MAX_SCALE_KEY = Math.max(...Object.keys(PLURAL_FORMS).map(Number))
|
|
316
|
+
export const cardinalMax = western(MAX_SCALE_KEY)
|
|
317
|
+
export const ordinalMax = western(ORDINAL_SCALES.length)
|
|
318
|
+
export const currencyMax = western(MAX_SCALE_KEY)
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* @typedef {object} CardinalOptions
|
|
322
|
+
* @property {('masculine'|'feminine')} [gender] - Gender for numbers < 1000
|
|
323
|
+
*/
|
|
324
|
+
|
|
325
|
+
/** @type {Required<CardinalOptions>} */
|
|
326
|
+
export const cardinalDefaults = { gender: 'masculine' }
|
|
327
|
+
|
|
328
|
+
/** @type {{ gender: ReadonlyArray<Required<CardinalOptions>['gender']> }} */
|
|
329
|
+
export const cardinalValues = { gender: ['masculine', 'feminine'] }
|
|
330
|
+
|
|
306
331
|
/**
|
|
307
332
|
* Converts a numeric value to Polish words.
|
|
308
333
|
*
|
|
309
334
|
* This is the main public API. It accepts any valid numeric input
|
|
310
335
|
* (number, string, or bigint) and handles parsing internally.
|
|
311
|
-
*
|
|
312
336
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
313
|
-
* @param {
|
|
314
|
-
* @param {string} [options.gender='masculine'] - Gender for numbers < 1000
|
|
337
|
+
* @param {CardinalOptions} [options] - Conversion options
|
|
315
338
|
* @returns {string} The number in Polish words
|
|
316
339
|
* @throws {TypeError} If value is not a valid numeric type
|
|
317
340
|
* @throws {Error} If value is not a valid number format
|
|
318
|
-
*
|
|
319
341
|
* @example
|
|
320
342
|
* toCardinal(1) // 'jeden'
|
|
321
343
|
* toCardinal(1, { gender: 'feminine' }) // 'jedna'
|
|
322
344
|
* toCardinal(1000) // 'tysiąc'
|
|
323
345
|
* toCardinal(2000) // 'dwa tysiące'
|
|
324
346
|
*/
|
|
325
|
-
function toCardinal
|
|
326
|
-
options = validateOptions(options)
|
|
347
|
+
function toCardinal(value, options) {
|
|
327
348
|
const { isNegative, integerPart, decimalPart } = parseCardinalValue(value)
|
|
349
|
+
// Both the integer part and the decimal's significant digits are spelled via
|
|
350
|
+
// the scale builder, so both must clear the ceiling.
|
|
351
|
+
checkMax(integerPart, cardinalMax, decimalPart)
|
|
328
352
|
|
|
329
353
|
// Apply option defaults
|
|
330
|
-
const { gender
|
|
354
|
+
const { gender } = resolveOptions(options, cardinalDefaults, cardinalValues)
|
|
331
355
|
|
|
332
356
|
let result = ''
|
|
333
357
|
|
|
@@ -351,11 +375,10 @@ function toCardinal (value, options) {
|
|
|
351
375
|
/**
|
|
352
376
|
* Builds ordinal for a 0-99 segment when it's the final (ordinal) part.
|
|
353
377
|
* Returns ordinal form: "pierwszy", "dwudziesty pierwszy", etc.
|
|
354
|
-
*
|
|
355
378
|
* @param {number} n - Number 0-99
|
|
356
379
|
* @returns {string} Ordinal words
|
|
357
380
|
*/
|
|
358
|
-
function buildOrdinalTensOnes
|
|
381
|
+
function buildOrdinalTensOnes(n) {
|
|
359
382
|
if (n === 0) return ''
|
|
360
383
|
|
|
361
384
|
const onesDigit = n % 10
|
|
@@ -386,11 +409,10 @@ function buildOrdinalTensOnes (n) {
|
|
|
386
409
|
*
|
|
387
410
|
* In Polish ordinals, only the LAST component becomes ordinal.
|
|
388
411
|
* E.g., 121 = "sto dwudziesty pierwszy" (one hundred twenty-first)
|
|
389
|
-
*
|
|
390
412
|
* @param {bigint} n - Positive integer to convert
|
|
391
413
|
* @returns {string} Ordinal Polish words
|
|
392
414
|
*/
|
|
393
|
-
function integerToOrdinal
|
|
415
|
+
function integerToOrdinal(n) {
|
|
394
416
|
// Fast path: numbers < 100
|
|
395
417
|
if (n < 100n) {
|
|
396
418
|
return buildOrdinalTensOnes(Number(n))
|
|
@@ -438,11 +460,10 @@ function integerToOrdinal (n) {
|
|
|
438
460
|
/**
|
|
439
461
|
* Builds ordinal words for numbers >= 1,000,000.
|
|
440
462
|
* All segments except the final one are cardinal; final segment is ordinal.
|
|
441
|
-
*
|
|
442
463
|
* @param {bigint} n - Number >= 1,000,000
|
|
443
464
|
* @returns {string} Ordinal Polish words
|
|
444
465
|
*/
|
|
445
|
-
function buildLargeOrdinal
|
|
466
|
+
function buildLargeOrdinal(n) {
|
|
446
467
|
const numStr = n.toString()
|
|
447
468
|
const len = numStr.length
|
|
448
469
|
|
|
@@ -480,26 +501,31 @@ function buildLargeOrdinal (n) {
|
|
|
480
501
|
// Units position (no scale)
|
|
481
502
|
if (isLastNonZero) {
|
|
482
503
|
parts.push(integerToOrdinal(BigInt(segment)))
|
|
483
|
-
}
|
|
504
|
+
}
|
|
505
|
+
else {
|
|
484
506
|
parts.push(buildSegment(segment))
|
|
485
507
|
}
|
|
486
|
-
}
|
|
508
|
+
}
|
|
509
|
+
else {
|
|
487
510
|
// Has scale word
|
|
488
511
|
if (isLastNonZero) {
|
|
489
512
|
// This scale position is the final ordinal
|
|
490
513
|
if (segment === 1) {
|
|
491
514
|
parts.push(ORDINAL_SCALES[scaleIndex - 1])
|
|
492
|
-
}
|
|
515
|
+
}
|
|
516
|
+
else {
|
|
493
517
|
// Use cardinal segment + ordinal scale
|
|
494
518
|
parts.push(buildSegment(segment) + ' ' + ORDINAL_SCALES[scaleIndex - 1])
|
|
495
519
|
}
|
|
496
|
-
}
|
|
520
|
+
}
|
|
521
|
+
else {
|
|
497
522
|
// Not the final segment: use cardinal
|
|
498
523
|
const forms = PLURAL_FORMS[scaleIndex]
|
|
499
524
|
const scaleWord = forms ? pluralize(BigInt(segment), forms) : ''
|
|
500
525
|
if (segment === 1) {
|
|
501
526
|
parts.push(scaleWord)
|
|
502
|
-
}
|
|
527
|
+
}
|
|
528
|
+
else {
|
|
503
529
|
parts.push(buildSegment(segment) + ' ' + scaleWord)
|
|
504
530
|
}
|
|
505
531
|
}
|
|
@@ -514,12 +540,10 @@ function buildLargeOrdinal (n) {
|
|
|
514
540
|
|
|
515
541
|
/**
|
|
516
542
|
* Converts a numeric value to Polish ordinal words (masculine nominative).
|
|
517
|
-
*
|
|
518
543
|
* @param {number | string | bigint} value - The numeric value to convert (must be a positive integer)
|
|
519
544
|
* @returns {string} The number as ordinal words (e.g., "pierwszy", "czterdziesty drugi")
|
|
520
545
|
* @throws {TypeError} If value is not a valid numeric type
|
|
521
546
|
* @throws {RangeError} If value is negative, zero, or has a decimal part
|
|
522
|
-
*
|
|
523
547
|
* @example
|
|
524
548
|
* toOrdinal(1) // 'pierwszy'
|
|
525
549
|
* toOrdinal(2) // 'drugi'
|
|
@@ -529,8 +553,9 @@ function buildLargeOrdinal (n) {
|
|
|
529
553
|
* toOrdinal(100) // 'setny'
|
|
530
554
|
* toOrdinal(1000) // 'tysięczny'
|
|
531
555
|
*/
|
|
532
|
-
function toOrdinal
|
|
556
|
+
function toOrdinal(value) {
|
|
533
557
|
const integerPart = parseOrdinalValue(value)
|
|
558
|
+
checkMax(integerPart, ordinalMax)
|
|
534
559
|
return integerToOrdinal(integerPart)
|
|
535
560
|
}
|
|
536
561
|
|
|
@@ -540,20 +565,19 @@ function toOrdinal (value) {
|
|
|
540
565
|
|
|
541
566
|
/**
|
|
542
567
|
* Converts a numeric value to Polish currency words (Polish Złoty).
|
|
543
|
-
*
|
|
544
568
|
* @param {number | string | bigint} value - The currency amount to convert
|
|
545
569
|
* @returns {string} The amount in Polish currency words
|
|
546
570
|
* @throws {TypeError} If value is not a valid numeric type
|
|
547
571
|
* @throws {Error} If value is not a valid number format
|
|
548
|
-
*
|
|
549
572
|
* @example
|
|
550
573
|
* toCurrency(42) // 'czterdzieści dwa złote'
|
|
551
574
|
* toCurrency(1) // 'jeden złoty'
|
|
552
575
|
* toCurrency(1.50) // 'jeden złoty pięćdziesiąt groszy'
|
|
553
576
|
* toCurrency(-5) // 'minus pięć złotych'
|
|
554
577
|
*/
|
|
555
|
-
function toCurrency
|
|
578
|
+
function toCurrency(value) {
|
|
556
579
|
const { isNegative, dollars: zloty, cents: grosze } = parseCurrencyValue(value)
|
|
580
|
+
checkMax(zloty, currencyMax)
|
|
557
581
|
|
|
558
582
|
let result = ''
|
|
559
583
|
if (isNegative) {
|
package/src/pt-BR.d.ts
CHANGED
|
@@ -1,31 +1,42 @@
|
|
|
1
|
+
export const cardinalMax: bigint;
|
|
2
|
+
export const ordinalMax: bigint;
|
|
3
|
+
export const currencyMax: bigint;
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {object} CurrencyOptions
|
|
6
|
+
* @property {boolean} [and] - Include "e" between major and minor units
|
|
7
|
+
* @property {string} [currency] - Currency code (e.g., 'BRL', 'USD'); empty means auto-detect for pt-BR
|
|
8
|
+
*/
|
|
9
|
+
/** @type {Required<CurrencyOptions>} */
|
|
10
|
+
export const currencyDefaults: Required<CurrencyOptions>;
|
|
11
|
+
export type CurrencyOptions = {
|
|
12
|
+
/**
|
|
13
|
+
* - Include "e" between major and minor units
|
|
14
|
+
*/
|
|
15
|
+
and?: boolean | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* - Currency code (e.g., 'BRL', 'USD'); empty means auto-detect for pt-BR
|
|
18
|
+
*/
|
|
19
|
+
currency?: string | undefined;
|
|
20
|
+
};
|
|
1
21
|
/**
|
|
2
22
|
* Converts a numeric value to Portuguese words.
|
|
3
|
-
*
|
|
4
23
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
5
24
|
* @returns {string} The number in Portuguese words
|
|
6
25
|
*/
|
|
7
26
|
export function toCardinal(value: number | string | bigint): string;
|
|
8
27
|
/**
|
|
9
28
|
* Converts a number to Portuguese ordinal words.
|
|
10
|
-
*
|
|
11
29
|
* @param {number | string | bigint} value - The number to convert
|
|
12
30
|
* @returns {string} Portuguese ordinal words
|
|
13
31
|
*/
|
|
14
32
|
export function toOrdinal(value: number | string | bigint): string;
|
|
15
33
|
/**
|
|
16
34
|
* Converts a number to Brazilian Portuguese currency words.
|
|
17
|
-
*
|
|
18
35
|
* @param {number | string | bigint} value - The amount to convert
|
|
19
|
-
* @param {
|
|
20
|
-
* @param {boolean} [options.and=true] - Include "e" between major and minor units
|
|
21
|
-
* @param {string} [options.currency] - Currency code (e.g., 'BRL', 'USD')
|
|
36
|
+
* @param {CurrencyOptions} [options] Currency formatting options
|
|
22
37
|
* @returns {string} Brazilian Portuguese currency words
|
|
23
|
-
*
|
|
24
38
|
* @example
|
|
25
39
|
* toCurrency(42.50) // 'quarenta e dois reais e cinquenta centavos'
|
|
26
40
|
* toCurrency(42.50, {currency: 'USD'}) // 'quarenta e dois dólares e cinquenta centavos'
|
|
27
41
|
*/
|
|
28
|
-
export function toCurrency(value: number | string | bigint, options?:
|
|
29
|
-
and?: boolean | undefined;
|
|
30
|
-
currency?: string | undefined;
|
|
31
|
-
}): string;
|
|
42
|
+
export function toCurrency(value: number | string | bigint, options?: CurrencyOptions): string;
|