n2words 1.23.1 → 1.24.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/LICENSE +1 -1
- package/README.md +181 -52
- package/dist/languages/ar.js +2 -0
- package/dist/languages/ar.js.map +1 -0
- package/dist/languages/az.js +2 -0
- package/dist/languages/az.js.map +1 -0
- package/dist/languages/bn.js +2 -0
- package/dist/languages/bn.js.map +1 -0
- package/dist/languages/cs.js +2 -0
- package/dist/languages/cs.js.map +1 -0
- package/dist/languages/da.js +2 -0
- package/dist/languages/da.js.map +1 -0
- package/dist/languages/de.js +2 -0
- package/dist/languages/de.js.map +1 -0
- package/dist/languages/el.js +2 -0
- package/dist/languages/el.js.map +1 -0
- package/dist/languages/en.js +2 -0
- package/dist/languages/en.js.map +1 -0
- package/dist/languages/es.js +2 -0
- package/dist/languages/es.js.map +1 -0
- package/dist/languages/fa.js +2 -0
- package/dist/languages/fa.js.map +1 -0
- package/dist/languages/fil.js +2 -0
- package/dist/languages/fil.js.map +1 -0
- package/dist/languages/fr-BE.js +2 -0
- package/dist/languages/fr-BE.js.map +1 -0
- package/dist/languages/fr.js +2 -0
- package/dist/languages/fr.js.map +1 -0
- package/dist/languages/gu.js +2 -0
- package/dist/languages/gu.js.map +1 -0
- package/dist/languages/he.js +2 -0
- package/dist/languages/he.js.map +1 -0
- package/dist/languages/hi.js +2 -0
- package/dist/languages/hi.js.map +1 -0
- package/dist/languages/hr.js +2 -0
- package/dist/languages/hr.js.map +1 -0
- package/dist/languages/hu.js +2 -0
- package/dist/languages/hu.js.map +1 -0
- package/dist/languages/id.js +2 -0
- package/dist/languages/id.js.map +1 -0
- package/dist/languages/it.js +2 -0
- package/dist/languages/it.js.map +1 -0
- package/dist/languages/ja.js +2 -0
- package/dist/languages/ja.js.map +1 -0
- package/dist/languages/kn.js +2 -0
- package/dist/languages/kn.js.map +1 -0
- package/dist/languages/ko.js +2 -0
- package/dist/languages/ko.js.map +1 -0
- package/dist/languages/lt.js +2 -0
- package/dist/languages/lt.js.map +1 -0
- package/dist/languages/lv.js +2 -0
- package/dist/languages/lv.js.map +1 -0
- package/dist/languages/mr.js +2 -0
- package/dist/languages/mr.js.map +1 -0
- package/dist/languages/ms.js +2 -0
- package/dist/languages/ms.js.map +1 -0
- package/dist/languages/nb.js +2 -0
- package/dist/languages/nb.js.map +1 -0
- package/dist/languages/nl.js +2 -0
- package/dist/languages/nl.js.map +1 -0
- package/dist/languages/pa-Guru.js +2 -0
- package/dist/languages/pa-Guru.js.map +1 -0
- package/dist/languages/pl.js +2 -0
- package/dist/languages/pl.js.map +1 -0
- package/dist/languages/pt.js +2 -0
- package/dist/languages/pt.js.map +1 -0
- package/dist/languages/ro.js +2 -0
- package/dist/languages/ro.js.map +1 -0
- package/dist/languages/ru.js +2 -0
- package/dist/languages/ru.js.map +1 -0
- package/dist/languages/sr-Latn.js +2 -0
- package/dist/languages/sr-Latn.js.map +1 -0
- package/dist/languages/sv.js +2 -0
- package/dist/languages/sv.js.map +1 -0
- package/dist/languages/sw.js +2 -0
- package/dist/languages/sw.js.map +1 -0
- package/dist/languages/ta.js +2 -0
- package/dist/languages/ta.js.map +1 -0
- package/dist/languages/te.js +2 -0
- package/dist/languages/te.js.map +1 -0
- package/dist/languages/th.js +2 -0
- package/dist/languages/th.js.map +1 -0
- package/dist/languages/tr.js +2 -0
- package/dist/languages/tr.js.map +1 -0
- package/dist/languages/uk.js +2 -0
- package/dist/languages/uk.js.map +1 -0
- package/dist/languages/ur.js +2 -0
- package/dist/languages/ur.js.map +1 -0
- package/dist/languages/vi.js +2 -0
- package/dist/languages/vi.js.map +1 -0
- package/dist/languages/zh-Hans.js +2 -0
- package/dist/languages/zh-Hans.js.map +1 -0
- package/dist/n2words.js +1 -1
- package/dist/n2words.js.map +1 -1
- package/lib/classes/abstract-language.js +211 -110
- package/lib/classes/greedy-scale-language.js +195 -0
- package/lib/classes/slavic-language.js +251 -0
- package/lib/classes/south-asian-language.js +161 -0
- package/lib/classes/turkic-language.js +63 -0
- package/lib/languages/ar.js +243 -0
- package/lib/languages/az.js +58 -0
- package/lib/languages/bn.js +126 -0
- package/lib/languages/cs.js +212 -0
- package/lib/languages/da.js +167 -0
- package/lib/languages/de.js +135 -0
- package/lib/languages/el.js +116 -0
- package/lib/languages/en.js +123 -0
- package/lib/languages/es.js +153 -0
- package/lib/languages/fa.js +127 -0
- package/lib/languages/fil.js +162 -0
- package/lib/languages/fr-BE.js +61 -0
- package/lib/languages/fr.js +145 -0
- package/lib/languages/gu.js +156 -0
- package/lib/languages/he.js +329 -0
- package/lib/languages/hi.js +126 -0
- package/lib/languages/hr.js +157 -0
- package/lib/languages/hu.js +155 -0
- package/lib/languages/id.js +174 -0
- package/lib/languages/it.js +148 -0
- package/lib/languages/ja.js +190 -0
- package/lib/languages/kn.js +71 -0
- package/lib/languages/ko.js +83 -0
- package/lib/languages/lt.js +171 -0
- package/lib/languages/lv.js +153 -0
- package/lib/languages/mr.js +156 -0
- package/lib/languages/ms.js +146 -0
- package/lib/languages/nb.js +120 -0
- package/lib/languages/nl.js +206 -0
- package/lib/languages/pa-Guru.js +126 -0
- package/lib/languages/pl.js +189 -0
- package/lib/languages/pt.js +147 -0
- package/lib/languages/ro.js +380 -0
- package/lib/languages/ru.js +116 -0
- package/lib/languages/sr-Latn.js +157 -0
- package/lib/languages/sv.js +127 -0
- package/lib/languages/sw.js +121 -0
- package/lib/languages/ta.js +226 -0
- package/lib/languages/te.js +229 -0
- package/lib/languages/th.js +123 -0
- package/lib/languages/tr.js +83 -0
- package/lib/{i18n → languages}/uk.js +50 -23
- package/lib/languages/ur.js +126 -0
- package/lib/languages/vi.js +193 -0
- package/lib/languages/zh-Hans.js +165 -0
- package/lib/n2words.js +246 -75
- package/package.json +80 -72
- package/typings/classes/abstract-language.d.ts +144 -0
- package/typings/classes/greedy-scale-language.d.ts +148 -0
- package/typings/classes/slavic-language.d.ts +145 -0
- package/typings/classes/south-asian-language.d.ts +101 -0
- package/typings/classes/turkic-language.d.ts +42 -0
- package/typings/languages/ar.d.ts +93 -0
- package/typings/languages/az.d.ts +25 -0
- package/typings/languages/bn.d.ts +1 -0
- package/typings/languages/cs.d.ts +120 -0
- package/typings/languages/da.d.ts +53 -0
- package/typings/languages/de.d.ts +26 -0
- package/typings/languages/el.d.ts +11 -0
- package/typings/languages/en.d.ts +30 -0
- package/typings/languages/es.d.ts +43 -0
- package/typings/languages/fa.d.ts +81 -0
- package/typings/languages/fil.d.ts +12 -0
- package/typings/languages/fr-BE.d.ts +41 -0
- package/typings/languages/fr.d.ts +43 -0
- package/typings/languages/gu.d.ts +12 -0
- package/typings/languages/he.d.ts +197 -0
- package/typings/languages/hi.d.ts +1 -0
- package/typings/languages/hr.d.ts +110 -0
- package/typings/languages/hu.d.ts +37 -0
- package/typings/languages/id.d.ts +69 -0
- package/typings/languages/it.d.ts +51 -0
- package/typings/languages/ja.d.ts +58 -0
- package/typings/languages/kn.d.ts +11 -0
- package/typings/languages/ko.d.ts +25 -0
- package/typings/languages/lt.d.ts +110 -0
- package/typings/languages/lv.d.ts +99 -0
- package/typings/languages/mr.d.ts +12 -0
- package/typings/languages/ms.d.ts +37 -0
- package/typings/languages/nb.d.ts +27 -0
- package/typings/languages/nl.d.ts +65 -0
- package/typings/languages/pa-Guru.d.ts +1 -0
- package/typings/languages/pl.d.ts +116 -0
- package/typings/languages/pt.d.ts +39 -0
- package/typings/languages/ro.d.ts +229 -0
- package/typings/languages/ru.d.ts +108 -0
- package/typings/languages/sr-Latn.d.ts +98 -0
- package/typings/languages/sv.d.ts +30 -0
- package/typings/languages/sw.d.ts +1 -0
- package/typings/languages/ta.d.ts +1 -0
- package/typings/languages/te.d.ts +1 -0
- package/typings/languages/th.d.ts +1 -0
- package/typings/languages/tr.d.ts +46 -0
- package/typings/languages/uk.d.ts +117 -0
- package/typings/languages/ur.d.ts +1 -0
- package/typings/languages/vi.d.ts +116 -0
- package/typings/languages/zh-Hans.d.ts +57 -0
- package/typings/n2words.d.ts +177 -0
- package/dist/ar.js +0 -2
- package/dist/ar.js.map +0 -1
- package/dist/az.js +0 -2
- package/dist/az.js.map +0 -1
- package/dist/cz.js +0 -2
- package/dist/cz.js.map +0 -1
- package/dist/de.js +0 -2
- package/dist/de.js.map +0 -1
- package/dist/dk.js +0 -2
- package/dist/dk.js.map +0 -1
- package/dist/en.js +0 -2
- package/dist/en.js.map +0 -1
- package/dist/es.js +0 -2
- package/dist/es.js.map +0 -1
- package/dist/fa.js +0 -2
- package/dist/fa.js.map +0 -1
- package/dist/fr-BE.js +0 -2
- package/dist/fr-BE.js.map +0 -1
- package/dist/fr.js +0 -2
- package/dist/fr.js.map +0 -1
- package/dist/he.js +0 -2
- package/dist/he.js.map +0 -1
- package/dist/hr.js +0 -2
- package/dist/hr.js.map +0 -1
- package/dist/hu.js +0 -2
- package/dist/hu.js.map +0 -1
- package/dist/id.js +0 -2
- package/dist/id.js.map +0 -1
- package/dist/it.js +0 -2
- package/dist/it.js.map +0 -1
- package/dist/ko.js +0 -2
- package/dist/ko.js.map +0 -1
- package/dist/lt.js +0 -2
- package/dist/lt.js.map +0 -1
- package/dist/lv.js +0 -2
- package/dist/lv.js.map +0 -1
- package/dist/n2words.d.ts +0 -2
- package/dist/nl.js +0 -2
- package/dist/nl.js.map +0 -1
- package/dist/no.js +0 -2
- package/dist/no.js.map +0 -1
- package/dist/pl.js +0 -2
- package/dist/pl.js.map +0 -1
- package/dist/pt.js +0 -2
- package/dist/pt.js.map +0 -1
- package/dist/ro.js +0 -2
- package/dist/ro.js.map +0 -1
- package/dist/ru.js +0 -2
- package/dist/ru.js.map +0 -1
- package/dist/sr.js +0 -2
- package/dist/sr.js.map +0 -1
- package/dist/tr.js +0 -2
- package/dist/tr.js.map +0 -1
- package/dist/uk.js +0 -2
- package/dist/uk.js.map +0 -1
- package/dist/vi.js +0 -2
- package/dist/vi.js.map +0 -1
- package/dist/zh.js +0 -2
- package/dist/zh.js.map +0 -1
- package/lib/classes/abstract-language.d.ts +0 -54
- package/lib/classes/base-language.d.ts +0 -58
- package/lib/classes/base-language.js +0 -172
- package/lib/i18n/ar.d.ts +0 -41
- package/lib/i18n/ar.js +0 -209
- package/lib/i18n/az.d.ts +0 -15
- package/lib/i18n/az.js +0 -66
- package/lib/i18n/cz.d.ts +0 -68
- package/lib/i18n/cz.js +0 -135
- package/lib/i18n/de.d.ts +0 -17
- package/lib/i18n/de.js +0 -103
- package/lib/i18n/dk.d.ts +0 -14
- package/lib/i18n/dk.js +0 -110
- package/lib/i18n/en.d.ts +0 -22
- package/lib/i18n/en.js +0 -86
- package/lib/i18n/es.d.ts +0 -16
- package/lib/i18n/es.js +0 -110
- package/lib/i18n/fa.d.ts +0 -54
- package/lib/i18n/fa.js +0 -106
- package/lib/i18n/fr-BE.d.ts +0 -11
- package/lib/i18n/fr-BE.js +0 -20
- package/lib/i18n/fr.d.ts +0 -15
- package/lib/i18n/fr.js +0 -99
- package/lib/i18n/he.d.ts +0 -61
- package/lib/i18n/he.js +0 -132
- package/lib/i18n/hr.d.ts +0 -68
- package/lib/i18n/hr.js +0 -129
- package/lib/i18n/hu.d.ts +0 -17
- package/lib/i18n/hu.js +0 -135
- package/lib/i18n/id.d.ts +0 -43
- package/lib/i18n/id.js +0 -156
- package/lib/i18n/it.d.ts +0 -29
- package/lib/i18n/it.js +0 -137
- package/lib/i18n/ko.d.ts +0 -15
- package/lib/i18n/ko.js +0 -56
- package/lib/i18n/lt.d.ts +0 -68
- package/lib/i18n/lt.js +0 -138
- package/lib/i18n/lv.d.ts +0 -57
- package/lib/i18n/lv.js +0 -120
- package/lib/i18n/nl.d.ts +0 -20
- package/lib/i18n/nl.js +0 -125
- package/lib/i18n/no.d.ts +0 -15
- package/lib/i18n/no.js +0 -77
- package/lib/i18n/pl.d.ts +0 -67
- package/lib/i18n/pl.js +0 -126
- package/lib/i18n/pt.d.ts +0 -26
- package/lib/i18n/pt.js +0 -118
- package/lib/i18n/ro.d.ts +0 -109
- package/lib/i18n/ro.js +0 -360
- package/lib/i18n/ru.d.ts +0 -30
- package/lib/i18n/ru.js +0 -198
- package/lib/i18n/sr.d.ts +0 -56
- package/lib/i18n/sr.js +0 -127
- package/lib/i18n/tr.d.ts +0 -15
- package/lib/i18n/tr.js +0 -64
- package/lib/i18n/uk.d.ts +0 -78
- package/lib/i18n/vi.d.ts +0 -70
- package/lib/i18n/vi.js +0 -151
- package/lib/i18n/zh.d.ts +0 -18
- package/lib/i18n/zh.js +0 -78
- package/lib/n2words.d.ts +0 -9
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import GreedyScaleLanguage from '../classes/greedy-scale-language.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {Object} DanishOptions
|
|
5
|
+
* @property {boolean} [ordFlag=false] Enable ordinal number conversion.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Danish language converter.
|
|
10
|
+
*
|
|
11
|
+
* GreedyScaleLanguage with Danish-specific extensions:
|
|
12
|
+
* - Unique vigesimal (base-20) number system for 50-90
|
|
13
|
+
* - Special composition rules ("og" for "and" between units and tens)
|
|
14
|
+
* - Reverse digit order (e.g., "fem-og-tyve" = five-and-twenty = 25)
|
|
15
|
+
* - Support for ordinal numbers via ordFlag option
|
|
16
|
+
*
|
|
17
|
+
* Key Features:
|
|
18
|
+
* - Vigesimal tens: halvtreds (50), treds (60), halvfjerds (70), firs (80), halvfems (90)
|
|
19
|
+
* - Units-before-tens pattern (e.g., "tre-og-tyve" = 23)
|
|
20
|
+
* - "et" prefix for hundreds/thousands (not "en")
|
|
21
|
+
* - Optional ordinal number conversion via ordFlag option
|
|
22
|
+
* - Inline merge logic tailored for Danish ordering
|
|
23
|
+
*/
|
|
24
|
+
export class Danish extends GreedyScaleLanguage {
|
|
25
|
+
negativeWord = 'minus'
|
|
26
|
+
decimalSeparatorWord = 'komma'
|
|
27
|
+
zeroWord = 'nul'
|
|
28
|
+
scaleWordPairs = [
|
|
29
|
+
[1_000_000_000_000_000_000_000_000_000n, 'quadrillarder'],
|
|
30
|
+
[1_000_000_000_000_000_000_000_000n, 'quadrillioner'],
|
|
31
|
+
[1_000_000_000_000_000_000_000n, 'trillarder'],
|
|
32
|
+
[1_000_000_000_000_000_000n, 'trillioner'],
|
|
33
|
+
[1_000_000_000_000_000n, 'billarder'],
|
|
34
|
+
[1_000_000_000_000n, 'billioner'],
|
|
35
|
+
[1_000_000_000n, 'millarder'],
|
|
36
|
+
[1_000_000n, 'millioner'],
|
|
37
|
+
[1000n, 'tusind'],
|
|
38
|
+
[100n, 'hundrede'],
|
|
39
|
+
[90n, 'halvfems'],
|
|
40
|
+
[80n, 'firs'],
|
|
41
|
+
[70n, 'halvfjerds'],
|
|
42
|
+
[60n, 'treds'],
|
|
43
|
+
[50n, 'halvtreds'],
|
|
44
|
+
[40n, 'fyrre'],
|
|
45
|
+
[30n, 'tredive'],
|
|
46
|
+
[20n, 'tyve'],
|
|
47
|
+
[19n, 'nitten'],
|
|
48
|
+
[18n, 'atten'],
|
|
49
|
+
[17n, 'sytten'],
|
|
50
|
+
[16n, 'seksten'],
|
|
51
|
+
[15n, 'femten'],
|
|
52
|
+
[14n, 'fjorten'],
|
|
53
|
+
[13n, 'tretten'],
|
|
54
|
+
[12n, 'tolv'],
|
|
55
|
+
[11n, 'elleve'],
|
|
56
|
+
[10n, 'ti'],
|
|
57
|
+
[9n, 'ni'],
|
|
58
|
+
[8n, 'otte'],
|
|
59
|
+
[7n, 'syv'],
|
|
60
|
+
[6n, 'seks'],
|
|
61
|
+
[5n, 'fem'],
|
|
62
|
+
[4n, 'fire'],
|
|
63
|
+
[3n, 'tre'],
|
|
64
|
+
[2n, 'to'],
|
|
65
|
+
[1n, 'et'],
|
|
66
|
+
[0n, 'nul']
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Initializes the Danish converter with language-specific options.
|
|
71
|
+
*
|
|
72
|
+
* @param {DanishOptions} [options={}] Configuration options.
|
|
73
|
+
*/
|
|
74
|
+
constructor ({ ordFlag = false } = {}) {
|
|
75
|
+
super()
|
|
76
|
+
|
|
77
|
+
this.ordFlag = ordFlag
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Merges two adjacent word-number pairs according to Danish grammar rules.
|
|
82
|
+
* Danish uses complex vigesimal (base-20) patterns and reverse digit ordering.
|
|
83
|
+
*
|
|
84
|
+
* Key Danish patterns:
|
|
85
|
+
* - Vigesimal tens: halvtreds(50), treds(60), halvfjerds(70), firs(80), halvfems(90)
|
|
86
|
+
* - Units-before-tens order with "og" (and): "tre-og-tyve" (3 and 20 = 25)
|
|
87
|
+
* - "et" prefix for hundreds/thousands (not "en")
|
|
88
|
+
* - Space separators for large magnitudes (≥ millions)
|
|
89
|
+
* - Ordinal support via this.ordFlag
|
|
90
|
+
*
|
|
91
|
+
* @param {Object} current The left operand as `{ word: bigint }`.
|
|
92
|
+
* @param {Object} next The right operand as `{ word: bigint }`.
|
|
93
|
+
* @returns {Object} Merged pair with combined word and resulting number (bigint).
|
|
94
|
+
*/
|
|
95
|
+
mergeScales (current, next) {
|
|
96
|
+
let cText = Object.keys(current)[0]
|
|
97
|
+
let nText = Object.keys(next)[0]
|
|
98
|
+
const cNumber = Object.values(current)[0] // BigInt (e.g., 1n, 100n, 1000n)
|
|
99
|
+
const nNumber = Object.values(next)[0] // BigInt (e.g., magnitude level like 100n, 1000n)
|
|
100
|
+
|
|
101
|
+
// Prepend "et" to hundreds and thousands (not "en") for proper Danish form
|
|
102
|
+
if (nNumber === 100n || nNumber === 1000n) {
|
|
103
|
+
next = { [`et${nText}`]: nNumber }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Implicit '1' handling: omit '1' before most magnitudes (except millions/ordinals)
|
|
107
|
+
if (cNumber === 1n) {
|
|
108
|
+
if (nNumber < 1_000_000n || this.ordFlag) {
|
|
109
|
+
return next // Just the magnitude word (e.g., "hundrede" not "en hundrede")
|
|
110
|
+
}
|
|
111
|
+
cText = 'en' // Explicit "en" (one) for millions and above
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Multiplication across magnitude boundaries
|
|
115
|
+
if (nNumber > cNumber) {
|
|
116
|
+
// Space for million+ (e.g., "en million", "to millioner")
|
|
117
|
+
if (nNumber >= 1_000_000n) {
|
|
118
|
+
cText += ' '
|
|
119
|
+
}
|
|
120
|
+
return { [`${cText}${nText}`]: cNumber * nNumber }
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Addition with separator rules:
|
|
124
|
+
// "og" (and) for hundreds + smaller numbers
|
|
125
|
+
if (cNumber >= 100n && cNumber < 1000n) {
|
|
126
|
+
cText += ' og '
|
|
127
|
+
} else if (cNumber >= 1000n && cNumber <= 100_000n) {
|
|
128
|
+
// Special "e og" for thousands (e.g., "tusinde og tyve")
|
|
129
|
+
cText += 'e og '
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Units-before-tens reversal (Danish vigesimal pattern):
|
|
133
|
+
// For small units (< 10) with tens (10-99), swap order: "tre og tyve" (25)
|
|
134
|
+
if (nNumber < 10n && cNumber > 10n && cNumber < 100n) {
|
|
135
|
+
if (nNumber === 1n) {
|
|
136
|
+
nText = 'en' // Convert 1 to "en" for vigesimal context
|
|
137
|
+
}
|
|
138
|
+
// Swap positions: units go after "og", tens go before
|
|
139
|
+
const temporary = nText
|
|
140
|
+
nText = cText
|
|
141
|
+
cText = temporary + 'og'
|
|
142
|
+
} else if (cNumber >= 1_000_000n) {
|
|
143
|
+
// Space for large magnitudes (millions+)
|
|
144
|
+
cText += ' '
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return { [`${cText}${nText}`]: cNumber + nNumber }
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Converts a number to Danish cardinal (written) form.
|
|
153
|
+
*
|
|
154
|
+
* @param {number|string|bigint} value The number to convert.
|
|
155
|
+
* @param {Object} [options] Conversion options (see Danish class options).
|
|
156
|
+
* @param {boolean} [options.ordFlag=false] Enable ordinal number conversion.
|
|
157
|
+
* @returns {string} The number expressed in Danish words.
|
|
158
|
+
* @throws {TypeError} If value is NaN or invalid type.
|
|
159
|
+
* @throws {Error} If value is an invalid number string.
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* convertToWords(25); // 'femogtyve' (five-and-twenty)
|
|
163
|
+
* convertToWords(50); // 'halvtreds' (half-third-times-twenty)
|
|
164
|
+
*/
|
|
165
|
+
export default function convertToWords (value, options = {}) {
|
|
166
|
+
return new Danish(options).convertToWords(value)
|
|
167
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import GreedyScaleLanguage from '../classes/greedy-scale-language.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* German language converter.
|
|
5
|
+
*
|
|
6
|
+
* Handles German grammatical features:
|
|
7
|
+
* - "eins" vs "ein" and "eine" forms for 1
|
|
8
|
+
* - Compound words without separators (e.g., "einundzwanzig" = 21)
|
|
9
|
+
* - Million/Billion pluralization
|
|
10
|
+
* - Special characters (e.g., "ü", "ö", "ß")
|
|
11
|
+
*/
|
|
12
|
+
export class German extends GreedyScaleLanguage {
|
|
13
|
+
negativeWord = 'minus'
|
|
14
|
+
decimalSeparatorWord = 'komma'
|
|
15
|
+
zeroWord = 'null'
|
|
16
|
+
scaleWordPairs = [
|
|
17
|
+
[1_000_000_000_000_000_000_000_000_000n, 'Quadrilliarde'],
|
|
18
|
+
[1_000_000_000_000_000_000_000_000n, 'Quadrillion'],
|
|
19
|
+
[1_000_000_000_000_000_000_000n, 'Trilliarde'],
|
|
20
|
+
[1_000_000_000_000_000_000n, 'Trillion'],
|
|
21
|
+
[1_000_000_000_000_000n, 'Billiarde'],
|
|
22
|
+
[1_000_000_000_000n, 'Billion'],
|
|
23
|
+
[1_000_000_000n, 'Milliarde'],
|
|
24
|
+
[1_000_000n, 'Million'],
|
|
25
|
+
[1000n, 'tausend'],
|
|
26
|
+
[100n, 'hundert'],
|
|
27
|
+
[90n, 'neunzig'],
|
|
28
|
+
[80n, 'achtzig'],
|
|
29
|
+
[70n, 'siebzig'],
|
|
30
|
+
[60n, 'sechzig'],
|
|
31
|
+
[50n, 'fünfzig'],
|
|
32
|
+
[40n, 'vierzig'],
|
|
33
|
+
[30n, 'dreißig'],
|
|
34
|
+
[20n, 'zwanzig'],
|
|
35
|
+
[19n, 'neunzehn'],
|
|
36
|
+
[18n, 'achtzehn'],
|
|
37
|
+
[17n, 'siebzehn'],
|
|
38
|
+
[16n, 'sechzehn'],
|
|
39
|
+
[15n, 'fünfzehn'],
|
|
40
|
+
[14n, 'vierzehn'],
|
|
41
|
+
[13n, 'dreizehn'],
|
|
42
|
+
[12n, 'zwölf'],
|
|
43
|
+
[11n, 'elf'],
|
|
44
|
+
[10n, 'zehn'],
|
|
45
|
+
[9n, 'neun'],
|
|
46
|
+
[8n, 'acht'],
|
|
47
|
+
[7n, 'sieben'],
|
|
48
|
+
[6n, 'sechs'],
|
|
49
|
+
[5n, 'fünf'],
|
|
50
|
+
[4n, 'vier'],
|
|
51
|
+
[3n, 'drei'],
|
|
52
|
+
[2n, 'zwei'],
|
|
53
|
+
[1n, 'eins'],
|
|
54
|
+
[0n, 'null']
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Merges two adjacent word-number pairs according to German grammar rules.
|
|
59
|
+
*
|
|
60
|
+
* German-specific rules:
|
|
61
|
+
* - Implicit "eins": `mergeScales({ 'eins': 1n }, { 'hundert': 100n })` → `{ 'einhundert': 100n }`
|
|
62
|
+
* - Compound words without separators (e.g., "einundzwanzig" = 21)
|
|
63
|
+
* - Special handling for forms of 1 (eins/ein/eine) depending on context
|
|
64
|
+
* - Pluralization of millions and higher: "Millionen", "Milliarden"
|
|
65
|
+
* - Reordering of tens and units: `mergeScales({ 'zwanzig': 20n }, { 'eins': 1n })` → `{ 'einundzwanzig': 21n }`
|
|
66
|
+
*
|
|
67
|
+
* @param {Object} currentPair The left operand as `{ word: BigInt }`.
|
|
68
|
+
* @param {Object} nextPair The right operand as `{ word: BigInt }`.
|
|
69
|
+
* @returns {Object} Merged pair with combined word and resulting numeric value.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* mergeScales({ 'eins': 1n }, { 'hundert': 100n }); // { 'einhundert': 100n }
|
|
73
|
+
* mergeScales({ 'zwanzig': 20n }, { 'drei': 3n }); // { 'dreiundzwanzig': 23n }
|
|
74
|
+
*/
|
|
75
|
+
mergeScales (currentPair, nextPair) {
|
|
76
|
+
let currentWord = Object.keys(currentPair)[0]
|
|
77
|
+
let nextWord = Object.keys(nextPair)[0]
|
|
78
|
+
const currentNumber = Object.values(currentPair)[0]
|
|
79
|
+
const nextNumber = Object.values(nextPair)[0]
|
|
80
|
+
|
|
81
|
+
// Handle form of 1: "eins" → "ein(e)" in certain contexts
|
|
82
|
+
if (currentNumber === 1n) {
|
|
83
|
+
if (nextNumber === 100n || nextNumber === 1000n) {
|
|
84
|
+
return { [`ein${nextWord}`]: nextNumber }
|
|
85
|
+
}
|
|
86
|
+
if (nextNumber < 1_000_000n) {
|
|
87
|
+
return nextPair
|
|
88
|
+
}
|
|
89
|
+
currentWord = 'eine'
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (nextNumber > currentNumber) {
|
|
93
|
+
// Multiply: apply pluralization rules for millions
|
|
94
|
+
if (nextNumber >= 1_000_000n) {
|
|
95
|
+
if (currentNumber > 1n) {
|
|
96
|
+
nextWord += nextWord.at(-1) === 'e' ? 'n' : 'en'
|
|
97
|
+
}
|
|
98
|
+
currentWord += ' '
|
|
99
|
+
}
|
|
100
|
+
return { [`${currentWord}${nextWord}`]: currentNumber * nextNumber }
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Add: handle special case of tens + units
|
|
104
|
+
if (nextNumber < 10n && currentNumber > 10n && currentNumber < 100n) {
|
|
105
|
+
// German reverses tens and units (einundzwanzig = one and twenty)
|
|
106
|
+
if (nextNumber === 1n) {
|
|
107
|
+
nextWord = 'ein'
|
|
108
|
+
}
|
|
109
|
+
const temp = nextWord
|
|
110
|
+
nextWord = currentWord
|
|
111
|
+
currentWord = `${temp}und`
|
|
112
|
+
} else if (currentNumber >= 1_000_000n) {
|
|
113
|
+
currentWord += ' '
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return { [`${currentWord}${nextWord}`]: currentNumber + nextNumber }
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Converts a number to German cardinal (written) form.
|
|
122
|
+
*
|
|
123
|
+
* @param {number|string|bigint} value The number to convert.
|
|
124
|
+
* @param {Object} [options] Conversion options (see German class options).
|
|
125
|
+
* @returns {string} The number expressed in German words.
|
|
126
|
+
* @throws {TypeError} If value is NaN or invalid type.
|
|
127
|
+
* @throws {Error} If value is an invalid number string.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* convertToWords(42); // 'zweiundvierzig'
|
|
131
|
+
* convertToWords('1.5'); // 'eins komma fünf'
|
|
132
|
+
*/
|
|
133
|
+
export default function convertToWords (value, options = {}) {
|
|
134
|
+
return new German(options).convertToWords(value)
|
|
135
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts numbers to their word representation in Greek (Ελληνικά).
|
|
3
|
+
* @module languages/el
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import GreedyScaleLanguage from '../classes/greedy-scale-language.js'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Greek language implementation using scale-based number conversion.
|
|
10
|
+
* @extends GreedyScaleLanguage
|
|
11
|
+
*/
|
|
12
|
+
class GreekLanguage extends GreedyScaleLanguage {
|
|
13
|
+
negativeWord = 'μείον'
|
|
14
|
+
decimalSeparatorWord = 'κόμμα'
|
|
15
|
+
zeroWord = 'μηδέν'
|
|
16
|
+
convertDecimalsPerDigit = true
|
|
17
|
+
|
|
18
|
+
scaleWordPairs = [
|
|
19
|
+
// Large numbers (limited set for now)
|
|
20
|
+
[1_000_000_000n, 'δισεκατομμύριο'],
|
|
21
|
+
[1_000_000n, 'εκατομμύριο'],
|
|
22
|
+
[1000n, 'χίλια'],
|
|
23
|
+
|
|
24
|
+
// Hundreds
|
|
25
|
+
[900n, 'εννιακόσια'],
|
|
26
|
+
[800n, 'οκτακόσια'],
|
|
27
|
+
[700n, 'επτακόσια'],
|
|
28
|
+
[600n, 'εξακόσια'],
|
|
29
|
+
[500n, 'πεντακόσια'],
|
|
30
|
+
[400n, 'τετρακόσια'],
|
|
31
|
+
[300n, 'τριακόσια'],
|
|
32
|
+
[200n, 'διακόσια'],
|
|
33
|
+
[100n, 'εκατό'],
|
|
34
|
+
|
|
35
|
+
// Tens
|
|
36
|
+
[90n, 'ενενήντα'],
|
|
37
|
+
[80n, 'ογδόντα'],
|
|
38
|
+
[70n, 'εβδομήντα'],
|
|
39
|
+
[60n, 'εξήντα'],
|
|
40
|
+
[50n, 'πενήντα'],
|
|
41
|
+
[40n, 'σαράντα'],
|
|
42
|
+
[30n, 'τριάντα'],
|
|
43
|
+
[20n, 'είκοσι'],
|
|
44
|
+
[19n, 'δεκαεννέα'],
|
|
45
|
+
[18n, 'δεκαοκτώ'],
|
|
46
|
+
[17n, 'δεκαεπτά'],
|
|
47
|
+
[16n, 'δεκαέξι'],
|
|
48
|
+
[15n, 'δεκαπέντε'],
|
|
49
|
+
[14n, 'δεκατέσσερα'],
|
|
50
|
+
[13n, 'δεκατρία'],
|
|
51
|
+
[12n, 'δώδεκα'],
|
|
52
|
+
[11n, 'έντεκα'],
|
|
53
|
+
[10n, 'δέκα'],
|
|
54
|
+
|
|
55
|
+
// Singles
|
|
56
|
+
[9n, 'εννέα'],
|
|
57
|
+
[8n, 'οκτώ'],
|
|
58
|
+
[7n, 'επτά'],
|
|
59
|
+
[6n, 'έξι'],
|
|
60
|
+
[5n, 'πέντε'],
|
|
61
|
+
[4n, 'τέσσερα'],
|
|
62
|
+
[3n, 'τρία'],
|
|
63
|
+
[2n, 'δύο'],
|
|
64
|
+
[1n, 'ένα'],
|
|
65
|
+
[0n, 'μηδέν']
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Merges two adjacent word-number pairs according to Greek grammar rules.
|
|
70
|
+
*
|
|
71
|
+
* Greek-specific rules:
|
|
72
|
+
* - Implicit "one": χίλια (thousand), not ένα χίλια
|
|
73
|
+
* - Space-separated composites
|
|
74
|
+
* - Multiplication for scales (e.g., δύο χίλια = two thousand)
|
|
75
|
+
*
|
|
76
|
+
* @param {Object} leftPair - Left word-number pair (e.g., { 'δύο': 2n })
|
|
77
|
+
* @param {Object} rightPair - Right word-number pair (e.g., { 'χίλια': 1000n })
|
|
78
|
+
* @returns {Object} Merged word-number pair
|
|
79
|
+
*/
|
|
80
|
+
mergeScales (leftPair, rightPair) {
|
|
81
|
+
const leftWord = Object.keys(leftPair)[0]
|
|
82
|
+
const leftNumber = Object.values(leftPair)[0]
|
|
83
|
+
const rightWord = Object.keys(rightPair)[0]
|
|
84
|
+
const rightNumber = Object.values(rightPair)[0]
|
|
85
|
+
|
|
86
|
+
// Implicit one: omit "ένα" before any following value (> 0)
|
|
87
|
+
if (leftNumber === 1n) {
|
|
88
|
+
return rightPair
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// No special handling needed for trailing 'ένα';
|
|
92
|
+
// nested merge will first collapse {1, 'ένα'} -> 'ένα'.
|
|
93
|
+
|
|
94
|
+
// Multiplication: larger right scale multiplied by left number
|
|
95
|
+
if (rightNumber > leftNumber) {
|
|
96
|
+
return { [`${leftWord} ${rightWord}`]: leftNumber * rightNumber }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Addition: smaller numbers added together
|
|
100
|
+
return { [`${leftWord} ${rightWord}`]: leftNumber + rightNumber }
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Converts a number to its word representation in Greek.
|
|
106
|
+
* @param {number|string|bigint} value - The number to convert
|
|
107
|
+
* @param {Object} [options={}] - Conversion options
|
|
108
|
+
* @returns {string} The word representation of the number
|
|
109
|
+
* @example
|
|
110
|
+
* convertToWords(42) // 'σαράντα δύο'
|
|
111
|
+
* convertToWords(1000) // 'χίλια'
|
|
112
|
+
* convertToWords(2000) // 'δύο χίλια'
|
|
113
|
+
*/
|
|
114
|
+
export default function convertToWords (value, options = {}) {
|
|
115
|
+
return new GreekLanguage(options).convertToWords(value)
|
|
116
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import GreedyScaleLanguage from '../classes/greedy-scale-language.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* English language converter.
|
|
5
|
+
*
|
|
6
|
+
* Converts numbers to English words, supporting:
|
|
7
|
+
* - Negative numbers (prepended with "minus")
|
|
8
|
+
* - Decimal numbers (word "point" between whole and fractional parts)
|
|
9
|
+
* - Numbers up to octillions
|
|
10
|
+
*
|
|
11
|
+
* Merge rules:
|
|
12
|
+
* - Hyphenated for compound tens (e.g., "twenty-three")
|
|
13
|
+
* - "and" after hundreds (e.g., "one hundred and one")
|
|
14
|
+
* - Space-separated for larger composites (e.g., "one thousand twenty-three")
|
|
15
|
+
*/
|
|
16
|
+
export class English extends GreedyScaleLanguage {
|
|
17
|
+
negativeWord = 'minus'
|
|
18
|
+
decimalSeparatorWord = 'point'
|
|
19
|
+
zeroWord = 'zero'
|
|
20
|
+
scaleWordPairs = [
|
|
21
|
+
[1_000_000_000_000_000_000_000_000_000n, 'octillion'],
|
|
22
|
+
[1_000_000_000_000_000_000_000_000n, 'septillion'],
|
|
23
|
+
[1_000_000_000_000_000_000_000n, 'sextillion'],
|
|
24
|
+
[1_000_000_000_000_000_000n, 'quintillion'],
|
|
25
|
+
[1_000_000_000_000_000n, 'quadrillion'],
|
|
26
|
+
[1_000_000_000_000n, 'trillion'],
|
|
27
|
+
[1_000_000_000n, 'billion'],
|
|
28
|
+
[1_000_000n, 'million'],
|
|
29
|
+
[1000n, 'thousand'],
|
|
30
|
+
[100n, 'hundred'],
|
|
31
|
+
[90n, 'ninety'],
|
|
32
|
+
[80n, 'eighty'],
|
|
33
|
+
[70n, 'seventy'],
|
|
34
|
+
[60n, 'sixty'],
|
|
35
|
+
[50n, 'fifty'],
|
|
36
|
+
[40n, 'forty'],
|
|
37
|
+
[30n, 'thirty'],
|
|
38
|
+
[20n, 'twenty'],
|
|
39
|
+
[19n, 'nineteen'],
|
|
40
|
+
[18n, 'eighteen'],
|
|
41
|
+
[17n, 'seventeen'],
|
|
42
|
+
[16n, 'sixteen'],
|
|
43
|
+
[15n, 'fifteen'],
|
|
44
|
+
[14n, 'fourteen'],
|
|
45
|
+
[13n, 'thirteen'],
|
|
46
|
+
[12n, 'twelve'],
|
|
47
|
+
[11n, 'eleven'],
|
|
48
|
+
[10n, 'ten'],
|
|
49
|
+
[9n, 'nine'],
|
|
50
|
+
[8n, 'eight'],
|
|
51
|
+
[7n, 'seven'],
|
|
52
|
+
[6n, 'six'],
|
|
53
|
+
[5n, 'five'],
|
|
54
|
+
[4n, 'four'],
|
|
55
|
+
[3n, 'three'],
|
|
56
|
+
[2n, 'two'],
|
|
57
|
+
[1n, 'one'],
|
|
58
|
+
[0n, 'zero']
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Merges two adjacent word-number pairs according to English grammar rules.
|
|
63
|
+
*
|
|
64
|
+
* English-specific rules:
|
|
65
|
+
* - Implicit "one": `mergeScales({ 'one': 1n }, { 'hundred': 100n })` → `{ 'one hundred': 100n }`
|
|
66
|
+
* - Hyphenated compounds: `mergeScales({ 'twenty': 20n }, { 'three': 3n })` → `{ 'twenty-three': 23n }`
|
|
67
|
+
* - "and" after hundreds: `mergeScales({ 'one hundred': 100n }, { 'one': 1n })` → `{ 'one hundred and one': 101n }`
|
|
68
|
+
* - Multiplication: `mergeScales({ 'one': 1n }, { 'thousand': 1000n })` → `{ 'one thousand': 1000n }`
|
|
69
|
+
*
|
|
70
|
+
* @param {Object} leftPair Left word-set as `{ word: BigInt }`.
|
|
71
|
+
* @param {Object} rightPair Right word-set as `{ word: BigInt }`.
|
|
72
|
+
* @returns {Object} Merged pair with combined word and resulting numeric value.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* mergeScales({ 'one': 1n }, { 'hundred': 100n }); // { 'one hundred': 100n }
|
|
76
|
+
* mergeScales({ 'twenty': 20n }, { 'three': 3n }); // { 'twenty-three': 23n }
|
|
77
|
+
*/
|
|
78
|
+
mergeScales (leftPair, rightPair) {
|
|
79
|
+
const leftWord = Object.keys(leftPair)[0]
|
|
80
|
+
const leftNumber = Object.values(leftPair)[0]
|
|
81
|
+
const rightWord = Object.keys(rightPair)[0]
|
|
82
|
+
const rightNumber = Object.values(rightPair)[0]
|
|
83
|
+
|
|
84
|
+
// Rule 1: Implicit "one" - omit when multiplying ("one hundred" → "hundred")
|
|
85
|
+
if (leftNumber === 1n && rightNumber < 100n) {
|
|
86
|
+
return { [rightWord]: rightNumber }
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Rule 2: Hyphenate compounds under 100 ("twenty-three")
|
|
90
|
+
if (leftNumber < 100n && leftNumber > rightNumber) {
|
|
91
|
+
return { [`${leftWord}-${rightWord}`]: leftNumber + rightNumber }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Rule 3: Add "and" before units after hundreds ("one hundred and one")
|
|
95
|
+
if (leftNumber >= 100n && rightNumber < 100n) {
|
|
96
|
+
return { [`${leftWord} and ${rightWord}`]: leftNumber + rightNumber }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Rule 4: Multiply when right > left ("one thousand")
|
|
100
|
+
if (rightNumber > leftNumber) {
|
|
101
|
+
return { [`${leftWord} ${rightWord}`]: leftNumber * rightNumber }
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return { [`${leftWord} ${rightWord}`]: leftNumber + rightNumber }
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Converts a number to English cardinal (written) form.
|
|
110
|
+
*
|
|
111
|
+
* @param {number|string|bigint} value The number to convert.
|
|
112
|
+
* @param {Object} [options] Conversion options (see English class options).
|
|
113
|
+
* @returns {string} The number expressed in English words.
|
|
114
|
+
* @throws {TypeError} If value is NaN or invalid type.
|
|
115
|
+
* @throws {Error} If value is an invalid number string.
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* convertToWords(42); // 'forty-two'
|
|
119
|
+
* convertToWords('1.5'); // 'one point five'
|
|
120
|
+
*/
|
|
121
|
+
export default function convertToWords (value, options = {}) {
|
|
122
|
+
return new English(options).convertToWords(value)
|
|
123
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import GreedyScaleLanguage from '../classes/greedy-scale-language.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {Object} SpanishOptions
|
|
5
|
+
* @property {string} [genderStem='o'] Masculine 'o' or feminine 'a' ending.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Spanish language converter.
|
|
10
|
+
*
|
|
11
|
+
* Handles Spanish grammatical features:
|
|
12
|
+
* - Gender agreement for numbers (masculine by default, feminine via `genderStem`)
|
|
13
|
+
* - "y" (and) between tens and units (e.g., "veinte y uno")
|
|
14
|
+
* - Special forms for hundreds (e.g., "cien", "ciento", "doscientos")
|
|
15
|
+
* - Million pluralization
|
|
16
|
+
*/
|
|
17
|
+
export class Spanish extends GreedyScaleLanguage {
|
|
18
|
+
negativeWord = 'menos'
|
|
19
|
+
decimalSeparatorWord = 'punto'
|
|
20
|
+
zeroWord = 'cero'
|
|
21
|
+
scaleWordPairs = [
|
|
22
|
+
[1_000_000_000_000_000_000_000_000n, 'cuatrillón'],
|
|
23
|
+
[1_000_000_000_000_000_000n, 'trillón'],
|
|
24
|
+
[1_000_000_000_000n, 'billón'],
|
|
25
|
+
[1_000_000n, 'millón'],
|
|
26
|
+
[1000n, 'mil'],
|
|
27
|
+
[100n, 'cien'],
|
|
28
|
+
[90n, 'noventa'],
|
|
29
|
+
[80n, 'ochenta'],
|
|
30
|
+
[70n, 'setenta'],
|
|
31
|
+
[60n, 'sesenta'],
|
|
32
|
+
[50n, 'cincuenta'],
|
|
33
|
+
[40n, 'cuarenta'],
|
|
34
|
+
[30n, 'treinta'],
|
|
35
|
+
[29n, 'veintinueve'],
|
|
36
|
+
[28n, 'veintiocho'],
|
|
37
|
+
[27n, 'veintisiete'],
|
|
38
|
+
[26n, 'veintiséis'],
|
|
39
|
+
[25n, 'veinticinco'],
|
|
40
|
+
[24n, 'veinticuatro'],
|
|
41
|
+
[23n, 'veintitrés'],
|
|
42
|
+
[22n, 'veintidós'],
|
|
43
|
+
[21n, 'veintiuno'],
|
|
44
|
+
[20n, 'veinte'],
|
|
45
|
+
[19n, 'diecinueve'],
|
|
46
|
+
[18n, 'dieciocho'],
|
|
47
|
+
[17n, 'diecisiete'],
|
|
48
|
+
[16n, 'dieciseis'],
|
|
49
|
+
[15n, 'quince'],
|
|
50
|
+
[14n, 'catorce'],
|
|
51
|
+
[13n, 'trece'],
|
|
52
|
+
[12n, 'doce'],
|
|
53
|
+
[11n, 'once'],
|
|
54
|
+
[10n, 'diez'],
|
|
55
|
+
[9n, 'nueve'],
|
|
56
|
+
[8n, 'ocho'],
|
|
57
|
+
[7n, 'siete'],
|
|
58
|
+
[6n, 'seis'],
|
|
59
|
+
[5n, 'cinco'],
|
|
60
|
+
[4n, 'cuatro'],
|
|
61
|
+
[3n, 'tres'],
|
|
62
|
+
[2n, 'dos'],
|
|
63
|
+
[1n, 'uno'],
|
|
64
|
+
[0n, 'cero']
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Initializes the Spanish converter.
|
|
69
|
+
*
|
|
70
|
+
* @param {SpanishOptions} [options={}] Configuration options.
|
|
71
|
+
*/
|
|
72
|
+
constructor ({ genderStem = 'o' } = {}) {
|
|
73
|
+
super()
|
|
74
|
+
|
|
75
|
+
this.genderStem = genderStem
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Merges two adjacent word-number pairs according to Spanish grammar rules.
|
|
80
|
+
*
|
|
81
|
+
* Spanish-specific rules:
|
|
82
|
+
* - Implicit "uno": `mergeScales({ 'uno': 1n }, { 'mil': 1000n })` → `{ 'mil': 1000n }`
|
|
83
|
+
* - "y" (and) between tens and units: `mergeScales({ 'veinte': 20n }, { 'uno': 1n })` → `{ 'veinte y uno': 21n }`
|
|
84
|
+
* - Gender agreement for hundreds: "cien" + suffix based on genderStem
|
|
85
|
+
* - Special forms for hundreds (cien/ciento/quinientos/setecientos/novecientos)
|
|
86
|
+
* - Million pluralization when coefficient > 1: "millones" instead of "millón"
|
|
87
|
+
*
|
|
88
|
+
* @param {Object} currentPair The left operand as `{ word: BigInt }`.
|
|
89
|
+
* @param {Object} nextPair The right operand as `{ word: BigInt }`.
|
|
90
|
+
* @returns {Object} Merged pair with combined word and resulting numeric value.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* mergeScales({ 'uno': 1n }, { 'mil': 1000n }); // { 'mil': 1000n }
|
|
94
|
+
* mergeScales({ 'veinte': 20n }, { 'tres': 3n }); // { 'veinte y tres': 23n }
|
|
95
|
+
*/
|
|
96
|
+
mergeScales (currentPair, nextPair) {
|
|
97
|
+
let currentWord = Object.keys(currentPair)[0]
|
|
98
|
+
let nextWord = Object.keys(nextPair)[0]
|
|
99
|
+
const currentNumber = Object.values(currentPair)[0]
|
|
100
|
+
const nextNumber = Object.values(nextPair)[0]
|
|
101
|
+
|
|
102
|
+
if (currentNumber === 1n) {
|
|
103
|
+
if (nextNumber < 1_000_000n) return nextPair
|
|
104
|
+
currentWord = 'un'
|
|
105
|
+
} else if (currentNumber === 100n && nextNumber % 1000n !== 0n) {
|
|
106
|
+
currentWord += 't' + this.genderStem
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (nextNumber < currentNumber) {
|
|
110
|
+
if (currentNumber < 100n) {
|
|
111
|
+
return { [`${currentWord} y ${nextWord}`]: currentNumber + nextNumber }
|
|
112
|
+
}
|
|
113
|
+
return { [`${currentWord} ${nextWord}`]: currentNumber + nextNumber }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (nextNumber % 1_000_000n === 0n && currentNumber > 1n) {
|
|
117
|
+
nextWord = nextWord.slice(0, -3) + 'lones'
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (nextNumber === 100n) {
|
|
121
|
+
if (currentNumber === 5n) {
|
|
122
|
+
currentWord = 'quinien'
|
|
123
|
+
nextWord = ''
|
|
124
|
+
} else if (currentNumber === 7n) {
|
|
125
|
+
currentWord = 'sete'
|
|
126
|
+
} else if (currentNumber === 9n) {
|
|
127
|
+
currentWord = 'nove'
|
|
128
|
+
}
|
|
129
|
+
nextWord += 't' + this.genderStem + 's'
|
|
130
|
+
} else {
|
|
131
|
+
nextWord = ' ' + nextWord
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return { [`${currentWord}${nextWord}`]: currentNumber * nextNumber }
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Converts a number to Spanish cardinal (written) form.
|
|
140
|
+
*
|
|
141
|
+
* @param {number|string|bigint} value The number to convert.
|
|
142
|
+
* @param {Object} [options] Conversion options (see ES class).
|
|
143
|
+
* @returns {string} The number expressed in Spanish words.
|
|
144
|
+
* @throws {TypeError} If value is NaN or invalid type.
|
|
145
|
+
* @throws {Error} If value is an invalid number string.
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* convertToWords(42, { lang: 'es' }); // 'cuarenta y dos'
|
|
149
|
+
* convertToWords(100, { lang: 'es' }); // 'cien'
|
|
150
|
+
*/
|
|
151
|
+
export default function convertToWords (value, options = {}) {
|
|
152
|
+
return new Spanish(options).convertToWords(value)
|
|
153
|
+
}
|