n2words 2.0.0 → 3.0.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 +49 -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/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/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 +164 -0
- package/lib/languages/am.d.ts +7 -0
- package/lib/languages/am.js +164 -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 +171 -37
- package/lib/languages/bn.d.ts +4 -8
- package/lib/languages/bn.js +138 -124
- package/lib/languages/cs.d.ts +15 -85
- package/lib/languages/cs.js +310 -114
- package/lib/languages/da.d.ts +11 -12
- package/lib/languages/da.js +276 -101
- package/lib/languages/de.d.ts +14 -11
- package/lib/languages/de.js +317 -86
- package/lib/languages/el.d.ts +11 -11
- package/lib/languages/el.js +231 -78
- package/lib/languages/en.d.ts +14 -13
- package/lib/languages/en.js +242 -72
- package/lib/languages/es.d.ts +18 -12
- package/lib/languages/es.js +317 -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 +245 -0
- package/lib/languages/fil.d.ts +4 -13
- package/lib/languages/fil.js +207 -106
- package/lib/languages/fr-BE.d.ts +8 -8
- package/lib/languages/fr-BE.js +294 -19
- package/lib/languages/fr.d.ts +18 -12
- package/lib/languages/fr.js +352 -89
- package/lib/languages/gu.d.ts +4 -8
- package/lib/languages/gu.js +130 -125
- package/lib/languages/ha.d.ts +7 -0
- package/lib/languages/ha.js +230 -0
- package/lib/languages/hbo.d.ts +10 -110
- package/lib/languages/hbo.js +263 -214
- package/lib/languages/he.d.ts +10 -77
- package/lib/languages/he.js +242 -172
- package/lib/languages/hi.d.ts +4 -8
- package/lib/languages/hi.js +138 -124
- package/lib/languages/hr.d.ts +8 -77
- package/lib/languages/hr.js +194 -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 +171 -129
- package/lib/languages/it.d.ts +16 -34
- package/lib/languages/it.js +339 -94
- package/lib/languages/ja.d.ts +14 -14
- package/lib/languages/ja.js +233 -111
- package/lib/languages/kn.d.ts +4 -8
- package/lib/languages/kn.js +130 -35
- package/lib/languages/ko.d.ts +11 -11
- package/lib/languages/ko.js +257 -49
- package/lib/languages/lt.d.ts +15 -67
- package/lib/languages/lt.js +296 -122
- package/lib/languages/lv.d.ts +15 -67
- package/lib/languages/lv.js +297 -106
- package/lib/languages/mr.d.ts +4 -8
- package/lib/languages/mr.js +130 -125
- package/lib/languages/ms.d.ts +4 -28
- package/lib/languages/ms.js +171 -116
- package/lib/languages/nb.d.ts +11 -9
- package/lib/languages/nb.js +282 -87
- package/lib/languages/nl.d.ts +23 -13
- package/lib/languages/nl.js +317 -133
- package/lib/languages/pa.d.ts +4 -8
- package/lib/languages/pa.js +156 -124
- package/lib/languages/pl.d.ts +19 -77
- package/lib/languages/pl.js +307 -87
- package/lib/languages/pt.d.ts +14 -26
- package/lib/languages/pt.js +286 -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 +222 -78
- package/lib/languages/sr-Cyrl.d.ts +8 -77
- package/lib/languages/sr-Cyrl.js +191 -89
- package/lib/languages/sr-Latn.d.ts +8 -77
- package/lib/languages/sr-Latn.js +191 -89
- package/lib/languages/sv.d.ts +11 -11
- package/lib/languages/sv.js +288 -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 +129 -201
- package/lib/languages/te.d.ts +4 -19
- package/lib/languages/te.js +141 -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 +256 -49
- package/lib/languages/uk.d.ts +8 -82
- package/lib/languages/uk.js +200 -78
- package/lib/languages/ur.d.ts +4 -8
- package/lib/languages/ur.js +156 -124
- package/lib/languages/vi.d.ts +14 -69
- package/lib/languages/vi.js +294 -125
- 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 +53 -209
- package/lib/n2words.js +111 -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/cs.js
CHANGED
|
@@ -1,143 +1,339 @@
|
|
|
1
|
-
import { SlavicLanguage } from '../classes/slavic-language.js'
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
|
-
* Czech language converter
|
|
2
|
+
* Czech language converter - Functional Implementation
|
|
3
|
+
*
|
|
4
|
+
* A performance-optimized number-to-words converter using precomputed lookup tables.
|
|
5
|
+
* Self-contained module with its own input validation, ready for subpath exports.
|
|
6
|
+
*
|
|
7
|
+
* Key optimization: Precompute all segment values (0-999) at module load.
|
|
8
|
+
* This eliminates all per-call string manipulation for segment conversion.
|
|
5
9
|
*
|
|
6
|
-
*
|
|
7
|
-
* - Three-form pluralization
|
|
8
|
-
* -
|
|
9
|
-
* - Gender
|
|
10
|
+
* Czech-specific rules (handled in precomputation):
|
|
11
|
+
* - Three-form pluralization: 1 = singular, 2-4 = few, 5+ = many
|
|
12
|
+
* - Irregular hundreds: sto, dvě stě, tři sta, čtyři sta, pět set...
|
|
13
|
+
* - Gender: dva (masc) vs dvě (fem) for 2
|
|
14
|
+
* - Omit "one" before scale words: "tisíc" not "jedna tisíc"
|
|
15
|
+
* - Dynamic decimal separator: celá/celé/celých based on integer
|
|
10
16
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
|
|
18
|
+
import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
19
|
+
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Vocabulary (module-level constants)
|
|
22
|
+
// ============================================================================
|
|
23
|
+
|
|
24
|
+
// Ones words (masculine form)
|
|
25
|
+
const ONES = ['', 'jedna', 'dva', 'tři', 'čtyři', 'pět', 'šest', 'sedm', 'osm', 'devět']
|
|
26
|
+
|
|
27
|
+
// Teens (10-19)
|
|
28
|
+
const TEENS = ['deset', 'jedenáct', 'dvanáct', 'třináct', 'čtrnáct', 'patnáct', 'šestnáct', 'sedmnáct', 'osmnáct', 'devatenáct']
|
|
29
|
+
|
|
30
|
+
// Tens (20-90)
|
|
31
|
+
const TENS = ['', '', 'dvacet', 'třicet', 'čtyřicet', 'padesát', 'šedesát', 'sedmdesát', 'osmdesát', 'devadesát']
|
|
32
|
+
|
|
33
|
+
// Irregular hundreds
|
|
34
|
+
const HUNDREDS = ['', 'sto', 'dvě stě', 'tři sta', 'čtyři sta', 'pět set', 'šest set', 'sedm set', 'osm set', 'devět set']
|
|
35
|
+
|
|
36
|
+
// Scale plural forms [singular, few (2-4), many (5+)]
|
|
37
|
+
const PLURAL_FORMS = {
|
|
38
|
+
1: ['tisíc', 'tisíce', 'tisíc'], // 10^3
|
|
39
|
+
2: ['milion', 'miliony', 'milionů'], // 10^6
|
|
40
|
+
3: ['miliarda', 'miliardy', 'miliard'], // 10^9
|
|
41
|
+
4: ['bilion', 'biliony', 'bilionů'], // 10^12
|
|
42
|
+
5: ['biliarda', 'biliardy', 'biliard'], // 10^15
|
|
43
|
+
6: ['trilion', 'triliony', 'trilionů'], // 10^18
|
|
44
|
+
7: ['triliarda', 'triliardy', 'triliard'], // 10^21
|
|
45
|
+
8: ['kvadrilion', 'kvadriliony', 'kvadrilionů'], // 10^24
|
|
46
|
+
9: ['kvadriliarda', 'kvadriliardy', 'kvadriliard'] // 10^27
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const ZERO = 'nula'
|
|
50
|
+
const NEGATIVE = 'mínus'
|
|
51
|
+
|
|
52
|
+
// ============================================================================
|
|
53
|
+
// Precomputed Lookup Tables (built once at module load)
|
|
54
|
+
// ============================================================================
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Builds segment word for 0-999 (masculine, default form).
|
|
58
|
+
* Only used during table construction.
|
|
59
|
+
*/
|
|
60
|
+
function buildSegment (n) {
|
|
61
|
+
if (n === 0) return ''
|
|
62
|
+
|
|
63
|
+
const ones = n % 10
|
|
64
|
+
const tens = Math.floor(n / 10) % 10
|
|
65
|
+
const hundreds = Math.floor(n / 100)
|
|
66
|
+
|
|
67
|
+
const parts = []
|
|
68
|
+
|
|
69
|
+
// Hundreds (irregular)
|
|
70
|
+
if (hundreds > 0) {
|
|
71
|
+
parts.push(HUNDREDS[hundreds])
|
|
25
72
|
}
|
|
26
73
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
74
|
+
// Tens and ones
|
|
75
|
+
if (tens === 1) {
|
|
76
|
+
// Teens
|
|
77
|
+
parts.push(TEENS[ones])
|
|
78
|
+
} else if (tens >= 2) {
|
|
79
|
+
parts.push(TENS[tens])
|
|
80
|
+
if (ones > 0) {
|
|
81
|
+
parts.push(ONES[ones])
|
|
82
|
+
}
|
|
83
|
+
} else if (ones > 0) {
|
|
84
|
+
parts.push(ONES[ones])
|
|
37
85
|
}
|
|
38
86
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
87
|
+
return parts.join(' ')
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Builds segment word for 0-999 with feminine hundreds.
|
|
92
|
+
* Hundreds use irregular forms (dvě stě, tři sta) but ones remain masculine.
|
|
93
|
+
*/
|
|
94
|
+
function buildSegmentWithHundreds (n) {
|
|
95
|
+
if (n === 0) return ''
|
|
96
|
+
|
|
97
|
+
const ones = n % 10
|
|
98
|
+
const tens = Math.floor(n / 10) % 10
|
|
99
|
+
const hundreds = Math.floor(n / 100)
|
|
100
|
+
|
|
101
|
+
const parts = []
|
|
102
|
+
|
|
103
|
+
// Hundreds use the irregular HUNDREDS array (already has "dvě stě" etc.)
|
|
104
|
+
if (hundreds > 0) {
|
|
105
|
+
parts.push(HUNDREDS[hundreds])
|
|
50
106
|
}
|
|
51
107
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
108
|
+
// Tens and ones use masculine form
|
|
109
|
+
if (tens === 1) {
|
|
110
|
+
parts.push(TEENS[ones])
|
|
111
|
+
} else if (tens >= 2) {
|
|
112
|
+
parts.push(TENS[tens])
|
|
113
|
+
if (ones > 0) {
|
|
114
|
+
parts.push(ONES[ones]) // masculine
|
|
115
|
+
}
|
|
116
|
+
} else if (ones > 0) {
|
|
117
|
+
parts.push(ONES[ones]) // masculine
|
|
61
118
|
}
|
|
62
119
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
120
|
+
return parts.join(' ')
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Precompute all 1000 segment words (0-999) - masculine form
|
|
124
|
+
const SEGMENTS = new Array(1000)
|
|
125
|
+
for (let i = 0; i < 1000; i++) {
|
|
126
|
+
SEGMENTS[i] = buildSegment(i)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Precompute all 1000 segment words with hundreds (irregular hundreds forms)
|
|
130
|
+
const SEGMENTS_WITH_HUNDREDS = new Array(1000)
|
|
131
|
+
for (let i = 0; i < 1000; i++) {
|
|
132
|
+
SEGMENTS_WITH_HUNDREDS[i] = buildSegmentWithHundreds(i)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ============================================================================
|
|
136
|
+
// Helper Functions
|
|
137
|
+
// ============================================================================
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Czech pluralization: 1 = singular, 2-4 = few, else = many.
|
|
141
|
+
* Teens (11-19) always use "many" form.
|
|
142
|
+
*
|
|
143
|
+
* @param {bigint} n - The number
|
|
144
|
+
* @param {string[]} forms - [singular, few, many]
|
|
145
|
+
* @returns {string} The appropriate form
|
|
146
|
+
*/
|
|
147
|
+
function pluralize (n, forms) {
|
|
148
|
+
if (n === 1n) return forms[0]
|
|
149
|
+
|
|
150
|
+
const lastDigit = n % 10n
|
|
151
|
+
const lastTwoDigits = n % 100n
|
|
152
|
+
|
|
153
|
+
// 2-4, but not 12-14 (teens use "many")
|
|
154
|
+
if (lastDigit >= 2n && lastDigit <= 4n && (lastTwoDigits < 10n || lastTwoDigits > 20n)) {
|
|
155
|
+
return forms[1]
|
|
73
156
|
}
|
|
74
157
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
158
|
+
return forms[2]
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Gets the decimal separator word based on integer part.
|
|
163
|
+
* celá (0-1), celé (2-4), celých (5+)
|
|
164
|
+
*/
|
|
165
|
+
function getDecimalSeparator (integerPart) {
|
|
166
|
+
if (integerPart === 0n || integerPart === 1n) {
|
|
167
|
+
return 'celá'
|
|
168
|
+
} else if (integerPart >= 2n && integerPart <= 4n) {
|
|
169
|
+
return 'celé'
|
|
170
|
+
} else {
|
|
171
|
+
return 'celých'
|
|
86
172
|
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// ============================================================================
|
|
176
|
+
// Conversion Functions
|
|
177
|
+
// ============================================================================
|
|
87
178
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
179
|
+
/**
|
|
180
|
+
* Converts a non-negative integer to Czech words.
|
|
181
|
+
*
|
|
182
|
+
* @param {bigint} n - Non-negative integer to convert
|
|
183
|
+
* @returns {string} Czech words
|
|
184
|
+
*/
|
|
185
|
+
function integerToWords (n) {
|
|
186
|
+
if (n === 0n) return ZERO
|
|
187
|
+
|
|
188
|
+
// Fast path: numbers < 1000 (direct lookup)
|
|
189
|
+
if (n < 1000n) {
|
|
190
|
+
return SEGMENTS[Number(n)]
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Fast path: numbers < 1,000,000 (thousands)
|
|
194
|
+
if (n < 1_000_000n) {
|
|
195
|
+
const thousands = n / 1000n
|
|
196
|
+
const remainder = Number(n % 1000n)
|
|
197
|
+
|
|
198
|
+
const scaleWord = pluralize(thousands, PLURAL_FORMS[1])
|
|
199
|
+
|
|
200
|
+
let result
|
|
201
|
+
if (thousands === 1n) {
|
|
202
|
+
// Omit "one" before tisíc
|
|
203
|
+
result = scaleWord
|
|
107
204
|
} else {
|
|
108
|
-
|
|
205
|
+
result = SEGMENTS[Number(thousands)] + ' ' + scaleWord
|
|
109
206
|
}
|
|
110
|
-
}
|
|
111
207
|
|
|
112
|
-
|
|
113
|
-
|
|
208
|
+
if (remainder > 0) {
|
|
209
|
+
// Use form with irregular hundreds (for "dvě stě" etc.)
|
|
210
|
+
result += ' ' + SEGMENTS_WITH_HUNDREDS[remainder]
|
|
211
|
+
}
|
|
114
212
|
|
|
115
|
-
|
|
116
|
-
delete this.decimalSeparatorWord
|
|
213
|
+
return result
|
|
117
214
|
}
|
|
118
215
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
216
|
+
// For numbers >= 1,000,000, use scale decomposition
|
|
217
|
+
return buildLargeNumberWords(n)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Builds words for numbers >= 1,000,000.
|
|
222
|
+
* Uses BigInt division for faster segment extraction.
|
|
223
|
+
*
|
|
224
|
+
* @param {bigint} n - Number >= 1,000,000
|
|
225
|
+
* @returns {string} Czech words
|
|
226
|
+
*/
|
|
227
|
+
function buildLargeNumberWords (n) {
|
|
228
|
+
// Extract segments using BigInt division (faster than string slicing)
|
|
229
|
+
// Segments stored least-significant first (index 0 = ones, 1 = thousands, etc.)
|
|
230
|
+
const segmentValues = []
|
|
231
|
+
let temp = n
|
|
232
|
+
while (temp > 0n) {
|
|
233
|
+
segmentValues.push(temp % 1000n)
|
|
234
|
+
temp = temp / 1000n
|
|
125
235
|
}
|
|
126
236
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
237
|
+
// Build result string directly
|
|
238
|
+
let result = ''
|
|
239
|
+
|
|
240
|
+
for (let i = segmentValues.length - 1; i >= 0; i--) {
|
|
241
|
+
const segment = segmentValues[i]
|
|
242
|
+
if (segment === 0n) continue
|
|
132
243
|
|
|
133
|
-
|
|
134
|
-
const lastDigit = n % 10n
|
|
135
|
-
const lastTwoDigits = n % 100n
|
|
244
|
+
if (result) result += ' '
|
|
136
245
|
|
|
137
|
-
if (
|
|
138
|
-
|
|
246
|
+
if (i === 0) {
|
|
247
|
+
// Units segment (no scale word) - use form with irregular hundreds
|
|
248
|
+
result += SEGMENTS_WITH_HUNDREDS[Number(segment)]
|
|
249
|
+
} else {
|
|
250
|
+
// Scale word needed
|
|
251
|
+
const forms = PLURAL_FORMS[i]
|
|
252
|
+
if (forms) {
|
|
253
|
+
const scaleWord = pluralize(segment, forms)
|
|
254
|
+
|
|
255
|
+
if (segment === 1n) {
|
|
256
|
+
// Omit "one" before scale words
|
|
257
|
+
result += scaleWord
|
|
258
|
+
} else {
|
|
259
|
+
// Use masculine form for multiplier before scale words
|
|
260
|
+
result += SEGMENTS[Number(segment)] + ' ' + scaleWord
|
|
261
|
+
}
|
|
262
|
+
} else {
|
|
263
|
+
// Fallback for very large scales without defined forms
|
|
264
|
+
result += SEGMENTS[Number(segment)]
|
|
265
|
+
}
|
|
139
266
|
}
|
|
267
|
+
}
|
|
140
268
|
|
|
141
|
-
|
|
269
|
+
return result
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Converts decimal digits to Czech words.
|
|
274
|
+
*
|
|
275
|
+
* @param {string} decimalPart - Decimal digits (without the point)
|
|
276
|
+
* @returns {string} Czech words for decimal part
|
|
277
|
+
*/
|
|
278
|
+
function decimalPartToWords (decimalPart) {
|
|
279
|
+
let result = ''
|
|
280
|
+
|
|
281
|
+
// Handle leading zeros
|
|
282
|
+
let i = 0
|
|
283
|
+
while (i < decimalPart.length && decimalPart[i] === '0') {
|
|
284
|
+
if (result) result += ' '
|
|
285
|
+
result += ZERO
|
|
286
|
+
i++
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Convert remainder as a single number
|
|
290
|
+
const remainder = decimalPart.slice(i)
|
|
291
|
+
if (remainder) {
|
|
292
|
+
if (result) result += ' '
|
|
293
|
+
result += integerToWords(BigInt(remainder))
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return result
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Converts a numeric value to Czech words.
|
|
301
|
+
*
|
|
302
|
+
* This is the main public API. It accepts any valid numeric input
|
|
303
|
+
* (number, string, or bigint) and handles parsing internally.
|
|
304
|
+
*
|
|
305
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
306
|
+
* @returns {string} The number in Czech words
|
|
307
|
+
* @throws {TypeError} If value is not a valid numeric type
|
|
308
|
+
* @throws {Error} If value is not a valid number format
|
|
309
|
+
*
|
|
310
|
+
* @example
|
|
311
|
+
* toWords(21) // 'dvacet jedna'
|
|
312
|
+
* toWords(1000) // 'tisíc'
|
|
313
|
+
* toWords(2000) // 'dva tisíce'
|
|
314
|
+
* toWords(5000) // 'pět tisíc'
|
|
315
|
+
*/
|
|
316
|
+
function toWords (value) {
|
|
317
|
+
const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
|
|
318
|
+
|
|
319
|
+
let result = ''
|
|
320
|
+
|
|
321
|
+
if (isNegative) {
|
|
322
|
+
result = NEGATIVE + ' '
|
|
142
323
|
}
|
|
324
|
+
|
|
325
|
+
result += integerToWords(integerPart)
|
|
326
|
+
|
|
327
|
+
if (decimalPart) {
|
|
328
|
+
const separator = getDecimalSeparator(integerPart)
|
|
329
|
+
result += ' ' + separator + ' ' + decimalPartToWords(decimalPart)
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return result
|
|
143
333
|
}
|
|
334
|
+
|
|
335
|
+
// ============================================================================
|
|
336
|
+
// Public API
|
|
337
|
+
// ============================================================================
|
|
338
|
+
|
|
339
|
+
export { toWords }
|
package/lib/languages/da.d.ts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Danish
|
|
2
|
+
* Converts a numeric value to Danish words.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
5
|
+
* @returns {string} The number in Danish words
|
|
6
|
+
* @throws {TypeError} If value is not a valid numeric type
|
|
7
|
+
* @throws {Error} If value is not a valid number format
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* toWords(21) // 'enogtyve'
|
|
11
|
+
* toWords(1000) // 'ettusind'
|
|
12
|
+
* toWords(1000000) // 'en millioner'
|
|
8
13
|
*/
|
|
9
|
-
export
|
|
10
|
-
constructor(options?: {});
|
|
11
|
-
scaleWords: (string | bigint)[][];
|
|
12
|
-
/** Combines two word-sets with Danish vigesimal and reversal rules. */
|
|
13
|
-
combineWordSets(preceding: any, following: any): any;
|
|
14
|
-
}
|
|
15
|
-
import { GreedyScaleLanguage } from '../classes/greedy-scale-language.js';
|
|
14
|
+
export function toWords(value: number | string | bigint): string;
|