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
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Base class for Slavic and related languages with complex pluralization.
|
|
3
|
-
*
|
|
4
|
-
* This class provides a reusable implementation for languages that share:
|
|
5
|
-
* - Three-form pluralization (singular/few/many)
|
|
6
|
-
* - Gender-aware number forms (masculine/feminine for 1-9)
|
|
7
|
-
* - Hundreds, tens, ones decomposition pattern
|
|
8
|
-
* - Segment-based large number handling (thousands, millions, etc.)
|
|
9
|
-
* - Inherits decimal handling from AbstractLanguage (supports both grouped and
|
|
10
|
-
* per-digit modes via the `usePerDigitDecimals` class property).
|
|
11
|
-
*
|
|
12
|
-
* Used by: Russian (ru), Czech (cs), Polish (pl), Ukrainian (uk), Serbian (sr-Latn),
|
|
13
|
-
* Croatian (hr), Lithuanian (lt), Latvian (lv), Hebrew (he), and Biblical Hebrew (hbo).
|
|
14
|
-
*
|
|
15
|
-
* Subclasses MUST define these properties with language-specific vocabulary:
|
|
16
|
-
* - `onesWords` - Object mapping 1-9 to masculine forms (or default forms)
|
|
17
|
-
* - `onesFeminineWords` - Object mapping 1-9 to feminine forms (if gender distinction exists)
|
|
18
|
-
* - `teensWords` - Object mapping 0-9 to teen numbers (10-19)
|
|
19
|
-
* - `twentiesWords` - Object mapping 2-9 to tens (20-90)
|
|
20
|
-
* - `hundredsWords` - Object mapping 1-9 to hundreds (100-900) or special hundreds handling
|
|
21
|
-
* - `pluralForms` - Object mapping segment indices to [singular, few, many] plural forms
|
|
22
|
-
*
|
|
23
|
-
* Optional properties:
|
|
24
|
-
* - `scaleGenders` - Object mapping segment indices to boolean (true = feminine scale word)
|
|
25
|
-
* If not defined, defaults to thousands (index 1) being feminine, others masculine.
|
|
26
|
-
*
|
|
27
|
-
* @abstract
|
|
28
|
-
* @extends AbstractLanguage
|
|
29
|
-
*/
|
|
30
|
-
export class SlavicLanguage extends AbstractLanguage {
|
|
31
|
-
/**
|
|
32
|
-
* Constructs a SlavicLanguage instance with optional configuration.
|
|
33
|
-
*
|
|
34
|
-
* @param {Object} [options] Configuration options.
|
|
35
|
-
* @param {('masculine'|'feminine')} [options.gender='masculine'] Grammatical gender for number forms.
|
|
36
|
-
*/
|
|
37
|
-
constructor(options?: {
|
|
38
|
-
gender?: "feminine" | "masculine" | undefined;
|
|
39
|
-
});
|
|
40
|
-
/**
|
|
41
|
-
* Masculine forms for digits 1-9 (or default forms if no gender distinction).
|
|
42
|
-
*
|
|
43
|
-
* @type {Object.<number, string>}
|
|
44
|
-
*/
|
|
45
|
-
onesWords: {
|
|
46
|
-
[x: number]: string;
|
|
47
|
-
};
|
|
48
|
-
/**
|
|
49
|
-
* Feminine forms for digits 1-9 (if language has gender distinction).
|
|
50
|
-
*
|
|
51
|
-
* @type {Object.<number, string>}
|
|
52
|
-
*/
|
|
53
|
-
onesFeminineWords: {
|
|
54
|
-
[x: number]: string;
|
|
55
|
-
};
|
|
56
|
-
/**
|
|
57
|
-
* Words for teen numbers (10-19).
|
|
58
|
-
*
|
|
59
|
-
* @type {Object.<number, string>}
|
|
60
|
-
*/
|
|
61
|
-
teensWords: {
|
|
62
|
-
[x: number]: string;
|
|
63
|
-
};
|
|
64
|
-
/**
|
|
65
|
-
* Words for multiples of ten (20, 30, 40, etc.).
|
|
66
|
-
*
|
|
67
|
-
* @type {Object.<number, string>}
|
|
68
|
-
*/
|
|
69
|
-
twentiesWords: {
|
|
70
|
-
[x: number]: string;
|
|
71
|
-
};
|
|
72
|
-
/**
|
|
73
|
-
* Words for hundreds (100, 200, 300, etc.) or special hundreds handling.
|
|
74
|
-
*
|
|
75
|
-
* @type {Object.<number, string>}
|
|
76
|
-
*/
|
|
77
|
-
hundredsWords: {
|
|
78
|
-
[x: number]: string;
|
|
79
|
-
};
|
|
80
|
-
/**
|
|
81
|
-
* Plural forms for scale words (thousands, millions, billions, etc.).
|
|
82
|
-
* Maps segment indices to [singular, few, many] forms.
|
|
83
|
-
*
|
|
84
|
-
* @type {Object.<number, string[]>}
|
|
85
|
-
*/
|
|
86
|
-
pluralForms: {
|
|
87
|
-
[x: number]: string[];
|
|
88
|
-
};
|
|
89
|
-
/**
|
|
90
|
-
* Gender of each scale word.
|
|
91
|
-
* Maps segment indices to boolean: true = feminine, false = masculine.
|
|
92
|
-
* Default is empty (all masculine). Languages with feminine thousands
|
|
93
|
-
* (Russian, Ukrainian, Serbian, Croatian) should set `{ 1: true }`.
|
|
94
|
-
*
|
|
95
|
-
* @type {Object.<number, boolean>}
|
|
96
|
-
*/
|
|
97
|
-
scaleGenders: {
|
|
98
|
-
[x: number]: boolean;
|
|
99
|
-
};
|
|
100
|
-
/**
|
|
101
|
-
* Whether to omit "one" before scale words (e.g., "thousand" instead of "one thousand").
|
|
102
|
-
* When true, 1000 becomes "tysiąc" (Polish) instead of "jeden tysiąc".
|
|
103
|
-
* Used by Polish, Czech, and similar languages.
|
|
104
|
-
*
|
|
105
|
-
* @type {boolean}
|
|
106
|
-
*/
|
|
107
|
-
omitOneBeforeScale: boolean;
|
|
108
|
-
/**
|
|
109
|
-
* Splits a number string into segments of specified size from right to left.
|
|
110
|
-
*
|
|
111
|
-
* Example: splitToSegments('1234567', 3) => [1n, 234n, 567n]
|
|
112
|
-
* This represents: 1 million + 234 thousand + 567 ones
|
|
113
|
-
*
|
|
114
|
-
* @param {string} numberString The number as a string.
|
|
115
|
-
* @param {number} segmentSize Segment size (typically 3 for thousands grouping).
|
|
116
|
-
* @returns {bigint[]} Array of BigInt segments from highest to lowest scale.
|
|
117
|
-
*/
|
|
118
|
-
splitToSegments(numberString: string, segmentSize: number): bigint[];
|
|
119
|
-
/**
|
|
120
|
-
* Extracts individual digits from a number (units, tens, hundreds).
|
|
121
|
-
*
|
|
122
|
-
* Returns digits in reverse order: [ones, tens, hundreds]
|
|
123
|
-
* Example: 456 => [6n, 5n, 4n]
|
|
124
|
-
*
|
|
125
|
-
* @param {bigint} value The number to extract digits from (0-999).
|
|
126
|
-
* @returns {bigint[]} Array of [ones, tens, hundreds] as BigInts.
|
|
127
|
-
*/
|
|
128
|
-
extractDigits(value: bigint): bigint[];
|
|
129
|
-
/**
|
|
130
|
-
* Selects the correct plural form based on Slavic pluralization rules.
|
|
131
|
-
*
|
|
132
|
-
* Slavic languages typically use three forms:
|
|
133
|
-
* - Form 0 (singular): numbers ending in 1, except 11 (1, 21, 31, 101...)
|
|
134
|
-
* - Form 1 (few): numbers ending in 2-4, except 12-14 (2-4, 22-24, 32-34...)
|
|
135
|
-
* - Form 2 (many): all other numbers (0, 5-20, 25-30, 100, 111-119...)
|
|
136
|
-
*
|
|
137
|
-
* Examples using Russian тысяча (thousand):
|
|
138
|
-
* - 1, 21, 31... ⇒ тысяча (form 0, singular)
|
|
139
|
-
* - 2-4, 22-24, 32-34... ⇒ тысячи (form 1, few)
|
|
140
|
-
* - 0, 5-20, 25-30, 100... ⇒ тысяч (form 2, many)
|
|
141
|
-
*
|
|
142
|
-
* @param {bigint} number The number to check.
|
|
143
|
-
* @param {string[]} pluralForms Array of [singular, few, many] forms.
|
|
144
|
-
* @returns {string} The appropriate form for the number.
|
|
145
|
-
*/
|
|
146
|
-
pluralize(number: bigint, pluralForms: string[]): string;
|
|
147
|
-
}
|
|
148
|
-
import { AbstractLanguage } from './abstract-language.js';
|
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
import { AbstractLanguage } from './abstract-language.js'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Base class for Slavic and related languages with complex pluralization.
|
|
5
|
-
*
|
|
6
|
-
* This class provides a reusable implementation for languages that share:
|
|
7
|
-
* - Three-form pluralization (singular/few/many)
|
|
8
|
-
* - Gender-aware number forms (masculine/feminine for 1-9)
|
|
9
|
-
* - Hundreds, tens, ones decomposition pattern
|
|
10
|
-
* - Segment-based large number handling (thousands, millions, etc.)
|
|
11
|
-
* - Inherits decimal handling from AbstractLanguage (supports both grouped and
|
|
12
|
-
* per-digit modes via the `usePerDigitDecimals` class property).
|
|
13
|
-
*
|
|
14
|
-
* Used by: Russian (ru), Czech (cs), Polish (pl), Ukrainian (uk), Serbian (sr-Latn),
|
|
15
|
-
* Croatian (hr), Lithuanian (lt), Latvian (lv), Hebrew (he), and Biblical Hebrew (hbo).
|
|
16
|
-
*
|
|
17
|
-
* Subclasses MUST define these properties with language-specific vocabulary:
|
|
18
|
-
* - `onesWords` - Object mapping 1-9 to masculine forms (or default forms)
|
|
19
|
-
* - `onesFeminineWords` - Object mapping 1-9 to feminine forms (if gender distinction exists)
|
|
20
|
-
* - `teensWords` - Object mapping 0-9 to teen numbers (10-19)
|
|
21
|
-
* - `twentiesWords` - Object mapping 2-9 to tens (20-90)
|
|
22
|
-
* - `hundredsWords` - Object mapping 1-9 to hundreds (100-900) or special hundreds handling
|
|
23
|
-
* - `pluralForms` - Object mapping segment indices to [singular, few, many] plural forms
|
|
24
|
-
*
|
|
25
|
-
* Optional properties:
|
|
26
|
-
* - `scaleGenders` - Object mapping segment indices to boolean (true = feminine scale word)
|
|
27
|
-
* If not defined, defaults to thousands (index 1) being feminine, others masculine.
|
|
28
|
-
*
|
|
29
|
-
* @abstract
|
|
30
|
-
* @extends AbstractLanguage
|
|
31
|
-
*/
|
|
32
|
-
export class SlavicLanguage extends AbstractLanguage {
|
|
33
|
-
// ============================================================================
|
|
34
|
-
// Required Properties (subclasses must define)
|
|
35
|
-
// ============================================================================
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Masculine forms for digits 1-9 (or default forms if no gender distinction).
|
|
39
|
-
*
|
|
40
|
-
* @type {Object.<number, string>}
|
|
41
|
-
*/
|
|
42
|
-
onesWords = {}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Feminine forms for digits 1-9 (if language has gender distinction).
|
|
46
|
-
*
|
|
47
|
-
* @type {Object.<number, string>}
|
|
48
|
-
*/
|
|
49
|
-
onesFeminineWords = {}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Words for teen numbers (10-19).
|
|
53
|
-
*
|
|
54
|
-
* @type {Object.<number, string>}
|
|
55
|
-
*/
|
|
56
|
-
teensWords = {}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Words for multiples of ten (20, 30, 40, etc.).
|
|
60
|
-
*
|
|
61
|
-
* @type {Object.<number, string>}
|
|
62
|
-
*/
|
|
63
|
-
twentiesWords = {}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Words for hundreds (100, 200, 300, etc.) or special hundreds handling.
|
|
67
|
-
*
|
|
68
|
-
* @type {Object.<number, string>}
|
|
69
|
-
*/
|
|
70
|
-
hundredsWords = {}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Plural forms for scale words (thousands, millions, billions, etc.).
|
|
74
|
-
* Maps segment indices to [singular, few, many] forms.
|
|
75
|
-
*
|
|
76
|
-
* @type {Object.<number, string[]>}
|
|
77
|
-
*/
|
|
78
|
-
pluralForms = {}
|
|
79
|
-
|
|
80
|
-
// ============================================================================
|
|
81
|
-
// Optional Properties (subclasses may override)
|
|
82
|
-
// ============================================================================
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Gender of each scale word.
|
|
86
|
-
* Maps segment indices to boolean: true = feminine, false = masculine.
|
|
87
|
-
* Default is empty (all masculine). Languages with feminine thousands
|
|
88
|
-
* (Russian, Ukrainian, Serbian, Croatian) should set `{ 1: true }`.
|
|
89
|
-
*
|
|
90
|
-
* @type {Object.<number, boolean>}
|
|
91
|
-
*/
|
|
92
|
-
scaleGenders = {}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Whether to omit "one" before scale words (e.g., "thousand" instead of "one thousand").
|
|
96
|
-
* When true, 1000 becomes "tysiąc" (Polish) instead of "jeden tysiąc".
|
|
97
|
-
* Used by Polish, Czech, and similar languages.
|
|
98
|
-
*
|
|
99
|
-
* @type {boolean}
|
|
100
|
-
*/
|
|
101
|
-
omitOneBeforeScale = false
|
|
102
|
-
|
|
103
|
-
// ============================================================================
|
|
104
|
-
// Constructor
|
|
105
|
-
// ============================================================================
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Constructs a SlavicLanguage instance with optional configuration.
|
|
109
|
-
*
|
|
110
|
-
* @param {Object} [options] Configuration options.
|
|
111
|
-
* @param {('masculine'|'feminine')} [options.gender='masculine'] Grammatical gender for number forms.
|
|
112
|
-
*/
|
|
113
|
-
constructor (options = {}) {
|
|
114
|
-
super()
|
|
115
|
-
|
|
116
|
-
this.setOptions({
|
|
117
|
-
gender: 'masculine'
|
|
118
|
-
}, options)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// ============================================================================
|
|
122
|
-
// Public Methods
|
|
123
|
-
// ============================================================================
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Converts an integer to its word representation.
|
|
127
|
-
*
|
|
128
|
-
* This method implements the Slavic number construction algorithm:
|
|
129
|
-
* 1. Split number into 3-digit segments from right to left (567, 234, 1 for 1,234,567)
|
|
130
|
-
* 2. For each segment (processing left to right): convert hundreds, tens, ones
|
|
131
|
-
* 3. Apply gender rules: feminine forms for thousands segment or when feminine=true
|
|
132
|
-
* 4. Add appropriate pluralized scale word (thousand/million/billion/etc.)
|
|
133
|
-
* 5. Join all parts with spaces
|
|
134
|
-
*
|
|
135
|
-
* @param {bigint} integerPart The integer to convert (non-negative).
|
|
136
|
-
* @returns {string} The number in words.
|
|
137
|
-
*/
|
|
138
|
-
integerToWords (integerPart) {
|
|
139
|
-
if (integerPart === 0n) {
|
|
140
|
-
return this.zeroWord
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const words = []
|
|
144
|
-
const segments = this.splitToSegments(integerPart.toString(), 3)
|
|
145
|
-
let segmentIndex = segments.length
|
|
146
|
-
|
|
147
|
-
for (const segmentValue of segments) {
|
|
148
|
-
segmentIndex = segmentIndex - 1
|
|
149
|
-
|
|
150
|
-
if (segmentValue === 0n) {
|
|
151
|
-
continue
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const [onesDigit, tensDigit, hundredsDigit] = this.extractDigits(segmentValue)
|
|
155
|
-
|
|
156
|
-
if (hundredsDigit > 0n) {
|
|
157
|
-
words.push(this.hundredsWords[hundredsDigit])
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (tensDigit > 1n) {
|
|
161
|
-
words.push(this.twentiesWords[tensDigit])
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Handle teens (10-19) or ones (1-9)
|
|
165
|
-
if (tensDigit === 1n) {
|
|
166
|
-
// Teens: use teensWords array directly
|
|
167
|
-
words.push(this.teensWords[onesDigit])
|
|
168
|
-
} else if (onesDigit > 0n) {
|
|
169
|
-
// Skip "one" before scale words if omitOneBeforeScale is set
|
|
170
|
-
// e.g., Polish says "tysiąc" not "jeden tysiąc" for 1000
|
|
171
|
-
const shouldOmitOne = this.omitOneBeforeScale && segmentIndex > 0 && segmentValue === 1n
|
|
172
|
-
|
|
173
|
-
if (!shouldOmitOne) {
|
|
174
|
-
// Determine if feminine forms should be used:
|
|
175
|
-
// 1. Check scaleGenders for this segment index (e.g., thousands = index 1)
|
|
176
|
-
// 2. Also use feminine if user requested gender='feminine' for the ones segment
|
|
177
|
-
const isScaleFeminine = this.scaleGenders[segmentIndex] === true
|
|
178
|
-
const isFeminine = isScaleFeminine || (this.options.gender === 'feminine' && segmentIndex === 0)
|
|
179
|
-
const onesArray = isFeminine ? this.onesFeminineWords : this.onesWords
|
|
180
|
-
words.push(onesArray[onesDigit])
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Add power word (thousand, million, etc.) with proper pluralization
|
|
185
|
-
if (segmentIndex > 0) {
|
|
186
|
-
words.push(this.pluralize(segmentValue, this.pluralForms[segmentIndex]))
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return words.join(' ')
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// ============================================================================
|
|
194
|
-
// Protected Methods (subclasses may call or override)
|
|
195
|
-
// ============================================================================
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Splits a number string into segments of specified size from right to left.
|
|
199
|
-
*
|
|
200
|
-
* Example: splitToSegments('1234567', 3) => [1n, 234n, 567n]
|
|
201
|
-
* This represents: 1 million + 234 thousand + 567 ones
|
|
202
|
-
*
|
|
203
|
-
* @param {string} numberString The number as a string.
|
|
204
|
-
* @param {number} segmentSize Segment size (typically 3 for thousands grouping).
|
|
205
|
-
* @returns {bigint[]} Array of BigInt segments from highest to lowest scale.
|
|
206
|
-
*/
|
|
207
|
-
splitToSegments (numberString, segmentSize) {
|
|
208
|
-
const segments = []
|
|
209
|
-
const stringLength = numberString.length
|
|
210
|
-
|
|
211
|
-
if (stringLength > segmentSize) {
|
|
212
|
-
const remainderLength = stringLength % segmentSize
|
|
213
|
-
|
|
214
|
-
if (remainderLength > 0) {
|
|
215
|
-
segments.push(BigInt(numberString.slice(0, remainderLength)))
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
for (let i = remainderLength; i < stringLength; i += segmentSize) {
|
|
219
|
-
segments.push(BigInt(numberString.slice(i, i + segmentSize)))
|
|
220
|
-
}
|
|
221
|
-
} else {
|
|
222
|
-
segments.push(BigInt(numberString))
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return segments
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Extracts individual digits from a number (units, tens, hundreds).
|
|
230
|
-
*
|
|
231
|
-
* Returns digits in reverse order: [ones, tens, hundreds]
|
|
232
|
-
* Example: 456 => [6n, 5n, 4n]
|
|
233
|
-
*
|
|
234
|
-
* @param {bigint} value The number to extract digits from (0-999).
|
|
235
|
-
* @returns {bigint[]} Array of [ones, tens, hundreds] as BigInts.
|
|
236
|
-
*/
|
|
237
|
-
extractDigits (value) {
|
|
238
|
-
// Direct BigInt arithmetic is faster than string manipulation
|
|
239
|
-
const onesPlace = value % 10n
|
|
240
|
-
const tensPlace = (value / 10n) % 10n
|
|
241
|
-
const hundredsPlace = value / 100n
|
|
242
|
-
return [onesPlace, tensPlace, hundredsPlace]
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Selects the correct plural form based on Slavic pluralization rules.
|
|
247
|
-
*
|
|
248
|
-
* Slavic languages typically use three forms:
|
|
249
|
-
* - Form 0 (singular): numbers ending in 1, except 11 (1, 21, 31, 101...)
|
|
250
|
-
* - Form 1 (few): numbers ending in 2-4, except 12-14 (2-4, 22-24, 32-34...)
|
|
251
|
-
* - Form 2 (many): all other numbers (0, 5-20, 25-30, 100, 111-119...)
|
|
252
|
-
*
|
|
253
|
-
* Examples using Russian тысяча (thousand):
|
|
254
|
-
* - 1, 21, 31... ⇒ тысяча (form 0, singular)
|
|
255
|
-
* - 2-4, 22-24, 32-34... ⇒ тысячи (form 1, few)
|
|
256
|
-
* - 0, 5-20, 25-30, 100... ⇒ тысяч (form 2, many)
|
|
257
|
-
*
|
|
258
|
-
* @param {bigint} number The number to check.
|
|
259
|
-
* @param {string[]} pluralForms Array of [singular, few, many] forms.
|
|
260
|
-
* @returns {string} The appropriate form for the number.
|
|
261
|
-
*/
|
|
262
|
-
pluralize (number, pluralForms) {
|
|
263
|
-
const remainder100 = number % 100n
|
|
264
|
-
const remainder10 = number % 10n
|
|
265
|
-
|
|
266
|
-
// Check if in 11-19 range (special case)
|
|
267
|
-
if (remainder100 >= 10n && remainder100 <= 20n) {
|
|
268
|
-
return pluralForms[2] // Always use "many" form for 11-20
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
if (remainder10 === 1n) {
|
|
272
|
-
return pluralForms[0] // Singular
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
if (remainder10 >= 2n && remainder10 <= 4n) {
|
|
276
|
-
return pluralForms[1] // Few (2-4)
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
return pluralForms[2] // Many
|
|
280
|
-
}
|
|
281
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Base class for South Asian languages with shared grouping patterns.
|
|
3
|
-
*
|
|
4
|
-
* This class provides a reusable implementation for South Asian languages that share:
|
|
5
|
-
* - Indian-style number grouping: last 3 digits, then 2-2 (1,23,45,67,89)
|
|
6
|
-
* - Lakh (100,000), Crore (10,000,000), Arab (1,000,000,000) scale words
|
|
7
|
-
* - Standard negative and decimal handling (inherits AbstractLanguage decimal logic,
|
|
8
|
-
* including `usePerDigitDecimals` support when set by subclasses)
|
|
9
|
-
*
|
|
10
|
-
* Used by: Hindi (hi), Bengali (bn), Urdu (ur), Punjabi (pa), Marathi (mr), Gujarati (gu), Kannada (kn)
|
|
11
|
-
*
|
|
12
|
-
* Subclasses MUST define language-specific vocabulary via class properties:
|
|
13
|
-
* - `belowHundredWords` array with digit and teen words (0-99)
|
|
14
|
-
* - `hundredWord` string used inside `segmentToWords`
|
|
15
|
-
* - `scaleWords` array with grouping words (hazaar, lakh, crore, etc.) indexed by grouping level
|
|
16
|
-
* - `negativeWord`, `decimalSeparatorWord`, `zeroWord`, `wordSeparator`
|
|
17
|
-
*
|
|
18
|
-
* @abstract
|
|
19
|
-
* @extends AbstractLanguage
|
|
20
|
-
*/
|
|
21
|
-
export class SouthAsianLanguage extends AbstractLanguage {
|
|
22
|
-
/**
|
|
23
|
-
* Array of words for numbers 0-99 (digits and teens).
|
|
24
|
-
* Index directly: belowHundredWords[0] through belowHundredWords[99].
|
|
25
|
-
* @type {Array<string>}
|
|
26
|
-
*/
|
|
27
|
-
belowHundredWords: Array<string>;
|
|
28
|
-
/**
|
|
29
|
-
* Word for "hundred" in the language (e.g., 'सौ' in Hindi, 'শত' in Bengali).
|
|
30
|
-
* Used to construct hundreds (e.g., "1 hundred", "2 hundred").
|
|
31
|
-
* @type {string}
|
|
32
|
-
*/
|
|
33
|
-
hundredWord: string;
|
|
34
|
-
/**
|
|
35
|
-
* Array of scale words for Indian-style grouping (hazaar, lakh, crore, arab, etc.).
|
|
36
|
-
* Index 0 contains empty string (ones place has no scale word).
|
|
37
|
-
* Index 1 is for thousands, Index 2 for lakhs, Index 3 for crores, etc.
|
|
38
|
-
* @type {Array<string>}
|
|
39
|
-
*/
|
|
40
|
-
scaleWords: Array<string>;
|
|
41
|
-
/**
|
|
42
|
-
* Splits a number into Indian numbering system segments.
|
|
43
|
-
*
|
|
44
|
-
* The Indian system segments differently than Western (3-3-3) systems:
|
|
45
|
-
* - First segment (rightmost): Up to 3 digits (ones, tens, hundreds)
|
|
46
|
-
* - Subsequent segments: Exactly 2 digits each (thousands, lakhs, crores, etc.)
|
|
47
|
-
*
|
|
48
|
-
* This creates the familiar Indian comma pattern: 1,23,45,67,890
|
|
49
|
-
*
|
|
50
|
-
* @protected
|
|
51
|
-
* @param {bigint} integerPart The integer to split into segments.
|
|
52
|
-
* @returns {Array<number>} Array of segments from most significant to least significant.
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
* // splitToSegments(1234567n) → [12, 34, 567]
|
|
56
|
-
* // Reads as: 12 lakhs, 34 thousands, 567 units
|
|
57
|
-
* // splitToSegments(98765432n) → [9, 87, 65, 432]
|
|
58
|
-
* // Reads as: 9 crores, 87 lakhs, 65 thousands, 432 units
|
|
59
|
-
*/
|
|
60
|
-
protected splitToSegments(integerPart: bigint): Array<number>;
|
|
61
|
-
/**
|
|
62
|
-
* Converts a segment (0-999) to words.
|
|
63
|
-
*
|
|
64
|
-
* @protected
|
|
65
|
-
* @param {number} segmentValue Value between 0 and 999.
|
|
66
|
-
* @returns {string} Language-specific word representation.
|
|
67
|
-
*/
|
|
68
|
-
protected segmentToWords(segmentValue: number): string;
|
|
69
|
-
}
|
|
70
|
-
import { AbstractLanguage } from './abstract-language.js';
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import { AbstractLanguage } from './abstract-language.js'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Base class for South Asian languages with shared grouping patterns.
|
|
5
|
-
*
|
|
6
|
-
* This class provides a reusable implementation for South Asian languages that share:
|
|
7
|
-
* - Indian-style number grouping: last 3 digits, then 2-2 (1,23,45,67,89)
|
|
8
|
-
* - Lakh (100,000), Crore (10,000,000), Arab (1,000,000,000) scale words
|
|
9
|
-
* - Standard negative and decimal handling (inherits AbstractLanguage decimal logic,
|
|
10
|
-
* including `usePerDigitDecimals` support when set by subclasses)
|
|
11
|
-
*
|
|
12
|
-
* Used by: Hindi (hi), Bengali (bn), Urdu (ur), Punjabi (pa), Marathi (mr), Gujarati (gu), Kannada (kn)
|
|
13
|
-
*
|
|
14
|
-
* Subclasses MUST define language-specific vocabulary via class properties:
|
|
15
|
-
* - `belowHundredWords` array with digit and teen words (0-99)
|
|
16
|
-
* - `hundredWord` string used inside `segmentToWords`
|
|
17
|
-
* - `scaleWords` array with grouping words (hazaar, lakh, crore, etc.) indexed by grouping level
|
|
18
|
-
* - `negativeWord`, `decimalSeparatorWord`, `zeroWord`, `wordSeparator`
|
|
19
|
-
*
|
|
20
|
-
* @abstract
|
|
21
|
-
* @extends AbstractLanguage
|
|
22
|
-
*/
|
|
23
|
-
export class SouthAsianLanguage extends AbstractLanguage {
|
|
24
|
-
// ============================================================================
|
|
25
|
-
// Required Properties (subclasses must define)
|
|
26
|
-
// ============================================================================
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Array of words for numbers 0-99 (digits and teens).
|
|
30
|
-
* Index directly: belowHundredWords[0] through belowHundredWords[99].
|
|
31
|
-
* @type {Array<string>}
|
|
32
|
-
*/
|
|
33
|
-
belowHundredWords
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Word for "hundred" in the language (e.g., 'सौ' in Hindi, 'শত' in Bengali).
|
|
37
|
-
* Used to construct hundreds (e.g., "1 hundred", "2 hundred").
|
|
38
|
-
* @type {string}
|
|
39
|
-
*/
|
|
40
|
-
hundredWord
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Array of scale words for Indian-style grouping (hazaar, lakh, crore, arab, etc.).
|
|
44
|
-
* Index 0 contains empty string (ones place has no scale word).
|
|
45
|
-
* Index 1 is for thousands, Index 2 for lakhs, Index 3 for crores, etc.
|
|
46
|
-
* @type {Array<string>}
|
|
47
|
-
*/
|
|
48
|
-
scaleWords
|
|
49
|
-
|
|
50
|
-
// ============================================================================
|
|
51
|
-
// Protected Methods (subclasses may call or override)
|
|
52
|
-
// ============================================================================
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Splits a number into Indian numbering system segments.
|
|
56
|
-
*
|
|
57
|
-
* The Indian system segments differently than Western (3-3-3) systems:
|
|
58
|
-
* - First segment (rightmost): Up to 3 digits (ones, tens, hundreds)
|
|
59
|
-
* - Subsequent segments: Exactly 2 digits each (thousands, lakhs, crores, etc.)
|
|
60
|
-
*
|
|
61
|
-
* This creates the familiar Indian comma pattern: 1,23,45,67,890
|
|
62
|
-
*
|
|
63
|
-
* @protected
|
|
64
|
-
* @param {bigint} integerPart The integer to split into segments.
|
|
65
|
-
* @returns {Array<number>} Array of segments from most significant to least significant.
|
|
66
|
-
*
|
|
67
|
-
* @example
|
|
68
|
-
* // splitToSegments(1234567n) → [12, 34, 567]
|
|
69
|
-
* // Reads as: 12 lakhs, 34 thousands, 567 units
|
|
70
|
-
* // splitToSegments(98765432n) → [9, 87, 65, 432]
|
|
71
|
-
* // Reads as: 9 crores, 87 lakhs, 65 thousands, 432 units
|
|
72
|
-
*/
|
|
73
|
-
splitToSegments (integerPart) {
|
|
74
|
-
const numStr = integerPart.toString()
|
|
75
|
-
|
|
76
|
-
if (numStr.length <= 3) {
|
|
77
|
-
return [Number(numStr)]
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const segments = []
|
|
81
|
-
const last3 = numStr.slice(-3)
|
|
82
|
-
segments.unshift(Number(last3))
|
|
83
|
-
|
|
84
|
-
let remaining = numStr.slice(0, -3)
|
|
85
|
-
while (remaining.length > 0) {
|
|
86
|
-
const segment = remaining.slice(-2)
|
|
87
|
-
segments.unshift(Number(segment))
|
|
88
|
-
remaining = remaining.slice(0, -2)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return segments
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Converts a segment (0-999) to words.
|
|
96
|
-
*
|
|
97
|
-
* @protected
|
|
98
|
-
* @param {number} segmentValue Value between 0 and 999.
|
|
99
|
-
* @returns {string} Language-specific word representation.
|
|
100
|
-
*/
|
|
101
|
-
segmentToWords (segmentValue) {
|
|
102
|
-
if (segmentValue === 0) return ''
|
|
103
|
-
if (segmentValue < 100) return this.belowHundredWords[segmentValue]
|
|
104
|
-
|
|
105
|
-
const hundreds = Math.trunc(segmentValue / 100)
|
|
106
|
-
const remainder = segmentValue % 100
|
|
107
|
-
const parts = []
|
|
108
|
-
|
|
109
|
-
if (hundreds === 1) {
|
|
110
|
-
parts.push(this.belowHundredWords[1] + ' ' + this.hundredWord)
|
|
111
|
-
} else {
|
|
112
|
-
parts.push(this.belowHundredWords[hundreds] + ' ' + this.hundredWord)
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (remainder > 0) {
|
|
116
|
-
parts.push(this.belowHundredWords[remainder])
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return parts.join(' ')
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// ============================================================================
|
|
123
|
-
// Public Methods
|
|
124
|
-
// ============================================================================
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Converts integer to cardinal words using South Asian grouping.
|
|
128
|
-
*
|
|
129
|
-
* @param {bigint} integerPart Number to convert.
|
|
130
|
-
* @returns {string} Cardinal representation.
|
|
131
|
-
*/
|
|
132
|
-
integerToWords (integerPart) {
|
|
133
|
-
if (integerPart === 0n) {
|
|
134
|
-
return this.zeroWord
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const segments = this.splitToSegments(integerPart)
|
|
138
|
-
const segmentCount = segments.length
|
|
139
|
-
const words = []
|
|
140
|
-
|
|
141
|
-
for (let i = 0; i < segmentCount; i++) {
|
|
142
|
-
const segmentValue = segments[i]
|
|
143
|
-
if (segmentValue === 0) continue
|
|
144
|
-
|
|
145
|
-
const scaleIndex = segmentCount - i - 1
|
|
146
|
-
words.push(this.segmentToWords(segmentValue))
|
|
147
|
-
if (scaleIndex > 0 && this.scaleWords[scaleIndex]) {
|
|
148
|
-
words.push(this.scaleWords[scaleIndex])
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return words.join(' ').trim()
|
|
153
|
-
}
|
|
154
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Base class for Turkic languages with shared grammar patterns.
|
|
3
|
-
*
|
|
4
|
-
* This class provides a reusable implementation for Turkic languages that share:
|
|
5
|
-
* - Space-separated number combinations
|
|
6
|
-
* - Implicit 'bir' (one) before hundreds and thousands
|
|
7
|
-
* - Simple multiplication/addition logic
|
|
8
|
-
* - Consistent magnitude handling
|
|
9
|
-
* - Inherits decimal handling from AbstractLanguage via GreedyScaleLanguage
|
|
10
|
-
* (supports both grouped and per-digit modes via the `usePerDigitDecimals` class property).
|
|
11
|
-
*
|
|
12
|
-
* Used by: Turkish (TR), Azerbaijani (AZ)
|
|
13
|
-
*
|
|
14
|
-
* Subclasses MUST define (from GreedyScaleLanguage requirements):
|
|
15
|
-
* - `scaleWords` array of [value, word] tuples as a class property (ordered descending by value).
|
|
16
|
-
* Optionally, language-specific class properties (e.g., `negativeWord`, `zeroWord`, `decimalSeparatorWord`, `wordSeparator`).
|
|
17
|
-
*
|
|
18
|
-
* TurkicLanguage provides a default `combineWordSets()` implementation; subclasses may override
|
|
19
|
-
* if specialized combine logic is needed (unlikely for Turkic languages).
|
|
20
|
-
*
|
|
21
|
-
* @abstract
|
|
22
|
-
* @extends GreedyScaleLanguage
|
|
23
|
-
*/
|
|
24
|
-
export class TurkicLanguage extends GreedyScaleLanguage {
|
|
25
|
-
}
|
|
26
|
-
import { GreedyScaleLanguage } from './greedy-scale-language.js';
|