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/nl.js
CHANGED
|
@@ -1,155 +1,321 @@
|
|
|
1
|
-
import { GreedyScaleLanguage } from '../classes/greedy-scale-language.js'
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
|
-
* Dutch language converter
|
|
2
|
+
* Dutch language converter - Functional Implementation
|
|
3
|
+
*
|
|
4
|
+
* Self-contained module with its own input validation, ready for subpath exports.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
9
|
-
* - Compound
|
|
6
|
+
* Dutch-specific rules:
|
|
7
|
+
* - Inverted tens-ones: eenentwintig (one-and-twenty)
|
|
8
|
+
* - "ën" connector when ones ends in 'e' (twee, drie)
|
|
9
|
+
* - Compound words without spaces
|
|
10
|
+
* - Hundred pairing for 1100-9999 (elfhonderd style)
|
|
11
|
+
* - "één" vs "een" (accentOne option)
|
|
12
|
+
* - Optional "en" separator (includeOptionalAnd option)
|
|
13
|
+
* - Long scale with -ard forms
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
17
|
+
import { validateOptions } from '../utils/validate-options.js'
|
|
18
|
+
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// Vocabulary (module-level constants)
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
const ONES = ['', 'een', 'twee', 'drie', 'vier', 'vijf', 'zes', 'zeven', 'acht', 'negen']
|
|
24
|
+
const TEENS = ['tien', 'elf', 'twaalf', 'dertien', 'veertien', 'vijftien', 'zestien', 'zeventien', 'achttien', 'negentien']
|
|
25
|
+
const TENS = ['', '', 'twintig', 'dertig', 'veertig', 'vijftig', 'zestig', 'zeventig', 'tachtig', 'negentig']
|
|
26
|
+
|
|
27
|
+
const HUNDRED = 'honderd'
|
|
28
|
+
|
|
29
|
+
// Scale words (long scale with -ard forms)
|
|
30
|
+
const SCALES = ['duizend', 'miljoen', 'miljard', 'biljoen', 'biljard', 'triljoen', 'triljard', 'quadriljoen', 'quadriljard']
|
|
31
|
+
|
|
32
|
+
const ZERO = 'nul'
|
|
33
|
+
const NEGATIVE = 'min'
|
|
34
|
+
const DECIMAL_SEP = 'komma'
|
|
35
|
+
|
|
36
|
+
// ============================================================================
|
|
37
|
+
// Segment Building
|
|
38
|
+
// ============================================================================
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Builds segment word for 0-999.
|
|
42
|
+
* @param {number} n - Segment value
|
|
43
|
+
* @param {boolean} withAnd - Include "en" for values < 13 after hundreds
|
|
44
|
+
* @returns {string} Dutch word (compound, no spaces)
|
|
10
45
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
[90n, 'negentig'],
|
|
28
|
-
[80n, 'tachtig'],
|
|
29
|
-
[70n, 'zeventig'],
|
|
30
|
-
[60n, 'zestig'],
|
|
31
|
-
[50n, 'vijftig'],
|
|
32
|
-
[40n, 'veertig'],
|
|
33
|
-
[30n, 'dertig'],
|
|
34
|
-
[20n, 'twintig'],
|
|
35
|
-
[19n, 'negentien'],
|
|
36
|
-
[18n, 'achttien'],
|
|
37
|
-
[17n, 'zeventien'],
|
|
38
|
-
[16n, 'zestien'],
|
|
39
|
-
[15n, 'vijftien'],
|
|
40
|
-
[14n, 'veertien'],
|
|
41
|
-
[13n, 'dertien'],
|
|
42
|
-
[12n, 'twaalf'],
|
|
43
|
-
[11n, 'elf'],
|
|
44
|
-
[10n, 'tien'],
|
|
45
|
-
[9n, 'negen'],
|
|
46
|
-
[8n, 'acht'],
|
|
47
|
-
[7n, 'zeven'],
|
|
48
|
-
[6n, 'zes'],
|
|
49
|
-
[5n, 'vijf'],
|
|
50
|
-
[4n, 'vier'],
|
|
51
|
-
[3n, 'drie'],
|
|
52
|
-
[2n, 'twee'],
|
|
53
|
-
[1n, 'één'],
|
|
54
|
-
[0n, 'nul']
|
|
55
|
-
]
|
|
56
|
-
|
|
57
|
-
constructor (options = {}) {
|
|
58
|
-
super()
|
|
59
|
-
|
|
60
|
-
this.setOptions({
|
|
61
|
-
includeOptionalAnd: false,
|
|
62
|
-
noHundredPairing: false,
|
|
63
|
-
accentOne: true
|
|
64
|
-
}, options)
|
|
65
|
-
|
|
66
|
-
if (!this.options.accentOne) {
|
|
67
|
-
this.scaleWords[this.scaleWords.length - 2][1] = 'een'
|
|
46
|
+
function buildSegment (n, withAnd) {
|
|
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
|
+
const tensOnes = n % 100
|
|
53
|
+
|
|
54
|
+
let result = ''
|
|
55
|
+
|
|
56
|
+
// Hundreds
|
|
57
|
+
if (hundreds > 0) {
|
|
58
|
+
if (hundreds === 1) {
|
|
59
|
+
result = HUNDRED
|
|
60
|
+
} else {
|
|
61
|
+
result = ONES[hundreds] + HUNDRED
|
|
68
62
|
}
|
|
69
63
|
}
|
|
70
64
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
65
|
+
// Tens and ones
|
|
66
|
+
if (tensOnes === 0) {
|
|
67
|
+
// Just hundreds
|
|
68
|
+
} else if (tensOnes < 10) {
|
|
69
|
+
// Single digit - add "en" if withAnd and after hundreds
|
|
70
|
+
if (hundreds > 0 && withAnd) {
|
|
71
|
+
result += 'en' + ONES[tensOnes]
|
|
72
|
+
} else {
|
|
73
|
+
result += ONES[tensOnes]
|
|
74
|
+
}
|
|
75
|
+
} else if (tensOnes < 20) {
|
|
76
|
+
// Teens - add "en" if withAnd and after hundreds and < 13
|
|
77
|
+
if (hundreds > 0 && withAnd && tensOnes < 13) {
|
|
78
|
+
result += 'en' + TEENS[ones]
|
|
79
|
+
} else {
|
|
80
|
+
result += TEENS[ones]
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
// 20-99: Dutch inverts with connector
|
|
84
|
+
if (ones === 0) {
|
|
85
|
+
result += TENS[tens]
|
|
86
|
+
} else {
|
|
87
|
+
// "ën" if ones ends in 'e' (twee, drie)
|
|
88
|
+
const onesWord = ONES[ones]
|
|
89
|
+
const connector = onesWord.endsWith('e') ? 'ën' : 'en'
|
|
90
|
+
result += onesWord + connector + TENS[tens]
|
|
84
91
|
}
|
|
92
|
+
}
|
|
85
93
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
94
|
+
return result
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ============================================================================
|
|
98
|
+
// Conversion Functions
|
|
99
|
+
// ============================================================================
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Converts a non-negative integer to Dutch words.
|
|
103
|
+
*
|
|
104
|
+
* @param {bigint} n - Non-negative integer to convert
|
|
105
|
+
* @param {Object} options - Conversion options
|
|
106
|
+
* @returns {string} Dutch words
|
|
107
|
+
*/
|
|
108
|
+
function integerToWords (n, options) {
|
|
109
|
+
if (n === 0n) return ZERO
|
|
110
|
+
|
|
111
|
+
const { accentOne, includeOptionalAnd, noHundredPairing } = options
|
|
112
|
+
|
|
113
|
+
// Apply één/een replacement
|
|
114
|
+
const applyAccent = (word) => {
|
|
115
|
+
if (accentOne) {
|
|
116
|
+
return word.replace(/\been\b/g, 'één')
|
|
117
|
+
}
|
|
118
|
+
return word
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Fast path: numbers < 1000
|
|
122
|
+
if (n < 1000n) {
|
|
123
|
+
return applyAccent(buildSegment(Number(n), includeOptionalAnd))
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Hundred pairing for 1100-9999
|
|
127
|
+
if (!noHundredPairing && n >= 1100n && n < 10000n) {
|
|
128
|
+
const high = Number(n / 100n)
|
|
129
|
+
const low = Number(n % 100n)
|
|
130
|
+
|
|
131
|
+
// Only use pairing when high is not a multiple of 10
|
|
132
|
+
if (high % 10 !== 0) {
|
|
133
|
+
let result = buildSegment(high, includeOptionalAnd) + HUNDRED
|
|
134
|
+
if (low > 0) {
|
|
135
|
+
const lowWord = buildSegment(low, includeOptionalAnd)
|
|
136
|
+
if (includeOptionalAnd && low < 13) {
|
|
137
|
+
result += ' en ' + lowWord
|
|
138
|
+
} else {
|
|
139
|
+
result += ' ' + lowWord
|
|
140
|
+
}
|
|
102
141
|
}
|
|
103
|
-
return
|
|
142
|
+
return applyAccent(result)
|
|
104
143
|
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Fast path: numbers < 1,000,000 (thousands)
|
|
147
|
+
if (n < 1_000_000n) {
|
|
148
|
+
const thousands = Number(n / 1000n)
|
|
149
|
+
const remainder = Number(n % 1000n)
|
|
105
150
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
precedingWord = `${temporary}${andTxt}`
|
|
114
|
-
} else if (followingValue < 13n && precedingValue < 1000n && this.options.includeOptionalAnd) {
|
|
115
|
-
precedingWord = `${precedingWord}en`
|
|
116
|
-
} else if (followingValue < 13n && precedingValue >= 1000n && this.options.includeOptionalAnd) {
|
|
117
|
-
followingWord = ` en ${followingWord}`
|
|
118
|
-
hasSpace = true
|
|
119
|
-
} else if (precedingValue >= 1_000_000n) {
|
|
120
|
-
precedingWord += ' '
|
|
121
|
-
hasSpace = true
|
|
122
|
-
} else if (precedingValue === 1000n) {
|
|
123
|
-
precedingWord += ' '
|
|
124
|
-
hasSpace = true
|
|
151
|
+
let result
|
|
152
|
+
if (thousands === 1) {
|
|
153
|
+
// "duizend" not "eenduizend"
|
|
154
|
+
result = SCALES[0]
|
|
155
|
+
} else {
|
|
156
|
+
// Compound: "vijfduizend"
|
|
157
|
+
result = buildSegment(thousands, includeOptionalAnd) + SCALES[0]
|
|
125
158
|
}
|
|
126
159
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
followingWord = followingWord.replace(/één/g, 'een')
|
|
160
|
+
if (remainder > 0) {
|
|
161
|
+
const remainderWord = buildSegment(remainder, includeOptionalAnd)
|
|
162
|
+
if (includeOptionalAnd && remainder < 13) {
|
|
163
|
+
result += ' en ' + remainderWord
|
|
164
|
+
} else {
|
|
165
|
+
result += ' ' + remainderWord
|
|
166
|
+
}
|
|
135
167
|
}
|
|
136
168
|
|
|
137
|
-
return
|
|
169
|
+
return applyAccent(result)
|
|
138
170
|
}
|
|
139
171
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
172
|
+
// For numbers >= 1,000,000, use scale decomposition
|
|
173
|
+
return applyAccent(buildLargeNumberWords(n, options))
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Builds words for numbers >= 1,000,000.
|
|
178
|
+
* Uses BigInt division for faster segment extraction (4x faster than string slicing).
|
|
179
|
+
*
|
|
180
|
+
* @param {bigint} n - Number >= 1,000,000
|
|
181
|
+
* @param {Object} options - Conversion options
|
|
182
|
+
* @returns {string} Dutch words
|
|
183
|
+
*/
|
|
184
|
+
function buildLargeNumberWords (n, options) {
|
|
185
|
+
const { includeOptionalAnd } = options
|
|
186
|
+
|
|
187
|
+
// Extract segments using BigInt division (faster than string slicing)
|
|
188
|
+
// Segments stored least-significant first (index 0 = ones, 1 = thousands, etc.)
|
|
189
|
+
const segmentValues = []
|
|
190
|
+
let temp = n
|
|
191
|
+
while (temp > 0n) {
|
|
192
|
+
segmentValues.push(Number(temp % 1000n))
|
|
193
|
+
temp = temp / 1000n
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Build result string directly (avoids object allocation and join)
|
|
197
|
+
let result = ''
|
|
198
|
+
let prevWasScale = false
|
|
199
|
+
|
|
200
|
+
for (let i = segmentValues.length - 1; i >= 0; i--) {
|
|
201
|
+
const segment = segmentValues[i]
|
|
202
|
+
if (segment === 0) continue
|
|
203
|
+
|
|
204
|
+
if (i === 0) {
|
|
205
|
+
// Units segment
|
|
206
|
+
const word = buildSegment(segment, includeOptionalAnd)
|
|
207
|
+
if (result) {
|
|
208
|
+
if (prevWasScale && includeOptionalAnd && segment < 13) {
|
|
209
|
+
result += ' en ' + word
|
|
210
|
+
} else {
|
|
211
|
+
result += ' ' + word
|
|
149
212
|
}
|
|
150
|
-
|
|
213
|
+
} else {
|
|
214
|
+
result = word
|
|
215
|
+
}
|
|
216
|
+
prevWasScale = false
|
|
217
|
+
} else if (i === 1) {
|
|
218
|
+
// Thousands - compound
|
|
219
|
+
if (result) result += ' '
|
|
220
|
+
if (segment === 1) {
|
|
221
|
+
result += SCALES[0]
|
|
222
|
+
} else {
|
|
223
|
+
result += buildSegment(segment, includeOptionalAnd) + SCALES[0]
|
|
224
|
+
}
|
|
225
|
+
prevWasScale = true
|
|
226
|
+
} else {
|
|
227
|
+
// Million and above - space around scale
|
|
228
|
+
const scaleWord = SCALES[i - 1]
|
|
229
|
+
if (result) result += ' '
|
|
230
|
+
if (segment === 1) {
|
|
231
|
+
result += 'een ' + scaleWord
|
|
232
|
+
} else {
|
|
233
|
+
result += buildSegment(segment, includeOptionalAnd) + ' ' + scaleWord
|
|
151
234
|
}
|
|
235
|
+
prevWasScale = true
|
|
152
236
|
}
|
|
153
|
-
return super.integerToWords(integerPart)
|
|
154
237
|
}
|
|
238
|
+
|
|
239
|
+
return result
|
|
155
240
|
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Converts decimal digits to Dutch words.
|
|
244
|
+
*
|
|
245
|
+
* @param {string} decimalPart - Decimal digits (without the point)
|
|
246
|
+
* @param {Object} options - Conversion options
|
|
247
|
+
* @returns {string} Dutch words for decimal part
|
|
248
|
+
*/
|
|
249
|
+
function decimalPartToWords (decimalPart, options) {
|
|
250
|
+
let result = ''
|
|
251
|
+
|
|
252
|
+
// Handle leading zeros
|
|
253
|
+
let i = 0
|
|
254
|
+
while (i < decimalPart.length && decimalPart[i] === '0') {
|
|
255
|
+
if (result) result += ' '
|
|
256
|
+
result += ZERO
|
|
257
|
+
i++
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Convert remainder as a single number
|
|
261
|
+
const remainder = decimalPart.slice(i)
|
|
262
|
+
if (remainder) {
|
|
263
|
+
if (result) result += ' '
|
|
264
|
+
const word = integerToWords(BigInt(remainder), { ...options, noHundredPairing: true })
|
|
265
|
+
result += word
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return result
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Converts a numeric value to Dutch words.
|
|
273
|
+
*
|
|
274
|
+
* This is the main public API. It accepts any valid numeric input
|
|
275
|
+
* (number, string, or bigint) and handles parsing internally.
|
|
276
|
+
*
|
|
277
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
278
|
+
* @param {Object} [options] - Optional configuration
|
|
279
|
+
* @param {boolean} [options.accentOne=true] - Use "één" instead of "een"
|
|
280
|
+
* @param {boolean} [options.includeOptionalAnd=false] - Include "en" before small numbers
|
|
281
|
+
* @param {boolean} [options.noHundredPairing=false] - Disable hundred pairing (1104→duizend honderdvier)
|
|
282
|
+
* @returns {string} The number in Dutch words
|
|
283
|
+
* @throws {TypeError} If value is not a valid numeric type
|
|
284
|
+
* @throws {Error} If value is not a valid number format
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* toWords(21) // 'eenentwintig'
|
|
288
|
+
* toWords(1) // 'één'
|
|
289
|
+
* toWords(1, {accentOne: false}) // 'een'
|
|
290
|
+
* toWords(1104) // 'elfhonderd vier'
|
|
291
|
+
*/
|
|
292
|
+
function toWords (value, options) {
|
|
293
|
+
options = validateOptions(options)
|
|
294
|
+
const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
|
|
295
|
+
|
|
296
|
+
const opts = {
|
|
297
|
+
accentOne: options.accentOne !== false, // default true
|
|
298
|
+
includeOptionalAnd: options.includeOptionalAnd || false,
|
|
299
|
+
noHundredPairing: options.noHundredPairing || false
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
let result = ''
|
|
303
|
+
|
|
304
|
+
if (isNegative) {
|
|
305
|
+
result = NEGATIVE + ' '
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
result += integerToWords(integerPart, opts)
|
|
309
|
+
|
|
310
|
+
if (decimalPart) {
|
|
311
|
+
result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart, opts)
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return result
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// ============================================================================
|
|
318
|
+
// Public API
|
|
319
|
+
// ============================================================================
|
|
320
|
+
|
|
321
|
+
export { toWords }
|
package/lib/languages/pa.d.ts
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Punjabi
|
|
2
|
+
* Converts a numeric value to Punjabi words.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* - Gurmukhi script
|
|
7
|
-
* - Complete word forms for 0-99
|
|
4
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
5
|
+
* @returns {string} The number in Punjabi words
|
|
8
6
|
*/
|
|
9
|
-
export
|
|
10
|
-
}
|
|
11
|
-
import { SouthAsianLanguage } from '../classes/south-asian-language.js';
|
|
7
|
+
export function toWords(value: number | string | bigint): string;
|