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,130 +1,321 @@
1
- import { SlavicLanguage } from '../classes/slavic-language.js'
2
-
3
1
  /**
4
- * Latvian language converter.
2
+ * Latvian language converter - Functional Implementation
3
+ *
4
+ * A performance-optimized number-to-words converter using precomputed lookup tables.
5
5
  *
6
- * Supports:
7
- * - Three-form pluralization (one/few/many)
8
- * - Latvian diacritical marks (ī, ā, ē, ū)
9
- * - Compound number formation (divdesmit, trīsdesmit)
6
+ * Key features:
7
+ * - Two-form pluralization (singular for 1 except 11, plural otherwise)
8
+ * - Gender agreement (masculine/feminine for numbers < 1000)
9
+ * - Special hundreds forms (simts/simti/simtu)
10
+ * - Omit "one" before scale words
11
+ * - Long scale naming
10
12
  */
11
- export class Latvian extends SlavicLanguage {
12
- negativeWord = 'mīnus'
13
- decimalSeparatorWord = 'komats'
14
- zeroWord = 'nulle'
15
-
16
- onesWords = {
17
- 1: 'viens',
18
- 2: 'divi',
19
- 3: 'trīs',
20
- 4: 'četri',
21
- 5: 'pieci',
22
- 6: 'seši',
23
- 7: 'septiņi',
24
- 8: 'astoņi',
25
- 9: 'deviņi'
13
+
14
+ import { parseNumericValue } from '../utils/parse-numeric.js'
15
+ import { validateOptions } from '../utils/validate-options.js'
16
+
17
+ // ============================================================================
18
+ // Vocabulary (module-level constants)
19
+ // ============================================================================
20
+
21
+ const ONES_MASC = ['', 'viens', 'divi', 'trīs', 'četri', 'pieci', 'seši', 'septiņi', 'astoņi', 'deviņi']
22
+ const ONES_FEM = ['', 'viena', 'divas', 'trīs', 'četras', 'piecas', 'sešas', 'septiņas', 'astoņas', 'deviņas']
23
+
24
+ const TEENS = ['desmit', 'vienpadsmit', 'divpadsmit', 'trīspadsmit', 'četrpadsmit', 'piecpadsmit', 'sešpadsmit', 'septiņpadsmit', 'astoņpadsmit', 'deviņpadsmit']
25
+ const TENS = ['', '', 'divdesmit', 'trīsdesmit', 'četrdesmit', 'piecdesmit', 'sešdesmit', 'septiņdesmit', 'astoņdesmit', 'deviņdesmit']
26
+
27
+ // Hundreds: simts (100, 110-199), simti (200-999), simtu (101-109)
28
+ const HUNDRED_SINGULAR = 'simts'
29
+ const HUNDRED_PLURAL = 'simti'
30
+ const HUNDRED_GENITIVE = 'simtu'
31
+
32
+ const ZERO = 'nulle'
33
+ const NEGATIVE = 'mīnus'
34
+ const DECIMAL_SEP = 'komats'
35
+
36
+ // Scale words: [singular, plural, genitive]
37
+ const SCALE_FORMS = [
38
+ ['tūkstotis', 'tūkstoši', 'tūkstošu'],
39
+ ['miljons', 'miljoni', 'miljonu'],
40
+ ['miljards', 'miljardi', 'miljardu'],
41
+ ['triljons', 'triljoni', 'triljonu'],
42
+ ['kvadriljons', 'kvadriljoni', 'kvadriljonu'],
43
+ ['kvintiljons', 'kvintiljoni', 'kvintiljonu'],
44
+ ['sikstiljons', 'sikstiljoni', 'sikstiljonu'],
45
+ ['septiljons', 'septiljoni', 'septiljonu'],
46
+ ['oktiljons', 'oktiljoni', 'oktiljonu']
47
+ ]
48
+
49
+ // ============================================================================
50
+ // Precomputed Lookup Tables (built once at module load)
51
+ // ============================================================================
52
+
53
+ /**
54
+ * Builds segment word for 0-999 (masculine form).
55
+ * Does NOT include special handling for segment=1 (omitOneBeforeScale).
56
+ * That's handled at join time.
57
+ */
58
+ function buildSegment (n) {
59
+ if (n === 0) return ''
60
+
61
+ const ones = n % 10
62
+ const tens = Math.floor(n / 10) % 10
63
+ const hundreds = Math.floor(n / 100)
64
+
65
+ const parts = []
66
+
67
+ // Hundreds - Latvian has special forms
68
+ if (hundreds > 0) {
69
+ if (hundreds === 1 && tens === 0 && ones > 0) {
70
+ // 101-109: use genitive form "simtu"
71
+ parts.push(HUNDRED_GENITIVE)
72
+ } else if (hundreds > 1) {
73
+ // 200-999: use plural "simti"
74
+ parts.push(ONES_MASC[hundreds])
75
+ parts.push(HUNDRED_PLURAL)
76
+ } else {
77
+ // 100, 110-199: use singular "simts"
78
+ parts.push(HUNDRED_SINGULAR)
79
+ }
26
80
  }
27
81
 
28
- onesFeminineWords = {
29
- 1: 'viena',
30
- 2: 'divas',
31
- 3: 'trīs',
32
- 4: 'četras',
33
- 5: 'piecas',
34
- 6: 'sešas',
35
- 7: 'septiņas',
36
- 8: 'astoņas',
37
- 9: 'deviņas'
82
+ // Tens
83
+ if (tens > 1) {
84
+ parts.push(TENS[tens])
38
85
  }
39
86
 
40
- teensWords = {
41
- 0: 'desmit',
42
- 1: 'vienpadsmit',
43
- 2: 'divpadsmit',
44
- 3: 'trīspadsmit',
45
- 4: 'četrpadsmit',
46
- 5: 'piecpadsmit',
47
- 6: 'sešpadsmit',
48
- 7: 'septiņpadsmit',
49
- 8: 'astoņpadsmit',
50
- 9: 'deviņpadsmit'
87
+ // Teens or ones
88
+ if (tens === 1) {
89
+ parts.push(TEENS[ones])
90
+ } else if (ones > 0) {
91
+ parts.push(ONES_MASC[ones])
92
+ }
93
+
94
+ return parts.join(' ')
95
+ }
96
+
97
+ /**
98
+ * Builds segment word for 0-999 (feminine form - only differs in ones).
99
+ */
100
+ function buildSegmentFeminine (n) {
101
+ if (n === 0) return ''
102
+
103
+ const ones = n % 10
104
+ const tens = Math.floor(n / 10) % 10
105
+ const hundreds = Math.floor(n / 100)
106
+
107
+ const parts = []
108
+
109
+ // Hundreds - always masculine
110
+ if (hundreds > 0) {
111
+ if (hundreds === 1 && tens === 0 && ones > 0) {
112
+ parts.push(HUNDRED_GENITIVE)
113
+ } else if (hundreds > 1) {
114
+ parts.push(ONES_MASC[hundreds])
115
+ parts.push(HUNDRED_PLURAL)
116
+ } else {
117
+ parts.push(HUNDRED_SINGULAR)
118
+ }
51
119
  }
52
120
 
53
- twentiesWords = {
54
- 2: 'divdesmit',
55
- 3: 'trīsdesmit',
56
- 4: 'četrdesmit',
57
- 5: 'piecdesmit',
58
- 6: 'sešdesmit',
59
- 7: 'septiņdesmit',
60
- 8: 'astoņdesmit',
61
- 9: 'deviņdesmit'
121
+ // Tens
122
+ if (tens > 1) {
123
+ parts.push(TENS[tens])
62
124
  }
63
125
 
64
- hundredsWords = ['simts', 'simti', 'simtu']
65
-
66
- pluralForms = {
67
- 1: ['tūkstotis', 'tūkstoši', 'tūkstošu'],
68
- 2: ['miljons', 'miljoni', 'miljonu'],
69
- 3: ['miljards', 'miljardi', 'miljardu'],
70
- 4: ['triljons', 'triljoni', 'triljonu'],
71
- 5: ['kvadriljons', 'kvadriljoni', 'kvadriljonu'],
72
- 6: ['kvintiljons', 'kvintiljoni', 'kvintiljonu'],
73
- 7: ['sikstiljons', 'sikstiljoni', 'sikstiljonu'],
74
- 8: ['septiljons', 'septiljoni', 'septiljonu'],
75
- 9: ['oktiljons', 'oktiljoni', 'oktiljonu'],
76
- 10: ['nontiljons', 'nontiljoni', 'nontiljonu']
126
+ // Teens or ones - feminine for ones only
127
+ if (tens === 1) {
128
+ parts.push(TEENS[ones])
129
+ } else if (ones > 0) {
130
+ parts.push(ONES_FEM[ones])
77
131
  }
78
132
 
79
- pluralize (n, forms) {
80
- if (n === 0n) {
81
- return forms[2]
82
- }
133
+ return parts.join(' ')
134
+ }
83
135
 
84
- const lastDigit = n % 10n
85
- const lastTwoDigits = n % 100n
136
+ // Precompute all 1000 segment words (0-999)
137
+ const SEGMENTS_MASC = new Array(1000)
138
+ const SEGMENTS_FEM = new Array(1000)
86
139
 
87
- if (lastDigit === 1n && lastTwoDigits !== 11n) {
88
- return forms[0]
89
- }
140
+ for (let i = 0; i < 1000; i++) {
141
+ SEGMENTS_MASC[i] = buildSegment(i)
142
+ SEGMENTS_FEM[i] = buildSegmentFeminine(i)
143
+ }
144
+
145
+ // ============================================================================
146
+ // Pluralization
147
+ // ============================================================================
90
148
 
91
- return forms[1]
149
+ /**
150
+ * Latvian pluralization - simpler than Slavic.
151
+ * Singular: ends in 1 (except 11)
152
+ * Plural: everything else
153
+ *
154
+ * @param {number} n - The segment value
155
+ * @param {string[]} forms - [singular, plural, genitive]
156
+ * @returns {string} The appropriate form
157
+ */
158
+ function pluralize (n, forms) {
159
+ if (n === 0) return forms[2]
160
+
161
+ const lastDigit = n % 10
162
+ const lastTwoDigits = n % 100
163
+
164
+ if (lastDigit === 1 && lastTwoDigits !== 11) {
165
+ return forms[0]
92
166
  }
93
167
 
94
- integerToWords (integerPart) {
95
- if (integerPart === 0n) {
96
- return this.zeroWord
97
- }
98
- const words = []
99
- const segments = this.splitToSegments(integerPart.toString(), 3)
100
- let index = segments.length
101
- for (const x of segments) {
102
- index = index - 1
103
- if (x === 0n) {
104
- continue
105
- }
106
- const [n1, n2, n3] = this.extractDigits(x)
107
- if (n3 > 0n) {
108
- if (n3 === 1n && n2 === 0n && n1 > 0n) {
109
- words.push(this.hundredsWords[2])
110
- } else if (n3 > 1n) {
111
- words.push(this.onesWords[n3], this.hundredsWords[1])
168
+ return forms[1]
169
+ }
170
+
171
+ // ============================================================================
172
+ // Conversion Functions
173
+ // ============================================================================
174
+
175
+ /**
176
+ * Converts a non-negative integer to Latvian words.
177
+ *
178
+ * @param {bigint} n - Non-negative integer to convert
179
+ * @param {Object} options - Conversion options
180
+ * @returns {string} Latvian words
181
+ */
182
+ function integerToWords (n, options = {}) {
183
+ if (n === 0n) return ZERO
184
+
185
+ // Fast path: numbers < 1000 (direct lookup)
186
+ if (n < 1000n) {
187
+ const segments = options.gender === 'feminine' ? SEGMENTS_FEM : SEGMENTS_MASC
188
+ return segments[Number(n)]
189
+ }
190
+
191
+ // For numbers >= 1000, feminine only applies to final segment if < 1000
192
+ // But we use masculine for all segments when n >= 1000
193
+ return buildLargeNumberWords(n, options)
194
+ }
195
+
196
+ /**
197
+ * Builds words for numbers >= 1000.
198
+ *
199
+ * @param {bigint} n - Number >= 1000
200
+ * @param {Object} options - Conversion options
201
+ * @returns {string} Latvian words
202
+ */
203
+ function buildLargeNumberWords (n, options) {
204
+ const numStr = n.toString()
205
+ const len = numStr.length
206
+
207
+ // Build segments of 3 digits from right to left
208
+ const segments = []
209
+ const segmentSize = 3
210
+
211
+ const remainderLen = len % segmentSize
212
+ let pos = 0
213
+ if (remainderLen > 0) {
214
+ segments.push(Number(numStr.slice(0, remainderLen)))
215
+ pos = remainderLen
216
+ }
217
+ while (pos < len) {
218
+ segments.push(Number(numStr.slice(pos, pos + segmentSize)))
219
+ pos += segmentSize
220
+ }
221
+
222
+ // Convert segments to words
223
+ const parts = []
224
+ let scaleIndex = segments.length - 1
225
+
226
+ for (let i = 0; i < segments.length; i++) {
227
+ const segment = segments[i]
228
+
229
+ if (segment !== 0) {
230
+ const segmentWord = SEGMENTS_MASC[segment]
231
+
232
+ if (scaleIndex === 0) {
233
+ // Units segment - use masculine (feminine doesn't apply when n >= 1000)
234
+ parts.push(segmentWord)
235
+ } else {
236
+ // Segment with scale word
237
+ const scaleForms = SCALE_FORMS[scaleIndex - 1]
238
+ const scaleWord = pluralize(segment, scaleForms)
239
+
240
+ // Latvian omits "one" before scale words
241
+ if (segment === 1) {
242
+ parts.push(scaleWord)
112
243
  } else {
113
- words.push(this.hundredsWords[0])
244
+ parts.push(segmentWord + ' ' + scaleWord)
114
245
  }
115
246
  }
116
- if (n2 > 1n) {
117
- words.push(this.twentiesWords[n2])
118
- }
119
- if (n2 === 1n) {
120
- words.push(this.teensWords[n1])
121
- } else if (n1 > 0n && !(index > 0 && x === 1n)) {
122
- words.push(this.onesWords[n1])
123
- }
124
- if (index > 0) {
125
- words.push(this.pluralize(x, this.pluralForms[index]))
126
- }
127
247
  }
128
- return words.join(' ')
248
+
249
+ scaleIndex--
250
+ }
251
+
252
+ return parts.join(' ')
253
+ }
254
+
255
+ /**
256
+ * Converts decimal digits to Latvian words.
257
+ *
258
+ * @param {string} decimalPart - Decimal digits (without the point)
259
+ * @param {Object} options - Conversion options
260
+ * @returns {string} Latvian words for decimal part
261
+ */
262
+ function decimalPartToWords (decimalPart, options) {
263
+ let result = ''
264
+
265
+ // Handle leading zeros
266
+ let i = 0
267
+ while (i < decimalPart.length && decimalPart[i] === '0') {
268
+ if (result) result += ' '
269
+ result += ZERO
270
+ i++
271
+ }
272
+
273
+ // Convert remainder as a single number
274
+ const remainder = decimalPart.slice(i)
275
+ if (remainder) {
276
+ if (result) result += ' '
277
+ result += integerToWords(BigInt(remainder), options)
129
278
  }
279
+
280
+ return result
130
281
  }
282
+
283
+ /**
284
+ * Converts a numeric value to Latvian words.
285
+ *
286
+ * @param {number | string | bigint} value - The numeric value to convert
287
+ * @param {Object} [options] - Conversion options
288
+ * @param {string} [options.gender='masculine'] - Gender for numbers < 1000
289
+ * @returns {string} The number in Latvian words
290
+ * @throws {TypeError} If value is not a valid numeric type
291
+ * @throws {Error} If value is not a valid number format
292
+ *
293
+ * @example
294
+ * toWords(42) // 'četrdesmit divi'
295
+ * toWords(1, { gender: 'feminine' }) // 'viena'
296
+ * toWords(1000) // 'tūkstotis'
297
+ */
298
+ function toWords (value, options) {
299
+ options = validateOptions(options)
300
+ const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
301
+
302
+ let result = ''
303
+
304
+ if (isNegative) {
305
+ result = NEGATIVE + ' '
306
+ }
307
+
308
+ result += integerToWords(integerPart, options)
309
+
310
+ if (decimalPart) {
311
+ result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart, options)
312
+ }
313
+
314
+ return result
315
+ }
316
+
317
+ // ============================================================================
318
+ // Public API
319
+ // ============================================================================
320
+
321
+ export { toWords }
@@ -1,11 +1,7 @@
1
1
  /**
2
- * Marathi language converter.
2
+ * Converts a numeric value to Marathi words.
3
3
  *
4
- * Supports:
5
- * - Indian numbering system (हजार, लाख, कोटी)
6
- * - Devanagari script
7
- * - Complete word forms for 0-99
4
+ * @param {number | string | bigint} value - The numeric value to convert
5
+ * @returns {string} The number in Marathi words
8
6
  */
9
- export class Marathi extends SouthAsianLanguage {
10
- }
11
- import { SouthAsianLanguage } from '../classes/south-asian-language.js';
7
+ export function toWords(value: number | string | bigint): string;