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/fil.js
CHANGED
|
@@ -1,121 +1,222 @@
|
|
|
1
|
-
import { GreedyScaleLanguage } from '../classes/greedy-scale-language.js'
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
|
-
* Filipino language converter
|
|
2
|
+
* Filipino language converter - Functional Implementation
|
|
3
|
+
*
|
|
4
|
+
* Self-contained converter with precomputed lookup tables.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* - "ng"
|
|
8
|
-
* -
|
|
9
|
-
* - Special
|
|
6
|
+
* Key features:
|
|
7
|
+
* - Linker "ng" after vowels: "isang daang" (100)
|
|
8
|
+
* - Linker " na " after consonants: "siyam na daang" (900)
|
|
9
|
+
* - Special tens with linker: "limampung anim" (56)
|
|
10
|
+
* - Per-digit decimal reading
|
|
10
11
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
[11n, 'labinisa'],
|
|
44
|
-
[10n, 'sampu'],
|
|
45
|
-
|
|
46
|
-
// Ones
|
|
47
|
-
[9n, 'siyam'],
|
|
48
|
-
[8n, 'walo'],
|
|
49
|
-
[7n, 'pito'],
|
|
50
|
-
[6n, 'anim'],
|
|
51
|
-
[5n, 'lima'],
|
|
52
|
-
[4n, 'apat'],
|
|
53
|
-
[3n, 'tatlo'],
|
|
54
|
-
[2n, 'dalawa'],
|
|
55
|
-
[1n, 'isa'],
|
|
56
|
-
[0n, 'zero']
|
|
57
|
-
]
|
|
58
|
-
|
|
59
|
-
/** Converts integer part with explicit zero handling. */
|
|
60
|
-
integerToWords (integerPart) {
|
|
61
|
-
// Handle zero explicitly
|
|
62
|
-
if (integerPart === 0n) {
|
|
63
|
-
return this.zeroWord
|
|
64
|
-
}
|
|
65
|
-
return super.integerToWords(integerPart)
|
|
12
|
+
|
|
13
|
+
import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
14
|
+
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// Vocabulary
|
|
17
|
+
// ============================================================================
|
|
18
|
+
|
|
19
|
+
const ONES = ['', 'isa', 'dalawa', 'tatlo', 'apat', 'lima', 'anim', 'pito', 'walo', 'siyam']
|
|
20
|
+
const TEENS = ['sampu', 'labinisa', 'labindalawa', 'labintatlo', 'labinapat', 'labinlima', 'labinanum', 'labimpito', 'labingwalo', 'labinsiyam']
|
|
21
|
+
const TENS = ['', '', 'dalawampu', 'tatlumpu', 'apatnapu', 'limampu', 'animnapu', 'pitumpu', 'walumpu', 'siyamnapu']
|
|
22
|
+
|
|
23
|
+
// Scale words include linker (end with "ng")
|
|
24
|
+
const HUNDRED = 'daang'
|
|
25
|
+
const THOUSAND = 'libong'
|
|
26
|
+
|
|
27
|
+
const ZERO = 'zero'
|
|
28
|
+
const NEGATIVE = 'negatibo'
|
|
29
|
+
const DECIMAL_SEP = 'punto'
|
|
30
|
+
|
|
31
|
+
// Short scale with linker
|
|
32
|
+
const SCALE_WORDS = ['', THOUSAND, 'milyong', 'bilyong', 'trilyong']
|
|
33
|
+
|
|
34
|
+
// ============================================================================
|
|
35
|
+
// Helper Functions
|
|
36
|
+
// ============================================================================
|
|
37
|
+
|
|
38
|
+
const VOWELS = ['a', 'e', 'i', 'o', 'u']
|
|
39
|
+
|
|
40
|
+
function addLinker (word) {
|
|
41
|
+
const lastChar = word[word.length - 1]
|
|
42
|
+
if (VOWELS.includes(lastChar)) {
|
|
43
|
+
return word + 'ng'
|
|
66
44
|
}
|
|
45
|
+
return word + ' na'
|
|
46
|
+
}
|
|
67
47
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const followingWord = Object.keys(following)[0]
|
|
72
|
-
const precedingValue = Object.values(preceding)[0]
|
|
73
|
-
const followingValue = Object.values(following)[0]
|
|
48
|
+
// ============================================================================
|
|
49
|
+
// Precomputed Lookup Table
|
|
50
|
+
// ============================================================================
|
|
74
51
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return following
|
|
78
|
-
}
|
|
79
|
-
if (followingValue === 0n) {
|
|
80
|
-
return preceding
|
|
81
|
-
}
|
|
52
|
+
function buildSegment (n) {
|
|
53
|
+
if (n === 0) return ''
|
|
82
54
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
55
|
+
const ones = n % 10
|
|
56
|
+
const tensDigit = Math.floor(n / 10) % 10
|
|
57
|
+
const hundredsDigit = Math.floor(n / 100)
|
|
58
|
+
|
|
59
|
+
const parts = []
|
|
87
60
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
61
|
+
// Hundreds: "isang daan", "dalawang daan", "siyam na daan"
|
|
62
|
+
if (hundredsDigit > 0) {
|
|
63
|
+
const hundredPrefix = addLinker(ONES[hundredsDigit])
|
|
64
|
+
parts.push(hundredPrefix + ' ' + HUNDRED)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Tens and ones
|
|
68
|
+
const tensOnes = n % 100
|
|
69
|
+
|
|
70
|
+
if (tensOnes === 0) {
|
|
71
|
+
// Just hundreds
|
|
72
|
+
} else if (tensOnes < 10) {
|
|
73
|
+
// Single digit
|
|
74
|
+
parts.push(ONES[ones])
|
|
75
|
+
} else if (tensOnes < 20) {
|
|
76
|
+
// Teens (10-19)
|
|
77
|
+
parts.push(TEENS[ones])
|
|
78
|
+
} else if (ones === 0) {
|
|
79
|
+
// Even tens (20, 30, 40, etc.)
|
|
80
|
+
parts.push(TENS[tensDigit])
|
|
81
|
+
} else {
|
|
82
|
+
// Tens + ones
|
|
83
|
+
// limampu (50) gets special linker: "limampung anim" (56)
|
|
84
|
+
if (tensDigit === 5) {
|
|
85
|
+
parts.push(TENS[tensDigit] + 'ng ' + ONES[ones])
|
|
86
|
+
} else {
|
|
87
|
+
parts.push(TENS[tensDigit] + ' ' + ONES[ones])
|
|
103
88
|
}
|
|
89
|
+
}
|
|
104
90
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
91
|
+
return parts.join(' ')
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const SEGMENTS = new Array(1000)
|
|
95
|
+
for (let i = 0; i < 1000; i++) {
|
|
96
|
+
SEGMENTS[i] = buildSegment(i)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Builds segment with linker added to last word (for use before scale words).
|
|
101
|
+
*/
|
|
102
|
+
function buildSegmentWithLinker (n) {
|
|
103
|
+
const segmentWord = SEGMENTS[n]
|
|
104
|
+
if (!segmentWord) return ''
|
|
105
|
+
|
|
106
|
+
// Find the last space to get the last word
|
|
107
|
+
const lastSpaceIdx = segmentWord.lastIndexOf(' ')
|
|
108
|
+
if (lastSpaceIdx === -1) {
|
|
109
|
+
// Single word
|
|
110
|
+
const lastChar = segmentWord[segmentWord.length - 1]
|
|
111
|
+
if (lastChar === 'g' && segmentWord.endsWith('ng')) {
|
|
112
|
+
return segmentWord // Already has linker
|
|
114
113
|
}
|
|
114
|
+
return addLinker(segmentWord)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Multi-word: add linker to last word
|
|
118
|
+
const prefix = segmentWord.slice(0, lastSpaceIdx + 1)
|
|
119
|
+
const lastWord = segmentWord.slice(lastSpaceIdx + 1)
|
|
115
120
|
|
|
116
|
-
|
|
117
|
-
return
|
|
118
|
-
|
|
121
|
+
if (lastWord.endsWith('ng')) {
|
|
122
|
+
return segmentWord // Already has linker
|
|
123
|
+
}
|
|
124
|
+
return prefix + addLinker(lastWord)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Precompute segments with linker for scale word usage
|
|
128
|
+
const SEGMENTS_WITH_LINKER = new Array(1000)
|
|
129
|
+
for (let i = 0; i < 1000; i++) {
|
|
130
|
+
SEGMENTS_WITH_LINKER[i] = buildSegmentWithLinker(i)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ============================================================================
|
|
134
|
+
// Conversion Functions
|
|
135
|
+
// ============================================================================
|
|
136
|
+
|
|
137
|
+
function integerToWords (n) {
|
|
138
|
+
if (n === 0n) return ZERO
|
|
139
|
+
|
|
140
|
+
if (n < 1000n) {
|
|
141
|
+
return SEGMENTS[Number(n)]
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return buildLargeNumberWords(n)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Builds words for large numbers using BigInt division.
|
|
149
|
+
* @param {bigint} n - Number >= 1000
|
|
150
|
+
* @returns {string} Filipino words
|
|
151
|
+
*/
|
|
152
|
+
function buildLargeNumberWords (n) {
|
|
153
|
+
// Extract segments using BigInt division (faster than string slicing)
|
|
154
|
+
const segmentValues = []
|
|
155
|
+
let temp = n
|
|
156
|
+
while (temp > 0n) {
|
|
157
|
+
segmentValues.push(Number(temp % 1000n))
|
|
158
|
+
temp = temp / 1000n
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Build result string directly
|
|
162
|
+
let result = ''
|
|
163
|
+
|
|
164
|
+
for (let i = segmentValues.length - 1; i >= 0; i--) {
|
|
165
|
+
const segment = segmentValues[i]
|
|
166
|
+
if (segment === 0) continue
|
|
167
|
+
|
|
168
|
+
const scaleWord = SCALE_WORDS[i] || ''
|
|
169
|
+
|
|
170
|
+
if (result) result += ' '
|
|
171
|
+
|
|
172
|
+
if (i === 0) {
|
|
173
|
+
result += SEGMENTS[segment]
|
|
174
|
+
} else {
|
|
175
|
+
// Add linker to segment before scale word
|
|
176
|
+
const segmentWord = SEGMENTS_WITH_LINKER[segment]
|
|
177
|
+
result += segmentWord + ' ' + scaleWord
|
|
119
178
|
}
|
|
120
179
|
}
|
|
180
|
+
|
|
181
|
+
return result
|
|
121
182
|
}
|
|
183
|
+
|
|
184
|
+
function decimalPartToWords (decimalPart) {
|
|
185
|
+
// Per-digit decimal reading
|
|
186
|
+
const digits = []
|
|
187
|
+
for (const char of decimalPart) {
|
|
188
|
+
const d = parseInt(char, 10)
|
|
189
|
+
digits.push(d === 0 ? ZERO : ONES[d])
|
|
190
|
+
}
|
|
191
|
+
return digits.join(' ')
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Converts a numeric value to Filipino words.
|
|
196
|
+
*
|
|
197
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
198
|
+
* @returns {string} The number in Filipino words
|
|
199
|
+
*/
|
|
200
|
+
function toWords (value) {
|
|
201
|
+
const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
|
|
202
|
+
|
|
203
|
+
let result = ''
|
|
204
|
+
|
|
205
|
+
if (isNegative) {
|
|
206
|
+
result = NEGATIVE + ' '
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
result += integerToWords(integerPart)
|
|
210
|
+
|
|
211
|
+
if (decimalPart) {
|
|
212
|
+
result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return result
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// ============================================================================
|
|
219
|
+
// Exports
|
|
220
|
+
// ============================================================================
|
|
221
|
+
|
|
222
|
+
export { toWords }
|
package/lib/languages/fr-BE.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Converts a numeric value to Belgian French words.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
5
|
+
* @param {Object} [options] - Optional configuration
|
|
6
|
+
* @param {boolean} [options.withHyphenSeparator=false] - Use hyphens between words
|
|
7
|
+
* @returns {string} The number in Belgian French words
|
|
8
8
|
*/
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
export function toWords(value: number | string | bigint, options?: {
|
|
10
|
+
withHyphenSeparator?: boolean | undefined;
|
|
11
|
+
}): string;
|
package/lib/languages/fr-BE.js
CHANGED
|
@@ -1,25 +1,300 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* French (Belgium) language converter - Functional Implementation
|
|
3
|
+
*
|
|
4
|
+
* Self-contained converter with precomputed lookup tables.
|
|
5
|
+
*
|
|
6
|
+
* Belgian French differences from standard French:
|
|
7
|
+
* - septante (70) instead of soixante-dix
|
|
8
|
+
* - nonante (90) instead of quatre-vingt-dix
|
|
9
|
+
* - Keeps quatre-vingts (80) like standard French
|
|
10
|
+
* - Uses "septante et un" (71), "nonante et un" (91)
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
14
|
+
import { validateOptions } from '../utils/validate-options.js'
|
|
15
|
+
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Vocabulary
|
|
18
|
+
// ============================================================================
|
|
19
|
+
|
|
20
|
+
const ONES = ['', 'un', 'deux', 'trois', 'quatre', 'cinq', 'six', 'sept', 'huit', 'neuf']
|
|
21
|
+
const TEENS = ['dix', 'onze', 'douze', 'treize', 'quatorze', 'quinze', 'seize', 'dix-sept', 'dix-huit', 'dix-neuf']
|
|
22
|
+
const TENS = ['', '', 'vingt', 'trente', 'quarante', 'cinquante', 'soixante', 'septante', 'quatre-vingt', 'nonante']
|
|
23
|
+
|
|
24
|
+
// Scale words (long scale with -ard forms)
|
|
25
|
+
const SCALES = ['million', 'billion', 'trillion', 'quadrillion']
|
|
26
|
+
const SCALES_ARD = ['milliard', 'billiard', 'trilliard', 'quadrilliard']
|
|
27
|
+
|
|
28
|
+
const THOUSAND = 'mille'
|
|
29
|
+
const HUNDRED = 'cent'
|
|
30
|
+
const ZERO = 'zéro'
|
|
31
|
+
const NEGATIVE = 'moins'
|
|
32
|
+
const DECIMAL_SEP = 'virgule'
|
|
33
|
+
|
|
34
|
+
// ============================================================================
|
|
35
|
+
// Precomputed Lookup Tables
|
|
36
|
+
// ============================================================================
|
|
37
|
+
|
|
38
|
+
function buildSegment (n) {
|
|
39
|
+
if (n === 0) return { word: '', endsWithCents: false, endsWithVingts: false }
|
|
40
|
+
|
|
41
|
+
const tensOnes = n % 100
|
|
42
|
+
const hundreds = Math.floor(n / 100)
|
|
43
|
+
|
|
44
|
+
const parts = []
|
|
45
|
+
let endsWithCents = false
|
|
46
|
+
let endsWithVingts = false
|
|
47
|
+
|
|
48
|
+
// Hundreds
|
|
49
|
+
if (hundreds > 0) {
|
|
50
|
+
if (hundreds === 1) {
|
|
51
|
+
parts.push(HUNDRED)
|
|
52
|
+
} else {
|
|
53
|
+
if (tensOnes === 0) {
|
|
54
|
+
parts.push(ONES[hundreds] + ' ' + HUNDRED + 's')
|
|
55
|
+
endsWithCents = true
|
|
56
|
+
} else {
|
|
57
|
+
parts.push(ONES[hundreds] + ' ' + HUNDRED)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Tens and ones - Belgian pattern
|
|
63
|
+
if (tensOnes === 0) {
|
|
64
|
+
// Just hundreds
|
|
65
|
+
} else if (tensOnes < 10) {
|
|
66
|
+
parts.push(ONES[tensOnes])
|
|
67
|
+
} else if (tensOnes < 17) {
|
|
68
|
+
parts.push(TEENS[tensOnes - 10])
|
|
69
|
+
} else if (tensOnes < 20) {
|
|
70
|
+
parts.push(TEENS[tensOnes - 10])
|
|
71
|
+
} else if (tensOnes < 70) {
|
|
72
|
+
// 20-69: standard pattern
|
|
73
|
+
const t = Math.floor(tensOnes / 10)
|
|
74
|
+
const o = tensOnes % 10
|
|
75
|
+
if (o === 0) {
|
|
76
|
+
parts.push(TENS[t])
|
|
77
|
+
} else if (o === 1) {
|
|
78
|
+
parts.push(TENS[t] + ' et ' + ONES[1])
|
|
79
|
+
} else {
|
|
80
|
+
parts.push(TENS[t] + '-' + ONES[o])
|
|
81
|
+
}
|
|
82
|
+
} else if (tensOnes < 80) {
|
|
83
|
+
// 70-79: septante pattern (Belgian)
|
|
84
|
+
const o = tensOnes % 10
|
|
85
|
+
if (o === 0) {
|
|
86
|
+
parts.push('septante')
|
|
87
|
+
} else if (o === 1) {
|
|
88
|
+
parts.push('septante et ' + ONES[1])
|
|
89
|
+
} else {
|
|
90
|
+
parts.push('septante-' + ONES[o])
|
|
91
|
+
}
|
|
92
|
+
} else if (tensOnes === 80) {
|
|
93
|
+
// 80: quatre-vingts (same as standard)
|
|
94
|
+
parts.push('quatre-vingts')
|
|
95
|
+
endsWithVingts = true
|
|
96
|
+
} else if (tensOnes < 90) {
|
|
97
|
+
// 81-89: quatre-vingt-X (same as standard)
|
|
98
|
+
const remainder = tensOnes - 80
|
|
99
|
+
parts.push('quatre-vingt-' + ONES[remainder])
|
|
100
|
+
} else {
|
|
101
|
+
// 90-99: nonante pattern (Belgian)
|
|
102
|
+
const o = tensOnes % 10
|
|
103
|
+
if (o === 0) {
|
|
104
|
+
parts.push('nonante')
|
|
105
|
+
} else if (o === 1) {
|
|
106
|
+
parts.push('nonante et ' + ONES[1])
|
|
107
|
+
} else {
|
|
108
|
+
parts.push('nonante-' + ONES[o])
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return { word: parts.join(' '), endsWithCents, endsWithVingts }
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Precompute all 1000 segment words
|
|
116
|
+
const SEGMENTS = new Array(1000)
|
|
117
|
+
const SEGMENTS_ENDS_CENTS = new Array(1000)
|
|
118
|
+
const SEGMENTS_ENDS_VINGTS = new Array(1000)
|
|
119
|
+
|
|
120
|
+
for (let i = 0; i < 1000; i++) {
|
|
121
|
+
const result = buildSegment(i)
|
|
122
|
+
SEGMENTS[i] = result.word
|
|
123
|
+
SEGMENTS_ENDS_CENTS[i] = result.endsWithCents
|
|
124
|
+
SEGMENTS_ENDS_VINGTS[i] = result.endsWithVingts
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ============================================================================
|
|
128
|
+
// Helper Functions
|
|
129
|
+
// ============================================================================
|
|
130
|
+
|
|
131
|
+
function getScaleWord (scaleIndex, segment) {
|
|
132
|
+
if (scaleIndex === 1) return THOUSAND
|
|
133
|
+
|
|
134
|
+
if (scaleIndex % 2 === 0) {
|
|
135
|
+
const arrayIndex = (scaleIndex / 2) - 1
|
|
136
|
+
const baseWord = SCALES[arrayIndex]
|
|
137
|
+
if (!baseWord) return ''
|
|
138
|
+
return segment > 1n ? baseWord + 's' : baseWord
|
|
139
|
+
} else {
|
|
140
|
+
const arrayIndex = ((scaleIndex - 1) / 2) - 1
|
|
141
|
+
const ardWord = SCALES_ARD[arrayIndex]
|
|
142
|
+
if (!ardWord) return THOUSAND
|
|
143
|
+
return segment > 1n ? ardWord + 's' : ardWord
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ============================================================================
|
|
148
|
+
// Conversion Functions
|
|
149
|
+
// ============================================================================
|
|
150
|
+
|
|
151
|
+
function integerToWords (n, withHyphen = false) {
|
|
152
|
+
if (n === 0n) return ZERO
|
|
153
|
+
|
|
154
|
+
if (n < 1000n) {
|
|
155
|
+
const word = SEGMENTS[Number(n)]
|
|
156
|
+
return withHyphen ? word.replace(/ /g, '-') : word
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (n < 1_000_000n) {
|
|
160
|
+
const thousands = Number(n / 1000n)
|
|
161
|
+
const remainder = Number(n % 1000n)
|
|
162
|
+
|
|
163
|
+
let result
|
|
164
|
+
if (thousands === 1) {
|
|
165
|
+
result = THOUSAND
|
|
166
|
+
} else {
|
|
167
|
+
let thousandsWord = SEGMENTS[thousands]
|
|
168
|
+
if (SEGMENTS_ENDS_CENTS[thousands] || SEGMENTS_ENDS_VINGTS[thousands]) {
|
|
169
|
+
thousandsWord = thousandsWord.slice(0, -1)
|
|
170
|
+
}
|
|
171
|
+
result = thousandsWord + (withHyphen ? '-' : ' ') + THOUSAND
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (remainder > 0) {
|
|
175
|
+
result += (withHyphen ? '-' : ' ') + SEGMENTS[remainder]
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (withHyphen) {
|
|
179
|
+
result = result.replace(/ /g, '-')
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return result
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return buildLargeNumberWords(n, withHyphen)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function buildLargeNumberWords (n, withHyphen) {
|
|
189
|
+
const numStr = n.toString()
|
|
190
|
+
const len = numStr.length
|
|
191
|
+
|
|
192
|
+
const segments = []
|
|
193
|
+
const segmentSize = 3
|
|
194
|
+
|
|
195
|
+
const remainderLen = len % segmentSize
|
|
196
|
+
let pos = 0
|
|
197
|
+
if (remainderLen > 0) {
|
|
198
|
+
segments.push(Number(numStr.slice(0, remainderLen)))
|
|
199
|
+
pos = remainderLen
|
|
200
|
+
}
|
|
201
|
+
while (pos < len) {
|
|
202
|
+
segments.push(Number(numStr.slice(pos, pos + segmentSize)))
|
|
203
|
+
pos += segmentSize
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const parts = []
|
|
207
|
+
let scaleIndex = segments.length - 1
|
|
208
|
+
|
|
209
|
+
for (let i = 0; i < segments.length; i++) {
|
|
210
|
+
const segment = segments[i]
|
|
211
|
+
|
|
212
|
+
if (segment !== 0) {
|
|
213
|
+
const scaleWord = scaleIndex > 0 ? getScaleWord(scaleIndex, BigInt(segment)) : ''
|
|
214
|
+
|
|
215
|
+
if (scaleIndex === 0) {
|
|
216
|
+
parts.push(SEGMENTS[segment])
|
|
217
|
+
} else if (scaleIndex === 1) {
|
|
218
|
+
if (segment === 1) {
|
|
219
|
+
parts.push(THOUSAND)
|
|
220
|
+
} else {
|
|
221
|
+
let segWords = SEGMENTS[segment]
|
|
222
|
+
if (SEGMENTS_ENDS_CENTS[segment] || SEGMENTS_ENDS_VINGTS[segment]) {
|
|
223
|
+
segWords = segWords.slice(0, -1)
|
|
224
|
+
}
|
|
225
|
+
parts.push(segWords)
|
|
226
|
+
parts.push(scaleWord)
|
|
227
|
+
}
|
|
228
|
+
} else {
|
|
229
|
+
parts.push(SEGMENTS[segment])
|
|
230
|
+
parts.push(scaleWord)
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
scaleIndex--
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const sep = withHyphen ? '-' : ' '
|
|
238
|
+
let result = parts.join(sep)
|
|
239
|
+
|
|
240
|
+
if (withHyphen) {
|
|
241
|
+
result = result.replace(/ /g, '-')
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return result
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function decimalPartToWords (decimalPart, withHyphen) {
|
|
248
|
+
let result = ''
|
|
249
|
+
const sep = withHyphen ? '-' : ' '
|
|
250
|
+
|
|
251
|
+
let i = 0
|
|
252
|
+
while (i < decimalPart.length && decimalPart[i] === '0') {
|
|
253
|
+
if (result) result += sep
|
|
254
|
+
result += ZERO
|
|
255
|
+
i++
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const remainder = decimalPart.slice(i)
|
|
259
|
+
if (remainder) {
|
|
260
|
+
if (result) result += sep
|
|
261
|
+
result += integerToWords(BigInt(remainder), withHyphen)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return result
|
|
265
|
+
}
|
|
2
266
|
|
|
3
267
|
/**
|
|
4
|
-
*
|
|
268
|
+
* Converts a numeric value to Belgian French words.
|
|
5
269
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
270
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
271
|
+
* @param {Object} [options] - Optional configuration
|
|
272
|
+
* @param {boolean} [options.withHyphenSeparator=false] - Use hyphens between words
|
|
273
|
+
* @returns {string} The number in Belgian French words
|
|
10
274
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
275
|
+
function toWords (value, options) {
|
|
276
|
+
options = validateOptions(options)
|
|
277
|
+
const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
|
|
278
|
+
const withHyphen = options.withHyphenSeparator || false
|
|
279
|
+
|
|
280
|
+
let result = ''
|
|
281
|
+
const sep = withHyphen ? '-' : ' '
|
|
282
|
+
|
|
283
|
+
if (isNegative) {
|
|
284
|
+
result = NEGATIVE + sep
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
result += integerToWords(integerPart, withHyphen)
|
|
288
|
+
|
|
289
|
+
if (decimalPart) {
|
|
290
|
+
result += sep + DECIMAL_SEP + sep + decimalPartToWords(decimalPart, withHyphen)
|
|
24
291
|
}
|
|
292
|
+
|
|
293
|
+
return result
|
|
25
294
|
}
|
|
295
|
+
|
|
296
|
+
// ============================================================================
|
|
297
|
+
// Exports
|
|
298
|
+
// ============================================================================
|
|
299
|
+
|
|
300
|
+
export { toWords }
|