n2words 2.0.0 → 3.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 +64 -0
- package/README.md +86 -188
- package/dist/languages/am-Latn.js +3 -0
- package/dist/languages/am-Latn.js.map +1 -0
- package/dist/languages/am.js +3 -0
- package/dist/languages/am.js.map +1 -0
- package/dist/languages/ar.js +3 -0
- package/dist/languages/ar.js.map +1 -0
- package/dist/languages/az.js +3 -0
- package/dist/languages/az.js.map +1 -0
- package/dist/languages/bn.js +3 -0
- package/dist/languages/bn.js.map +1 -0
- package/dist/languages/cs.js +3 -0
- package/dist/languages/cs.js.map +1 -0
- package/dist/languages/da.js +3 -0
- package/dist/languages/da.js.map +1 -0
- package/dist/languages/de.js +3 -0
- package/dist/languages/de.js.map +1 -0
- package/dist/languages/el.js +3 -0
- package/dist/languages/el.js.map +1 -0
- package/dist/languages/en.js +3 -0
- package/dist/languages/en.js.map +1 -0
- package/dist/languages/es.js +3 -0
- package/dist/languages/es.js.map +1 -0
- package/dist/languages/fa.js +3 -0
- package/dist/languages/fa.js.map +1 -0
- package/dist/languages/fi.js +3 -0
- package/dist/languages/fi.js.map +1 -0
- package/dist/languages/fil.js +3 -0
- package/dist/languages/fil.js.map +1 -0
- package/dist/languages/fr-BE.js +3 -0
- package/dist/languages/fr-BE.js.map +1 -0
- package/dist/languages/fr.js +3 -0
- package/dist/languages/fr.js.map +1 -0
- package/dist/languages/gu.js +3 -0
- package/dist/languages/gu.js.map +1 -0
- package/dist/languages/ha.js +3 -0
- package/dist/languages/ha.js.map +1 -0
- package/dist/languages/hbo.js +3 -0
- package/dist/languages/hbo.js.map +1 -0
- package/dist/languages/he.js +3 -0
- package/dist/languages/he.js.map +1 -0
- package/dist/languages/hi.js +3 -0
- package/dist/languages/hi.js.map +1 -0
- package/dist/languages/hr.js +3 -0
- package/dist/languages/hr.js.map +1 -0
- package/dist/languages/hu.js +3 -0
- package/dist/languages/hu.js.map +1 -0
- package/dist/languages/id.js +3 -0
- package/dist/languages/id.js.map +1 -0
- package/dist/languages/it.js +3 -0
- package/dist/languages/it.js.map +1 -0
- package/dist/languages/ja.js +3 -0
- package/dist/languages/ja.js.map +1 -0
- package/dist/languages/ka.js +3 -0
- package/dist/languages/ka.js.map +1 -0
- package/dist/languages/kn.js +3 -0
- package/dist/languages/kn.js.map +1 -0
- package/dist/languages/ko.js +3 -0
- package/dist/languages/ko.js.map +1 -0
- package/dist/languages/lt.js +3 -0
- package/dist/languages/lt.js.map +1 -0
- package/dist/languages/lv.js +3 -0
- package/dist/languages/lv.js.map +1 -0
- package/dist/languages/mr.js +3 -0
- package/dist/languages/mr.js.map +1 -0
- package/dist/languages/ms.js +3 -0
- package/dist/languages/ms.js.map +1 -0
- package/dist/languages/nb.js +3 -0
- package/dist/languages/nb.js.map +1 -0
- package/dist/languages/nl.js +3 -0
- package/dist/languages/nl.js.map +1 -0
- package/dist/languages/pa.js +3 -0
- package/dist/languages/pa.js.map +1 -0
- package/dist/languages/pl.js +3 -0
- package/dist/languages/pl.js.map +1 -0
- package/dist/languages/pt.js +3 -0
- package/dist/languages/pt.js.map +1 -0
- package/dist/languages/ro.js +3 -0
- package/dist/languages/ro.js.map +1 -0
- package/dist/languages/ru.js +3 -0
- package/dist/languages/ru.js.map +1 -0
- package/dist/languages/sr-Cyrl.js +3 -0
- package/dist/languages/sr-Cyrl.js.map +1 -0
- package/dist/languages/sr-Latn.js +3 -0
- package/dist/languages/sr-Latn.js.map +1 -0
- package/dist/languages/sv.js +3 -0
- package/dist/languages/sv.js.map +1 -0
- package/dist/languages/sw.js +3 -0
- package/dist/languages/sw.js.map +1 -0
- package/dist/languages/ta.js +3 -0
- package/dist/languages/ta.js.map +1 -0
- package/dist/languages/te.js +3 -0
- package/dist/languages/te.js.map +1 -0
- package/dist/languages/th.js +3 -0
- package/dist/languages/th.js.map +1 -0
- package/dist/languages/tr.js +3 -0
- package/dist/languages/tr.js.map +1 -0
- package/dist/languages/uk.js +3 -0
- package/dist/languages/uk.js.map +1 -0
- package/dist/languages/ur.js +3 -0
- package/dist/languages/ur.js.map +1 -0
- package/dist/languages/vi.js +3 -0
- package/dist/languages/vi.js.map +1 -0
- package/dist/languages/yo.js +3 -0
- package/dist/languages/yo.js.map +1 -0
- package/dist/languages/zh-Hans.js +3 -0
- package/dist/languages/zh-Hans.js.map +1 -0
- package/dist/languages/zh-Hant.js +3 -0
- package/dist/languages/zh-Hant.js.map +1 -0
- package/dist/n2words.js +2 -2
- package/dist/n2words.js.map +1 -1
- package/lib/languages/am-Latn.d.ts +7 -0
- package/lib/languages/am-Latn.js +159 -0
- package/lib/languages/am.d.ts +7 -0
- package/lib/languages/am.js +159 -0
- package/lib/languages/ar.d.ts +14 -27
- package/lib/languages/ar.js +175 -129
- package/lib/languages/az.d.ts +4 -9
- package/lib/languages/az.js +166 -37
- package/lib/languages/bn.d.ts +4 -8
- package/lib/languages/bn.js +159 -124
- package/lib/languages/cs.d.ts +15 -85
- package/lib/languages/cs.js +293 -114
- package/lib/languages/da.d.ts +11 -12
- package/lib/languages/da.js +269 -101
- package/lib/languages/de.d.ts +14 -11
- package/lib/languages/de.js +305 -86
- package/lib/languages/el.d.ts +11 -11
- package/lib/languages/el.js +224 -78
- package/lib/languages/en.d.ts +14 -13
- package/lib/languages/en.js +228 -72
- package/lib/languages/es.d.ts +18 -12
- package/lib/languages/es.js +297 -103
- package/lib/languages/fa.d.ts +4 -44
- package/lib/languages/fa.js +112 -122
- package/lib/languages/fi.d.ts +14 -0
- package/lib/languages/fi.js +238 -0
- package/lib/languages/fil.d.ts +4 -13
- package/lib/languages/fil.js +196 -106
- package/lib/languages/fr-BE.d.ts +8 -8
- package/lib/languages/fr-BE.js +285 -19
- package/lib/languages/fr.d.ts +18 -12
- package/lib/languages/fr.js +339 -89
- package/lib/languages/gu.d.ts +4 -8
- package/lib/languages/gu.js +143 -125
- package/lib/languages/ha.d.ts +7 -0
- package/lib/languages/ha.js +225 -0
- package/lib/languages/hbo.d.ts +10 -110
- package/lib/languages/hbo.js +245 -214
- package/lib/languages/he.d.ts +10 -77
- package/lib/languages/he.js +231 -172
- package/lib/languages/hi.d.ts +4 -8
- package/lib/languages/hi.js +163 -124
- package/lib/languages/hr.d.ts +8 -77
- package/lib/languages/hr.js +200 -89
- package/lib/languages/hu.d.ts +4 -19
- package/lib/languages/hu.js +198 -119
- package/lib/languages/id.d.ts +4 -34
- package/lib/languages/id.js +166 -129
- package/lib/languages/it.d.ts +16 -34
- package/lib/languages/it.js +307 -97
- package/lib/languages/ja.d.ts +14 -14
- package/lib/languages/ja.js +221 -111
- package/lib/languages/ka.d.ts +17 -0
- package/lib/languages/ka.js +291 -0
- package/lib/languages/kn.d.ts +4 -8
- package/lib/languages/kn.js +143 -35
- package/lib/languages/ko.d.ts +11 -11
- package/lib/languages/ko.js +250 -49
- package/lib/languages/lt.d.ts +15 -67
- package/lib/languages/lt.js +287 -122
- package/lib/languages/lv.d.ts +15 -67
- package/lib/languages/lv.js +288 -106
- package/lib/languages/mr.d.ts +4 -8
- package/lib/languages/mr.js +143 -125
- package/lib/languages/ms.d.ts +4 -28
- package/lib/languages/ms.js +166 -116
- package/lib/languages/nb.d.ts +11 -9
- package/lib/languages/nb.js +272 -87
- package/lib/languages/nl.d.ts +23 -13
- package/lib/languages/nl.js +299 -133
- package/lib/languages/pa.d.ts +4 -8
- package/lib/languages/pa.js +151 -124
- package/lib/languages/pl.d.ts +19 -77
- package/lib/languages/pl.js +294 -87
- package/lib/languages/pt.d.ts +14 -26
- package/lib/languages/pt.js +272 -92
- package/lib/languages/ro.d.ts +15 -155
- package/lib/languages/ro.js +219 -235
- package/lib/languages/ru.d.ts +8 -82
- package/lib/languages/ru.js +239 -90
- package/lib/languages/sr-Cyrl.d.ts +8 -77
- package/lib/languages/sr-Cyrl.js +197 -89
- package/lib/languages/sr-Latn.d.ts +8 -77
- package/lib/languages/sr-Latn.js +197 -89
- package/lib/languages/sv.d.ts +11 -11
- package/lib/languages/sv.js +278 -74
- package/lib/languages/sw.d.ts +4 -36
- package/lib/languages/sw.js +133 -106
- package/lib/languages/ta.d.ts +4 -17
- package/lib/languages/ta.js +143 -202
- package/lib/languages/te.d.ts +4 -19
- package/lib/languages/te.js +133 -196
- package/lib/languages/th.d.ts +4 -14
- package/lib/languages/th.js +135 -91
- package/lib/languages/tr.d.ts +15 -9
- package/lib/languages/tr.js +245 -49
- package/lib/languages/uk.d.ts +8 -82
- package/lib/languages/uk.js +206 -78
- package/lib/languages/ur.d.ts +4 -8
- package/lib/languages/ur.js +151 -124
- package/lib/languages/vi.d.ts +14 -69
- package/lib/languages/vi.js +278 -129
- package/lib/languages/yo.d.ts +7 -0
- package/lib/languages/yo.js +303 -0
- package/lib/languages/zh-Hans.d.ts +8 -18
- package/lib/languages/zh-Hans.js +163 -92
- package/lib/languages/zh-Hant.d.ts +8 -18
- package/lib/languages/zh-Hant.js +181 -90
- package/lib/n2words.d.ts +55 -209
- package/lib/n2words.js +115 -530
- package/lib/utils/is-plain-object.d.ts +13 -0
- package/lib/utils/is-plain-object.js +17 -0
- package/lib/utils/parse-numeric.d.ts +17 -0
- package/lib/utils/parse-numeric.js +108 -0
- package/lib/utils/validate-options.d.ts +8 -0
- package/lib/utils/validate-options.js +16 -0
- package/package.json +26 -14
- package/dist/ArabicConverter.js +0 -3
- package/dist/ArabicConverter.js.map +0 -1
- package/dist/AzerbaijaniConverter.js +0 -3
- package/dist/AzerbaijaniConverter.js.map +0 -1
- package/dist/BanglaConverter.js +0 -3
- package/dist/BanglaConverter.js.map +0 -1
- package/dist/BiblicalHebrewConverter.js +0 -3
- package/dist/BiblicalHebrewConverter.js.map +0 -1
- package/dist/CroatianConverter.js +0 -3
- package/dist/CroatianConverter.js.map +0 -1
- package/dist/CzechConverter.js +0 -3
- package/dist/CzechConverter.js.map +0 -1
- package/dist/DanishConverter.js +0 -3
- package/dist/DanishConverter.js.map +0 -1
- package/dist/DutchConverter.js +0 -3
- package/dist/DutchConverter.js.map +0 -1
- package/dist/EnglishConverter.js +0 -3
- package/dist/EnglishConverter.js.map +0 -1
- package/dist/FilipinoConverter.js +0 -3
- package/dist/FilipinoConverter.js.map +0 -1
- package/dist/FrenchBelgiumConverter.js +0 -3
- package/dist/FrenchBelgiumConverter.js.map +0 -1
- package/dist/FrenchConverter.js +0 -3
- package/dist/FrenchConverter.js.map +0 -1
- package/dist/GermanConverter.js +0 -3
- package/dist/GermanConverter.js.map +0 -1
- package/dist/GreekConverter.js +0 -3
- package/dist/GreekConverter.js.map +0 -1
- package/dist/GujaratiConverter.js +0 -3
- package/dist/GujaratiConverter.js.map +0 -1
- package/dist/HebrewConverter.js +0 -3
- package/dist/HebrewConverter.js.map +0 -1
- package/dist/HindiConverter.js +0 -3
- package/dist/HindiConverter.js.map +0 -1
- package/dist/HungarianConverter.js +0 -3
- package/dist/HungarianConverter.js.map +0 -1
- package/dist/IndonesianConverter.js +0 -3
- package/dist/IndonesianConverter.js.map +0 -1
- package/dist/ItalianConverter.js +0 -3
- package/dist/ItalianConverter.js.map +0 -1
- package/dist/JapaneseConverter.js +0 -3
- package/dist/JapaneseConverter.js.map +0 -1
- package/dist/KannadaConverter.js +0 -3
- package/dist/KannadaConverter.js.map +0 -1
- package/dist/KoreanConverter.js +0 -3
- package/dist/KoreanConverter.js.map +0 -1
- package/dist/LatvianConverter.js +0 -3
- package/dist/LatvianConverter.js.map +0 -1
- package/dist/LithuanianConverter.js +0 -3
- package/dist/LithuanianConverter.js.map +0 -1
- package/dist/MalayConverter.js +0 -3
- package/dist/MalayConverter.js.map +0 -1
- package/dist/MarathiConverter.js +0 -3
- package/dist/MarathiConverter.js.map +0 -1
- package/dist/NorwegianBokmalConverter.js +0 -3
- package/dist/NorwegianBokmalConverter.js.map +0 -1
- package/dist/PersianConverter.js +0 -3
- package/dist/PersianConverter.js.map +0 -1
- package/dist/PolishConverter.js +0 -3
- package/dist/PolishConverter.js.map +0 -1
- package/dist/PortugueseConverter.js +0 -3
- package/dist/PortugueseConverter.js.map +0 -1
- package/dist/PunjabiConverter.js +0 -3
- package/dist/PunjabiConverter.js.map +0 -1
- package/dist/RomanianConverter.js +0 -3
- package/dist/RomanianConverter.js.map +0 -1
- package/dist/RussianConverter.js +0 -3
- package/dist/RussianConverter.js.map +0 -1
- package/dist/SerbianCyrillicConverter.js +0 -3
- package/dist/SerbianCyrillicConverter.js.map +0 -1
- package/dist/SerbianLatinConverter.js +0 -3
- package/dist/SerbianLatinConverter.js.map +0 -1
- package/dist/SimplifiedChineseConverter.js +0 -3
- package/dist/SimplifiedChineseConverter.js.map +0 -1
- package/dist/SpanishConverter.js +0 -3
- package/dist/SpanishConverter.js.map +0 -1
- package/dist/SwahiliConverter.js +0 -3
- package/dist/SwahiliConverter.js.map +0 -1
- package/dist/SwedishConverter.js +0 -3
- package/dist/SwedishConverter.js.map +0 -1
- package/dist/TamilConverter.js +0 -3
- package/dist/TamilConverter.js.map +0 -1
- package/dist/TeluguConverter.js +0 -3
- package/dist/TeluguConverter.js.map +0 -1
- package/dist/ThaiConverter.js +0 -3
- package/dist/ThaiConverter.js.map +0 -1
- package/dist/TraditionalChineseConverter.js +0 -3
- package/dist/TraditionalChineseConverter.js.map +0 -1
- package/dist/TurkishConverter.js +0 -3
- package/dist/TurkishConverter.js.map +0 -1
- package/dist/UkrainianConverter.js +0 -3
- package/dist/UkrainianConverter.js.map +0 -1
- package/dist/UrduConverter.js +0 -3
- package/dist/UrduConverter.js.map +0 -1
- package/dist/VietnameseConverter.js +0 -3
- package/dist/VietnameseConverter.js.map +0 -1
- package/lib/classes/abstract-language.d.ts +0 -178
- package/lib/classes/abstract-language.js +0 -268
- package/lib/classes/greedy-scale-language.d.ts +0 -109
- package/lib/classes/greedy-scale-language.js +0 -201
- package/lib/classes/slavic-language.d.ts +0 -148
- package/lib/classes/slavic-language.js +0 -281
- package/lib/classes/south-asian-language.d.ts +0 -70
- package/lib/classes/south-asian-language.js +0 -154
- package/lib/classes/turkic-language.d.ts +0 -26
- package/lib/classes/turkic-language.js +0 -59
package/lib/languages/da.js
CHANGED
|
@@ -1,120 +1,288 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Danish language converter - Functional Implementation
|
|
3
|
+
*
|
|
4
|
+
* Self-contained module with its own input validation, ready for subpath exports.
|
|
5
|
+
*
|
|
6
|
+
* Key features:
|
|
7
|
+
* - Vigesimal (base-20) tens naming: halvtreds (50), treds (60), etc.
|
|
8
|
+
* - Units-before-tens: "enogtyve" (21) = one-and-twenty
|
|
9
|
+
* - Compound thousands: "ettusind", "firetusinde"
|
|
10
|
+
* - "og" conjunction after hundreds and thousands
|
|
11
|
+
* - Long scale for millions+
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
15
|
+
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Vocabulary (module-level constants)
|
|
18
|
+
// ============================================================================
|
|
19
|
+
|
|
20
|
+
const ONES = ['', 'et', 'to', 'tre', 'fire', 'fem', 'seks', 'syv', 'otte', 'ni']
|
|
21
|
+
// "en" form used in vigesimal pattern (X og Y) and before millions
|
|
22
|
+
const ONES_VIGESIMAL = ['', 'en', 'to', 'tre', 'fire', 'fem', 'seks', 'syv', 'otte', 'ni']
|
|
23
|
+
|
|
24
|
+
const TEENS = ['ti', 'elleve', 'tolv', 'tretten', 'fjorten', 'femten', 'seksten', 'sytten', 'atten', 'nitten']
|
|
25
|
+
|
|
26
|
+
// Danish vigesimal tens (base-20 derived names)
|
|
27
|
+
const TENS = ['', '', 'tyve', 'tredive', 'fyrre', 'halvtreds', 'treds', 'halvfjerds', 'firs', 'halvfems']
|
|
28
|
+
|
|
29
|
+
const HUNDRED = 'hundrede'
|
|
30
|
+
const THOUSAND = 'tusind'
|
|
31
|
+
|
|
32
|
+
const ZERO = 'nul'
|
|
33
|
+
const NEGATIVE = 'minus'
|
|
34
|
+
const DECIMAL_SEP = 'komma'
|
|
35
|
+
|
|
36
|
+
// Long scale: millioner, millarder, billioner, etc.
|
|
37
|
+
const SCALES = ['millioner', 'millarder', 'billioner', 'billarder', 'trillioner', 'trillarder', 'quadrillioner', 'quadrillarder']
|
|
38
|
+
|
|
39
|
+
// ============================================================================
|
|
40
|
+
// Segment Building
|
|
41
|
+
// ============================================================================
|
|
2
42
|
|
|
3
43
|
/**
|
|
4
|
-
*
|
|
44
|
+
* Builds segment word for 0-999.
|
|
45
|
+
*/
|
|
46
|
+
function buildSegment (n) {
|
|
47
|
+
if (n === 0) return ''
|
|
48
|
+
|
|
49
|
+
const ones = n % 10
|
|
50
|
+
const tens = Math.floor(n / 10) % 10
|
|
51
|
+
const hundreds = Math.floor(n / 100)
|
|
52
|
+
|
|
53
|
+
const parts = []
|
|
54
|
+
|
|
55
|
+
// Hundreds: "ethundrede", "tohundrede" (compound, no space)
|
|
56
|
+
if (hundreds > 0) {
|
|
57
|
+
parts.push(ONES[hundreds] + HUNDRED)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Tens and ones
|
|
61
|
+
const tensOnes = n % 100
|
|
62
|
+
|
|
63
|
+
if (tensOnes === 0) {
|
|
64
|
+
// Just hundreds
|
|
65
|
+
} else if (tensOnes < 10) {
|
|
66
|
+
// Single digit
|
|
67
|
+
parts.push(ONES[ones])
|
|
68
|
+
} else if (tensOnes < 20) {
|
|
69
|
+
// Teens
|
|
70
|
+
parts.push(TEENS[ones])
|
|
71
|
+
} else if (ones === 0) {
|
|
72
|
+
// Even tens
|
|
73
|
+
parts.push(TENS[tens])
|
|
74
|
+
} else {
|
|
75
|
+
// Units-before-tens: "enogtyve", "treogfyrre"
|
|
76
|
+
parts.push(ONES_VIGESIMAL[ones] + 'og' + TENS[tens])
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Combine with " og " between hundreds and remainder
|
|
80
|
+
if (parts.length === 2) {
|
|
81
|
+
return parts[0] + ' og ' + parts[1]
|
|
82
|
+
}
|
|
83
|
+
return parts[0] || ''
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ============================================================================
|
|
87
|
+
// Conversion Functions
|
|
88
|
+
// ============================================================================
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Converts a non-negative integer to Danish words.
|
|
5
92
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* - Units-before-tens ordering (e.g., "tre-og-tyve" = 23)
|
|
9
|
-
* - Optional ordinal numbers via ordFlag option
|
|
93
|
+
* @param {bigint} n - Non-negative integer to convert
|
|
94
|
+
* @returns {string} Danish words
|
|
10
95
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
[1_000_000_000_000_000_000_000_000_000n, 'quadrillarder'],
|
|
18
|
-
[1_000_000_000_000_000_000_000_000n, 'quadrillioner'],
|
|
19
|
-
[1_000_000_000_000_000_000_000n, 'trillarder'],
|
|
20
|
-
[1_000_000_000_000_000_000n, 'trillioner'],
|
|
21
|
-
[1_000_000_000_000_000n, 'billarder'],
|
|
22
|
-
[1_000_000_000_000n, 'billioner'],
|
|
23
|
-
[1_000_000_000n, 'millarder'],
|
|
24
|
-
[1_000_000n, 'millioner'],
|
|
25
|
-
[1000n, 'tusind'],
|
|
26
|
-
[100n, 'hundrede'],
|
|
27
|
-
[90n, 'halvfems'],
|
|
28
|
-
[80n, 'firs'],
|
|
29
|
-
[70n, 'halvfjerds'],
|
|
30
|
-
[60n, 'treds'],
|
|
31
|
-
[50n, 'halvtreds'],
|
|
32
|
-
[40n, 'fyrre'],
|
|
33
|
-
[30n, 'tredive'],
|
|
34
|
-
[20n, 'tyve'],
|
|
35
|
-
[19n, 'nitten'],
|
|
36
|
-
[18n, 'atten'],
|
|
37
|
-
[17n, 'sytten'],
|
|
38
|
-
[16n, 'seksten'],
|
|
39
|
-
[15n, 'femten'],
|
|
40
|
-
[14n, 'fjorten'],
|
|
41
|
-
[13n, 'tretten'],
|
|
42
|
-
[12n, 'tolv'],
|
|
43
|
-
[11n, 'elleve'],
|
|
44
|
-
[10n, 'ti'],
|
|
45
|
-
[9n, 'ni'],
|
|
46
|
-
[8n, 'otte'],
|
|
47
|
-
[7n, 'syv'],
|
|
48
|
-
[6n, 'seks'],
|
|
49
|
-
[5n, 'fem'],
|
|
50
|
-
[4n, 'fire'],
|
|
51
|
-
[3n, 'tre'],
|
|
52
|
-
[2n, 'to'],
|
|
53
|
-
[1n, 'et'],
|
|
54
|
-
[0n, 'nul']
|
|
55
|
-
]
|
|
56
|
-
|
|
57
|
-
constructor (options = {}) {
|
|
58
|
-
super()
|
|
59
|
-
|
|
60
|
-
this.setOptions({
|
|
61
|
-
ordFlag: false
|
|
62
|
-
}, options)
|
|
96
|
+
function integerToWords (n) {
|
|
97
|
+
if (n === 0n) return ZERO
|
|
98
|
+
|
|
99
|
+
// Fast path: numbers < 1000 (direct lookup)
|
|
100
|
+
if (n < 1000n) {
|
|
101
|
+
return buildSegment(Number(n))
|
|
63
102
|
}
|
|
64
103
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const precedingValue = Object.values(preceding)[0] // BigInt (e.g., 1n, 100n, 1000n)
|
|
70
|
-
const followingValue = Object.values(following)[0] // BigInt (e.g., magnitude level like 100n, 1000n)
|
|
104
|
+
// Fast path: numbers < 1,000,000 (thousands)
|
|
105
|
+
if (n < 1_000_000n) {
|
|
106
|
+
const thousands = Number(n / 1000n)
|
|
107
|
+
const remainder = Number(n % 1000n)
|
|
71
108
|
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
following = { [`et${followingWord}`]: followingValue }
|
|
75
|
-
}
|
|
109
|
+
// Compound thousands: "ettusind", "firetusind"
|
|
110
|
+
let result = buildSegment(thousands) + THOUSAND
|
|
76
111
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return following // Just the magnitude word (e.g., "hundrede" not "en hundrede")
|
|
81
|
-
}
|
|
82
|
-
precedingWord = 'en' // Explicit "en" (one) for millions and above
|
|
112
|
+
if (remainder > 0) {
|
|
113
|
+
// Add 'e' suffix and " og " for remainder: "firetusinde og ..."
|
|
114
|
+
result += 'e og ' + buildSegment(remainder)
|
|
83
115
|
}
|
|
84
116
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
117
|
+
return result
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// For numbers >= 1,000,000, use scale decomposition
|
|
121
|
+
return buildLargeNumberWords(n)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Builds words for numbers >= 1,000,000.
|
|
126
|
+
*
|
|
127
|
+
* @param {bigint} n - Number >= 1,000,000
|
|
128
|
+
* @returns {string} Danish words
|
|
129
|
+
*/
|
|
130
|
+
function buildLargeNumberWords (n) {
|
|
131
|
+
const numStr = n.toString()
|
|
132
|
+
const len = numStr.length
|
|
133
|
+
|
|
134
|
+
// Build segments of 3 digits from right to left
|
|
135
|
+
const segments = []
|
|
136
|
+
const segmentSize = 3
|
|
137
|
+
|
|
138
|
+
const remainderLen = len % segmentSize
|
|
139
|
+
let pos = 0
|
|
140
|
+
if (remainderLen > 0) {
|
|
141
|
+
segments.push(Number(numStr.slice(0, remainderLen)))
|
|
142
|
+
pos = remainderLen
|
|
143
|
+
}
|
|
144
|
+
while (pos < len) {
|
|
145
|
+
segments.push(Number(numStr.slice(pos, pos + segmentSize)))
|
|
146
|
+
pos += segmentSize
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Convert segments to words with scale tracking
|
|
150
|
+
// scaleIndex: 0 = units, 1 = thousands, 2 = millions, etc.
|
|
151
|
+
const parts = []
|
|
152
|
+
let scaleIndex = segments.length - 1
|
|
153
|
+
|
|
154
|
+
for (let i = 0; i < segments.length; i++) {
|
|
155
|
+
const segment = segments[i]
|
|
156
|
+
|
|
157
|
+
if (segment !== 0) {
|
|
158
|
+
const segmentWord = buildSegment(segment)
|
|
159
|
+
|
|
160
|
+
if (scaleIndex === 0) {
|
|
161
|
+
// Units segment
|
|
162
|
+
parts.push({ word: segmentWord, type: 'units' })
|
|
163
|
+
} else if (scaleIndex === 1) {
|
|
164
|
+
// Thousands - compound form
|
|
165
|
+
parts.push({ word: segmentWord + THOUSAND, type: 'thousand' })
|
|
166
|
+
} else {
|
|
167
|
+
// Millions+ - space-separated, use "en" for 1
|
|
168
|
+
const scaleWord = SCALES[scaleIndex - 2]
|
|
169
|
+
let numWord = segmentWord
|
|
170
|
+
// "et" → "en" before millions+
|
|
171
|
+
if (segment === 1) {
|
|
172
|
+
numWord = 'en'
|
|
173
|
+
}
|
|
174
|
+
parts.push({ word: numWord + ' ' + scaleWord, type: 'million' })
|
|
90
175
|
}
|
|
91
|
-
return { [`${precedingWord}${followingWord}`]: precedingValue * followingValue }
|
|
92
176
|
}
|
|
93
177
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if (precedingValue >= 100n && precedingValue < 1000n) {
|
|
97
|
-
precedingWord += ' og '
|
|
98
|
-
} else if (precedingValue >= 1000n && precedingValue <= 100_000n) {
|
|
99
|
-
// Special "e og" for thousands (e.g., "tusinde og tyve")
|
|
100
|
-
precedingWord += 'e og '
|
|
101
|
-
}
|
|
178
|
+
scaleIndex--
|
|
179
|
+
}
|
|
102
180
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
181
|
+
// Join parts with Danish rules
|
|
182
|
+
return joinDanishParts(parts)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Joins parts with Danish spacing rules.
|
|
187
|
+
* - After thousands with remainder: "tusinde og"
|
|
188
|
+
* - Millions are space-separated
|
|
189
|
+
*
|
|
190
|
+
* @param {Array} parts - Parts with type metadata
|
|
191
|
+
* @returns {string} Joined string
|
|
192
|
+
*/
|
|
193
|
+
function joinDanishParts (parts) {
|
|
194
|
+
if (parts.length === 0) return ZERO
|
|
195
|
+
if (parts.length === 1) return parts[0].word
|
|
196
|
+
|
|
197
|
+
const result = []
|
|
198
|
+
|
|
199
|
+
for (let i = 0; i < parts.length; i++) {
|
|
200
|
+
const part = parts[i]
|
|
201
|
+
const nextPart = parts[i + 1]
|
|
202
|
+
|
|
203
|
+
if (part.type === 'thousand' && nextPart && nextPart.type === 'units') {
|
|
204
|
+
// Thousands followed by units: add "e og"
|
|
205
|
+
result.push(part.word + 'e og ' + nextPart.word)
|
|
206
|
+
i++ // Skip the units part
|
|
207
|
+
} else if (part.type === 'million') {
|
|
208
|
+
if (result.length > 0) {
|
|
209
|
+
result.push(' ')
|
|
210
|
+
}
|
|
211
|
+
result.push(part.word)
|
|
212
|
+
if (nextPart) {
|
|
213
|
+
result.push(' ')
|
|
214
|
+
}
|
|
215
|
+
} else {
|
|
216
|
+
if (result.length > 0 && !result[result.length - 1].endsWith(' ')) {
|
|
217
|
+
result.push(' ')
|
|
108
218
|
}
|
|
109
|
-
|
|
110
|
-
const temporary = followingWord
|
|
111
|
-
followingWord = precedingWord
|
|
112
|
-
precedingWord = temporary + 'og'
|
|
113
|
-
} else if (precedingValue >= 1_000_000n) {
|
|
114
|
-
// Space for large magnitudes (millions+)
|
|
115
|
-
precedingWord += ' '
|
|
219
|
+
result.push(part.word)
|
|
116
220
|
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return result.join('')
|
|
224
|
+
}
|
|
117
225
|
|
|
118
|
-
|
|
226
|
+
/**
|
|
227
|
+
* Converts decimal digits to Danish words.
|
|
228
|
+
*
|
|
229
|
+
* @param {string} decimalPart - Decimal digits (without the point)
|
|
230
|
+
* @returns {string} Danish words for decimal part
|
|
231
|
+
*/
|
|
232
|
+
function decimalPartToWords (decimalPart) {
|
|
233
|
+
let result = ''
|
|
234
|
+
|
|
235
|
+
// Handle leading zeros
|
|
236
|
+
let i = 0
|
|
237
|
+
while (i < decimalPart.length && decimalPart[i] === '0') {
|
|
238
|
+
if (result) result += ' '
|
|
239
|
+
result += ZERO
|
|
240
|
+
i++
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Convert remainder as a single number
|
|
244
|
+
const remainder = decimalPart.slice(i)
|
|
245
|
+
if (remainder) {
|
|
246
|
+
if (result) result += ' '
|
|
247
|
+
result += integerToWords(BigInt(remainder))
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return result
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Converts a numeric value to Danish words.
|
|
255
|
+
*
|
|
256
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
257
|
+
* @returns {string} The number in Danish words
|
|
258
|
+
* @throws {TypeError} If value is not a valid numeric type
|
|
259
|
+
* @throws {Error} If value is not a valid number format
|
|
260
|
+
*
|
|
261
|
+
* @example
|
|
262
|
+
* toWords(21) // 'enogtyve'
|
|
263
|
+
* toWords(1000) // 'ettusind'
|
|
264
|
+
* toWords(1000000) // 'en millioner'
|
|
265
|
+
*/
|
|
266
|
+
function toWords (value) {
|
|
267
|
+
const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
|
|
268
|
+
|
|
269
|
+
let result = ''
|
|
270
|
+
|
|
271
|
+
if (isNegative) {
|
|
272
|
+
result = NEGATIVE + ' '
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
result += integerToWords(integerPart)
|
|
276
|
+
|
|
277
|
+
if (decimalPart) {
|
|
278
|
+
result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart)
|
|
119
279
|
}
|
|
280
|
+
|
|
281
|
+
return result
|
|
120
282
|
}
|
|
283
|
+
|
|
284
|
+
// ============================================================================
|
|
285
|
+
// Public API
|
|
286
|
+
// ============================================================================
|
|
287
|
+
|
|
288
|
+
export { toWords }
|
package/lib/languages/de.d.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* German
|
|
2
|
+
* Converts a numeric value to German words.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* This is the main public API. It accepts any valid numeric input
|
|
5
|
+
* (number, string, or bigint) and handles parsing internally.
|
|
6
|
+
*
|
|
7
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
8
|
+
* @returns {string} The number in German words
|
|
9
|
+
* @throws {TypeError} If value is not a valid numeric type
|
|
10
|
+
* @throws {Error} If value is not a valid number format
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* toWords(21) // 'einundzwanzig'
|
|
14
|
+
* toWords(1000) // 'eintausend'
|
|
15
|
+
* toWords(1000000) // 'eine Million'
|
|
8
16
|
*/
|
|
9
|
-
export
|
|
10
|
-
scaleWords: (string | bigint)[][];
|
|
11
|
-
/** Combines two word-sets with German compound formation and reversal rules. */
|
|
12
|
-
combineWordSets(preceding: any, following: any): any;
|
|
13
|
-
}
|
|
14
|
-
import { GreedyScaleLanguage } from '../classes/greedy-scale-language.js';
|
|
17
|
+
export function toWords(value: number | string | bigint): string;
|