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.
Files changed (335) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/README.md +86 -188
  3. package/dist/languages/am-Latn.js +3 -0
  4. package/dist/languages/am-Latn.js.map +1 -0
  5. package/dist/languages/am.js +3 -0
  6. package/dist/languages/am.js.map +1 -0
  7. package/dist/languages/ar.js +3 -0
  8. package/dist/languages/ar.js.map +1 -0
  9. package/dist/languages/az.js +3 -0
  10. package/dist/languages/az.js.map +1 -0
  11. package/dist/languages/bn.js +3 -0
  12. package/dist/languages/bn.js.map +1 -0
  13. package/dist/languages/cs.js +3 -0
  14. package/dist/languages/cs.js.map +1 -0
  15. package/dist/languages/da.js +3 -0
  16. package/dist/languages/da.js.map +1 -0
  17. package/dist/languages/de.js +3 -0
  18. package/dist/languages/de.js.map +1 -0
  19. package/dist/languages/el.js +3 -0
  20. package/dist/languages/el.js.map +1 -0
  21. package/dist/languages/en.js +3 -0
  22. package/dist/languages/en.js.map +1 -0
  23. package/dist/languages/es.js +3 -0
  24. package/dist/languages/es.js.map +1 -0
  25. package/dist/languages/fa.js +3 -0
  26. package/dist/languages/fa.js.map +1 -0
  27. package/dist/languages/fi.js +3 -0
  28. package/dist/languages/fi.js.map +1 -0
  29. package/dist/languages/fil.js +3 -0
  30. package/dist/languages/fil.js.map +1 -0
  31. package/dist/languages/fr-BE.js +3 -0
  32. package/dist/languages/fr-BE.js.map +1 -0
  33. package/dist/languages/fr.js +3 -0
  34. package/dist/languages/fr.js.map +1 -0
  35. package/dist/languages/gu.js +3 -0
  36. package/dist/languages/gu.js.map +1 -0
  37. package/dist/languages/ha.js +3 -0
  38. package/dist/languages/ha.js.map +1 -0
  39. package/dist/languages/hbo.js +3 -0
  40. package/dist/languages/hbo.js.map +1 -0
  41. package/dist/languages/he.js +3 -0
  42. package/dist/languages/he.js.map +1 -0
  43. package/dist/languages/hi.js +3 -0
  44. package/dist/languages/hi.js.map +1 -0
  45. package/dist/languages/hr.js +3 -0
  46. package/dist/languages/hr.js.map +1 -0
  47. package/dist/languages/hu.js +3 -0
  48. package/dist/languages/hu.js.map +1 -0
  49. package/dist/languages/id.js +3 -0
  50. package/dist/languages/id.js.map +1 -0
  51. package/dist/languages/it.js +3 -0
  52. package/dist/languages/it.js.map +1 -0
  53. package/dist/languages/ja.js +3 -0
  54. package/dist/languages/ja.js.map +1 -0
  55. package/dist/languages/ka.js +3 -0
  56. package/dist/languages/ka.js.map +1 -0
  57. package/dist/languages/kn.js +3 -0
  58. package/dist/languages/kn.js.map +1 -0
  59. package/dist/languages/ko.js +3 -0
  60. package/dist/languages/ko.js.map +1 -0
  61. package/dist/languages/lt.js +3 -0
  62. package/dist/languages/lt.js.map +1 -0
  63. package/dist/languages/lv.js +3 -0
  64. package/dist/languages/lv.js.map +1 -0
  65. package/dist/languages/mr.js +3 -0
  66. package/dist/languages/mr.js.map +1 -0
  67. package/dist/languages/ms.js +3 -0
  68. package/dist/languages/ms.js.map +1 -0
  69. package/dist/languages/nb.js +3 -0
  70. package/dist/languages/nb.js.map +1 -0
  71. package/dist/languages/nl.js +3 -0
  72. package/dist/languages/nl.js.map +1 -0
  73. package/dist/languages/pa.js +3 -0
  74. package/dist/languages/pa.js.map +1 -0
  75. package/dist/languages/pl.js +3 -0
  76. package/dist/languages/pl.js.map +1 -0
  77. package/dist/languages/pt.js +3 -0
  78. package/dist/languages/pt.js.map +1 -0
  79. package/dist/languages/ro.js +3 -0
  80. package/dist/languages/ro.js.map +1 -0
  81. package/dist/languages/ru.js +3 -0
  82. package/dist/languages/ru.js.map +1 -0
  83. package/dist/languages/sr-Cyrl.js +3 -0
  84. package/dist/languages/sr-Cyrl.js.map +1 -0
  85. package/dist/languages/sr-Latn.js +3 -0
  86. package/dist/languages/sr-Latn.js.map +1 -0
  87. package/dist/languages/sv.js +3 -0
  88. package/dist/languages/sv.js.map +1 -0
  89. package/dist/languages/sw.js +3 -0
  90. package/dist/languages/sw.js.map +1 -0
  91. package/dist/languages/ta.js +3 -0
  92. package/dist/languages/ta.js.map +1 -0
  93. package/dist/languages/te.js +3 -0
  94. package/dist/languages/te.js.map +1 -0
  95. package/dist/languages/th.js +3 -0
  96. package/dist/languages/th.js.map +1 -0
  97. package/dist/languages/tr.js +3 -0
  98. package/dist/languages/tr.js.map +1 -0
  99. package/dist/languages/uk.js +3 -0
  100. package/dist/languages/uk.js.map +1 -0
  101. package/dist/languages/ur.js +3 -0
  102. package/dist/languages/ur.js.map +1 -0
  103. package/dist/languages/vi.js +3 -0
  104. package/dist/languages/vi.js.map +1 -0
  105. package/dist/languages/yo.js +3 -0
  106. package/dist/languages/yo.js.map +1 -0
  107. package/dist/languages/zh-Hans.js +3 -0
  108. package/dist/languages/zh-Hans.js.map +1 -0
  109. package/dist/languages/zh-Hant.js +3 -0
  110. package/dist/languages/zh-Hant.js.map +1 -0
  111. package/dist/n2words.js +2 -2
  112. package/dist/n2words.js.map +1 -1
  113. package/lib/languages/am-Latn.d.ts +7 -0
  114. package/lib/languages/am-Latn.js +159 -0
  115. package/lib/languages/am.d.ts +7 -0
  116. package/lib/languages/am.js +159 -0
  117. package/lib/languages/ar.d.ts +14 -27
  118. package/lib/languages/ar.js +175 -129
  119. package/lib/languages/az.d.ts +4 -9
  120. package/lib/languages/az.js +166 -37
  121. package/lib/languages/bn.d.ts +4 -8
  122. package/lib/languages/bn.js +159 -124
  123. package/lib/languages/cs.d.ts +15 -85
  124. package/lib/languages/cs.js +293 -114
  125. package/lib/languages/da.d.ts +11 -12
  126. package/lib/languages/da.js +269 -101
  127. package/lib/languages/de.d.ts +14 -11
  128. package/lib/languages/de.js +305 -86
  129. package/lib/languages/el.d.ts +11 -11
  130. package/lib/languages/el.js +224 -78
  131. package/lib/languages/en.d.ts +14 -13
  132. package/lib/languages/en.js +228 -72
  133. package/lib/languages/es.d.ts +18 -12
  134. package/lib/languages/es.js +297 -103
  135. package/lib/languages/fa.d.ts +4 -44
  136. package/lib/languages/fa.js +112 -122
  137. package/lib/languages/fi.d.ts +14 -0
  138. package/lib/languages/fi.js +238 -0
  139. package/lib/languages/fil.d.ts +4 -13
  140. package/lib/languages/fil.js +196 -106
  141. package/lib/languages/fr-BE.d.ts +8 -8
  142. package/lib/languages/fr-BE.js +285 -19
  143. package/lib/languages/fr.d.ts +18 -12
  144. package/lib/languages/fr.js +339 -89
  145. package/lib/languages/gu.d.ts +4 -8
  146. package/lib/languages/gu.js +143 -125
  147. package/lib/languages/ha.d.ts +7 -0
  148. package/lib/languages/ha.js +225 -0
  149. package/lib/languages/hbo.d.ts +10 -110
  150. package/lib/languages/hbo.js +245 -214
  151. package/lib/languages/he.d.ts +10 -77
  152. package/lib/languages/he.js +231 -172
  153. package/lib/languages/hi.d.ts +4 -8
  154. package/lib/languages/hi.js +163 -124
  155. package/lib/languages/hr.d.ts +8 -77
  156. package/lib/languages/hr.js +200 -89
  157. package/lib/languages/hu.d.ts +4 -19
  158. package/lib/languages/hu.js +198 -119
  159. package/lib/languages/id.d.ts +4 -34
  160. package/lib/languages/id.js +166 -129
  161. package/lib/languages/it.d.ts +16 -34
  162. package/lib/languages/it.js +307 -97
  163. package/lib/languages/ja.d.ts +14 -14
  164. package/lib/languages/ja.js +221 -111
  165. package/lib/languages/ka.d.ts +17 -0
  166. package/lib/languages/ka.js +291 -0
  167. package/lib/languages/kn.d.ts +4 -8
  168. package/lib/languages/kn.js +143 -35
  169. package/lib/languages/ko.d.ts +11 -11
  170. package/lib/languages/ko.js +250 -49
  171. package/lib/languages/lt.d.ts +15 -67
  172. package/lib/languages/lt.js +287 -122
  173. package/lib/languages/lv.d.ts +15 -67
  174. package/lib/languages/lv.js +288 -106
  175. package/lib/languages/mr.d.ts +4 -8
  176. package/lib/languages/mr.js +143 -125
  177. package/lib/languages/ms.d.ts +4 -28
  178. package/lib/languages/ms.js +166 -116
  179. package/lib/languages/nb.d.ts +11 -9
  180. package/lib/languages/nb.js +272 -87
  181. package/lib/languages/nl.d.ts +23 -13
  182. package/lib/languages/nl.js +299 -133
  183. package/lib/languages/pa.d.ts +4 -8
  184. package/lib/languages/pa.js +151 -124
  185. package/lib/languages/pl.d.ts +19 -77
  186. package/lib/languages/pl.js +294 -87
  187. package/lib/languages/pt.d.ts +14 -26
  188. package/lib/languages/pt.js +272 -92
  189. package/lib/languages/ro.d.ts +15 -155
  190. package/lib/languages/ro.js +219 -235
  191. package/lib/languages/ru.d.ts +8 -82
  192. package/lib/languages/ru.js +239 -90
  193. package/lib/languages/sr-Cyrl.d.ts +8 -77
  194. package/lib/languages/sr-Cyrl.js +197 -89
  195. package/lib/languages/sr-Latn.d.ts +8 -77
  196. package/lib/languages/sr-Latn.js +197 -89
  197. package/lib/languages/sv.d.ts +11 -11
  198. package/lib/languages/sv.js +278 -74
  199. package/lib/languages/sw.d.ts +4 -36
  200. package/lib/languages/sw.js +133 -106
  201. package/lib/languages/ta.d.ts +4 -17
  202. package/lib/languages/ta.js +143 -202
  203. package/lib/languages/te.d.ts +4 -19
  204. package/lib/languages/te.js +133 -196
  205. package/lib/languages/th.d.ts +4 -14
  206. package/lib/languages/th.js +135 -91
  207. package/lib/languages/tr.d.ts +15 -9
  208. package/lib/languages/tr.js +245 -49
  209. package/lib/languages/uk.d.ts +8 -82
  210. package/lib/languages/uk.js +206 -78
  211. package/lib/languages/ur.d.ts +4 -8
  212. package/lib/languages/ur.js +151 -124
  213. package/lib/languages/vi.d.ts +14 -69
  214. package/lib/languages/vi.js +278 -129
  215. package/lib/languages/yo.d.ts +7 -0
  216. package/lib/languages/yo.js +303 -0
  217. package/lib/languages/zh-Hans.d.ts +8 -18
  218. package/lib/languages/zh-Hans.js +163 -92
  219. package/lib/languages/zh-Hant.d.ts +8 -18
  220. package/lib/languages/zh-Hant.js +181 -90
  221. package/lib/n2words.d.ts +55 -209
  222. package/lib/n2words.js +115 -530
  223. package/lib/utils/is-plain-object.d.ts +13 -0
  224. package/lib/utils/is-plain-object.js +17 -0
  225. package/lib/utils/parse-numeric.d.ts +17 -0
  226. package/lib/utils/parse-numeric.js +108 -0
  227. package/lib/utils/validate-options.d.ts +8 -0
  228. package/lib/utils/validate-options.js +16 -0
  229. package/package.json +26 -14
  230. package/dist/ArabicConverter.js +0 -3
  231. package/dist/ArabicConverter.js.map +0 -1
  232. package/dist/AzerbaijaniConverter.js +0 -3
  233. package/dist/AzerbaijaniConverter.js.map +0 -1
  234. package/dist/BanglaConverter.js +0 -3
  235. package/dist/BanglaConverter.js.map +0 -1
  236. package/dist/BiblicalHebrewConverter.js +0 -3
  237. package/dist/BiblicalHebrewConverter.js.map +0 -1
  238. package/dist/CroatianConverter.js +0 -3
  239. package/dist/CroatianConverter.js.map +0 -1
  240. package/dist/CzechConverter.js +0 -3
  241. package/dist/CzechConverter.js.map +0 -1
  242. package/dist/DanishConverter.js +0 -3
  243. package/dist/DanishConverter.js.map +0 -1
  244. package/dist/DutchConverter.js +0 -3
  245. package/dist/DutchConverter.js.map +0 -1
  246. package/dist/EnglishConverter.js +0 -3
  247. package/dist/EnglishConverter.js.map +0 -1
  248. package/dist/FilipinoConverter.js +0 -3
  249. package/dist/FilipinoConverter.js.map +0 -1
  250. package/dist/FrenchBelgiumConverter.js +0 -3
  251. package/dist/FrenchBelgiumConverter.js.map +0 -1
  252. package/dist/FrenchConverter.js +0 -3
  253. package/dist/FrenchConverter.js.map +0 -1
  254. package/dist/GermanConverter.js +0 -3
  255. package/dist/GermanConverter.js.map +0 -1
  256. package/dist/GreekConverter.js +0 -3
  257. package/dist/GreekConverter.js.map +0 -1
  258. package/dist/GujaratiConverter.js +0 -3
  259. package/dist/GujaratiConverter.js.map +0 -1
  260. package/dist/HebrewConverter.js +0 -3
  261. package/dist/HebrewConverter.js.map +0 -1
  262. package/dist/HindiConverter.js +0 -3
  263. package/dist/HindiConverter.js.map +0 -1
  264. package/dist/HungarianConverter.js +0 -3
  265. package/dist/HungarianConverter.js.map +0 -1
  266. package/dist/IndonesianConverter.js +0 -3
  267. package/dist/IndonesianConverter.js.map +0 -1
  268. package/dist/ItalianConverter.js +0 -3
  269. package/dist/ItalianConverter.js.map +0 -1
  270. package/dist/JapaneseConverter.js +0 -3
  271. package/dist/JapaneseConverter.js.map +0 -1
  272. package/dist/KannadaConverter.js +0 -3
  273. package/dist/KannadaConverter.js.map +0 -1
  274. package/dist/KoreanConverter.js +0 -3
  275. package/dist/KoreanConverter.js.map +0 -1
  276. package/dist/LatvianConverter.js +0 -3
  277. package/dist/LatvianConverter.js.map +0 -1
  278. package/dist/LithuanianConverter.js +0 -3
  279. package/dist/LithuanianConverter.js.map +0 -1
  280. package/dist/MalayConverter.js +0 -3
  281. package/dist/MalayConverter.js.map +0 -1
  282. package/dist/MarathiConverter.js +0 -3
  283. package/dist/MarathiConverter.js.map +0 -1
  284. package/dist/NorwegianBokmalConverter.js +0 -3
  285. package/dist/NorwegianBokmalConverter.js.map +0 -1
  286. package/dist/PersianConverter.js +0 -3
  287. package/dist/PersianConverter.js.map +0 -1
  288. package/dist/PolishConverter.js +0 -3
  289. package/dist/PolishConverter.js.map +0 -1
  290. package/dist/PortugueseConverter.js +0 -3
  291. package/dist/PortugueseConverter.js.map +0 -1
  292. package/dist/PunjabiConverter.js +0 -3
  293. package/dist/PunjabiConverter.js.map +0 -1
  294. package/dist/RomanianConverter.js +0 -3
  295. package/dist/RomanianConverter.js.map +0 -1
  296. package/dist/RussianConverter.js +0 -3
  297. package/dist/RussianConverter.js.map +0 -1
  298. package/dist/SerbianCyrillicConverter.js +0 -3
  299. package/dist/SerbianCyrillicConverter.js.map +0 -1
  300. package/dist/SerbianLatinConverter.js +0 -3
  301. package/dist/SerbianLatinConverter.js.map +0 -1
  302. package/dist/SimplifiedChineseConverter.js +0 -3
  303. package/dist/SimplifiedChineseConverter.js.map +0 -1
  304. package/dist/SpanishConverter.js +0 -3
  305. package/dist/SpanishConverter.js.map +0 -1
  306. package/dist/SwahiliConverter.js +0 -3
  307. package/dist/SwahiliConverter.js.map +0 -1
  308. package/dist/SwedishConverter.js +0 -3
  309. package/dist/SwedishConverter.js.map +0 -1
  310. package/dist/TamilConverter.js +0 -3
  311. package/dist/TamilConverter.js.map +0 -1
  312. package/dist/TeluguConverter.js +0 -3
  313. package/dist/TeluguConverter.js.map +0 -1
  314. package/dist/ThaiConverter.js +0 -3
  315. package/dist/ThaiConverter.js.map +0 -1
  316. package/dist/TraditionalChineseConverter.js +0 -3
  317. package/dist/TraditionalChineseConverter.js.map +0 -1
  318. package/dist/TurkishConverter.js +0 -3
  319. package/dist/TurkishConverter.js.map +0 -1
  320. package/dist/UkrainianConverter.js +0 -3
  321. package/dist/UkrainianConverter.js.map +0 -1
  322. package/dist/UrduConverter.js +0 -3
  323. package/dist/UrduConverter.js.map +0 -1
  324. package/dist/VietnameseConverter.js +0 -3
  325. package/dist/VietnameseConverter.js.map +0 -1
  326. package/lib/classes/abstract-language.d.ts +0 -178
  327. package/lib/classes/abstract-language.js +0 -268
  328. package/lib/classes/greedy-scale-language.d.ts +0 -109
  329. package/lib/classes/greedy-scale-language.js +0 -201
  330. package/lib/classes/slavic-language.d.ts +0 -148
  331. package/lib/classes/slavic-language.js +0 -281
  332. package/lib/classes/south-asian-language.d.ts +0 -70
  333. package/lib/classes/south-asian-language.js +0 -154
  334. package/lib/classes/turkic-language.d.ts +0 -26
  335. package/lib/classes/turkic-language.js +0 -59
@@ -1,96 +1,245 @@
1
- import { SlavicLanguage } from '../classes/slavic-language.js'
2
-
3
1
  /**
4
- * Russian language converter.
2
+ * Russian language converter - Functional Implementation
3
+ *
4
+ * Self-contained module with its own input validation, ready for subpath exports.
5
5
  *
6
- * Supports:
7
- * - Gender agreement (masculine/feminine forms)
6
+ * Key features:
8
7
  * - Three-form pluralization (one/few/many)
9
- * - Large numbers up to nonillions
8
+ * - Gender: thousands are feminine, millions+ are masculine
9
+ * - Irregular hundreds (двести, триста, etc.)
10
+ * - Long scale naming
10
11
  */
11
- export class Russian extends SlavicLanguage {
12
- negativeWord = 'минус'
13
- decimalSeparatorWord = 'запятая'
14
- zeroWord = 'ноль'
15
-
16
- onesWords = {
17
- 1: 'один',
18
- 2: 'два',
19
- 3: 'три',
20
- 4: 'четыре',
21
- 5: 'пять',
22
- 6: 'шесть',
23
- 7: 'семь',
24
- 8: 'восемь',
25
- 9: 'девять'
26
- }
27
-
28
- onesFeminineWords = {
29
- 1: 'одна',
30
- 2: 'две',
31
- 3: 'три',
32
- 4: 'четыре',
33
- 5: 'пять',
34
- 6: 'шесть',
35
- 7: 'семь',
36
- 8: 'восемь',
37
- 9: 'девять'
38
- }
39
-
40
- teensWords = {
41
- 0: 'десять',
42
- 1: 'одиннадцать',
43
- 2: 'двенадцать',
44
- 3: 'тринадцать',
45
- 4: 'четырнадцать',
46
- 5: 'пятнадцать',
47
- 6: 'шестнадцать',
48
- 7: 'семнадцать',
49
- 8: 'восемнадцать',
50
- 9: 'девятнадцать'
51
- }
52
-
53
- twentiesWords = {
54
- 2: 'двадцать',
55
- 3: 'тридцать',
56
- 4: 'сорок',
57
- 5: 'пятьдесят',
58
- 6: 'шестьдесят',
59
- 7: 'семьдесят',
60
- 8: 'восемьдесят',
61
- 9: 'девяносто'
62
- }
63
-
64
- hundredsWords = {
65
- 1: 'сто',
66
- 2: 'двести',
67
- 3: 'триста',
68
- 4: 'четыреста',
69
- 5: 'пятьсот',
70
- 6: 'шестьсот',
71
- 7: 'семьсот',
72
- 8: 'восемьсот',
73
- 9: 'девятьсот'
74
- }
75
-
76
- pluralForms = {
77
- 1: ['тысяча', 'тысячи', 'тысяч'], // 10^ 3
78
- 2: ['миллион', 'миллиона', 'миллионов'], // 10^ 6
79
- 3: ['миллиард', 'миллиарда', 'миллиардов'], // 10^ 9
80
- 4: ['триллион', 'триллиона', 'триллионов'], // 10^ 12
81
- 5: ['квадриллион', 'квадриллиона', 'квадриллионов'], // 10^ 15
82
- 6: ['квинтиллион', 'квинтиллиона', 'квинтиллионов'], // 10^ 18
83
- 7: ['секстиллион', 'секстиллиона', 'секстиллионов'], // 10^ 21
84
- 8: ['септиллион', 'септиллиона', 'септиллионов'], // 10^ 24
85
- 9: ['октиллион', 'октиллиона', 'октиллионов'], // 10^ 27
86
- 10: ['нониллион', 'нониллиона', 'нониллионов'] // 10^ 30
87
- }
88
-
89
- /**
90
- * Russian thousands (тысяча) are feminine, requiring одна/две forms.
91
- * Other scales (million, billion, etc.) are masculine.
92
- */
93
- scaleGenders = {
94
- 1: true // thousands are feminine
12
+
13
+ import { parseNumericValue } from '../utils/parse-numeric.js'
14
+ import { validateOptions } from '../utils/validate-options.js'
15
+
16
+ // ============================================================================
17
+ // Vocabulary
18
+ // ============================================================================
19
+
20
+ const ONES_MASC = ['', 'один', 'два', 'три', 'четыре', 'пять', 'шесть', 'семь', 'восемь', 'девять']
21
+ const ONES_FEM = ['', 'одна', 'две', 'три', 'четыре', 'пять', 'шесть', 'семь', 'восемь', 'девять']
22
+
23
+ const TEENS = ['десять', 'одиннадцать', 'двенадцать', 'тринадцать', 'четырнадцать', 'пятнадцать', 'шестнадцать', 'семнадцать', 'восемнадцать', 'девятнадцать']
24
+ const TENS = ['', '', 'двадцать', 'тридцать', 'сорок', 'пятьдесят', 'шестьдесят', 'семьдесят', 'восемьдесят', 'девяносто']
25
+
26
+ // Irregular hundreds
27
+ const HUNDREDS = ['', 'сто', 'двести', 'триста', 'четыреста', 'пятьсот', 'шестьсот', 'семьсот', 'восемьсот', 'девятьсот']
28
+
29
+ const ZERO = 'ноль'
30
+ const NEGATIVE = 'минус'
31
+ const DECIMAL_SEP = 'запятая'
32
+
33
+ // Scale words: [singular, few, many]
34
+ // Thousands (index 0) are feminine, rest are masculine
35
+ const SCALE_FORMS = [
36
+ ['тысяча', 'тысячи', 'тысяч'],
37
+ ['миллион', 'миллиона', 'миллионов'],
38
+ ['миллиард', 'миллиарда', 'миллиардов'],
39
+ ['триллион', 'триллиона', 'триллионов'],
40
+ ['квадриллион', 'квадриллиона', 'квадриллионов'],
41
+ ['квинтиллион', 'квинтиллиона', 'квинтиллионов'],
42
+ ['секстиллион', 'секстиллиона', 'секстиллионов'],
43
+ ['септиллион', 'септиллиона', 'септиллионов'],
44
+ ['октиллион', 'октиллиона', 'октиллионов'],
45
+ ['нониллион', 'нониллиона', 'нониллионов']
46
+ ]
47
+
48
+ // ============================================================================
49
+ // Segment Building
50
+ // ============================================================================
51
+
52
+ function pluralize (n, forms) {
53
+ const num = typeof n === 'bigint' ? Number(n) : n
54
+ const lastDigit = num % 10
55
+ const lastTwoDigits = num % 100
56
+
57
+ if (lastTwoDigits >= 11 && lastTwoDigits <= 19) {
58
+ return forms[2]
95
59
  }
60
+
61
+ if (lastDigit === 1) return forms[0]
62
+ if (lastDigit >= 2 && lastDigit <= 4) return forms[1]
63
+ return forms[2]
96
64
  }
65
+
66
+ function buildSegmentMasc (n) {
67
+ if (n === 0) return ''
68
+
69
+ const onesDigit = n % 10
70
+ const tensDigit = Math.floor(n / 10) % 10
71
+ const hundredsDigit = Math.floor(n / 100)
72
+
73
+ const parts = []
74
+
75
+ if (hundredsDigit > 0) {
76
+ parts.push(HUNDREDS[hundredsDigit])
77
+ }
78
+
79
+ if (tensDigit > 1) {
80
+ parts.push(TENS[tensDigit])
81
+ }
82
+
83
+ if (tensDigit === 1) {
84
+ parts.push(TEENS[onesDigit])
85
+ } else if (onesDigit > 0) {
86
+ parts.push(ONES_MASC[onesDigit])
87
+ }
88
+
89
+ return parts.join(' ')
90
+ }
91
+
92
+ function buildSegmentFem (n) {
93
+ if (n === 0) return ''
94
+
95
+ const onesDigit = n % 10
96
+ const tensDigit = Math.floor(n / 10) % 10
97
+ const hundredsDigit = Math.floor(n / 100)
98
+
99
+ const parts = []
100
+
101
+ if (hundredsDigit > 0) {
102
+ parts.push(HUNDREDS[hundredsDigit])
103
+ }
104
+
105
+ if (tensDigit > 1) {
106
+ parts.push(TENS[tensDigit])
107
+ }
108
+
109
+ if (tensDigit === 1) {
110
+ parts.push(TEENS[onesDigit])
111
+ } else if (onesDigit > 0) {
112
+ parts.push(ONES_FEM[onesDigit])
113
+ }
114
+
115
+ return parts.join(' ')
116
+ }
117
+
118
+ // ============================================================================
119
+ // Conversion Functions
120
+ // ============================================================================
121
+
122
+ function integerToWords (n, options = {}) {
123
+ if (n === 0n) return ZERO
124
+
125
+ const feminine = options.gender === 'feminine'
126
+
127
+ if (n < 1000n) {
128
+ return feminine ? buildSegmentFem(Number(n)) : buildSegmentMasc(Number(n))
129
+ }
130
+
131
+ if (n < 1_000_000n) {
132
+ const thousands = Number(n / 1000n)
133
+ const remainder = Number(n % 1000n)
134
+
135
+ // Thousands are always feminine in Russian
136
+ const thousandsWord = buildSegmentFem(thousands)
137
+ const scaleWord = pluralize(thousands, SCALE_FORMS[0])
138
+
139
+ let result = thousandsWord + ' ' + scaleWord
140
+
141
+ if (remainder > 0) {
142
+ result += ' ' + (feminine ? buildSegmentFem(remainder) : buildSegmentMasc(remainder))
143
+ }
144
+
145
+ return result
146
+ }
147
+
148
+ return buildLargeNumberWords(n, options)
149
+ }
150
+
151
+ function buildLargeNumberWords (n, options) {
152
+ const feminine = options.gender === 'feminine'
153
+ const numStr = n.toString()
154
+ const len = numStr.length
155
+
156
+ const segments = []
157
+ const segmentSize = 3
158
+
159
+ const remainderLen = len % segmentSize
160
+ let pos = 0
161
+ if (remainderLen > 0) {
162
+ segments.push(Number(numStr.slice(0, remainderLen)))
163
+ pos = remainderLen
164
+ }
165
+ while (pos < len) {
166
+ segments.push(Number(numStr.slice(pos, pos + segmentSize)))
167
+ pos += segmentSize
168
+ }
169
+
170
+ const parts = []
171
+ let scaleIndex = segments.length - 1
172
+
173
+ for (let i = 0; i < segments.length; i++) {
174
+ const segment = segments[i]
175
+
176
+ if (segment !== 0) {
177
+ if (scaleIndex === 0) {
178
+ parts.push(feminine ? buildSegmentFem(segment) : buildSegmentMasc(segment))
179
+ } else {
180
+ const scaleForms = SCALE_FORMS[scaleIndex - 1]
181
+ const scaleWord = pluralize(segment, scaleForms)
182
+ // Thousands (scaleIndex=1) are feminine, others masculine
183
+ const isFeminine = scaleIndex === 1
184
+ const segmentWord = isFeminine ? buildSegmentFem(segment) : buildSegmentMasc(segment)
185
+ parts.push(segmentWord + ' ' + scaleWord)
186
+ }
187
+ }
188
+
189
+ scaleIndex--
190
+ }
191
+
192
+ return parts.join(' ')
193
+ }
194
+
195
+ function decimalPartToWords (decimalPart, options) {
196
+ let result = ''
197
+ let i = 0
198
+
199
+ while (i < decimalPart.length && decimalPart[i] === '0') {
200
+ if (result) result += ' '
201
+ result += ZERO
202
+ i++
203
+ }
204
+
205
+ const remainder = decimalPart.slice(i)
206
+ if (remainder) {
207
+ if (result) result += ' '
208
+ result += integerToWords(BigInt(remainder), options)
209
+ }
210
+
211
+ return result
212
+ }
213
+
214
+ /**
215
+ * Converts a numeric value to Russian words.
216
+ *
217
+ * @param {number | string | bigint} value - The numeric value to convert
218
+ * @param {Object} [options] - Optional configuration
219
+ * @param {('masculine'|'feminine')} [options.gender='masculine'] - Grammatical gender
220
+ * @returns {string} The number in Russian words
221
+ */
222
+ function toWords (value, options) {
223
+ options = validateOptions(options)
224
+ const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
225
+
226
+ let result = ''
227
+
228
+ if (isNegative) {
229
+ result = NEGATIVE + ' '
230
+ }
231
+
232
+ result += integerToWords(integerPart, options)
233
+
234
+ if (decimalPart) {
235
+ result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart, options)
236
+ }
237
+
238
+ return result
239
+ }
240
+
241
+ // ============================================================================
242
+ // Exports
243
+ // ============================================================================
244
+
245
+ export { toWords }
@@ -1,80 +1,11 @@
1
1
  /**
2
- * Serbian language converter (Cyrillic script).
2
+ * Converts a numeric value to Serbian (Cyrillic) words.
3
3
  *
4
- * Supports:
5
- * - Three-form pluralization (one/few/many)
6
- * - Gender agreement (један/једна, два/две)
7
- * - Cyrillic script representation
4
+ * @param {number | string | bigint} value - The numeric value to convert
5
+ * @param {Object} [options] - Optional configuration
6
+ * @param {('masculine'|'feminine')} [options.gender='masculine'] - Grammatical gender
7
+ * @returns {string} The number in Serbian Cyrillic words
8
8
  */
9
- export class SerbianCyrillic extends SlavicLanguage {
10
- onesWords: {
11
- 1: string;
12
- 2: string;
13
- 3: string;
14
- 4: string;
15
- 5: string;
16
- 6: string;
17
- 7: string;
18
- 8: string;
19
- 9: string;
20
- };
21
- onesFeminineWords: {
22
- 1: string;
23
- 2: string;
24
- 3: string;
25
- 4: string;
26
- 5: string;
27
- 6: string;
28
- 7: string;
29
- 8: string;
30
- 9: string;
31
- };
32
- teensWords: {
33
- 0: string;
34
- 1: string;
35
- 2: string;
36
- 3: string;
37
- 4: string;
38
- 5: string;
39
- 6: string;
40
- 7: string;
41
- 8: string;
42
- 9: string;
43
- };
44
- twentiesWords: {
45
- 2: string;
46
- 3: string;
47
- 4: string;
48
- 5: string;
49
- 6: string;
50
- 7: string;
51
- 8: string;
52
- 9: string;
53
- };
54
- hundredsWords: {
55
- 1: string;
56
- 2: string;
57
- 3: string;
58
- 4: string;
59
- 5: string;
60
- 6: string;
61
- 7: string;
62
- 8: string;
63
- 9: string;
64
- };
65
- pluralForms: {
66
- 1: string[];
67
- 2: string[];
68
- 3: string[];
69
- 4: string[];
70
- 5: string[];
71
- 6: string[];
72
- 7: string[];
73
- 8: string[];
74
- 9: string[];
75
- 10: string[];
76
- };
77
- /** Selects Serbian plural form: 1 = singular, 2-4 = few, else = many. */
78
- pluralize(n: any, forms: any): any;
79
- }
80
- import { SlavicLanguage } from '../classes/slavic-language.js';
9
+ export function toWords(value: number | string | bigint, options?: {
10
+ gender?: "masculine" | "feminine" | undefined;
11
+ }): string;