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.
Files changed (327) hide show
  1. package/CHANGELOG.md +49 -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/kn.js +3 -0
  56. package/dist/languages/kn.js.map +1 -0
  57. package/dist/languages/ko.js +3 -0
  58. package/dist/languages/ko.js.map +1 -0
  59. package/dist/languages/lt.js +3 -0
  60. package/dist/languages/lt.js.map +1 -0
  61. package/dist/languages/lv.js +3 -0
  62. package/dist/languages/lv.js.map +1 -0
  63. package/dist/languages/mr.js +3 -0
  64. package/dist/languages/mr.js.map +1 -0
  65. package/dist/languages/ms.js +3 -0
  66. package/dist/languages/ms.js.map +1 -0
  67. package/dist/languages/nb.js +3 -0
  68. package/dist/languages/nb.js.map +1 -0
  69. package/dist/languages/nl.js +3 -0
  70. package/dist/languages/nl.js.map +1 -0
  71. package/dist/languages/pa.js +3 -0
  72. package/dist/languages/pa.js.map +1 -0
  73. package/dist/languages/pl.js +3 -0
  74. package/dist/languages/pl.js.map +1 -0
  75. package/dist/languages/pt.js +3 -0
  76. package/dist/languages/pt.js.map +1 -0
  77. package/dist/languages/ro.js +3 -0
  78. package/dist/languages/ro.js.map +1 -0
  79. package/dist/languages/ru.js +3 -0
  80. package/dist/languages/ru.js.map +1 -0
  81. package/dist/languages/sr-Cyrl.js +3 -0
  82. package/dist/languages/sr-Cyrl.js.map +1 -0
  83. package/dist/languages/sr-Latn.js +3 -0
  84. package/dist/languages/sr-Latn.js.map +1 -0
  85. package/dist/languages/sv.js +3 -0
  86. package/dist/languages/sv.js.map +1 -0
  87. package/dist/languages/sw.js +3 -0
  88. package/dist/languages/sw.js.map +1 -0
  89. package/dist/languages/ta.js +3 -0
  90. package/dist/languages/ta.js.map +1 -0
  91. package/dist/languages/te.js +3 -0
  92. package/dist/languages/te.js.map +1 -0
  93. package/dist/languages/th.js +3 -0
  94. package/dist/languages/th.js.map +1 -0
  95. package/dist/languages/tr.js +3 -0
  96. package/dist/languages/tr.js.map +1 -0
  97. package/dist/languages/uk.js +3 -0
  98. package/dist/languages/uk.js.map +1 -0
  99. package/dist/languages/ur.js +3 -0
  100. package/dist/languages/ur.js.map +1 -0
  101. package/dist/languages/vi.js +3 -0
  102. package/dist/languages/vi.js.map +1 -0
  103. package/dist/languages/zh-Hans.js +3 -0
  104. package/dist/languages/zh-Hans.js.map +1 -0
  105. package/dist/languages/zh-Hant.js +3 -0
  106. package/dist/languages/zh-Hant.js.map +1 -0
  107. package/dist/n2words.js +2 -2
  108. package/dist/n2words.js.map +1 -1
  109. package/lib/languages/am-Latn.d.ts +7 -0
  110. package/lib/languages/am-Latn.js +164 -0
  111. package/lib/languages/am.d.ts +7 -0
  112. package/lib/languages/am.js +164 -0
  113. package/lib/languages/ar.d.ts +14 -27
  114. package/lib/languages/ar.js +175 -129
  115. package/lib/languages/az.d.ts +4 -9
  116. package/lib/languages/az.js +171 -37
  117. package/lib/languages/bn.d.ts +4 -8
  118. package/lib/languages/bn.js +138 -124
  119. package/lib/languages/cs.d.ts +15 -85
  120. package/lib/languages/cs.js +310 -114
  121. package/lib/languages/da.d.ts +11 -12
  122. package/lib/languages/da.js +276 -101
  123. package/lib/languages/de.d.ts +14 -11
  124. package/lib/languages/de.js +317 -86
  125. package/lib/languages/el.d.ts +11 -11
  126. package/lib/languages/el.js +231 -78
  127. package/lib/languages/en.d.ts +14 -13
  128. package/lib/languages/en.js +242 -72
  129. package/lib/languages/es.d.ts +18 -12
  130. package/lib/languages/es.js +317 -103
  131. package/lib/languages/fa.d.ts +4 -44
  132. package/lib/languages/fa.js +112 -122
  133. package/lib/languages/fi.d.ts +14 -0
  134. package/lib/languages/fi.js +245 -0
  135. package/lib/languages/fil.d.ts +4 -13
  136. package/lib/languages/fil.js +207 -106
  137. package/lib/languages/fr-BE.d.ts +8 -8
  138. package/lib/languages/fr-BE.js +294 -19
  139. package/lib/languages/fr.d.ts +18 -12
  140. package/lib/languages/fr.js +352 -89
  141. package/lib/languages/gu.d.ts +4 -8
  142. package/lib/languages/gu.js +130 -125
  143. package/lib/languages/ha.d.ts +7 -0
  144. package/lib/languages/ha.js +230 -0
  145. package/lib/languages/hbo.d.ts +10 -110
  146. package/lib/languages/hbo.js +263 -214
  147. package/lib/languages/he.d.ts +10 -77
  148. package/lib/languages/he.js +242 -172
  149. package/lib/languages/hi.d.ts +4 -8
  150. package/lib/languages/hi.js +138 -124
  151. package/lib/languages/hr.d.ts +8 -77
  152. package/lib/languages/hr.js +194 -89
  153. package/lib/languages/hu.d.ts +4 -19
  154. package/lib/languages/hu.js +198 -119
  155. package/lib/languages/id.d.ts +4 -34
  156. package/lib/languages/id.js +171 -129
  157. package/lib/languages/it.d.ts +16 -34
  158. package/lib/languages/it.js +339 -94
  159. package/lib/languages/ja.d.ts +14 -14
  160. package/lib/languages/ja.js +233 -111
  161. package/lib/languages/kn.d.ts +4 -8
  162. package/lib/languages/kn.js +130 -35
  163. package/lib/languages/ko.d.ts +11 -11
  164. package/lib/languages/ko.js +257 -49
  165. package/lib/languages/lt.d.ts +15 -67
  166. package/lib/languages/lt.js +296 -122
  167. package/lib/languages/lv.d.ts +15 -67
  168. package/lib/languages/lv.js +297 -106
  169. package/lib/languages/mr.d.ts +4 -8
  170. package/lib/languages/mr.js +130 -125
  171. package/lib/languages/ms.d.ts +4 -28
  172. package/lib/languages/ms.js +171 -116
  173. package/lib/languages/nb.d.ts +11 -9
  174. package/lib/languages/nb.js +282 -87
  175. package/lib/languages/nl.d.ts +23 -13
  176. package/lib/languages/nl.js +317 -133
  177. package/lib/languages/pa.d.ts +4 -8
  178. package/lib/languages/pa.js +156 -124
  179. package/lib/languages/pl.d.ts +19 -77
  180. package/lib/languages/pl.js +307 -87
  181. package/lib/languages/pt.d.ts +14 -26
  182. package/lib/languages/pt.js +286 -92
  183. package/lib/languages/ro.d.ts +15 -155
  184. package/lib/languages/ro.js +219 -235
  185. package/lib/languages/ru.d.ts +8 -82
  186. package/lib/languages/ru.js +222 -78
  187. package/lib/languages/sr-Cyrl.d.ts +8 -77
  188. package/lib/languages/sr-Cyrl.js +191 -89
  189. package/lib/languages/sr-Latn.d.ts +8 -77
  190. package/lib/languages/sr-Latn.js +191 -89
  191. package/lib/languages/sv.d.ts +11 -11
  192. package/lib/languages/sv.js +288 -74
  193. package/lib/languages/sw.d.ts +4 -36
  194. package/lib/languages/sw.js +133 -106
  195. package/lib/languages/ta.d.ts +4 -17
  196. package/lib/languages/ta.js +129 -201
  197. package/lib/languages/te.d.ts +4 -19
  198. package/lib/languages/te.js +141 -196
  199. package/lib/languages/th.d.ts +4 -14
  200. package/lib/languages/th.js +135 -91
  201. package/lib/languages/tr.d.ts +15 -9
  202. package/lib/languages/tr.js +256 -49
  203. package/lib/languages/uk.d.ts +8 -82
  204. package/lib/languages/uk.js +200 -78
  205. package/lib/languages/ur.d.ts +4 -8
  206. package/lib/languages/ur.js +156 -124
  207. package/lib/languages/vi.d.ts +14 -69
  208. package/lib/languages/vi.js +294 -125
  209. package/lib/languages/zh-Hans.d.ts +8 -18
  210. package/lib/languages/zh-Hans.js +163 -92
  211. package/lib/languages/zh-Hant.d.ts +8 -18
  212. package/lib/languages/zh-Hant.js +181 -90
  213. package/lib/n2words.d.ts +53 -209
  214. package/lib/n2words.js +111 -530
  215. package/lib/utils/is-plain-object.d.ts +13 -0
  216. package/lib/utils/is-plain-object.js +17 -0
  217. package/lib/utils/parse-numeric.d.ts +17 -0
  218. package/lib/utils/parse-numeric.js +108 -0
  219. package/lib/utils/validate-options.d.ts +8 -0
  220. package/lib/utils/validate-options.js +16 -0
  221. package/package.json +26 -14
  222. package/dist/ArabicConverter.js +0 -3
  223. package/dist/ArabicConverter.js.map +0 -1
  224. package/dist/AzerbaijaniConverter.js +0 -3
  225. package/dist/AzerbaijaniConverter.js.map +0 -1
  226. package/dist/BanglaConverter.js +0 -3
  227. package/dist/BanglaConverter.js.map +0 -1
  228. package/dist/BiblicalHebrewConverter.js +0 -3
  229. package/dist/BiblicalHebrewConverter.js.map +0 -1
  230. package/dist/CroatianConverter.js +0 -3
  231. package/dist/CroatianConverter.js.map +0 -1
  232. package/dist/CzechConverter.js +0 -3
  233. package/dist/CzechConverter.js.map +0 -1
  234. package/dist/DanishConverter.js +0 -3
  235. package/dist/DanishConverter.js.map +0 -1
  236. package/dist/DutchConverter.js +0 -3
  237. package/dist/DutchConverter.js.map +0 -1
  238. package/dist/EnglishConverter.js +0 -3
  239. package/dist/EnglishConverter.js.map +0 -1
  240. package/dist/FilipinoConverter.js +0 -3
  241. package/dist/FilipinoConverter.js.map +0 -1
  242. package/dist/FrenchBelgiumConverter.js +0 -3
  243. package/dist/FrenchBelgiumConverter.js.map +0 -1
  244. package/dist/FrenchConverter.js +0 -3
  245. package/dist/FrenchConverter.js.map +0 -1
  246. package/dist/GermanConverter.js +0 -3
  247. package/dist/GermanConverter.js.map +0 -1
  248. package/dist/GreekConverter.js +0 -3
  249. package/dist/GreekConverter.js.map +0 -1
  250. package/dist/GujaratiConverter.js +0 -3
  251. package/dist/GujaratiConverter.js.map +0 -1
  252. package/dist/HebrewConverter.js +0 -3
  253. package/dist/HebrewConverter.js.map +0 -1
  254. package/dist/HindiConverter.js +0 -3
  255. package/dist/HindiConverter.js.map +0 -1
  256. package/dist/HungarianConverter.js +0 -3
  257. package/dist/HungarianConverter.js.map +0 -1
  258. package/dist/IndonesianConverter.js +0 -3
  259. package/dist/IndonesianConverter.js.map +0 -1
  260. package/dist/ItalianConverter.js +0 -3
  261. package/dist/ItalianConverter.js.map +0 -1
  262. package/dist/JapaneseConverter.js +0 -3
  263. package/dist/JapaneseConverter.js.map +0 -1
  264. package/dist/KannadaConverter.js +0 -3
  265. package/dist/KannadaConverter.js.map +0 -1
  266. package/dist/KoreanConverter.js +0 -3
  267. package/dist/KoreanConverter.js.map +0 -1
  268. package/dist/LatvianConverter.js +0 -3
  269. package/dist/LatvianConverter.js.map +0 -1
  270. package/dist/LithuanianConverter.js +0 -3
  271. package/dist/LithuanianConverter.js.map +0 -1
  272. package/dist/MalayConverter.js +0 -3
  273. package/dist/MalayConverter.js.map +0 -1
  274. package/dist/MarathiConverter.js +0 -3
  275. package/dist/MarathiConverter.js.map +0 -1
  276. package/dist/NorwegianBokmalConverter.js +0 -3
  277. package/dist/NorwegianBokmalConverter.js.map +0 -1
  278. package/dist/PersianConverter.js +0 -3
  279. package/dist/PersianConverter.js.map +0 -1
  280. package/dist/PolishConverter.js +0 -3
  281. package/dist/PolishConverter.js.map +0 -1
  282. package/dist/PortugueseConverter.js +0 -3
  283. package/dist/PortugueseConverter.js.map +0 -1
  284. package/dist/PunjabiConverter.js +0 -3
  285. package/dist/PunjabiConverter.js.map +0 -1
  286. package/dist/RomanianConverter.js +0 -3
  287. package/dist/RomanianConverter.js.map +0 -1
  288. package/dist/RussianConverter.js +0 -3
  289. package/dist/RussianConverter.js.map +0 -1
  290. package/dist/SerbianCyrillicConverter.js +0 -3
  291. package/dist/SerbianCyrillicConverter.js.map +0 -1
  292. package/dist/SerbianLatinConverter.js +0 -3
  293. package/dist/SerbianLatinConverter.js.map +0 -1
  294. package/dist/SimplifiedChineseConverter.js +0 -3
  295. package/dist/SimplifiedChineseConverter.js.map +0 -1
  296. package/dist/SpanishConverter.js +0 -3
  297. package/dist/SpanishConverter.js.map +0 -1
  298. package/dist/SwahiliConverter.js +0 -3
  299. package/dist/SwahiliConverter.js.map +0 -1
  300. package/dist/SwedishConverter.js +0 -3
  301. package/dist/SwedishConverter.js.map +0 -1
  302. package/dist/TamilConverter.js +0 -3
  303. package/dist/TamilConverter.js.map +0 -1
  304. package/dist/TeluguConverter.js +0 -3
  305. package/dist/TeluguConverter.js.map +0 -1
  306. package/dist/ThaiConverter.js +0 -3
  307. package/dist/ThaiConverter.js.map +0 -1
  308. package/dist/TraditionalChineseConverter.js +0 -3
  309. package/dist/TraditionalChineseConverter.js.map +0 -1
  310. package/dist/TurkishConverter.js +0 -3
  311. package/dist/TurkishConverter.js.map +0 -1
  312. package/dist/UkrainianConverter.js +0 -3
  313. package/dist/UkrainianConverter.js.map +0 -1
  314. package/dist/UrduConverter.js +0 -3
  315. package/dist/UrduConverter.js.map +0 -1
  316. package/dist/VietnameseConverter.js +0 -3
  317. package/dist/VietnameseConverter.js.map +0 -1
  318. package/lib/classes/abstract-language.d.ts +0 -178
  319. package/lib/classes/abstract-language.js +0 -268
  320. package/lib/classes/greedy-scale-language.d.ts +0 -109
  321. package/lib/classes/greedy-scale-language.js +0 -201
  322. package/lib/classes/slavic-language.d.ts +0 -148
  323. package/lib/classes/slavic-language.js +0 -281
  324. package/lib/classes/south-asian-language.d.ts +0 -70
  325. package/lib/classes/south-asian-language.js +0 -154
  326. package/lib/classes/turkic-language.d.ts +0 -26
  327. package/lib/classes/turkic-language.js +0 -59
@@ -1,136 +1,310 @@
1
- import { SlavicLanguage } from '../classes/slavic-language.js'
1
+ /**
2
+ * Lithuanian language converter - Functional Implementation
3
+ *
4
+ * A performance-optimized number-to-words converter using precomputed lookup tables.
5
+ *
6
+ * Key features:
7
+ * - Three-form pluralization (singular/plural/genitive)
8
+ * - Gender agreement (masculine/feminine for numbers < 1000)
9
+ * - Two-form hundreds (šimtas/šimtai)
10
+ * - Long scale naming
11
+ */
12
+
13
+ import { parseNumericValue } from '../utils/parse-numeric.js'
14
+ import { validateOptions } from '../utils/validate-options.js'
15
+
16
+ // ============================================================================
17
+ // Vocabulary (module-level constants)
18
+ // ============================================================================
19
+
20
+ const ONES_MASC = ['', 'vienas', 'du', 'trys', 'keturi', 'penki', 'šeši', 'septyni', 'aštuoni', 'devyni']
21
+ const ONES_FEM = ['', 'viena', 'dvi', 'trys', 'keturios', 'penkios', 'šešios', 'septynios', 'aštuonios', 'devynios']
22
+
23
+ const TEENS = ['dešimt', 'vienuolika', 'dvylika', 'trylika', 'keturiolika', 'penkiolika', 'šešiolika', 'septyniolika', 'aštuoniolika', 'devyniolika']
24
+ const TENS = ['', '', 'dvidešimt', 'trisdešimt', 'keturiasdešimt', 'penkiasdešimt', 'šešiasdešimt', 'septyniasdešimt', 'aštuoniasdešimt', 'devyniasdešimt']
25
+
26
+ // Hundreds: šimtas (singular), šimtai (plural)
27
+ const HUNDRED_SINGULAR = 'šimtas'
28
+ const HUNDRED_PLURAL = 'šimtai'
29
+
30
+ const ZERO = 'nulis'
31
+ const NEGATIVE = 'minus'
32
+ const DECIMAL_SEP = 'kablelis'
33
+
34
+ // Scale words: [singular, plural, genitive]
35
+ const SCALE_FORMS = [
36
+ ['tūkstantis', 'tūkstančiai', 'tūkstančių'],
37
+ ['milijonas', 'milijonai', 'milijonų'],
38
+ ['milijardas', 'milijardai', 'milijardų'],
39
+ ['trilijonas', 'trilijonai', 'trilijonų'],
40
+ ['kvadrilijonas', 'kvadrilijonai', 'kvadrilijonų'],
41
+ ['kvintilijonas', 'kvintilijonai', 'kvintilijonų'],
42
+ ['sikstilijonas', 'sikstilijonai', 'sikstilijonų'],
43
+ ['septilijonas', 'septilijonai', 'septilijonų'],
44
+ ['oktilijonas', 'oktilijonai', 'oktilijonų']
45
+ ]
46
+
47
+ // ============================================================================
48
+ // Precomputed Lookup Tables (built once at module load)
49
+ // ============================================================================
50
+
51
+ /**
52
+ * Builds segment word for 0-999 (masculine form).
53
+ */
54
+ function buildSegment (n) {
55
+ if (n === 0) return ''
56
+
57
+ const ones = n % 10
58
+ const tens = Math.floor(n / 10) % 10
59
+ const hundreds = Math.floor(n / 100)
60
+
61
+ const parts = []
62
+
63
+ // Hundreds - Lithuanian always includes the numeral
64
+ if (hundreds > 0) {
65
+ parts.push(ONES_MASC[hundreds])
66
+ parts.push(hundreds === 1 ? HUNDRED_SINGULAR : HUNDRED_PLURAL)
67
+ }
68
+
69
+ // Tens
70
+ if (tens > 1) {
71
+ parts.push(TENS[tens])
72
+ }
73
+
74
+ // Teens or ones
75
+ if (tens === 1) {
76
+ parts.push(TEENS[ones])
77
+ } else if (ones > 0) {
78
+ parts.push(ONES_MASC[ones])
79
+ }
80
+
81
+ return parts.join(' ')
82
+ }
2
83
 
3
84
  /**
4
- * Lithuanian language converter.
85
+ * Builds segment word for 0-999 (feminine form - only differs in ones).
86
+ */
87
+ function buildSegmentFeminine (n) {
88
+ if (n === 0) return ''
89
+
90
+ const ones = n % 10
91
+ const tens = Math.floor(n / 10) % 10
92
+ const hundreds = Math.floor(n / 100)
93
+
94
+ const parts = []
95
+
96
+ // Hundreds - always masculine
97
+ if (hundreds > 0) {
98
+ parts.push(ONES_MASC[hundreds])
99
+ parts.push(hundreds === 1 ? HUNDRED_SINGULAR : HUNDRED_PLURAL)
100
+ }
101
+
102
+ // Tens
103
+ if (tens > 1) {
104
+ parts.push(TENS[tens])
105
+ }
106
+
107
+ // Teens or ones - feminine for ones only
108
+ if (tens === 1) {
109
+ parts.push(TEENS[ones])
110
+ } else if (ones > 0) {
111
+ parts.push(ONES_FEM[ones])
112
+ }
113
+
114
+ return parts.join(' ')
115
+ }
116
+
117
+ // Precompute all 1000 segment words (0-999)
118
+ const SEGMENTS_MASC = new Array(1000)
119
+ const SEGMENTS_FEM = new Array(1000)
120
+
121
+ for (let i = 0; i < 1000; i++) {
122
+ SEGMENTS_MASC[i] = buildSegment(i)
123
+ SEGMENTS_FEM[i] = buildSegmentFeminine(i)
124
+ }
125
+
126
+ // ============================================================================
127
+ // Pluralization
128
+ // ============================================================================
129
+
130
+ /**
131
+ * Lithuanian pluralization rules.
132
+ * - Singular: ends in 1 (except 11)
133
+ * - Plural: ends in 2-9 (except 12-19)
134
+ * - Genitive: 0, 10-19, or ends in 0
5
135
  *
6
- * Supports:
7
- * - Three-form pluralization (one/few/many)
8
- * - Gender agreement (vienas/viena, du/dvi)
9
- * - Baltic declension patterns
136
+ * @param {number} n - The segment value
137
+ * @param {string[]} forms - [singular, plural, genitive]
138
+ * @returns {string} The appropriate form
10
139
  */
11
- export class Lithuanian extends SlavicLanguage {
12
- negativeWord = 'minus'
13
- decimalSeparatorWord = 'kablelis'
14
- zeroWord = 'nulis'
15
-
16
- onesWords = {
17
- 1: 'vienas',
18
- 2: 'du',
19
- 3: 'trys',
20
- 4: 'keturi',
21
- 5: 'penki',
22
- 6: 'šeši',
23
- 7: 'septyni',
24
- 8: 'aštuoni',
25
- 9: 'devyni'
26
- }
27
-
28
- onesFeminineWords = {
29
- 1: 'viena',
30
- 2: 'dvi',
31
- 3: 'trys',
32
- 4: 'keturios',
33
- 5: 'penkios',
34
- 6: 'šešios',
35
- 7: 'septynios',
36
- 8: 'aštuonios',
37
- 9: 'devynios'
38
- }
39
-
40
- teensWords = {
41
- 0: 'dešimt',
42
- 1: 'vienuolika',
43
- 2: 'dvylika',
44
- 3: 'trylika',
45
- 4: 'keturiolika',
46
- 5: 'penkiolika',
47
- 6: 'šešiolika',
48
- 7: 'septyniolika',
49
- 8: 'aštuoniolika',
50
- 9: 'devyniolika'
51
- }
52
-
53
- twentiesWords = {
54
- 2: 'dvidešimt',
55
- 3: 'trisdešimt',
56
- 4: 'keturiasdešimt',
57
- 5: 'penkiasdešimt',
58
- 6: 'šešiasdešimt',
59
- 7: 'septyniasdešimt',
60
- 8: 'aštuoniasdešimt',
61
- 9: 'devyniasdešimt'
62
- }
63
-
64
- hundredsWords = ['šimtas', 'šimtai']
65
-
66
- pluralForms = {
67
- 1: ['tūkstantis', 'tūkstančiai', 'tūkstančių'],
68
- 2: ['milijonas', 'milijonai', 'milijonų'],
69
- 3: ['milijardas', 'milijardai', 'milijardų'],
70
- 4: ['trilijonas', 'trilijonai', 'trilijonų'],
71
- 5: ['kvadrilijonas', 'kvadrilijonai', 'kvadrilijonų'],
72
- 6: ['kvintilijonas', 'kvintilijonai', 'kvintilijonų'],
73
- 7: ['sikstilijonas', 'sikstilijonai', 'sikstilijonų'],
74
- 8: ['septilijonas', 'septilijonai', 'septilijonų'],
75
- 9: ['oktilijonas', 'oktilijonai', 'oktilijonų'],
76
- 10: ['naintilijonas', 'naintilijonai', 'naintilijonų']
77
- }
78
-
79
- pluralize (n, forms) {
80
- if (n === 0n) {
81
- return forms[2]
82
- }
140
+ function pluralize (n, forms) {
141
+ if (n === 0) return forms[2]
83
142
 
84
- const [n1, n2] = this.extractDigits(n)
143
+ const lastDigit = n % 10
144
+ const lastTwoDigits = n % 100
85
145
 
86
- if (n2 === 1n || n1 === 0n) {
87
- return forms[2]
88
- }
146
+ // 10-19 always use genitive
147
+ if (lastTwoDigits >= 10 && lastTwoDigits <= 19) {
148
+ return forms[2]
149
+ }
89
150
 
90
- if (n1 === 1n) {
91
- return forms[0]
92
- }
151
+ // Ends in 0 → genitive
152
+ if (lastDigit === 0) {
153
+ return forms[2]
154
+ }
93
155
 
94
- return forms[1]
156
+ // Ends in 1 → singular
157
+ if (lastDigit === 1) {
158
+ return forms[0]
95
159
  }
96
160
 
97
- integerToWords (integerPart) {
98
- if (integerPart === 0n) {
99
- return this.zeroWord
100
- }
101
- const words = []
102
- const segments = this.splitToSegments(integerPart.toString(), 3)
103
- let index = segments.length
104
- for (const x of segments) {
105
- index = index - 1
106
- if (x === 0n) {
107
- continue
108
- }
109
- const [n1, n2, n3] = this.extractDigits(x)
110
- if (n3 > 0n) {
111
- words.push(this.onesWords[n3])
112
- if (n3 > 1n) {
113
- words.push(this.hundredsWords[1])
114
- } else {
115
- words.push(this.hundredsWords[0])
116
- }
117
- }
118
- if (n2 > 1n) {
119
- words.push(this.twentiesWords[n2])
120
- }
121
- if (n2 === 1n) {
122
- words.push(this.teensWords[n1])
123
- } else if (n1 > 0n) {
124
- if ((index === 1 || (this.options.gender === 'feminine' && index === 0)) && integerPart < 1000n) {
125
- words.push(this.onesFeminineWords[n1])
126
- } else {
127
- words.push(this.onesWords[n1])
128
- }
129
- }
130
- if (index > 0) {
131
- words.push(this.pluralize(x, this.pluralForms[index]))
161
+ // Ends in 2-9 → plural
162
+ return forms[1]
163
+ }
164
+
165
+ // ============================================================================
166
+ // Conversion Functions
167
+ // ============================================================================
168
+
169
+ /**
170
+ * Converts a non-negative integer to Lithuanian words.
171
+ *
172
+ * @param {bigint} n - Non-negative integer to convert
173
+ * @param {Object} options - Conversion options
174
+ * @returns {string} Lithuanian words
175
+ */
176
+ function integerToWords (n, options = {}) {
177
+ if (n === 0n) return ZERO
178
+
179
+ // Fast path: numbers < 1000 (direct lookup)
180
+ if (n < 1000n) {
181
+ const segments = options.gender === 'feminine' ? SEGMENTS_FEM : SEGMENTS_MASC
182
+ return segments[Number(n)]
183
+ }
184
+
185
+ // For numbers >= 1000, feminine only applies to final segment if < 1000
186
+ // But the fixture shows feminine NOT applying for n >= 1000
187
+ // So we use masculine for all segments when n >= 1000
188
+ return buildLargeNumberWords(n, options)
189
+ }
190
+
191
+ /**
192
+ * Builds words for numbers >= 1000.
193
+ *
194
+ * @param {bigint} n - Number >= 1000
195
+ * @param {Object} options - Conversion options
196
+ * @returns {string} Lithuanian words
197
+ */
198
+ function buildLargeNumberWords (n, options) {
199
+ const numStr = n.toString()
200
+ const len = numStr.length
201
+
202
+ // Build segments of 3 digits from right to left
203
+ const segments = []
204
+ const segmentSize = 3
205
+
206
+ const remainderLen = len % segmentSize
207
+ let pos = 0
208
+ if (remainderLen > 0) {
209
+ segments.push(Number(numStr.slice(0, remainderLen)))
210
+ pos = remainderLen
211
+ }
212
+ while (pos < len) {
213
+ segments.push(Number(numStr.slice(pos, pos + segmentSize)))
214
+ pos += segmentSize
215
+ }
216
+
217
+ // Convert segments to words
218
+ const parts = []
219
+ let scaleIndex = segments.length - 1
220
+
221
+ for (let i = 0; i < segments.length; i++) {
222
+ const segment = segments[i]
223
+
224
+ if (segment !== 0) {
225
+ const segmentWord = SEGMENTS_MASC[segment]
226
+
227
+ if (scaleIndex === 0) {
228
+ // Units segment - use masculine (feminine doesn't apply when n >= 1000)
229
+ parts.push(segmentWord)
230
+ } else {
231
+ // Segment with scale word
232
+ const scaleForms = SCALE_FORMS[scaleIndex - 1]
233
+ const scaleWord = pluralize(segment, scaleForms)
234
+ parts.push(segmentWord + ' ' + scaleWord)
132
235
  }
133
236
  }
134
- return words.join(' ')
237
+
238
+ scaleIndex--
239
+ }
240
+
241
+ return parts.join(' ')
242
+ }
243
+
244
+ /**
245
+ * Converts decimal digits to Lithuanian words.
246
+ *
247
+ * @param {string} decimalPart - Decimal digits (without the point)
248
+ * @param {Object} options - Conversion options
249
+ * @returns {string} Lithuanian words for decimal part
250
+ */
251
+ function decimalPartToWords (decimalPart, options) {
252
+ let result = ''
253
+
254
+ // Handle leading zeros
255
+ let i = 0
256
+ while (i < decimalPart.length && decimalPart[i] === '0') {
257
+ if (result) result += ' '
258
+ result += ZERO
259
+ i++
135
260
  }
261
+
262
+ // Convert remainder as a single number
263
+ const remainder = decimalPart.slice(i)
264
+ if (remainder) {
265
+ if (result) result += ' '
266
+ result += integerToWords(BigInt(remainder), options)
267
+ }
268
+
269
+ return result
136
270
  }
271
+
272
+ /**
273
+ * Converts a numeric value to Lithuanian words.
274
+ *
275
+ * @param {number | string | bigint} value - The numeric value to convert
276
+ * @param {Object} [options] - Conversion options
277
+ * @param {string} [options.gender='masculine'] - Gender for numbers < 1000
278
+ * @returns {string} The number in Lithuanian words
279
+ * @throws {TypeError} If value is not a valid numeric type
280
+ * @throws {Error} If value is not a valid number format
281
+ *
282
+ * @example
283
+ * toWords(42) // 'keturiasdešimt du'
284
+ * toWords(1, { gender: 'feminine' }) // 'viena'
285
+ * toWords(1000000) // 'vienas milijonas'
286
+ */
287
+ function toWords (value, options) {
288
+ options = validateOptions(options)
289
+ const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
290
+
291
+ let result = ''
292
+
293
+ if (isNegative) {
294
+ result = NEGATIVE + ' '
295
+ }
296
+
297
+ result += integerToWords(integerPart, options)
298
+
299
+ if (decimalPart) {
300
+ result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart, options)
301
+ }
302
+
303
+ return result
304
+ }
305
+
306
+ // ============================================================================
307
+ // Public API
308
+ // ============================================================================
309
+
310
+ export { toWords }
@@ -1,70 +1,18 @@
1
1
  /**
2
- * Latvian language converter.
2
+ * Converts a numeric value to Latvian words.
3
3
  *
4
- * Supports:
5
- * - Three-form pluralization (one/few/many)
6
- * - Latvian diacritical marks (ī, ā, ē, ū)
7
- * - Compound number formation (divdesmit, trīsdesmit)
4
+ * @param {number | string | bigint} value - The numeric value to convert
5
+ * @param {Object} [options] - Conversion options
6
+ * @param {string} [options.gender='masculine'] - Gender for numbers < 1000
7
+ * @returns {string} The number in Latvian words
8
+ * @throws {TypeError} If value is not a valid numeric type
9
+ * @throws {Error} If value is not a valid number format
10
+ *
11
+ * @example
12
+ * toWords(42) // 'četrdesmit divi'
13
+ * toWords(1, { gender: 'feminine' }) // 'viena'
14
+ * toWords(1000) // 'tūkstotis'
8
15
  */
9
- export class Latvian 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: string[];
55
- pluralForms: {
56
- 1: string[];
57
- 2: string[];
58
- 3: string[];
59
- 4: string[];
60
- 5: string[];
61
- 6: string[];
62
- 7: string[];
63
- 8: string[];
64
- 9: string[];
65
- 10: string[];
66
- };
67
- pluralize(n: any, forms: any): any;
68
- integerToWords(integerPart: any): string;
69
- }
70
- import { SlavicLanguage } from '../classes/slavic-language.js';
16
+ export function toWords(value: number | string | bigint, options?: {
17
+ gender?: string | undefined;
18
+ }): string;