n2words 2.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +64 -0
- package/README.md +86 -188
- package/dist/languages/am-Latn.js +3 -0
- package/dist/languages/am-Latn.js.map +1 -0
- package/dist/languages/am.js +3 -0
- package/dist/languages/am.js.map +1 -0
- package/dist/languages/ar.js +3 -0
- package/dist/languages/ar.js.map +1 -0
- package/dist/languages/az.js +3 -0
- package/dist/languages/az.js.map +1 -0
- package/dist/languages/bn.js +3 -0
- package/dist/languages/bn.js.map +1 -0
- package/dist/languages/cs.js +3 -0
- package/dist/languages/cs.js.map +1 -0
- package/dist/languages/da.js +3 -0
- package/dist/languages/da.js.map +1 -0
- package/dist/languages/de.js +3 -0
- package/dist/languages/de.js.map +1 -0
- package/dist/languages/el.js +3 -0
- package/dist/languages/el.js.map +1 -0
- package/dist/languages/en.js +3 -0
- package/dist/languages/en.js.map +1 -0
- package/dist/languages/es.js +3 -0
- package/dist/languages/es.js.map +1 -0
- package/dist/languages/fa.js +3 -0
- package/dist/languages/fa.js.map +1 -0
- package/dist/languages/fi.js +3 -0
- package/dist/languages/fi.js.map +1 -0
- package/dist/languages/fil.js +3 -0
- package/dist/languages/fil.js.map +1 -0
- package/dist/languages/fr-BE.js +3 -0
- package/dist/languages/fr-BE.js.map +1 -0
- package/dist/languages/fr.js +3 -0
- package/dist/languages/fr.js.map +1 -0
- package/dist/languages/gu.js +3 -0
- package/dist/languages/gu.js.map +1 -0
- package/dist/languages/ha.js +3 -0
- package/dist/languages/ha.js.map +1 -0
- package/dist/languages/hbo.js +3 -0
- package/dist/languages/hbo.js.map +1 -0
- package/dist/languages/he.js +3 -0
- package/dist/languages/he.js.map +1 -0
- package/dist/languages/hi.js +3 -0
- package/dist/languages/hi.js.map +1 -0
- package/dist/languages/hr.js +3 -0
- package/dist/languages/hr.js.map +1 -0
- package/dist/languages/hu.js +3 -0
- package/dist/languages/hu.js.map +1 -0
- package/dist/languages/id.js +3 -0
- package/dist/languages/id.js.map +1 -0
- package/dist/languages/it.js +3 -0
- package/dist/languages/it.js.map +1 -0
- package/dist/languages/ja.js +3 -0
- package/dist/languages/ja.js.map +1 -0
- package/dist/languages/ka.js +3 -0
- package/dist/languages/ka.js.map +1 -0
- package/dist/languages/kn.js +3 -0
- package/dist/languages/kn.js.map +1 -0
- package/dist/languages/ko.js +3 -0
- package/dist/languages/ko.js.map +1 -0
- package/dist/languages/lt.js +3 -0
- package/dist/languages/lt.js.map +1 -0
- package/dist/languages/lv.js +3 -0
- package/dist/languages/lv.js.map +1 -0
- package/dist/languages/mr.js +3 -0
- package/dist/languages/mr.js.map +1 -0
- package/dist/languages/ms.js +3 -0
- package/dist/languages/ms.js.map +1 -0
- package/dist/languages/nb.js +3 -0
- package/dist/languages/nb.js.map +1 -0
- package/dist/languages/nl.js +3 -0
- package/dist/languages/nl.js.map +1 -0
- package/dist/languages/pa.js +3 -0
- package/dist/languages/pa.js.map +1 -0
- package/dist/languages/pl.js +3 -0
- package/dist/languages/pl.js.map +1 -0
- package/dist/languages/pt.js +3 -0
- package/dist/languages/pt.js.map +1 -0
- package/dist/languages/ro.js +3 -0
- package/dist/languages/ro.js.map +1 -0
- package/dist/languages/ru.js +3 -0
- package/dist/languages/ru.js.map +1 -0
- package/dist/languages/sr-Cyrl.js +3 -0
- package/dist/languages/sr-Cyrl.js.map +1 -0
- package/dist/languages/sr-Latn.js +3 -0
- package/dist/languages/sr-Latn.js.map +1 -0
- package/dist/languages/sv.js +3 -0
- package/dist/languages/sv.js.map +1 -0
- package/dist/languages/sw.js +3 -0
- package/dist/languages/sw.js.map +1 -0
- package/dist/languages/ta.js +3 -0
- package/dist/languages/ta.js.map +1 -0
- package/dist/languages/te.js +3 -0
- package/dist/languages/te.js.map +1 -0
- package/dist/languages/th.js +3 -0
- package/dist/languages/th.js.map +1 -0
- package/dist/languages/tr.js +3 -0
- package/dist/languages/tr.js.map +1 -0
- package/dist/languages/uk.js +3 -0
- package/dist/languages/uk.js.map +1 -0
- package/dist/languages/ur.js +3 -0
- package/dist/languages/ur.js.map +1 -0
- package/dist/languages/vi.js +3 -0
- package/dist/languages/vi.js.map +1 -0
- package/dist/languages/yo.js +3 -0
- package/dist/languages/yo.js.map +1 -0
- package/dist/languages/zh-Hans.js +3 -0
- package/dist/languages/zh-Hans.js.map +1 -0
- package/dist/languages/zh-Hant.js +3 -0
- package/dist/languages/zh-Hant.js.map +1 -0
- package/dist/n2words.js +2 -2
- package/dist/n2words.js.map +1 -1
- package/lib/languages/am-Latn.d.ts +7 -0
- package/lib/languages/am-Latn.js +159 -0
- package/lib/languages/am.d.ts +7 -0
- package/lib/languages/am.js +159 -0
- package/lib/languages/ar.d.ts +14 -27
- package/lib/languages/ar.js +175 -129
- package/lib/languages/az.d.ts +4 -9
- package/lib/languages/az.js +166 -37
- package/lib/languages/bn.d.ts +4 -8
- package/lib/languages/bn.js +159 -124
- package/lib/languages/cs.d.ts +15 -85
- package/lib/languages/cs.js +293 -114
- package/lib/languages/da.d.ts +11 -12
- package/lib/languages/da.js +269 -101
- package/lib/languages/de.d.ts +14 -11
- package/lib/languages/de.js +305 -86
- package/lib/languages/el.d.ts +11 -11
- package/lib/languages/el.js +224 -78
- package/lib/languages/en.d.ts +14 -13
- package/lib/languages/en.js +228 -72
- package/lib/languages/es.d.ts +18 -12
- package/lib/languages/es.js +297 -103
- package/lib/languages/fa.d.ts +4 -44
- package/lib/languages/fa.js +112 -122
- package/lib/languages/fi.d.ts +14 -0
- package/lib/languages/fi.js +238 -0
- package/lib/languages/fil.d.ts +4 -13
- package/lib/languages/fil.js +196 -106
- package/lib/languages/fr-BE.d.ts +8 -8
- package/lib/languages/fr-BE.js +285 -19
- package/lib/languages/fr.d.ts +18 -12
- package/lib/languages/fr.js +339 -89
- package/lib/languages/gu.d.ts +4 -8
- package/lib/languages/gu.js +143 -125
- package/lib/languages/ha.d.ts +7 -0
- package/lib/languages/ha.js +225 -0
- package/lib/languages/hbo.d.ts +10 -110
- package/lib/languages/hbo.js +245 -214
- package/lib/languages/he.d.ts +10 -77
- package/lib/languages/he.js +231 -172
- package/lib/languages/hi.d.ts +4 -8
- package/lib/languages/hi.js +163 -124
- package/lib/languages/hr.d.ts +8 -77
- package/lib/languages/hr.js +200 -89
- package/lib/languages/hu.d.ts +4 -19
- package/lib/languages/hu.js +198 -119
- package/lib/languages/id.d.ts +4 -34
- package/lib/languages/id.js +166 -129
- package/lib/languages/it.d.ts +16 -34
- package/lib/languages/it.js +307 -97
- package/lib/languages/ja.d.ts +14 -14
- package/lib/languages/ja.js +221 -111
- package/lib/languages/ka.d.ts +17 -0
- package/lib/languages/ka.js +291 -0
- package/lib/languages/kn.d.ts +4 -8
- package/lib/languages/kn.js +143 -35
- package/lib/languages/ko.d.ts +11 -11
- package/lib/languages/ko.js +250 -49
- package/lib/languages/lt.d.ts +15 -67
- package/lib/languages/lt.js +287 -122
- package/lib/languages/lv.d.ts +15 -67
- package/lib/languages/lv.js +288 -106
- package/lib/languages/mr.d.ts +4 -8
- package/lib/languages/mr.js +143 -125
- package/lib/languages/ms.d.ts +4 -28
- package/lib/languages/ms.js +166 -116
- package/lib/languages/nb.d.ts +11 -9
- package/lib/languages/nb.js +272 -87
- package/lib/languages/nl.d.ts +23 -13
- package/lib/languages/nl.js +299 -133
- package/lib/languages/pa.d.ts +4 -8
- package/lib/languages/pa.js +151 -124
- package/lib/languages/pl.d.ts +19 -77
- package/lib/languages/pl.js +294 -87
- package/lib/languages/pt.d.ts +14 -26
- package/lib/languages/pt.js +272 -92
- package/lib/languages/ro.d.ts +15 -155
- package/lib/languages/ro.js +219 -235
- package/lib/languages/ru.d.ts +8 -82
- package/lib/languages/ru.js +239 -90
- package/lib/languages/sr-Cyrl.d.ts +8 -77
- package/lib/languages/sr-Cyrl.js +197 -89
- package/lib/languages/sr-Latn.d.ts +8 -77
- package/lib/languages/sr-Latn.js +197 -89
- package/lib/languages/sv.d.ts +11 -11
- package/lib/languages/sv.js +278 -74
- package/lib/languages/sw.d.ts +4 -36
- package/lib/languages/sw.js +133 -106
- package/lib/languages/ta.d.ts +4 -17
- package/lib/languages/ta.js +143 -202
- package/lib/languages/te.d.ts +4 -19
- package/lib/languages/te.js +133 -196
- package/lib/languages/th.d.ts +4 -14
- package/lib/languages/th.js +135 -91
- package/lib/languages/tr.d.ts +15 -9
- package/lib/languages/tr.js +245 -49
- package/lib/languages/uk.d.ts +8 -82
- package/lib/languages/uk.js +206 -78
- package/lib/languages/ur.d.ts +4 -8
- package/lib/languages/ur.js +151 -124
- package/lib/languages/vi.d.ts +14 -69
- package/lib/languages/vi.js +278 -129
- package/lib/languages/yo.d.ts +7 -0
- package/lib/languages/yo.js +303 -0
- package/lib/languages/zh-Hans.d.ts +8 -18
- package/lib/languages/zh-Hans.js +163 -92
- package/lib/languages/zh-Hant.d.ts +8 -18
- package/lib/languages/zh-Hant.js +181 -90
- package/lib/n2words.d.ts +55 -209
- package/lib/n2words.js +115 -530
- package/lib/utils/is-plain-object.d.ts +13 -0
- package/lib/utils/is-plain-object.js +17 -0
- package/lib/utils/parse-numeric.d.ts +17 -0
- package/lib/utils/parse-numeric.js +108 -0
- package/lib/utils/validate-options.d.ts +8 -0
- package/lib/utils/validate-options.js +16 -0
- package/package.json +26 -14
- package/dist/ArabicConverter.js +0 -3
- package/dist/ArabicConverter.js.map +0 -1
- package/dist/AzerbaijaniConverter.js +0 -3
- package/dist/AzerbaijaniConverter.js.map +0 -1
- package/dist/BanglaConverter.js +0 -3
- package/dist/BanglaConverter.js.map +0 -1
- package/dist/BiblicalHebrewConverter.js +0 -3
- package/dist/BiblicalHebrewConverter.js.map +0 -1
- package/dist/CroatianConverter.js +0 -3
- package/dist/CroatianConverter.js.map +0 -1
- package/dist/CzechConverter.js +0 -3
- package/dist/CzechConverter.js.map +0 -1
- package/dist/DanishConverter.js +0 -3
- package/dist/DanishConverter.js.map +0 -1
- package/dist/DutchConverter.js +0 -3
- package/dist/DutchConverter.js.map +0 -1
- package/dist/EnglishConverter.js +0 -3
- package/dist/EnglishConverter.js.map +0 -1
- package/dist/FilipinoConverter.js +0 -3
- package/dist/FilipinoConverter.js.map +0 -1
- package/dist/FrenchBelgiumConverter.js +0 -3
- package/dist/FrenchBelgiumConverter.js.map +0 -1
- package/dist/FrenchConverter.js +0 -3
- package/dist/FrenchConverter.js.map +0 -1
- package/dist/GermanConverter.js +0 -3
- package/dist/GermanConverter.js.map +0 -1
- package/dist/GreekConverter.js +0 -3
- package/dist/GreekConverter.js.map +0 -1
- package/dist/GujaratiConverter.js +0 -3
- package/dist/GujaratiConverter.js.map +0 -1
- package/dist/HebrewConverter.js +0 -3
- package/dist/HebrewConverter.js.map +0 -1
- package/dist/HindiConverter.js +0 -3
- package/dist/HindiConverter.js.map +0 -1
- package/dist/HungarianConverter.js +0 -3
- package/dist/HungarianConverter.js.map +0 -1
- package/dist/IndonesianConverter.js +0 -3
- package/dist/IndonesianConverter.js.map +0 -1
- package/dist/ItalianConverter.js +0 -3
- package/dist/ItalianConverter.js.map +0 -1
- package/dist/JapaneseConverter.js +0 -3
- package/dist/JapaneseConverter.js.map +0 -1
- package/dist/KannadaConverter.js +0 -3
- package/dist/KannadaConverter.js.map +0 -1
- package/dist/KoreanConverter.js +0 -3
- package/dist/KoreanConverter.js.map +0 -1
- package/dist/LatvianConverter.js +0 -3
- package/dist/LatvianConverter.js.map +0 -1
- package/dist/LithuanianConverter.js +0 -3
- package/dist/LithuanianConverter.js.map +0 -1
- package/dist/MalayConverter.js +0 -3
- package/dist/MalayConverter.js.map +0 -1
- package/dist/MarathiConverter.js +0 -3
- package/dist/MarathiConverter.js.map +0 -1
- package/dist/NorwegianBokmalConverter.js +0 -3
- package/dist/NorwegianBokmalConverter.js.map +0 -1
- package/dist/PersianConverter.js +0 -3
- package/dist/PersianConverter.js.map +0 -1
- package/dist/PolishConverter.js +0 -3
- package/dist/PolishConverter.js.map +0 -1
- package/dist/PortugueseConverter.js +0 -3
- package/dist/PortugueseConverter.js.map +0 -1
- package/dist/PunjabiConverter.js +0 -3
- package/dist/PunjabiConverter.js.map +0 -1
- package/dist/RomanianConverter.js +0 -3
- package/dist/RomanianConverter.js.map +0 -1
- package/dist/RussianConverter.js +0 -3
- package/dist/RussianConverter.js.map +0 -1
- package/dist/SerbianCyrillicConverter.js +0 -3
- package/dist/SerbianCyrillicConverter.js.map +0 -1
- package/dist/SerbianLatinConverter.js +0 -3
- package/dist/SerbianLatinConverter.js.map +0 -1
- package/dist/SimplifiedChineseConverter.js +0 -3
- package/dist/SimplifiedChineseConverter.js.map +0 -1
- package/dist/SpanishConverter.js +0 -3
- package/dist/SpanishConverter.js.map +0 -1
- package/dist/SwahiliConverter.js +0 -3
- package/dist/SwahiliConverter.js.map +0 -1
- package/dist/SwedishConverter.js +0 -3
- package/dist/SwedishConverter.js.map +0 -1
- package/dist/TamilConverter.js +0 -3
- package/dist/TamilConverter.js.map +0 -1
- package/dist/TeluguConverter.js +0 -3
- package/dist/TeluguConverter.js.map +0 -1
- package/dist/ThaiConverter.js +0 -3
- package/dist/ThaiConverter.js.map +0 -1
- package/dist/TraditionalChineseConverter.js +0 -3
- package/dist/TraditionalChineseConverter.js.map +0 -1
- package/dist/TurkishConverter.js +0 -3
- package/dist/TurkishConverter.js.map +0 -1
- package/dist/UkrainianConverter.js +0 -3
- package/dist/UkrainianConverter.js.map +0 -1
- package/dist/UrduConverter.js +0 -3
- package/dist/UrduConverter.js.map +0 -1
- package/dist/VietnameseConverter.js +0 -3
- package/dist/VietnameseConverter.js.map +0 -1
- package/lib/classes/abstract-language.d.ts +0 -178
- package/lib/classes/abstract-language.js +0 -268
- package/lib/classes/greedy-scale-language.d.ts +0 -109
- package/lib/classes/greedy-scale-language.js +0 -201
- package/lib/classes/slavic-language.d.ts +0 -148
- package/lib/classes/slavic-language.js +0 -281
- package/lib/classes/south-asian-language.d.ts +0 -70
- package/lib/classes/south-asian-language.js +0 -154
- package/lib/classes/turkic-language.d.ts +0 -26
- package/lib/classes/turkic-language.js +0 -59
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Yoruba language converter - Functional Implementation
|
|
3
|
+
*
|
|
4
|
+
* A number-to-words converter for Yoruba (yo), a Niger-Congo language
|
|
5
|
+
* spoken by ~45 million people in Nigeria, Benin, and Togo.
|
|
6
|
+
*
|
|
7
|
+
* Yoruba uses a complex vigesimal (base-20) system with:
|
|
8
|
+
* - Additive patterns: 1-4 added to decade (lé = "plus")
|
|
9
|
+
* - Subtractive patterns: 5-9 subtracted from next decade (dín = "minus")
|
|
10
|
+
* - Odd decades (30,50,70,90) formed by subtracting 10 from next even decade
|
|
11
|
+
* - Even decades (20,40,60,80,100) are multiples of 20
|
|
12
|
+
*
|
|
13
|
+
* Examples:
|
|
14
|
+
* - 21 = ọ̀kan lé lógún (1 + 20)
|
|
15
|
+
* - 15 = àrùndínlógún (20 - 5)
|
|
16
|
+
* - 50 = àádọ́ta (60 - 10)
|
|
17
|
+
* - 45 = àrùndínláàádọ́ta (50 - 5)
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
21
|
+
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// Vocabulary (module-level constants)
|
|
24
|
+
// ============================================================================
|
|
25
|
+
|
|
26
|
+
// Basic numbers 1-10
|
|
27
|
+
const ONES = [
|
|
28
|
+
'',
|
|
29
|
+
'ọ̀kan', // 1
|
|
30
|
+
'èjì', // 2
|
|
31
|
+
'ẹ̀ta', // 3
|
|
32
|
+
'ẹ̀rin', // 4
|
|
33
|
+
'àrùn', // 5
|
|
34
|
+
'ẹ̀fà', // 6
|
|
35
|
+
'èje', // 7
|
|
36
|
+
'ẹ̀jọ', // 8
|
|
37
|
+
'ẹ̀sán', // 9
|
|
38
|
+
'ẹ̀wá' // 10
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
// Numbers 11-14 (additive: X + 10, using "lá")
|
|
42
|
+
const TEENS_ADD = [
|
|
43
|
+
'',
|
|
44
|
+
'ọ̀kànlá', // 11 = 1 + 10
|
|
45
|
+
'èjìlá', // 12 = 2 + 10
|
|
46
|
+
'ẹ̀talá', // 13 = 3 + 10
|
|
47
|
+
'ẹ̀rinlá' // 14 = 4 + 10
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
// Numbers 15-19 (subtractive: 20 - X, using "dín")
|
|
51
|
+
const TEENS_SUB = [
|
|
52
|
+
'àrùndínlógún', // 15 = 20 - 5
|
|
53
|
+
'ẹ̀rìndínlógún', // 16 = 20 - 4
|
|
54
|
+
'ẹ̀tadínlógún', // 17 = 20 - 3
|
|
55
|
+
'èjìdínlógún', // 18 = 20 - 2
|
|
56
|
+
'ọ̀kàndínlógún' // 19 = 20 - 1
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
// Decades (base-20 structure)
|
|
60
|
+
// Even decades are multiples of 20
|
|
61
|
+
// Odd decades subtract 10 from next even decade
|
|
62
|
+
const DECADES = {
|
|
63
|
+
20: 'ogún', // 20 = 20 × 1
|
|
64
|
+
30: 'ọgbọ̀n', // 30 = 20 + 10 (special word)
|
|
65
|
+
40: 'ogójì', // 40 = 20 × 2
|
|
66
|
+
50: 'àádọ́ta', // 50 = 60 - 10
|
|
67
|
+
60: 'ogóta', // 60 = 20 × 3
|
|
68
|
+
70: 'àádọ́rin', // 70 = 80 - 10
|
|
69
|
+
80: 'ogórin', // 80 = 20 × 4
|
|
70
|
+
90: 'àádọ́rùn', // 90 = 100 - 10
|
|
71
|
+
100: 'ọgọ́rùn' // 100 = 20 × 5
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Prefixes for adding to decades (lé lógún, lé lọgbọ̀n, etc.)
|
|
75
|
+
const DECADE_ADD_SUFFIX = {
|
|
76
|
+
20: 'lógún',
|
|
77
|
+
30: 'lọgbọ̀n',
|
|
78
|
+
40: 'lógójì',
|
|
79
|
+
50: 'láàádọ́ta',
|
|
80
|
+
60: 'lógóta',
|
|
81
|
+
70: 'láàádọ́rin',
|
|
82
|
+
80: 'lógórin',
|
|
83
|
+
90: 'láàádọ́rùn',
|
|
84
|
+
100: 'lọ́gọ́rùn'
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Prefixes for subtracting from decades (dín lógójì, etc.)
|
|
88
|
+
const DECADE_SUB_SUFFIX = {
|
|
89
|
+
20: 'dínlógún',
|
|
90
|
+
30: 'dínlọgbọ̀n',
|
|
91
|
+
40: 'dínlógójì',
|
|
92
|
+
50: 'dínláàádọ́ta',
|
|
93
|
+
60: 'dínlógóta',
|
|
94
|
+
70: 'dínláàádọ́rin',
|
|
95
|
+
80: 'dínlógórin',
|
|
96
|
+
90: 'dínláàádọ́rùn',
|
|
97
|
+
100: 'dínlọ́gọ́rùn'
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Scale words
|
|
101
|
+
const HUNDRED = 'ọgọ́rùn'
|
|
102
|
+
const TWO_HUNDRED = 'igba' // 200 (special word, historically 200 cowries)
|
|
103
|
+
const FOUR_HUNDRED = 'irinwó' // 400 (20 × 20)
|
|
104
|
+
const THOUSAND = 'ẹgbẹ̀rún' // 1000
|
|
105
|
+
const TEN_THOUSAND = 'ẹgbàárùn' // 10,000 (special)
|
|
106
|
+
const TWENTY_THOUSAND = 'ọ̀kẹ́' // 20,000 (bag of cowries)
|
|
107
|
+
const MILLION = 'mílíọ̀nù' // million (loanword)
|
|
108
|
+
|
|
109
|
+
const ZERO = 'òdo'
|
|
110
|
+
const NEGATIVE = 'àìní'
|
|
111
|
+
const DECIMAL_SEP = 'àmì'
|
|
112
|
+
const AND = 'ó lé' // "and" / "plus" connector
|
|
113
|
+
|
|
114
|
+
// ============================================================================
|
|
115
|
+
// Segment Building
|
|
116
|
+
// ============================================================================
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Builds word for numbers 0-99
|
|
120
|
+
*/
|
|
121
|
+
function buildUnder100 (n) {
|
|
122
|
+
if (n === 0) return ''
|
|
123
|
+
if (n <= 10) return ONES[n]
|
|
124
|
+
|
|
125
|
+
// 11-14: additive from 10
|
|
126
|
+
if (n <= 14) return TEENS_ADD[n - 10]
|
|
127
|
+
|
|
128
|
+
// 15-19: subtractive from 20
|
|
129
|
+
if (n <= 19) return TEENS_SUB[n - 15]
|
|
130
|
+
|
|
131
|
+
// Exact decades
|
|
132
|
+
if (n % 10 === 0) return DECADES[n]
|
|
133
|
+
|
|
134
|
+
const decade = Math.floor(n / 10) * 10
|
|
135
|
+
const unit = n % 10
|
|
136
|
+
|
|
137
|
+
// 1-4 are added to current decade (21 = 1 + 20, not 1 + 30)
|
|
138
|
+
if (unit <= 4) {
|
|
139
|
+
return ONES[unit] + ' lé ' + DECADE_ADD_SUFFIX[decade]
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// 5-9 are subtracted from next decade
|
|
143
|
+
const nextDecade = decade + 10
|
|
144
|
+
const subtractAmount = 10 - unit
|
|
145
|
+
return ONES[subtractAmount] + DECADE_SUB_SUFFIX[nextDecade]
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ============================================================================
|
|
149
|
+
// Conversion Functions
|
|
150
|
+
// ============================================================================
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Converts hundreds (100-999)
|
|
154
|
+
*/
|
|
155
|
+
function convertHundreds (n) {
|
|
156
|
+
if (n < 100) return buildUnder100(n)
|
|
157
|
+
|
|
158
|
+
const hundreds = Math.floor(n / 100)
|
|
159
|
+
const remainder = n % 100
|
|
160
|
+
|
|
161
|
+
let result
|
|
162
|
+
|
|
163
|
+
// Special cases for 200 and 400
|
|
164
|
+
if (hundreds === 2 && remainder === 0) {
|
|
165
|
+
return TWO_HUNDRED
|
|
166
|
+
}
|
|
167
|
+
if (hundreds === 4 && remainder === 0) {
|
|
168
|
+
return FOUR_HUNDRED
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Build hundreds
|
|
172
|
+
if (hundreds === 1) {
|
|
173
|
+
result = HUNDRED
|
|
174
|
+
} else if (hundreds === 2) {
|
|
175
|
+
result = TWO_HUNDRED
|
|
176
|
+
} else if (hundreds === 4) {
|
|
177
|
+
result = FOUR_HUNDRED
|
|
178
|
+
} else {
|
|
179
|
+
// Other hundreds: X ọgọ́rùn
|
|
180
|
+
result = ONES[hundreds] + ' ' + HUNDRED
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (remainder > 0) {
|
|
184
|
+
result += ' ' + AND + ' ' + buildUnder100(remainder)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return result
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Converts a non-negative integer to Yoruba words.
|
|
192
|
+
*
|
|
193
|
+
* @param {bigint} n - Non-negative integer to convert
|
|
194
|
+
* @returns {string} Yoruba words
|
|
195
|
+
*/
|
|
196
|
+
function integerToWords (n) {
|
|
197
|
+
if (n === 0n) return ZERO
|
|
198
|
+
|
|
199
|
+
// Fast path: numbers < 100
|
|
200
|
+
if (n < 100n) {
|
|
201
|
+
return buildUnder100(Number(n))
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Numbers < 1000
|
|
205
|
+
if (n < 1000n) {
|
|
206
|
+
return convertHundreds(Number(n))
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Build from segments
|
|
210
|
+
const parts = []
|
|
211
|
+
let remaining = n
|
|
212
|
+
|
|
213
|
+
// Millions
|
|
214
|
+
if (remaining >= 1_000_000n) {
|
|
215
|
+
const millions = remaining / 1_000_000n
|
|
216
|
+
remaining = remaining % 1_000_000n
|
|
217
|
+
if (millions === 1n) {
|
|
218
|
+
parts.push(MILLION + ' kan')
|
|
219
|
+
} else {
|
|
220
|
+
parts.push(MILLION + ' ' + integerToWords(millions))
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Thousands
|
|
225
|
+
if (remaining >= 1000n) {
|
|
226
|
+
const thousands = remaining / 1000n
|
|
227
|
+
remaining = remaining % 1000n
|
|
228
|
+
|
|
229
|
+
if (thousands === 1n) {
|
|
230
|
+
parts.push(THOUSAND + ' kan')
|
|
231
|
+
} else if (thousands === 10n) {
|
|
232
|
+
parts.push(TEN_THOUSAND)
|
|
233
|
+
} else if (thousands === 20n) {
|
|
234
|
+
parts.push(TWENTY_THOUSAND)
|
|
235
|
+
} else if (thousands < 100n) {
|
|
236
|
+
parts.push(THOUSAND + ' ' + buildUnder100(Number(thousands)))
|
|
237
|
+
} else {
|
|
238
|
+
parts.push(THOUSAND + ' ' + convertHundreds(Number(thousands)))
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Hundreds and below
|
|
243
|
+
if (remaining > 0n) {
|
|
244
|
+
if (remaining < 100n) {
|
|
245
|
+
if (parts.length > 0) {
|
|
246
|
+
parts.push(AND + ' ' + buildUnder100(Number(remaining)))
|
|
247
|
+
} else {
|
|
248
|
+
parts.push(buildUnder100(Number(remaining)))
|
|
249
|
+
}
|
|
250
|
+
} else {
|
|
251
|
+
if (parts.length > 0) {
|
|
252
|
+
parts.push(AND + ' ' + convertHundreds(Number(remaining)))
|
|
253
|
+
} else {
|
|
254
|
+
parts.push(convertHundreds(Number(remaining)))
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return parts.join(', ')
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Converts decimal digits to Yoruba words.
|
|
264
|
+
*
|
|
265
|
+
* @param {string} decimalPart - Decimal digits
|
|
266
|
+
* @returns {string} Yoruba words for decimal
|
|
267
|
+
*/
|
|
268
|
+
function decimalPartToWords (decimalPart) {
|
|
269
|
+
const parts = []
|
|
270
|
+
|
|
271
|
+
for (const digit of decimalPart) {
|
|
272
|
+
const d = parseInt(digit, 10)
|
|
273
|
+
parts.push(d === 0 ? ZERO : ONES[d])
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return parts.join(' ')
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Converts a numeric value to Yoruba words.
|
|
281
|
+
*
|
|
282
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
283
|
+
* @returns {string} The number in Yoruba words
|
|
284
|
+
*/
|
|
285
|
+
function toWords (value) {
|
|
286
|
+
const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
|
|
287
|
+
|
|
288
|
+
let result = ''
|
|
289
|
+
|
|
290
|
+
if (isNegative) {
|
|
291
|
+
result = NEGATIVE + ' '
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
result += integerToWords(integerPart)
|
|
295
|
+
|
|
296
|
+
if (decimalPart) {
|
|
297
|
+
result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart)
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return result
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export { toWords }
|
|
@@ -1,21 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Simplified Chinese
|
|
2
|
+
* Converts a numeric value to Simplified Chinese 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.formal=true] - Use formal/financial numerals
|
|
7
|
+
* @returns {string} The number in Simplified Chinese words
|
|
8
8
|
*/
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
/** Combines two word-sets according to Chinese grammar rules. */
|
|
13
|
-
combineWordSets(preceding: any, following: any): any;
|
|
14
|
-
/** Returns the number of digits in a number. */
|
|
15
|
-
digit(number_: any): any;
|
|
16
|
-
/** Counts the number of zero digits in a number. */
|
|
17
|
-
zeroDigit(number_: any): number;
|
|
18
|
-
/** Converts decimal digits to words by reading each digit individually. */
|
|
19
|
-
decimalDigitsToWords(decimalString: any): string[];
|
|
20
|
-
}
|
|
21
|
-
import { GreedyScaleLanguage } from '../classes/greedy-scale-language.js';
|
|
9
|
+
export function toWords(value: number | string | bigint, options?: {
|
|
10
|
+
formal?: boolean | undefined;
|
|
11
|
+
}): string;
|
package/lib/languages/zh-Hans.js
CHANGED
|
@@ -1,111 +1,182 @@
|
|
|
1
|
-
import { GreedyScaleLanguage } from '../classes/greedy-scale-language.js'
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
|
-
* Simplified Chinese language converter
|
|
2
|
+
* Simplified Chinese language converter - Functional Implementation
|
|
3
|
+
*
|
|
4
|
+
* Self-contained converter for Simplified Chinese.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* -
|
|
6
|
+
* Key features:
|
|
7
|
+
* - Myriad-based (万, 亿) grouping - 4 digits
|
|
8
|
+
* - Formal (financial) vs common numerals
|
|
9
|
+
* - Zero insertion for skipped positions
|
|
8
10
|
* - No word separators (concatenated format)
|
|
9
|
-
* - Optional formal (financial) vs common numerals
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
[2n, '二'],
|
|
59
|
-
[1n, '一'],
|
|
60
|
-
[0n, '零']
|
|
61
|
-
]
|
|
62
|
-
}
|
|
12
|
+
|
|
13
|
+
import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
14
|
+
import { validateOptions } from '../utils/validate-options.js'
|
|
15
|
+
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Vocabulary
|
|
18
|
+
// ============================================================================
|
|
19
|
+
|
|
20
|
+
// Common (everyday) numerals
|
|
21
|
+
const ONES_COMMON = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']
|
|
22
|
+
const TEN_COMMON = '十'
|
|
23
|
+
const HUNDRED_COMMON = '百'
|
|
24
|
+
const THOUSAND_COMMON = '千'
|
|
25
|
+
|
|
26
|
+
// Formal (financial) numerals - harder to alter/forge
|
|
27
|
+
const ONES_FORMAL = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
|
|
28
|
+
const TEN_FORMAL = '拾'
|
|
29
|
+
const HUNDRED_FORMAL = '佰'
|
|
30
|
+
const THOUSAND_FORMAL = '仟'
|
|
31
|
+
|
|
32
|
+
// Scale words
|
|
33
|
+
const WAN_WORD = '万' // 10,000
|
|
34
|
+
const YI_WORD = '亿' // 100,000,000
|
|
35
|
+
|
|
36
|
+
const ZERO = '零'
|
|
37
|
+
const NEGATIVE = '负'
|
|
38
|
+
const DECIMAL_SEP = '点'
|
|
39
|
+
|
|
40
|
+
// ============================================================================
|
|
41
|
+
// Conversion Functions
|
|
42
|
+
// ============================================================================
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Convert number below 万 (10,000) to words using direct string concatenation.
|
|
46
|
+
*/
|
|
47
|
+
function convertBelowWan (value, ones, ten, hundred, thousand) {
|
|
48
|
+
if (value === 0n) return ''
|
|
49
|
+
|
|
50
|
+
let result = ''
|
|
51
|
+
let needsZero = false
|
|
52
|
+
|
|
53
|
+
// Thousands (千)
|
|
54
|
+
const thousandsVal = value / 1000n
|
|
55
|
+
const thousandsRemainder = value % 1000n
|
|
56
|
+
if (thousandsVal > 0n) {
|
|
57
|
+
result = ones[Number(thousandsVal)] + thousand
|
|
58
|
+
needsZero = thousandsRemainder > 0n && thousandsRemainder < 100n
|
|
63
59
|
}
|
|
64
60
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
61
|
+
// Hundreds (百)
|
|
62
|
+
const hundredsVal = thousandsRemainder / 100n
|
|
63
|
+
const hundredsRemainder = thousandsRemainder % 100n
|
|
64
|
+
if (hundredsVal > 0n) {
|
|
65
|
+
if (needsZero) result += ZERO
|
|
66
|
+
result += ones[Number(hundredsVal)] + hundred
|
|
67
|
+
needsZero = hundredsRemainder > 0n && hundredsRemainder < 10n
|
|
68
|
+
} else if (thousandsVal > 0n && hundredsRemainder > 0n) {
|
|
69
|
+
needsZero = true
|
|
70
|
+
}
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
// Tens (十)
|
|
73
|
+
const tensVal = hundredsRemainder / 10n
|
|
74
|
+
const onesVal = hundredsRemainder % 10n
|
|
75
|
+
if (tensVal > 0n) {
|
|
76
|
+
if (needsZero) result += ZERO
|
|
77
|
+
result += ones[Number(tensVal)] + ten
|
|
78
|
+
needsZero = false
|
|
79
|
+
} else if ((hundredsVal > 0n || thousandsVal > 0n) && onesVal > 0n) {
|
|
80
|
+
needsZero = true
|
|
81
|
+
}
|
|
76
82
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
83
|
+
// Ones
|
|
84
|
+
if (onesVal > 0n) {
|
|
85
|
+
if (needsZero) result += ZERO
|
|
86
|
+
result += ones[Number(onesVal)]
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return result
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Convert number below 亿 (100 million) to words.
|
|
94
|
+
*/
|
|
95
|
+
function convertBelowYi (value, ones, ten, hundred, thousand) {
|
|
96
|
+
if (value === 0n) return ''
|
|
81
97
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
98
|
+
if (value >= 10_000n) {
|
|
99
|
+
const wanValue = value / 10_000n
|
|
100
|
+
const wanRemainder = value % 10_000n
|
|
101
|
+
|
|
102
|
+
let result = convertBelowWan(wanValue, ones, ten, hundred, thousand) + WAN_WORD
|
|
103
|
+
|
|
104
|
+
if (wanRemainder > 0n) {
|
|
105
|
+
const needsZero = (wanValue % 10n === 0n) || (wanRemainder < 1000n)
|
|
106
|
+
if (needsZero) result += ZERO
|
|
107
|
+
result += convertBelowWan(wanRemainder, ones, ten, hundred, thousand)
|
|
86
108
|
}
|
|
87
109
|
|
|
88
|
-
|
|
89
|
-
return { [`${precedingWord}${followingWord}`]: precedingValue + followingValue }
|
|
110
|
+
return result
|
|
90
111
|
}
|
|
91
112
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
113
|
+
return convertBelowWan(value, ones, ten, hundred, thousand)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function integerToWords (n, formal = true) {
|
|
117
|
+
if (n === 0n) return ZERO
|
|
118
|
+
|
|
119
|
+
const ones = formal ? ONES_FORMAL : ONES_COMMON
|
|
120
|
+
const ten = formal ? TEN_FORMAL : TEN_COMMON
|
|
121
|
+
const hundred = formal ? HUNDRED_FORMAL : HUNDRED_COMMON
|
|
122
|
+
const thousand = formal ? THOUSAND_FORMAL : THOUSAND_COMMON
|
|
123
|
+
|
|
124
|
+
// Handle numbers >= 亿 (100 million)
|
|
125
|
+
if (n >= 100_000_000n) {
|
|
126
|
+
const yiValue = n / 100_000_000n
|
|
127
|
+
const yiRemainder = n % 100_000_000n
|
|
128
|
+
|
|
129
|
+
let result = convertBelowYi(yiValue, ones, ten, hundred, thousand) + YI_WORD
|
|
130
|
+
|
|
131
|
+
if (yiRemainder > 0n) {
|
|
132
|
+
if (yiRemainder < 10_000_000n) result += ZERO
|
|
133
|
+
result += convertBelowYi(yiRemainder, ones, ten, hundred, thousand)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return result
|
|
95
137
|
}
|
|
96
138
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
139
|
+
return convertBelowYi(n, ones, ten, hundred, thousand)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Convert decimal digits to words using direct concatenation.
|
|
144
|
+
*/
|
|
145
|
+
function decimalDigitsToWords (decimalString, ones) {
|
|
146
|
+
let result = ''
|
|
147
|
+
for (let i = 0; i < decimalString.length; i++) {
|
|
148
|
+
result += ones[Number(decimalString[i])]
|
|
100
149
|
}
|
|
150
|
+
return result
|
|
151
|
+
}
|
|
101
152
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
153
|
+
/**
|
|
154
|
+
* Converts a numeric value to Simplified Chinese words.
|
|
155
|
+
*
|
|
156
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
157
|
+
* @param {Object} [options] - Optional configuration
|
|
158
|
+
* @param {boolean} [options.formal=true] - Use formal/financial numerals
|
|
159
|
+
* @returns {string} The number in Simplified Chinese words
|
|
160
|
+
*/
|
|
161
|
+
function toWords (value, options) {
|
|
162
|
+
options = validateOptions(options)
|
|
163
|
+
const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
|
|
164
|
+
const formal = options.formal !== false // Default to true
|
|
165
|
+
|
|
166
|
+
let result = isNegative ? NEGATIVE : ''
|
|
167
|
+
|
|
168
|
+
result += integerToWords(integerPart, formal)
|
|
169
|
+
|
|
170
|
+
if (decimalPart) {
|
|
171
|
+
const ones = formal ? ONES_FORMAL : ONES_COMMON
|
|
172
|
+
result += DECIMAL_SEP + decimalDigitsToWords(decimalPart, ones)
|
|
110
173
|
}
|
|
174
|
+
|
|
175
|
+
return result
|
|
111
176
|
}
|
|
177
|
+
|
|
178
|
+
// ============================================================================
|
|
179
|
+
// Exports
|
|
180
|
+
// ============================================================================
|
|
181
|
+
|
|
182
|
+
export { toWords }
|
|
@@ -1,21 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Traditional Chinese
|
|
2
|
+
* Converts a numeric value to Traditional Chinese 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.formal=true] - Use formal/financial numerals
|
|
7
|
+
* @returns {string} The number in Traditional Chinese words
|
|
8
8
|
*/
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
/** Combines two word-sets with Traditional Chinese grammar rules and zero insertion. */
|
|
13
|
-
combineWordSets(preceding: any, following: any): any;
|
|
14
|
-
/** Returns the number of digits in a number. */
|
|
15
|
-
digit(number_: any): any;
|
|
16
|
-
/** Counts the number of zero digits in a number. */
|
|
17
|
-
zeroDigit(number_: any): number;
|
|
18
|
-
/** Converts decimal digits to words by reading each digit individually. */
|
|
19
|
-
decimalDigitsToWords(decimalString: any): string[];
|
|
20
|
-
}
|
|
21
|
-
import { GreedyScaleLanguage } from '../classes/greedy-scale-language.js';
|
|
9
|
+
export function toWords(value: number | string | bigint, options?: {
|
|
10
|
+
formal?: boolean | undefined;
|
|
11
|
+
}): string;
|