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/uk.js
CHANGED
|
@@ -1,96 +1,218 @@
|
|
|
1
|
-
import { SlavicLanguage } from '../classes/slavic-language.js'
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
|
-
* Ukrainian language converter
|
|
2
|
+
* Ukrainian language converter - Functional Implementation
|
|
3
|
+
*
|
|
4
|
+
* Self-contained converter using shared Slavic utilities.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* Key features:
|
|
7
7
|
* - Three-form pluralization (one/few/many)
|
|
8
|
-
* - Gender
|
|
9
|
-
* -
|
|
8
|
+
* - Gender: thousands are feminine, millions+ are masculine
|
|
9
|
+
* - Irregular hundreds
|
|
10
|
+
* - Long scale naming
|
|
10
11
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
12
|
+
|
|
13
|
+
import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
14
|
+
import { validateOptions } from '../utils/validate-options.js'
|
|
15
|
+
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Slavic Utilities (inlined for performance)
|
|
18
|
+
// ============================================================================
|
|
19
|
+
|
|
20
|
+
function pluralize (n, forms) {
|
|
21
|
+
const num = typeof n === 'bigint' ? Number(n) : n
|
|
22
|
+
const lastDigit = num % 10
|
|
23
|
+
const lastTwoDigits = num % 100
|
|
24
|
+
|
|
25
|
+
if (lastTwoDigits >= 11 && lastTwoDigits <= 19) {
|
|
26
|
+
return forms[2]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (lastDigit === 1) return forms[0]
|
|
30
|
+
if (lastDigit >= 2 && lastDigit <= 4) return forms[1]
|
|
31
|
+
return forms[2]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function buildAllSegments (onesMasc, onesFem, teens, tens, hundreds) {
|
|
35
|
+
const masc = new Array(1000)
|
|
36
|
+
const fem = new Array(1000)
|
|
37
|
+
|
|
38
|
+
for (let i = 0; i < 1000; i++) {
|
|
39
|
+
masc[i] = buildSegment(i, onesMasc, teens, tens, hundreds)
|
|
40
|
+
fem[i] = buildSegment(i, onesFem, teens, tens, hundreds)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return { masc, fem }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function buildSegment (n, ones, teens, tens, hundreds) {
|
|
47
|
+
if (n === 0) return ''
|
|
48
|
+
|
|
49
|
+
const onesDigit = n % 10
|
|
50
|
+
const tensDigit = Math.floor(n / 10) % 10
|
|
51
|
+
const hundredsDigit = Math.floor(n / 100)
|
|
52
|
+
|
|
53
|
+
const parts = []
|
|
54
|
+
|
|
55
|
+
if (hundredsDigit > 0) {
|
|
56
|
+
parts.push(hundreds[hundredsDigit])
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (tensDigit > 1) {
|
|
60
|
+
parts.push(tens[tensDigit])
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (tensDigit === 1) {
|
|
64
|
+
parts.push(teens[onesDigit])
|
|
65
|
+
} else if (onesDigit > 0) {
|
|
66
|
+
parts.push(ones[onesDigit])
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return parts.join(' ')
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ============================================================================
|
|
73
|
+
// Vocabulary
|
|
74
|
+
// ============================================================================
|
|
75
|
+
|
|
76
|
+
const ONES_MASC = ['', 'один', 'два', 'три', 'чотири', 'п\'ять', 'шiсть', 'сiм', 'вiсiм', 'дев\'ять']
|
|
77
|
+
const ONES_FEM = ['', 'одна', 'двi', 'три', 'чотири', 'п\'ять', 'шiсть', 'сiм', 'вiсiм', 'дев\'ять']
|
|
78
|
+
|
|
79
|
+
const TEENS = ['десять', 'одинадцять', 'дванадцять', 'тринадцять', 'чотирнадцять', 'п\'ятнадцять', 'шiстнадцять', 'сiмнадцять', 'вiсiмнадцять', 'дев\'ятнадцять']
|
|
80
|
+
const TENS = ['', '', 'двадцять', 'тридцять', 'сорок', 'п\'ятдесят', 'шiстдесят', 'сiмдесят', 'вiсiмдесят', 'дев\'яносто']
|
|
81
|
+
|
|
82
|
+
// Irregular hundreds
|
|
83
|
+
const HUNDREDS = ['', 'сто', 'двiстi', 'триста', 'чотириста', 'п\'ятсот', 'шiстсот', 'сiмсот', 'вiсiмсот', 'дев\'ятсот']
|
|
84
|
+
|
|
85
|
+
const ZERO = 'нуль'
|
|
86
|
+
const NEGATIVE = 'мiнус'
|
|
87
|
+
const DECIMAL_SEP = 'кома'
|
|
88
|
+
|
|
89
|
+
// Scale words: [singular, few, many]
|
|
90
|
+
// Thousands (index 0) are feminine, rest are masculine
|
|
91
|
+
const SCALE_FORMS = [
|
|
92
|
+
['тисяча', 'тисячi', 'тисяч'],
|
|
93
|
+
['мiльйон', 'мiльйони', 'мiльйонiв'],
|
|
94
|
+
['мiльярд', 'мiльярди', 'мiльярдiв'],
|
|
95
|
+
['трильйон', 'трильйони', 'трильйонiв'],
|
|
96
|
+
['квадрильйон', 'квадрильйони', 'квадрильйонiв'],
|
|
97
|
+
['квiнтильйон', 'квiнтильйони', 'квiнтильйонiв'],
|
|
98
|
+
['секстильйон', 'секстильйони', 'секстильйонiв'],
|
|
99
|
+
['септильйон', 'септильйони', 'септильйонiв'],
|
|
100
|
+
['октильйон', 'октильйони', 'октильйонiв']
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
// ============================================================================
|
|
104
|
+
// Precomputed Lookup Tables
|
|
105
|
+
// ============================================================================
|
|
106
|
+
|
|
107
|
+
const { masc: SEGMENTS_MASC, fem: SEGMENTS_FEM } = buildAllSegments(ONES_MASC, ONES_FEM, TEENS, TENS, HUNDREDS)
|
|
108
|
+
|
|
109
|
+
// ============================================================================
|
|
110
|
+
// Conversion Functions
|
|
111
|
+
// ============================================================================
|
|
112
|
+
|
|
113
|
+
function integerToWords (n, options = {}) {
|
|
114
|
+
if (n === 0n) return ZERO
|
|
115
|
+
|
|
116
|
+
if (n < 1000n) {
|
|
117
|
+
const segments = options.gender === 'feminine' ? SEGMENTS_FEM : SEGMENTS_MASC
|
|
118
|
+
return segments[Number(n)]
|
|
26
119
|
}
|
|
27
120
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
121
|
+
return buildLargeNumberWords(n, options)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function buildLargeNumberWords (n, options) {
|
|
125
|
+
const numStr = n.toString()
|
|
126
|
+
const len = numStr.length
|
|
127
|
+
|
|
128
|
+
const segments = []
|
|
129
|
+
const segmentSize = 3
|
|
130
|
+
|
|
131
|
+
const remainderLen = len % segmentSize
|
|
132
|
+
let pos = 0
|
|
133
|
+
if (remainderLen > 0) {
|
|
134
|
+
segments.push(Number(numStr.slice(0, remainderLen)))
|
|
135
|
+
pos = remainderLen
|
|
136
|
+
}
|
|
137
|
+
while (pos < len) {
|
|
138
|
+
segments.push(Number(numStr.slice(pos, pos + segmentSize)))
|
|
139
|
+
pos += segmentSize
|
|
38
140
|
}
|
|
39
141
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
142
|
+
const parts = []
|
|
143
|
+
let scaleIndex = segments.length - 1
|
|
144
|
+
|
|
145
|
+
for (let i = 0; i < segments.length; i++) {
|
|
146
|
+
const segment = segments[i]
|
|
147
|
+
|
|
148
|
+
if (segment !== 0) {
|
|
149
|
+
if (scaleIndex === 0) {
|
|
150
|
+
const segmentWords = options.gender === 'feminine' ? SEGMENTS_FEM : SEGMENTS_MASC
|
|
151
|
+
parts.push(segmentWords[segment])
|
|
152
|
+
} else {
|
|
153
|
+
const scaleForms = SCALE_FORMS[scaleIndex - 1]
|
|
154
|
+
const scaleWord = pluralize(segment, scaleForms)
|
|
155
|
+
// Thousands (scaleIndex=1) are feminine, others masculine
|
|
156
|
+
const isFeminine = scaleIndex === 1
|
|
157
|
+
const segmentWords = isFeminine ? SEGMENTS_FEM : SEGMENTS_MASC
|
|
158
|
+
parts.push(segmentWords[segment] + ' ' + scaleWord)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
scaleIndex--
|
|
51
163
|
}
|
|
52
164
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
165
|
+
return parts.join(' ')
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function decimalPartToWords (decimalPart, options) {
|
|
169
|
+
let result = ''
|
|
170
|
+
let i = 0
|
|
171
|
+
|
|
172
|
+
while (i < decimalPart.length && decimalPart[i] === '0') {
|
|
173
|
+
if (result) result += ' '
|
|
174
|
+
result += ZERO
|
|
175
|
+
i++
|
|
62
176
|
}
|
|
63
177
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
4: 'чотириста',
|
|
69
|
-
5: 'п\'ятсот',
|
|
70
|
-
6: 'шiстсот',
|
|
71
|
-
7: 'сiмсот',
|
|
72
|
-
8: 'вiсiмсот',
|
|
73
|
-
9: 'дев\'ятсот'
|
|
178
|
+
const remainder = decimalPart.slice(i)
|
|
179
|
+
if (remainder) {
|
|
180
|
+
if (result) result += ' '
|
|
181
|
+
result += integerToWords(BigInt(remainder), options)
|
|
74
182
|
}
|
|
75
183
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
184
|
+
return result
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Converts a numeric value to Ukrainian words.
|
|
189
|
+
*
|
|
190
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
191
|
+
* @param {Object} [options] - Optional configuration
|
|
192
|
+
* @param {('masculine'|'feminine')} [options.gender='masculine'] - Grammatical gender
|
|
193
|
+
* @returns {string} The number in Ukrainian words
|
|
194
|
+
*/
|
|
195
|
+
function toWords (value, options) {
|
|
196
|
+
options = validateOptions(options)
|
|
197
|
+
const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
|
|
198
|
+
|
|
199
|
+
let result = ''
|
|
200
|
+
|
|
201
|
+
if (isNegative) {
|
|
202
|
+
result = NEGATIVE + ' '
|
|
87
203
|
}
|
|
88
204
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
scaleGenders = {
|
|
94
|
-
1: true // thousands are feminine
|
|
205
|
+
result += integerToWords(integerPart, options)
|
|
206
|
+
|
|
207
|
+
if (decimalPart) {
|
|
208
|
+
result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart, options)
|
|
95
209
|
}
|
|
210
|
+
|
|
211
|
+
return result
|
|
96
212
|
}
|
|
213
|
+
|
|
214
|
+
// ============================================================================
|
|
215
|
+
// Exports
|
|
216
|
+
// ============================================================================
|
|
217
|
+
|
|
218
|
+
export { toWords }
|
package/lib/languages/ur.d.ts
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Urdu
|
|
2
|
+
* Converts a numeric value to Urdu words.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* - Urdu script (right-to-left)
|
|
7
|
-
* - Complete word forms for 0-99
|
|
4
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
5
|
+
* @returns {string} The number in Urdu words
|
|
8
6
|
*/
|
|
9
|
-
export
|
|
10
|
-
}
|
|
11
|
-
import { SouthAsianLanguage } from '../classes/south-asian-language.js';
|
|
7
|
+
export function toWords(value: number | string | bigint): string;
|
package/lib/languages/ur.js
CHANGED
|
@@ -1,131 +1,163 @@
|
|
|
1
|
-
import { SouthAsianLanguage } from '../classes/south-asian-language.js'
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
|
-
* Urdu language converter
|
|
2
|
+
* Urdu language converter - Functional Implementation
|
|
3
|
+
*
|
|
4
|
+
* Self-contained converter for South Asian numbering.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* Key features:
|
|
7
7
|
* - Indian numbering system (ہزار, لاکھ, کروڑ)
|
|
8
8
|
* - Urdu script (right-to-left)
|
|
9
|
+
* - 3-2-2 grouping pattern (last 3 digits, then groups of 2)
|
|
9
10
|
* - Complete word forms for 0-99
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
'ستاون',
|
|
76
|
-
'اٹھاون',
|
|
77
|
-
'انسٹھ',
|
|
78
|
-
'ساٹھ',
|
|
79
|
-
'اکسٹھ',
|
|
80
|
-
'باسٹھ',
|
|
81
|
-
'ترسٹھ',
|
|
82
|
-
'چونسٹھ',
|
|
83
|
-
'پینسٹھ',
|
|
84
|
-
'چھیاسٹھ',
|
|
85
|
-
'سڑسٹھ',
|
|
86
|
-
'اڑسٹھ',
|
|
87
|
-
'انہتر',
|
|
88
|
-
'ستر',
|
|
89
|
-
'اکہتر',
|
|
90
|
-
'بہتر',
|
|
91
|
-
'تہتر',
|
|
92
|
-
'چوہتر',
|
|
93
|
-
'پچھتر',
|
|
94
|
-
'چھہتر',
|
|
95
|
-
'ستتر',
|
|
96
|
-
'اٹھہتر',
|
|
97
|
-
'اناسی',
|
|
98
|
-
'اسی',
|
|
99
|
-
'اکیاسی',
|
|
100
|
-
'بیاسی',
|
|
101
|
-
'تریاسی',
|
|
102
|
-
'چوراسی',
|
|
103
|
-
'پچاسی',
|
|
104
|
-
'چھیاسی',
|
|
105
|
-
'ستاسی',
|
|
106
|
-
'اٹھاسی',
|
|
107
|
-
'نواسی',
|
|
108
|
-
'نوے',
|
|
109
|
-
'اکانوے',
|
|
110
|
-
'بانوے',
|
|
111
|
-
'ترانوے',
|
|
112
|
-
'چورانوے',
|
|
113
|
-
'پچانوے',
|
|
114
|
-
'چھیانوے',
|
|
115
|
-
'ستانوے',
|
|
116
|
-
'اٹھانوے',
|
|
117
|
-
'ننانوے'
|
|
118
|
-
]
|
|
119
|
-
|
|
120
|
-
scaleWords = [
|
|
121
|
-
'',
|
|
122
|
-
'ہزار',
|
|
123
|
-
'لاکھ',
|
|
124
|
-
'کروڑ',
|
|
125
|
-
'ارب',
|
|
126
|
-
'کھرب',
|
|
127
|
-
'نیل',
|
|
128
|
-
'پدم',
|
|
129
|
-
'شنکھ'
|
|
130
|
-
]
|
|
12
|
+
|
|
13
|
+
import { parseNumericValue } from '../utils/parse-numeric.js'
|
|
14
|
+
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// Vocabulary
|
|
17
|
+
// ============================================================================
|
|
18
|
+
|
|
19
|
+
const ZERO = 'صفر'
|
|
20
|
+
const NEGATIVE = 'منفی'
|
|
21
|
+
const DECIMAL_SEP = 'اعشاریہ'
|
|
22
|
+
const HUNDRED = 'سو'
|
|
23
|
+
|
|
24
|
+
const BELOW_HUNDRED = [
|
|
25
|
+
'صفر', 'ایک', 'دو', 'تین', 'چار', 'پانچ', 'چھ', 'سات', 'آٹھ', 'نو',
|
|
26
|
+
'دس', 'گیارہ', 'بارہ', 'تیرہ', 'چودہ', 'پندرہ', 'سولہ', 'سترہ', 'اٹھارہ', 'انیس',
|
|
27
|
+
'بیس', 'اکیس', 'بائیس', 'تیئیس', 'چوبیس', 'پچیس', 'چھبیس', 'ستائیس', 'اٹھائیس', 'انتیس',
|
|
28
|
+
'تیس', 'اکتیس', 'بتیس', 'تینتیس', 'چونتیس', 'پینتیس', 'چھتیس', 'سینتیس', 'اڑتیس', 'انتالیس',
|
|
29
|
+
'چالیس', 'اکتالیس', 'بیالیس', 'تینتالیس', 'چوالیس', 'پینتالیس', 'چھالیس', 'سینتالیس', 'اڑتالیس', 'انچاس',
|
|
30
|
+
'پچاس', 'اکاون', 'باون', 'ترپن', 'چون', 'پچپن', 'چھپن', 'ستاون', 'اٹھاون', 'انسٹھ',
|
|
31
|
+
'ساٹھ', 'اکسٹھ', 'باسٹھ', 'ترسٹھ', 'چونسٹھ', 'پینسٹھ', 'چھیاسٹھ', 'سڑسٹھ', 'اڑسٹھ', 'انہتر',
|
|
32
|
+
'ستر', 'اکہتر', 'بہتر', 'تہتر', 'چوہتر', 'پچھتر', 'چھہتر', 'ستتر', 'اٹھہتر', 'اناسی',
|
|
33
|
+
'اسی', 'اکیاسی', 'بیاسی', 'تریاسی', 'چوراسی', 'پچاسی', 'چھیاسی', 'ستاسی', 'اٹھاسی', 'نواسی',
|
|
34
|
+
'نوے', 'اکانوے', 'بانوے', 'ترانوے', 'چورانوے', 'پچانوے', 'چھیانوے', 'ستانوے', 'اٹھانوے', 'ننانوے'
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
// Scale words: index 0 = units (empty), 1 = thousand, 2 = lakh, 3 = crore, etc.
|
|
38
|
+
const SCALE_WORDS = ['', 'ہزار', 'لاکھ', 'کروڑ', 'ارب', 'کھرب', 'نیل', 'پدم', 'شنکھ']
|
|
39
|
+
|
|
40
|
+
// ============================================================================
|
|
41
|
+
// Conversion Functions
|
|
42
|
+
// ============================================================================
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Converts 0-999 to Urdu words.
|
|
46
|
+
*/
|
|
47
|
+
function segmentToWords (n) {
|
|
48
|
+
if (n === 0) return ''
|
|
49
|
+
if (n < 100) return BELOW_HUNDRED[n]
|
|
50
|
+
|
|
51
|
+
const hundreds = Math.trunc(n / 100)
|
|
52
|
+
const remainder = n % 100
|
|
53
|
+
|
|
54
|
+
if (remainder === 0) {
|
|
55
|
+
return BELOW_HUNDRED[hundreds] + ' ' + HUNDRED
|
|
56
|
+
}
|
|
57
|
+
return BELOW_HUNDRED[hundreds] + ' ' + HUNDRED + ' ' + BELOW_HUNDRED[remainder]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Converts a non-negative integer to Urdu words.
|
|
62
|
+
* Uses recursive approach for Indian 3-2-2 grouping pattern.
|
|
63
|
+
*
|
|
64
|
+
* @param {bigint} n - Non-negative integer to convert
|
|
65
|
+
* @returns {string} Urdu words
|
|
66
|
+
*/
|
|
67
|
+
function integerToWords (n) {
|
|
68
|
+
if (n === 0n) return ZERO
|
|
69
|
+
|
|
70
|
+
// Fast path: numbers < 1000 (direct lookup)
|
|
71
|
+
if (n < 1000n) {
|
|
72
|
+
return segmentToWords(Number(n))
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return buildLargeNumberWords(n, 0)
|
|
131
76
|
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Recursively builds words for numbers >= 1000.
|
|
80
|
+
* Indian grouping: first 3 digits, then 2-digit groups.
|
|
81
|
+
*
|
|
82
|
+
* @param {bigint} n - Number to convert
|
|
83
|
+
* @param {number} scale - Current scale index (0=units, 1=thousands, etc.)
|
|
84
|
+
* @returns {string} Urdu words
|
|
85
|
+
*/
|
|
86
|
+
function buildLargeNumberWords (n, scale) {
|
|
87
|
+
if (n === 0n) return ''
|
|
88
|
+
|
|
89
|
+
// Determine divisor: 1000 for first split, 100 for rest
|
|
90
|
+
const divisor = scale === 0 ? 1000n : 100n
|
|
91
|
+
const segment = Number(n % divisor)
|
|
92
|
+
const rest = n / divisor
|
|
93
|
+
|
|
94
|
+
// Build higher segments first (recursive)
|
|
95
|
+
let result = ''
|
|
96
|
+
if (rest > 0n) {
|
|
97
|
+
result = buildLargeNumberWords(rest, scale + 1)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Add current segment
|
|
101
|
+
if (segment > 0) {
|
|
102
|
+
if (result) result += ' '
|
|
103
|
+
|
|
104
|
+
if (scale === 0) {
|
|
105
|
+
// Units segment (0-999)
|
|
106
|
+
result += segmentToWords(segment)
|
|
107
|
+
} else {
|
|
108
|
+
// Scale segments (0-99)
|
|
109
|
+
result += BELOW_HUNDRED[segment] + ' ' + SCALE_WORDS[scale]
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return result
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function decimalPartToWords (decimalPart) {
|
|
117
|
+
let result = ''
|
|
118
|
+
let i = 0
|
|
119
|
+
|
|
120
|
+
while (i < decimalPart.length && decimalPart[i] === '0') {
|
|
121
|
+
if (result) result += ' '
|
|
122
|
+
result += ZERO
|
|
123
|
+
i++
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const remainder = decimalPart.slice(i)
|
|
127
|
+
if (remainder) {
|
|
128
|
+
if (result) result += ' '
|
|
129
|
+
result += integerToWords(BigInt(remainder))
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return result
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Converts a numeric value to Urdu words.
|
|
137
|
+
*
|
|
138
|
+
* @param {number | string | bigint} value - The numeric value to convert
|
|
139
|
+
* @returns {string} The number in Urdu words
|
|
140
|
+
*/
|
|
141
|
+
function toWords (value) {
|
|
142
|
+
const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
|
|
143
|
+
|
|
144
|
+
let result = ''
|
|
145
|
+
|
|
146
|
+
if (isNegative) {
|
|
147
|
+
result = NEGATIVE + ' '
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
result += integerToWords(integerPart)
|
|
151
|
+
|
|
152
|
+
if (decimalPart) {
|
|
153
|
+
result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return result
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// ============================================================================
|
|
160
|
+
// Exports
|
|
161
|
+
// ============================================================================
|
|
162
|
+
|
|
163
|
+
export { toWords }
|