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/it.js
CHANGED
|
@@ -1,132 +1,377 @@
|
|
|
1
|
-
import { AbstractLanguage } from '../classes/abstract-language.js'
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
|
-
* Italian language converter
|
|
2
|
+
* Italian language converter - Functional Implementation v2
|
|
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 1000 segment values (0-999) at module load.
|
|
8
|
+
* This eliminates all per-call string manipulation for segment conversion.
|
|
5
9
|
*
|
|
6
|
-
*
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
9
|
-
* -
|
|
10
|
+
* Italian-specific rules (handled in precomputation):
|
|
11
|
+
* - Concatenation without spaces within segments ("ventotto" not "venti otto")
|
|
12
|
+
* - Phonetic vowel elision: "venti" + "otto" → "ventotto"
|
|
13
|
+
* - Accent on final "tre" in compounds: "ventitré"
|
|
14
|
+
* - mille/mila alternation for thousands
|
|
15
|
+
* - Scale words: milione/milioni, miliardo/miliardi, etc.
|
|
16
|
+
* - "e" connector before simple final remainder
|
|
10
17
|
*/
|
|
11
|
-
export class Italian extends AbstractLanguage {
|
|
12
|
-
negativeWord = 'meno'
|
|
13
|
-
decimalSeparatorWord = 'virgola'
|
|
14
|
-
zeroWord = 'zero'
|
|
15
18
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
20
|
+
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// Vocabulary (module-level constants)
|
|
23
|
+
// ============================================================================
|
|
24
|
+
|
|
25
|
+
// Base vocabulary for building lookup tables
|
|
26
|
+
const ONES = ['', 'uno', 'due', 'tre', 'quattro', 'cinque', 'sei', 'sette', 'otto', 'nove']
|
|
27
|
+
const TEENS = ['dieci', 'undici', 'dodici', 'tredici', 'quattordici', 'quindici', 'sedici', 'diciassette', 'diciotto', 'diciannove']
|
|
28
|
+
const TENS = ['', '', 'venti', 'trenta', 'quaranta', 'cinquanta', 'sessanta', 'settanta', 'ottanta', 'novanta']
|
|
29
|
+
const HUNDREDS = ['', 'cento', 'duecento', 'trecento', 'quattrocento', 'cinquecento', 'seicento', 'settecento', 'ottocento', 'novecento']
|
|
30
|
+
|
|
31
|
+
const ZERO = 'zero'
|
|
32
|
+
const NEGATIVE = 'meno'
|
|
33
|
+
const DECIMAL_SEP = 'virgola'
|
|
21
34
|
|
|
22
|
-
|
|
35
|
+
// Thousands
|
|
36
|
+
const THOUSAND_SINGULAR = 'mille'
|
|
37
|
+
const THOUSAND_PLURAL_SUFFIX = 'mila'
|
|
23
38
|
|
|
24
|
-
|
|
39
|
+
// Scale word generation
|
|
40
|
+
const SCALE_PREFIXES = ['m', 'b', 'tr', 'quadr', 'quint', 'sest', 'sett', 'ott', 'nov', 'dec']
|
|
25
41
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
42
|
+
// ============================================================================
|
|
43
|
+
// Precomputed Lookup Tables (built once at module load)
|
|
44
|
+
// ============================================================================
|
|
29
45
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Applies Italian phonetic vowel elision rules.
|
|
48
|
+
* Only used during table construction.
|
|
49
|
+
*/
|
|
50
|
+
function applyPhoneticRules (str) {
|
|
51
|
+
return str
|
|
52
|
+
.replace(/io/g, 'o')
|
|
53
|
+
.replace(/ao/g, 'o')
|
|
54
|
+
.replace(/oo/g, 'o')
|
|
55
|
+
.replace(/iu/g, 'u')
|
|
56
|
+
.replace(/au/g, 'u')
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Adds accent to final "tre" in a word.
|
|
61
|
+
* Only used during table construction.
|
|
62
|
+
*/
|
|
63
|
+
function accentuateTre (word) {
|
|
64
|
+
if (word.length > 3 && word.slice(-3) === 'tre') {
|
|
65
|
+
return word.slice(0, -3) + 'tré'
|
|
34
66
|
}
|
|
67
|
+
return word
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Builds the segment word for a number 0-999.
|
|
72
|
+
* Only used during table construction.
|
|
73
|
+
*/
|
|
74
|
+
function buildSegmentWord (n) {
|
|
75
|
+
if (n === 0) return ''
|
|
76
|
+
|
|
77
|
+
const ones = n % 10
|
|
78
|
+
const tens = Math.floor(n / 10) % 10
|
|
79
|
+
const hundreds = Math.floor(n / 100)
|
|
80
|
+
|
|
81
|
+
let result = ''
|
|
35
82
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
83
|
+
// Hundreds
|
|
84
|
+
if (hundreds > 0) {
|
|
85
|
+
result = HUNDREDS[hundreds]
|
|
39
86
|
}
|
|
40
87
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
88
|
+
// Tens and ones
|
|
89
|
+
if (tens === 0 && ones === 0) {
|
|
90
|
+
// Nothing more
|
|
91
|
+
} else if (tens === 1) {
|
|
92
|
+
// Teens: 10-19
|
|
93
|
+
result += TEENS[ones]
|
|
94
|
+
} else if (tens >= 2) {
|
|
95
|
+
// 20-99
|
|
96
|
+
result += TENS[tens]
|
|
97
|
+
if (ones > 0) {
|
|
98
|
+
result += ONES[ones]
|
|
99
|
+
}
|
|
100
|
+
} else if (ones > 0) {
|
|
101
|
+
// 1-9 (tens === 0)
|
|
102
|
+
result += ONES[ones]
|
|
44
103
|
}
|
|
45
104
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
105
|
+
// Apply phonetic rules and accent
|
|
106
|
+
return accentuateTre(applyPhoneticRules(result))
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Builds segment word with "un" for scale context (millions, billions).
|
|
111
|
+
* Only used during table construction.
|
|
112
|
+
*/
|
|
113
|
+
function buildSegmentWordForScale (n) {
|
|
114
|
+
if (n === 0) return ''
|
|
115
|
+
if (n === 1) return 'un' // "un milione" not "uno milione"
|
|
116
|
+
|
|
117
|
+
const ones = n % 10
|
|
118
|
+
const tens = Math.floor(n / 10) % 10
|
|
119
|
+
const hundreds = Math.floor(n / 100)
|
|
120
|
+
|
|
121
|
+
let result = ''
|
|
122
|
+
|
|
123
|
+
if (hundreds > 0) {
|
|
124
|
+
result = HUNDREDS[hundreds]
|
|
53
125
|
}
|
|
54
126
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
127
|
+
if (tens === 0 && ones === 0) {
|
|
128
|
+
// Nothing more
|
|
129
|
+
} else if (tens === 1) {
|
|
130
|
+
result += TEENS[ones]
|
|
131
|
+
} else if (tens >= 2) {
|
|
132
|
+
result += TENS[tens]
|
|
133
|
+
if (ones > 0) {
|
|
134
|
+
result += ONES[ones]
|
|
61
135
|
}
|
|
62
|
-
|
|
63
|
-
|
|
136
|
+
} else if (ones > 0) {
|
|
137
|
+
// 1-9 with tens === 0
|
|
138
|
+
// "un" only for exactly 1, others normal
|
|
139
|
+
result += ONES[ones]
|
|
64
140
|
}
|
|
65
141
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
142
|
+
return accentuateTre(applyPhoneticRules(result))
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Precompute all 1000 segment words (0-999)
|
|
146
|
+
// SEGMENTS[n] gives the Italian word for n within a segment
|
|
147
|
+
const SEGMENTS = new Array(1000)
|
|
148
|
+
for (let i = 0; i < 1000; i++) {
|
|
149
|
+
SEGMENTS[i] = buildSegmentWord(i)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Precompute segment words for scale context (uses "un" for 1)
|
|
153
|
+
const SEGMENTS_SCALE = new Array(1000)
|
|
154
|
+
for (let i = 0; i < 1000; i++) {
|
|
155
|
+
SEGMENTS_SCALE[i] = buildSegmentWordForScale(i)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Precompute thousands words (1-999) + "mila" suffix
|
|
159
|
+
// THOUSANDS[n] gives the word for n thousand (e.g., THOUSANDS[2] = "duemila")
|
|
160
|
+
const THOUSANDS = new Array(1000)
|
|
161
|
+
THOUSANDS[0] = ''
|
|
162
|
+
THOUSANDS[1] = THOUSAND_SINGULAR // "mille"
|
|
163
|
+
for (let i = 2; i < 1000; i++) {
|
|
164
|
+
THOUSANDS[i] = applyPhoneticRules(SEGMENTS[i] + THOUSAND_PLURAL_SUFFIX)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ============================================================================
|
|
168
|
+
// Scale Word Functions
|
|
169
|
+
// ============================================================================
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Gets singular scale word for index.
|
|
173
|
+
* @param {number} scaleIndex - 2=million, 3=billion, etc.
|
|
174
|
+
*/
|
|
175
|
+
function getScaleWordSingular (scaleIndex) {
|
|
176
|
+
if (scaleIndex < 2) return ''
|
|
177
|
+
const prefixIndex = Math.floor((scaleIndex - 2) / 2)
|
|
178
|
+
const isIardo = (scaleIndex - 2) % 2 === 1
|
|
179
|
+
const prefix = SCALE_PREFIXES[prefixIndex]
|
|
180
|
+
if (!prefix) return ''
|
|
181
|
+
return prefix + (isIardo ? 'iliardo' : 'ilione')
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Gets plural scale word for index.
|
|
186
|
+
* @param {number} scaleIndex - 2=million, 3=billion, etc.
|
|
187
|
+
*/
|
|
188
|
+
function getScaleWordPlural (scaleIndex) {
|
|
189
|
+
if (scaleIndex < 2) return ''
|
|
190
|
+
const prefixIndex = Math.floor((scaleIndex - 2) / 2)
|
|
191
|
+
const isIardo = (scaleIndex - 2) % 2 === 1
|
|
192
|
+
const prefix = SCALE_PREFIXES[prefixIndex]
|
|
193
|
+
if (!prefix) return ''
|
|
194
|
+
return prefix + (isIardo ? 'iliardi' : 'ilioni')
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// ============================================================================
|
|
198
|
+
// Conversion Functions
|
|
199
|
+
// ============================================================================
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Converts a non-negative integer to Italian words.
|
|
203
|
+
*
|
|
204
|
+
* @param {bigint} n - Non-negative integer to convert
|
|
205
|
+
* @returns {string} Italian words
|
|
206
|
+
*/
|
|
207
|
+
function integerToWords (n) {
|
|
208
|
+
if (n === 0n) return ZERO
|
|
73
209
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return exponentLength % 6 === 0 ? prefix + 'ilione' : prefix + 'iliardo'
|
|
210
|
+
// Fast path: numbers < 1000 (direct lookup)
|
|
211
|
+
if (n < 1000n) {
|
|
212
|
+
return SEGMENTS[Number(n)]
|
|
78
213
|
}
|
|
79
214
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const
|
|
215
|
+
// Fast path: numbers < 1,000,000 (thousands)
|
|
216
|
+
if (n < 1_000_000n) {
|
|
217
|
+
const thousands = Number(n / 1000n)
|
|
218
|
+
const remainder = Number(n % 1000n)
|
|
83
219
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
preDigits = 3
|
|
220
|
+
if (remainder === 0) {
|
|
221
|
+
return THOUSANDS[thousands]
|
|
87
222
|
}
|
|
88
223
|
|
|
89
|
-
|
|
90
|
-
|
|
224
|
+
// Concatenate thousands + remainder
|
|
225
|
+
return THOUSANDS[thousands] + SEGMENTS[remainder]
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// For numbers >= 1,000,000, use scale decomposition
|
|
229
|
+
return buildLargeNumberWords(n)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Builds words for numbers >= 1,000,000.
|
|
234
|
+
*
|
|
235
|
+
* @param {bigint} n - Number >= 1,000,000
|
|
236
|
+
* @returns {string} Italian words
|
|
237
|
+
*/
|
|
238
|
+
function buildLargeNumberWords (n) {
|
|
239
|
+
const parts = []
|
|
240
|
+
let remaining = n
|
|
241
|
+
|
|
242
|
+
// Find the highest scale
|
|
243
|
+
let maxScale = 2
|
|
244
|
+
let testValue = 1_000_000n
|
|
245
|
+
while (testValue * 1000n <= remaining) {
|
|
246
|
+
testValue *= 1000n
|
|
247
|
+
maxScale++
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Process from highest scale down
|
|
251
|
+
for (let scaleIndex = maxScale; scaleIndex >= 0; scaleIndex--) {
|
|
252
|
+
const divisor = 1000n ** BigInt(scaleIndex)
|
|
253
|
+
const segment = remaining / divisor
|
|
254
|
+
remaining = remaining % divisor
|
|
91
255
|
|
|
92
|
-
|
|
93
|
-
let infix = this.exponentLengthToString(exponent.length)
|
|
256
|
+
if (segment === 0n) continue
|
|
94
257
|
|
|
95
|
-
|
|
96
|
-
|
|
258
|
+
const segNum = Number(segment)
|
|
259
|
+
|
|
260
|
+
if (scaleIndex >= 2) {
|
|
261
|
+
// Millions and above: "segment scaleWord"
|
|
262
|
+
const segmentWords = SEGMENTS_SCALE[segNum]
|
|
263
|
+
const scaleWord = segment === 1n
|
|
264
|
+
? getScaleWordSingular(scaleIndex)
|
|
265
|
+
: getScaleWordPlural(scaleIndex)
|
|
266
|
+
parts.push(segmentWords + ' ' + scaleWord)
|
|
267
|
+
} else if (scaleIndex === 1) {
|
|
268
|
+
// Thousands: use precomputed table
|
|
269
|
+
parts.push(THOUSANDS[segNum])
|
|
97
270
|
} else {
|
|
98
|
-
|
|
99
|
-
|
|
271
|
+
// Units (scaleIndex === 0): just the segment
|
|
272
|
+
parts.push(SEGMENTS[segNum])
|
|
100
273
|
}
|
|
274
|
+
}
|
|
101
275
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
postfix = ''
|
|
105
|
-
} else {
|
|
106
|
-
postfix = this.integerToWords(Math.trunc(exponent.join('')))
|
|
276
|
+
return joinPartsWithConnector(parts)
|
|
277
|
+
}
|
|
107
278
|
|
|
108
|
-
|
|
279
|
+
/**
|
|
280
|
+
* Joins parts with Italian connector rules.
|
|
281
|
+
* Uses "e" before simple (non-compound) final segment.
|
|
282
|
+
*
|
|
283
|
+
* @param {string[]} parts - Parts to join
|
|
284
|
+
* @returns {string} Joined string
|
|
285
|
+
*/
|
|
286
|
+
function joinPartsWithConnector (parts) {
|
|
287
|
+
const len = parts.length
|
|
288
|
+
if (len === 0) return ''
|
|
289
|
+
if (len === 1) return parts[0]
|
|
290
|
+
|
|
291
|
+
// Check if last part is "simple" (no space = no scale word)
|
|
292
|
+
const lastPart = parts[len - 1]
|
|
293
|
+
if (lastPart.indexOf(' ') === -1) {
|
|
294
|
+
// Join all but last with space, then add "e" connector
|
|
295
|
+
let result = parts[0]
|
|
296
|
+
for (let i = 1; i < len - 1; i++) {
|
|
297
|
+
result += ' ' + parts[i]
|
|
109
298
|
}
|
|
299
|
+
return result + ' e ' + lastPart
|
|
300
|
+
}
|
|
110
301
|
|
|
111
|
-
|
|
302
|
+
// Join with spaces
|
|
303
|
+
let result = parts[0]
|
|
304
|
+
for (let i = 1; i < len; i++) {
|
|
305
|
+
result += ' ' + parts[i]
|
|
112
306
|
}
|
|
307
|
+
return result
|
|
308
|
+
}
|
|
113
309
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
310
|
+
/**
|
|
311
|
+
* Converts decimal digits to Italian words.
|
|
312
|
+
*
|
|
313
|
+
* @param {string} decimalPart - Decimal digits (without the point)
|
|
314
|
+
* @returns {string} Italian words for decimal part
|
|
315
|
+
*/
|
|
316
|
+
function decimalPartToWords (decimalPart) {
|
|
317
|
+
let result = ''
|
|
318
|
+
|
|
319
|
+
// Handle leading zeros
|
|
320
|
+
let i = 0
|
|
321
|
+
while (i < decimalPart.length && decimalPart[i] === '0') {
|
|
322
|
+
if (result) result += ' '
|
|
323
|
+
result += ZERO
|
|
324
|
+
i++
|
|
325
|
+
}
|
|
129
326
|
|
|
130
|
-
|
|
327
|
+
// Convert remainder as a single number
|
|
328
|
+
const remainder = decimalPart.slice(i)
|
|
329
|
+
if (remainder) {
|
|
330
|
+
if (result) result += ' '
|
|
331
|
+
result += integerToWords(BigInt(remainder))
|
|
131
332
|
}
|
|
333
|
+
|
|
334
|
+
return result
|
|
132
335
|
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Converts a numeric value to Italian words.
|
|
339
|
+
*
|
|
340
|
+
* This is the main public API. It accepts any valid numeric input
|
|
341
|
+
* (number, string, or bigint) and handles parsing internally.
|
|
342
|
+
*
|
|
343
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
344
|
+
* @returns {string} The number in Italian words
|
|
345
|
+
* @throws {TypeError} If value is not a valid numeric type
|
|
346
|
+
* @throws {Error} If value is not a valid number format
|
|
347
|
+
*
|
|
348
|
+
* @example
|
|
349
|
+
* toWords(28) // 'ventotto'
|
|
350
|
+
* toWords(23) // 'ventitré'
|
|
351
|
+
* toWords(1000) // 'mille'
|
|
352
|
+
* toWords(2000) // 'duemila'
|
|
353
|
+
* toWords(1000000) // 'un milione'
|
|
354
|
+
*/
|
|
355
|
+
function toWords (value) {
|
|
356
|
+
const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
|
|
357
|
+
|
|
358
|
+
let result = ''
|
|
359
|
+
|
|
360
|
+
if (isNegative) {
|
|
361
|
+
result = NEGATIVE + ' '
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
result += integerToWords(integerPart)
|
|
365
|
+
|
|
366
|
+
if (decimalPart) {
|
|
367
|
+
result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart)
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return result
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// ============================================================================
|
|
374
|
+
// Public API
|
|
375
|
+
// ============================================================================
|
|
376
|
+
|
|
377
|
+
export { toWords }
|
package/lib/languages/ja.d.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Japanese
|
|
2
|
+
* Converts a numeric value to Japanese words.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* This is the main public API. It accepts any valid numeric input
|
|
5
|
+
* (number, string, or bigint) and handles parsing internally.
|
|
6
|
+
*
|
|
7
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
8
|
+
* @returns {string} The number in Japanese kanji words
|
|
9
|
+
* @throws {TypeError} If value is not a valid numeric type
|
|
10
|
+
* @throws {Error} If value is not a valid number format
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* toWords(42) // '四十二'
|
|
14
|
+
* toWords(10000) // '一万'
|
|
15
|
+
* toWords(100000000) // '一億'
|
|
8
16
|
*/
|
|
9
|
-
export
|
|
10
|
-
onesWords: string[];
|
|
11
|
-
scaleWords: string[];
|
|
12
|
-
/** Converts a segment of up to 4 digits to Japanese kanji with 一 omission rules. */
|
|
13
|
-
segmentToWords(num: any): string;
|
|
14
|
-
/** Converts integer part using Japanese 万-based grouping system. */
|
|
15
|
-
integerToWords(integerPart: any): string;
|
|
16
|
-
}
|
|
17
|
-
import { AbstractLanguage } from '../classes/abstract-language.js';
|
|
17
|
+
export function toWords(value: number | string | bigint): string;
|