n2words 4.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 +53 -0
- package/README.md +14 -12
- 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 -0
- package/dist/pt-BR.umd.js +2 -0
- 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 +53 -36
- 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 +42 -0
- package/src/pt-BR.js +574 -0
- 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/pt-PT.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)
|
|
@@ -51,8 +53,10 @@ const CENTIMOS = 'cêntimos'
|
|
|
51
53
|
/**
|
|
52
54
|
* Builds segment word for 0-999 with Portuguese "e" rules.
|
|
53
55
|
* Returns the word and whether it's an exact hundred (for "cem" handling).
|
|
56
|
+
* @param {number} n - Number 0-999
|
|
57
|
+
* @returns {{ word: string, isExactHundred: boolean, startsWithHundreds?: boolean }} The segment word and "e"/"cem" handling flags
|
|
54
58
|
*/
|
|
55
|
-
function buildSegment
|
|
59
|
+
function buildSegment(n) {
|
|
56
60
|
if (n === 0) return { word: '', isExactHundred: false }
|
|
57
61
|
|
|
58
62
|
// Special case: exact 100 is "cem"
|
|
@@ -73,14 +77,17 @@ function buildSegment (n) {
|
|
|
73
77
|
if (tens === 1) {
|
|
74
78
|
// Teens (10-19)
|
|
75
79
|
parts.push(TEENS[ones])
|
|
76
|
-
}
|
|
80
|
+
}
|
|
81
|
+
else if (tens >= 2) {
|
|
77
82
|
if (ones > 0) {
|
|
78
83
|
// Tens + ones with "e": "vinte e um"
|
|
79
84
|
parts.push(TENS[tens] + ' e ' + ONES[ones])
|
|
80
|
-
}
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
81
87
|
parts.push(TENS[tens])
|
|
82
88
|
}
|
|
83
|
-
}
|
|
89
|
+
}
|
|
90
|
+
else if (ones > 0) {
|
|
84
91
|
parts.push(ONES[ones])
|
|
85
92
|
}
|
|
86
93
|
|
|
@@ -105,7 +112,7 @@ const SCALE_WORDS_SINGULAR = [
|
|
|
105
112
|
'mil biliões', // 5: 10^15 (compound)
|
|
106
113
|
'trilião', // 6: 10^18
|
|
107
114
|
'mil triliões', // 7: 10^21 (compound)
|
|
108
|
-
'quatrilião' // 8: 10^24
|
|
115
|
+
'quatrilião', // 8: 10^24
|
|
109
116
|
]
|
|
110
117
|
|
|
111
118
|
const SCALE_WORDS_PLURAL = [
|
|
@@ -117,20 +124,32 @@ const SCALE_WORDS_PLURAL = [
|
|
|
117
124
|
'mil biliões', // 5: 10^15 (compound, same)
|
|
118
125
|
'triliões', // 6: 10^18
|
|
119
126
|
'mil triliões', // 7: 10^21 (compound, same)
|
|
120
|
-
'quatriliões' // 8: 10^24
|
|
127
|
+
'quatriliões', // 8: 10^24
|
|
121
128
|
]
|
|
122
129
|
|
|
130
|
+
// Scale ordinal words (long scale for pt-PT). Module-scope so its length can
|
|
131
|
+
// derive the ordinal ceiling and so it isn't rebuilt on every call.
|
|
132
|
+
const SCALE_ORDINAL = ['', 'milésimo', 'milionésimo', 'mil milionésimo', 'bilionésimo', 'mil bilionésimo', 'trilionésimo']
|
|
133
|
+
|
|
134
|
+
// Supported magnitude ceilings (checked at the public entry points). Cardinal
|
|
135
|
+
// scale words reach index SCALE_WORDS_SINGULAR.length-1 (quatrilião, 10^24), so
|
|
136
|
+
// cardinals/currency must stay below 10^27. The ordinal of a number whose
|
|
137
|
+
// lowest non-zero group is a scale group uses SCALE_ORDINAL, which is shorter,
|
|
138
|
+
// so ordinals must stay below 10^(SCALE_ORDINAL.length * 3).
|
|
139
|
+
export const cardinalMax = western(SCALE_WORDS_SINGULAR.length - 1)
|
|
140
|
+
export const ordinalMax = western(SCALE_ORDINAL.length - 1)
|
|
141
|
+
export const currencyMax = western(SCALE_WORDS_SINGULAR.length - 1)
|
|
142
|
+
|
|
123
143
|
// ============================================================================
|
|
124
144
|
// Conversion Functions
|
|
125
145
|
// ============================================================================
|
|
126
146
|
|
|
127
147
|
/**
|
|
128
148
|
* Converts a non-negative integer to Portuguese words.
|
|
129
|
-
*
|
|
130
149
|
* @param {bigint} n - Non-negative integer to convert
|
|
131
150
|
* @returns {string} Portuguese words
|
|
132
151
|
*/
|
|
133
|
-
function integerToWords
|
|
152
|
+
function integerToWords(n) {
|
|
134
153
|
if (n === 0n) return ZERO
|
|
135
154
|
|
|
136
155
|
// Fast path: numbers < 1000
|
|
@@ -147,7 +166,8 @@ function integerToWords (n) {
|
|
|
147
166
|
if (thousands === 1) {
|
|
148
167
|
// "mil" not "um mil"
|
|
149
168
|
result = THOUSAND
|
|
150
|
-
}
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
151
171
|
result = buildSegment(thousands).word + ' ' + THOUSAND
|
|
152
172
|
}
|
|
153
173
|
|
|
@@ -156,7 +176,8 @@ function integerToWords (n) {
|
|
|
156
176
|
// Insert "e" before remainder if it doesn't start with hundreds (< 100)
|
|
157
177
|
if (!remainderResult.startsWithHundreds) {
|
|
158
178
|
result += ' e ' + remainderResult.word
|
|
159
|
-
}
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
160
181
|
result += ' ' + remainderResult.word
|
|
161
182
|
}
|
|
162
183
|
}
|
|
@@ -171,11 +192,10 @@ function integerToWords (n) {
|
|
|
171
192
|
/**
|
|
172
193
|
* Builds words for numbers >= 1,000,000.
|
|
173
194
|
* Uses BigInt division for faster segment extraction.
|
|
174
|
-
*
|
|
175
195
|
* @param {bigint} n - Number >= 1,000,000
|
|
176
196
|
* @returns {string} Portuguese words
|
|
177
197
|
*/
|
|
178
|
-
function buildLargeNumberWords
|
|
198
|
+
function buildLargeNumberWords(n) {
|
|
179
199
|
// Extract segments using BigInt division
|
|
180
200
|
// Segments stored least-significant first (index 0 = ones, 1 = thousands, etc.)
|
|
181
201
|
const segments = []
|
|
@@ -216,20 +236,24 @@ function buildLargeNumberWords (n) {
|
|
|
216
236
|
// Units segment
|
|
217
237
|
result += segmentResult.word
|
|
218
238
|
prevWasScale = false
|
|
219
|
-
}
|
|
239
|
+
}
|
|
240
|
+
else if (i === 1) {
|
|
220
241
|
// Thousands
|
|
221
242
|
if (segment === 1) {
|
|
222
243
|
result += THOUSAND
|
|
223
|
-
}
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
224
246
|
result += segmentResult.word + ' ' + THOUSAND
|
|
225
247
|
}
|
|
226
248
|
prevWasScale = true
|
|
227
|
-
}
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
228
251
|
// Million and above - use scale arrays
|
|
229
252
|
const scaleWord = segment === 1 ? SCALE_WORDS_SINGULAR[i] : SCALE_WORDS_PLURAL[i]
|
|
230
253
|
if (segment === 1) {
|
|
231
254
|
result += 'um ' + scaleWord
|
|
232
|
-
}
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
233
257
|
result += segmentResult.word + ' ' + scaleWord
|
|
234
258
|
}
|
|
235
259
|
prevWasScale = true
|
|
@@ -241,11 +265,10 @@ function buildLargeNumberWords (n) {
|
|
|
241
265
|
|
|
242
266
|
/**
|
|
243
267
|
* Converts decimal digits to Portuguese words.
|
|
244
|
-
*
|
|
245
268
|
* @param {string} decimalPart - Decimal digits (without the point)
|
|
246
269
|
* @returns {string} Portuguese words for decimal part
|
|
247
270
|
*/
|
|
248
|
-
function decimalPartToWords
|
|
271
|
+
function decimalPartToWords(decimalPart) {
|
|
249
272
|
let result = ''
|
|
250
273
|
|
|
251
274
|
// Handle leading zeros
|
|
@@ -271,19 +294,20 @@ function decimalPartToWords (decimalPart) {
|
|
|
271
294
|
*
|
|
272
295
|
* This is the main public API. It accepts any valid numeric input
|
|
273
296
|
* (number, string, or bigint) and handles parsing internally.
|
|
274
|
-
*
|
|
275
297
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
276
298
|
* @returns {string} The number in Portuguese words
|
|
277
299
|
* @throws {TypeError} If value is not a valid numeric type
|
|
278
300
|
* @throws {Error} If value is not a valid number format
|
|
279
|
-
*
|
|
280
301
|
* @example
|
|
281
302
|
* toCardinal(21) // 'vinte e um'
|
|
282
303
|
* toCardinal(100) // 'cem'
|
|
283
304
|
* toCardinal(1000000) // 'um milhão'
|
|
284
305
|
*/
|
|
285
|
-
function toCardinal
|
|
306
|
+
function toCardinal(value) {
|
|
286
307
|
const { isNegative, integerPart, decimalPart } = parseCardinalValue(value)
|
|
308
|
+
// Both the integer part and the decimal's significant digits are spelled via
|
|
309
|
+
// the scale builder, so both must clear the ceiling.
|
|
310
|
+
checkMax(integerPart, cardinalMax, decimalPart)
|
|
287
311
|
|
|
288
312
|
let result = ''
|
|
289
313
|
|
|
@@ -306,11 +330,10 @@ function toCardinal (value) {
|
|
|
306
330
|
|
|
307
331
|
/**
|
|
308
332
|
* Builds ordinal words for 0-999.
|
|
309
|
-
*
|
|
310
333
|
* @param {number} n - Number 0-999
|
|
311
334
|
* @returns {string} Portuguese ordinal words
|
|
312
335
|
*/
|
|
313
|
-
function buildOrdinalSegment
|
|
336
|
+
function buildOrdinalSegment(n) {
|
|
314
337
|
if (n === 0) return ''
|
|
315
338
|
|
|
316
339
|
const ones = n % 10
|
|
@@ -328,12 +351,14 @@ function buildOrdinalSegment (n) {
|
|
|
328
351
|
if (tens === 1) {
|
|
329
352
|
// 10-19: use teens array (décimo, décimo primeiro, etc.)
|
|
330
353
|
parts.push(ORDINAL_TEENS[ones])
|
|
331
|
-
}
|
|
354
|
+
}
|
|
355
|
+
else if (tens >= 2) {
|
|
332
356
|
parts.push(ORDINAL_TENS[tens])
|
|
333
357
|
if (ones > 0) {
|
|
334
358
|
parts.push(ORDINAL_ONES[ones])
|
|
335
359
|
}
|
|
336
|
-
}
|
|
360
|
+
}
|
|
361
|
+
else if (ones > 0) {
|
|
337
362
|
parts.push(ORDINAL_ONES[ones])
|
|
338
363
|
}
|
|
339
364
|
|
|
@@ -342,11 +367,10 @@ function buildOrdinalSegment (n) {
|
|
|
342
367
|
|
|
343
368
|
/**
|
|
344
369
|
* Builds ordinal words for large numbers.
|
|
345
|
-
*
|
|
346
370
|
* @param {bigint} n - Non-negative integer
|
|
347
371
|
* @returns {string} Portuguese ordinal words
|
|
348
372
|
*/
|
|
349
|
-
function buildLargeOrdinal
|
|
373
|
+
function buildLargeOrdinal(n) {
|
|
350
374
|
// Extract segments
|
|
351
375
|
const segments = []
|
|
352
376
|
let temp = n
|
|
@@ -364,9 +388,6 @@ function buildLargeOrdinal (n) {
|
|
|
364
388
|
}
|
|
365
389
|
}
|
|
366
390
|
|
|
367
|
-
// Scale ordinal words (singular forms)
|
|
368
|
-
const SCALE_ORDINAL = ['', 'milésimo', 'milionésimo', 'mil milionésimo', 'bilionésimo', 'mil bilionésimo', 'trilionésimo']
|
|
369
|
-
|
|
370
391
|
let result = ''
|
|
371
392
|
|
|
372
393
|
for (let i = segments.length - 1; i >= 0; i--) {
|
|
@@ -380,28 +401,35 @@ function buildLargeOrdinal (n) {
|
|
|
380
401
|
if (i === 0) {
|
|
381
402
|
// Units: just ordinal
|
|
382
403
|
result += buildOrdinalSegment(segment)
|
|
383
|
-
}
|
|
404
|
+
}
|
|
405
|
+
else if (segment === 1 && i > 0) {
|
|
384
406
|
// Exact scale: "milésimo", "milionésimo", etc.
|
|
385
407
|
result += SCALE_ORDINAL[i]
|
|
386
|
-
}
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
387
410
|
// Segment + scale ordinal
|
|
388
411
|
result += buildOrdinalSegment(segment) + ' ' + SCALE_ORDINAL[i]
|
|
389
412
|
}
|
|
390
|
-
}
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
391
415
|
// Higher segments use cardinal form
|
|
392
416
|
if (i === 0) {
|
|
393
417
|
result += buildSegment(segment).word
|
|
394
|
-
}
|
|
418
|
+
}
|
|
419
|
+
else if (i === 1) {
|
|
395
420
|
if (segment === 1) {
|
|
396
421
|
result += THOUSAND
|
|
397
|
-
}
|
|
422
|
+
}
|
|
423
|
+
else {
|
|
398
424
|
result += buildSegment(segment).word + ' ' + THOUSAND
|
|
399
425
|
}
|
|
400
|
-
}
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
401
428
|
const scaleWord = segment === 1 ? SCALE_WORDS_SINGULAR[i] : SCALE_WORDS_PLURAL[i]
|
|
402
429
|
if (segment === 1) {
|
|
403
430
|
result += 'um ' + scaleWord
|
|
404
|
-
}
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
405
433
|
result += buildSegment(segment).word + ' ' + scaleWord
|
|
406
434
|
}
|
|
407
435
|
}
|
|
@@ -413,17 +441,16 @@ function buildLargeOrdinal (n) {
|
|
|
413
441
|
|
|
414
442
|
/**
|
|
415
443
|
* Converts a number to Portuguese ordinal words.
|
|
416
|
-
*
|
|
417
444
|
* @param {number | string | bigint} value - The number to convert
|
|
418
445
|
* @returns {string} Portuguese ordinal words
|
|
419
|
-
*
|
|
420
446
|
* @example
|
|
421
447
|
* toOrdinal(1) // 'primeiro'
|
|
422
448
|
* toOrdinal(21) // 'vigésimo primeiro'
|
|
423
449
|
* toOrdinal(100) // 'centésimo'
|
|
424
450
|
*/
|
|
425
|
-
function toOrdinal
|
|
451
|
+
function toOrdinal(value) {
|
|
426
452
|
const n = parseOrdinalValue(value)
|
|
453
|
+
checkMax(n, ordinalMax)
|
|
427
454
|
|
|
428
455
|
// Fast path: 1-9
|
|
429
456
|
if (n < 10n) {
|
|
@@ -458,23 +485,28 @@ function toOrdinal (value) {
|
|
|
458
485
|
// Currency Functions
|
|
459
486
|
// ============================================================================
|
|
460
487
|
|
|
488
|
+
/**
|
|
489
|
+
* @typedef {object} CurrencyOptions
|
|
490
|
+
* @property {boolean} [and] - Include "e" between euros and cents
|
|
491
|
+
*/
|
|
492
|
+
|
|
493
|
+
/** @type {Required<CurrencyOptions>} */
|
|
494
|
+
export const currencyDefaults = { and: true }
|
|
495
|
+
|
|
461
496
|
/**
|
|
462
497
|
* Converts a number to Portuguese currency words (Euro).
|
|
463
|
-
*
|
|
464
498
|
* @param {number | string | bigint} value - The amount to convert
|
|
465
|
-
* @param {
|
|
466
|
-
* @param {boolean} [options.and=true] - Include "e" between euros and cents
|
|
499
|
+
* @param {CurrencyOptions} [options] Currency formatting options
|
|
467
500
|
* @returns {string} Portuguese currency words
|
|
468
|
-
*
|
|
469
501
|
* @example
|
|
470
502
|
* toCurrency(42.50) // 'quarenta e dois euros e cinquenta cêntimos'
|
|
471
503
|
* toCurrency(1) // 'um euro'
|
|
472
504
|
* toCurrency(0.01) // 'um cêntimo'
|
|
473
505
|
*/
|
|
474
|
-
function toCurrency
|
|
475
|
-
options = validateOptions(options)
|
|
506
|
+
function toCurrency(value, options) {
|
|
476
507
|
const { isNegative, dollars: euros, cents } = parseCurrencyValue(value)
|
|
477
|
-
|
|
508
|
+
checkMax(euros, currencyMax)
|
|
509
|
+
const { and } = resolveOptions(options, currencyDefaults)
|
|
478
510
|
|
|
479
511
|
let result = ''
|
|
480
512
|
|
package/src/ro-RO.d.ts
CHANGED
|
@@ -1,29 +1,41 @@
|
|
|
1
|
+
export const cardinalMax: bigint;
|
|
2
|
+
export const ordinalMax: bigint;
|
|
3
|
+
export const currencyMax: bigint;
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {object} CardinalOptions
|
|
6
|
+
* @property {('masculine'|'feminine')} [gender] - Gender for numbers
|
|
7
|
+
*/
|
|
8
|
+
/** @type {Required<CardinalOptions>} */
|
|
9
|
+
export const cardinalDefaults: Required<CardinalOptions>;
|
|
10
|
+
/** @type {{ gender: ReadonlyArray<Required<CardinalOptions>['gender']> }} */
|
|
11
|
+
export const cardinalValues: {
|
|
12
|
+
gender: ReadonlyArray<Required<CardinalOptions>["gender"]>;
|
|
13
|
+
};
|
|
14
|
+
export type CardinalOptions = {
|
|
15
|
+
/**
|
|
16
|
+
* - Gender for numbers
|
|
17
|
+
*/
|
|
18
|
+
gender?: "feminine" | "masculine" | undefined;
|
|
19
|
+
};
|
|
1
20
|
/**
|
|
2
21
|
* Converts a numeric value to Romanian words.
|
|
3
|
-
*
|
|
4
22
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
5
|
-
* @param {
|
|
6
|
-
* @param {string} [options.gender='masculine'] - Gender for numbers
|
|
23
|
+
* @param {CardinalOptions} [options] - Conversion options
|
|
7
24
|
* @returns {string} The number in Romanian words
|
|
8
25
|
* @throws {TypeError} If value is not a valid numeric type
|
|
9
26
|
* @throws {Error} If value is not a valid number format
|
|
10
|
-
*
|
|
11
27
|
* @example
|
|
12
28
|
* toCardinal(21) // 'douăzeci și unu'
|
|
13
29
|
* toCardinal(1, { gender: 'feminine' }) // 'una'
|
|
14
30
|
* toCardinal(1000) // 'o mie'
|
|
15
31
|
*/
|
|
16
|
-
export function toCardinal(value: number | string | bigint, options?:
|
|
17
|
-
gender?: string | undefined;
|
|
18
|
-
}): string;
|
|
32
|
+
export function toCardinal(value: number | string | bigint, options?: CardinalOptions): string;
|
|
19
33
|
/**
|
|
20
34
|
* Converts a numeric value to Romanian ordinal words.
|
|
21
|
-
*
|
|
22
35
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
23
36
|
* @returns {string} The ordinal in Romanian words
|
|
24
37
|
* @throws {TypeError} If value is not a valid numeric type
|
|
25
38
|
* @throws {Error} If value is not a positive integer
|
|
26
|
-
*
|
|
27
39
|
* @example
|
|
28
40
|
* toOrdinal(1) // 'primul'
|
|
29
41
|
* toOrdinal(21) // 'douăzeci și primul'
|
|
@@ -31,12 +43,10 @@ export function toCardinal(value: number | string | bigint, options?: {
|
|
|
31
43
|
export function toOrdinal(value: number | string | bigint): string;
|
|
32
44
|
/**
|
|
33
45
|
* Converts a numeric value to Romanian Leu currency words.
|
|
34
|
-
*
|
|
35
46
|
* @param {number | string | bigint} value - The numeric value to convert
|
|
36
47
|
* @returns {string} The currency in Romanian words
|
|
37
48
|
* @throws {TypeError} If value is not a valid numeric type
|
|
38
49
|
* @throws {Error} If value is not a valid number format
|
|
39
|
-
*
|
|
40
50
|
* @example
|
|
41
51
|
* toCurrency(1) // 'un leu'
|
|
42
52
|
* toCurrency(2.50) // 'doi lei cincizeci de bani'
|