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/nb.js
CHANGED
|
@@ -1,100 +1,285 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Norwegian Bokmål language converter - Functional Implementation
|
|
3
|
+
*
|
|
4
|
+
* Self-contained module with its own input validation, ready for subpath exports.
|
|
5
|
+
*
|
|
6
|
+
* Key features:
|
|
7
|
+
* - Hyphenated tens+ones: "tjue-en" (21)
|
|
8
|
+
* - "og" conjunction after hundreds
|
|
9
|
+
* - Comma separator after thousands before hundreds
|
|
10
|
+
* - Short scale: million, milliard, billion, etc.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
14
|
+
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// Vocabulary (module-level constants)
|
|
17
|
+
// ============================================================================
|
|
18
|
+
|
|
19
|
+
const ONES = ['', 'en', 'to', 'tre', 'fire', 'fem', 'seks', 'syv', 'åtte', 'ni']
|
|
20
|
+
|
|
21
|
+
const TEENS = ['ti', 'elleve', 'tolv', 'tretten', 'fjorten', 'femten', 'seksten', 'sytten', 'atten', 'nitten']
|
|
22
|
+
const TENS = ['', '', 'tjue', 'tretti', 'førti', 'femti', 'seksti', 'sytti', 'åtti', 'nitti']
|
|
23
|
+
|
|
24
|
+
const HUNDRED = 'hundre'
|
|
25
|
+
const THOUSAND = 'tusen'
|
|
26
|
+
|
|
27
|
+
const ZERO = 'null'
|
|
28
|
+
const NEGATIVE = 'minus'
|
|
29
|
+
const DECIMAL_SEP = 'komma'
|
|
30
|
+
|
|
31
|
+
// Short scale: million, milliard, billion, etc.
|
|
32
|
+
const SCALES = ['million', 'milliard', 'billion', 'billiard', 'kvintillion', 'sekstillion', 'septillion', 'oktillion']
|
|
33
|
+
|
|
34
|
+
// ============================================================================
|
|
35
|
+
// Segment Building
|
|
36
|
+
// ============================================================================
|
|
2
37
|
|
|
3
38
|
/**
|
|
4
|
-
*
|
|
39
|
+
* Builds segment word for 0-999.
|
|
40
|
+
* Returns object with word and hasHundred flag.
|
|
41
|
+
*/
|
|
42
|
+
function buildSegment (n) {
|
|
43
|
+
if (n === 0) return { word: '', hasHundred: false }
|
|
44
|
+
|
|
45
|
+
const ones = n % 10
|
|
46
|
+
const tens = Math.floor(n / 10) % 10
|
|
47
|
+
const hundreds = Math.floor(n / 100)
|
|
48
|
+
|
|
49
|
+
const parts = []
|
|
50
|
+
let hasHundred = false
|
|
51
|
+
|
|
52
|
+
// Hundreds: "en hundre", "to hundre"
|
|
53
|
+
if (hundreds > 0) {
|
|
54
|
+
hasHundred = true
|
|
55
|
+
parts.push(ONES[hundreds] + ' ' + HUNDRED)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Tens and ones
|
|
59
|
+
const tensOnes = n % 100
|
|
60
|
+
|
|
61
|
+
if (tensOnes === 0) {
|
|
62
|
+
// Just hundreds
|
|
63
|
+
} else if (tensOnes < 10) {
|
|
64
|
+
// Single digit
|
|
65
|
+
parts.push(ONES[ones])
|
|
66
|
+
} else if (tensOnes < 20) {
|
|
67
|
+
// Teens
|
|
68
|
+
parts.push(TEENS[ones])
|
|
69
|
+
} else if (ones === 0) {
|
|
70
|
+
// Even tens
|
|
71
|
+
parts.push(TENS[tens])
|
|
72
|
+
} else {
|
|
73
|
+
// Hyphenated: "tjue-en"
|
|
74
|
+
parts.push(TENS[tens] + '-' + ONES[ones])
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Combine with " og " between hundreds and remainder
|
|
78
|
+
if (parts.length === 2) {
|
|
79
|
+
return { word: parts[0] + ' og ' + parts[1], hasHundred: true }
|
|
80
|
+
}
|
|
81
|
+
return { word: parts[0] || '', hasHundred }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ============================================================================
|
|
85
|
+
// Conversion Functions
|
|
86
|
+
// ============================================================================
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Converts a non-negative integer to Norwegian Bokmål words.
|
|
5
90
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* - "og" (and) for hundreds combinations
|
|
9
|
-
* - Implicit '1' omission before tens and magnitudes
|
|
91
|
+
* @param {bigint} n - Non-negative integer to convert
|
|
92
|
+
* @returns {string} Norwegian words
|
|
10
93
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
[1000n, 'tusen'],
|
|
26
|
-
[100n, 'hundre'],
|
|
27
|
-
[90n, 'nitti'],
|
|
28
|
-
[80n, 'åtti'],
|
|
29
|
-
[70n, 'sytti'],
|
|
30
|
-
[60n, 'seksti'],
|
|
31
|
-
[50n, 'femti'],
|
|
32
|
-
[40n, 'førti'],
|
|
33
|
-
[30n, 'tretti'],
|
|
34
|
-
[20n, 'tjue'],
|
|
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, 'åtte'],
|
|
47
|
-
[7n, 'syv'],
|
|
48
|
-
[6n, 'seks'],
|
|
49
|
-
[5n, 'fem'],
|
|
50
|
-
[4n, 'fire'],
|
|
51
|
-
[3n, 'tre'],
|
|
52
|
-
[2n, 'to'],
|
|
53
|
-
[1n, 'en'],
|
|
54
|
-
[0n, 'null']
|
|
55
|
-
]
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Merges two adjacent word-sets according to Norwegian grammar rules.
|
|
59
|
-
*
|
|
60
|
-
* Norwegian-specific rules:
|
|
61
|
-
* - Implicit "en": `combineWordSets({ 'en': 1n }, { 'hundre': 100n })` → `{ 'hundre': 100n }`
|
|
62
|
-
* - Hyphenation for compound tens: `combineWordSets({ 'tjue': 20n }, { 'en': 1n })` → `{ 'tjue-en': 21n }`
|
|
63
|
-
* - "og" (and) after hundreds: `combineWordSets({ 'hundre': 100n }, { 'en': 1n })` → `{ 'hundre og en': 101n }`
|
|
64
|
-
* - Space-separated for large numbers (thousands+)
|
|
65
|
-
* - Comma separator for non-magnitude additions (e.g., \"tusen, en\")
|
|
66
|
-
*
|
|
67
|
-
* @param {Object} preceding The preceding word-set as `{ word: BigInt }`.
|
|
68
|
-
* @param {Object} following The following word-set as `{ word: BigInt }`.
|
|
69
|
-
* @returns {Object} Merged pair with combined word and resulting numeric value.
|
|
70
|
-
*
|
|
71
|
-
* @example
|
|
72
|
-
* combineWordSets({ 'en': 1n }, { 'hundre': 100n }); // { 'hundre': 100n }
|
|
73
|
-
* combineWordSets({ 'tjue': 20n }, { 'tre': 3n }); // { 'tjue-tre': 23n }
|
|
74
|
-
*/
|
|
75
|
-
// Norwegian merge rules mirror the former Scandinavian base logic
|
|
76
|
-
combineWordSets (preceding, following) {
|
|
77
|
-
const precedingWord = Object.keys(preceding)[0]
|
|
78
|
-
const followingWord = Object.keys(following)[0]
|
|
79
|
-
const precedingValue = Object.values(preceding)[0]
|
|
80
|
-
const followingValue = Object.values(following)[0]
|
|
81
|
-
|
|
82
|
-
if (precedingValue === 1n && followingValue < 100n) {
|
|
83
|
-
return following
|
|
84
|
-
}
|
|
94
|
+
function integerToWords (n) {
|
|
95
|
+
if (n === 0n) return ZERO
|
|
96
|
+
|
|
97
|
+
// Fast path: numbers < 1000
|
|
98
|
+
if (n < 1000n) {
|
|
99
|
+
return buildSegment(Number(n)).word
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Fast path: numbers < 1,000,000 (thousands)
|
|
103
|
+
if (n < 1_000_000n) {
|
|
104
|
+
const thousands = Number(n / 1000n)
|
|
105
|
+
const remainder = Number(n % 1000n)
|
|
106
|
+
|
|
107
|
+
let result = buildSegment(thousands).word + ' ' + THOUSAND
|
|
85
108
|
|
|
86
|
-
if (
|
|
87
|
-
|
|
109
|
+
if (remainder > 0) {
|
|
110
|
+
const remainderResult = buildSegment(remainder)
|
|
111
|
+
// Comma before hundreds, " og " before small numbers
|
|
112
|
+
if (remainderResult.hasHundred) {
|
|
113
|
+
result += ', ' + remainderResult.word
|
|
114
|
+
} else {
|
|
115
|
+
result += ' og ' + remainderResult.word
|
|
116
|
+
}
|
|
88
117
|
}
|
|
89
118
|
|
|
90
|
-
|
|
91
|
-
|
|
119
|
+
return result
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// For numbers >= 1,000,000, use scale decomposition
|
|
123
|
+
return buildLargeNumberWords(n)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Builds words for numbers >= 1,000,000.
|
|
128
|
+
*
|
|
129
|
+
* @param {bigint} n - Number >= 1,000,000
|
|
130
|
+
* @returns {string} Norwegian words
|
|
131
|
+
*/
|
|
132
|
+
function buildLargeNumberWords (n) {
|
|
133
|
+
const numStr = n.toString()
|
|
134
|
+
const len = numStr.length
|
|
135
|
+
|
|
136
|
+
// Build segments of 3 digits from right to left
|
|
137
|
+
const segments = []
|
|
138
|
+
const segmentSize = 3
|
|
139
|
+
|
|
140
|
+
const remainderLen = len % segmentSize
|
|
141
|
+
let pos = 0
|
|
142
|
+
if (remainderLen > 0) {
|
|
143
|
+
segments.push(Number(numStr.slice(0, remainderLen)))
|
|
144
|
+
pos = remainderLen
|
|
145
|
+
}
|
|
146
|
+
while (pos < len) {
|
|
147
|
+
segments.push(Number(numStr.slice(pos, pos + segmentSize)))
|
|
148
|
+
pos += segmentSize
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Convert segments to words
|
|
152
|
+
const parts = []
|
|
153
|
+
let scaleIndex = segments.length - 1
|
|
154
|
+
|
|
155
|
+
for (let i = 0; i < segments.length; i++) {
|
|
156
|
+
const segment = segments[i]
|
|
157
|
+
|
|
158
|
+
if (segment !== 0) {
|
|
159
|
+
const segmentResult = buildSegment(segment)
|
|
160
|
+
|
|
161
|
+
if (scaleIndex === 0) {
|
|
162
|
+
// Units segment
|
|
163
|
+
parts.push({ word: segmentResult.word, hasHundred: segmentResult.hasHundred, type: 'units' })
|
|
164
|
+
} else if (scaleIndex === 1) {
|
|
165
|
+
// Thousands
|
|
166
|
+
parts.push({ word: segmentResult.word + ' ' + THOUSAND, hasHundred: false, type: 'thousand' })
|
|
167
|
+
} else {
|
|
168
|
+
// Millions+
|
|
169
|
+
const scaleWord = SCALES[scaleIndex - 2]
|
|
170
|
+
parts.push({ word: segmentResult.word + ' ' + scaleWord, hasHundred: false, type: 'million' })
|
|
171
|
+
}
|
|
92
172
|
}
|
|
93
173
|
|
|
94
|
-
|
|
95
|
-
|
|
174
|
+
scaleIndex--
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Join parts with Norwegian rules
|
|
178
|
+
return joinNorwegianParts(parts)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Joins parts with Norwegian spacing and comma rules.
|
|
183
|
+
*
|
|
184
|
+
* @param {Array} parts - Parts with type metadata
|
|
185
|
+
* @returns {string} Joined string
|
|
186
|
+
*/
|
|
187
|
+
function joinNorwegianParts (parts) {
|
|
188
|
+
if (parts.length === 0) return ZERO
|
|
189
|
+
if (parts.length === 1) return parts[0].word
|
|
190
|
+
|
|
191
|
+
const result = []
|
|
192
|
+
|
|
193
|
+
for (let i = 0; i < parts.length; i++) {
|
|
194
|
+
const part = parts[i]
|
|
195
|
+
const nextPart = parts[i + 1]
|
|
196
|
+
|
|
197
|
+
result.push(part.word)
|
|
198
|
+
|
|
199
|
+
if (nextPart) {
|
|
200
|
+
if (part.type === 'thousand') {
|
|
201
|
+
// After thousands: comma if next has hundred, else " og "
|
|
202
|
+
if (nextPart.hasHundred) {
|
|
203
|
+
result.push(', ')
|
|
204
|
+
} else {
|
|
205
|
+
result.push(' og ')
|
|
206
|
+
}
|
|
207
|
+
} else if (part.type === 'million') {
|
|
208
|
+
// After millions: " og " for units without hundred, space otherwise
|
|
209
|
+
if (nextPart.type === 'units' && !nextPart.hasHundred) {
|
|
210
|
+
result.push(' og ')
|
|
211
|
+
} else {
|
|
212
|
+
result.push(' ')
|
|
213
|
+
}
|
|
214
|
+
} else {
|
|
215
|
+
result.push(' ')
|
|
216
|
+
}
|
|
96
217
|
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return result.join('')
|
|
221
|
+
}
|
|
97
222
|
|
|
98
|
-
|
|
223
|
+
/**
|
|
224
|
+
* Converts decimal digits to Norwegian words.
|
|
225
|
+
*
|
|
226
|
+
* @param {string} decimalPart - Decimal digits (without the point)
|
|
227
|
+
* @returns {string} Norwegian words for decimal part
|
|
228
|
+
*/
|
|
229
|
+
function decimalPartToWords (decimalPart) {
|
|
230
|
+
let result = ''
|
|
231
|
+
|
|
232
|
+
// Handle leading zeros
|
|
233
|
+
let i = 0
|
|
234
|
+
while (i < decimalPart.length && decimalPart[i] === '0') {
|
|
235
|
+
if (result) result += ' '
|
|
236
|
+
result += ZERO
|
|
237
|
+
i++
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Convert remainder as a single number
|
|
241
|
+
const remainder = decimalPart.slice(i)
|
|
242
|
+
if (remainder) {
|
|
243
|
+
if (result) result += ' '
|
|
244
|
+
result += integerToWords(BigInt(remainder))
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return result
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Converts a numeric value to Norwegian Bokmål words.
|
|
252
|
+
*
|
|
253
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
254
|
+
* @returns {string} The number in Norwegian words
|
|
255
|
+
* @throws {TypeError} If value is not a valid numeric type
|
|
256
|
+
* @throws {Error} If value is not a valid number format
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* toWords(21) // 'tjue-en'
|
|
260
|
+
* toWords(101) // 'en hundre og en'
|
|
261
|
+
* toWords(1000000) // 'en million'
|
|
262
|
+
*/
|
|
263
|
+
function toWords (value) {
|
|
264
|
+
const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
|
|
265
|
+
|
|
266
|
+
let result = ''
|
|
267
|
+
|
|
268
|
+
if (isNegative) {
|
|
269
|
+
result = NEGATIVE + ' '
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
result += integerToWords(integerPart)
|
|
273
|
+
|
|
274
|
+
if (decimalPart) {
|
|
275
|
+
result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart)
|
|
99
276
|
}
|
|
277
|
+
|
|
278
|
+
return result
|
|
100
279
|
}
|
|
280
|
+
|
|
281
|
+
// ============================================================================
|
|
282
|
+
// Public API
|
|
283
|
+
// ============================================================================
|
|
284
|
+
|
|
285
|
+
export { toWords }
|
package/lib/languages/nl.d.ts
CHANGED
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Dutch
|
|
2
|
+
* Converts a numeric value to Dutch 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
|
+
* @param {Object} [options] - Optional configuration
|
|
9
|
+
* @param {boolean} [options.accentOne=true] - Use "één" instead of "een"
|
|
10
|
+
* @param {boolean} [options.includeOptionalAnd=false] - Include "en" before small numbers
|
|
11
|
+
* @param {boolean} [options.noHundredPairing=false] - Disable hundred pairing (1104→duizend honderdvier)
|
|
12
|
+
* @returns {string} The number in Dutch words
|
|
13
|
+
* @throws {TypeError} If value is not a valid numeric type
|
|
14
|
+
* @throws {Error} If value is not a valid number format
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* toWords(21) // 'eenentwintig'
|
|
18
|
+
* toWords(1) // 'één'
|
|
19
|
+
* toWords(1, {accentOne: false}) // 'een'
|
|
20
|
+
* toWords(1104) // 'elfhonderd vier'
|
|
8
21
|
*/
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
integerToWords(integerPart: any): string;
|
|
15
|
-
}
|
|
16
|
-
import { GreedyScaleLanguage } from '../classes/greedy-scale-language.js';
|
|
22
|
+
export function toWords(value: number | string | bigint, options?: {
|
|
23
|
+
accentOne?: boolean | undefined;
|
|
24
|
+
includeOptionalAnd?: boolean | undefined;
|
|
25
|
+
noHundredPairing?: boolean | undefined;
|
|
26
|
+
}): string;
|