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,130 +1,312 @@
1
- import { SlavicLanguage } from '../classes/slavic-language.js'
2
-
3
1
  /**
4
- * Latvian language converter.
2
+ * Latvian language converter - Functional Implementation
3
+ *
4
+ * Self-contained module with its own input validation, ready for subpath exports.
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
+ // Segment Building
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])
51
92
  }
52
93
 
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'
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
+ }
62
119
  }
63
120
 
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']
121
+ // Tens
122
+ if (tens > 1) {
123
+ parts.push(TENS[tens])
77
124
  }
78
125
 
79
- pluralize (n, forms) {
80
- if (n === 0n) {
81
- return forms[2]
82
- }
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])
131
+ }
83
132
 
84
- const lastDigit = n % 10n
85
- const lastTwoDigits = n % 100n
133
+ return parts.join(' ')
134
+ }
86
135
 
87
- if (lastDigit === 1n && lastTwoDigits !== 11n) {
88
- return forms[0]
89
- }
136
+ // ============================================================================
137
+ // Pluralization
138
+ // ============================================================================
139
+
140
+ /**
141
+ * Latvian pluralization - simpler than Slavic.
142
+ * Singular: ends in 1 (except 11)
143
+ * Plural: everything else
144
+ *
145
+ * @param {number} n - The segment value
146
+ * @param {string[]} forms - [singular, plural, genitive]
147
+ * @returns {string} The appropriate form
148
+ */
149
+ function pluralize (n, forms) {
150
+ if (n === 0) return forms[2]
151
+
152
+ const lastDigit = n % 10
153
+ const lastTwoDigits = n % 100
90
154
 
91
- return forms[1]
155
+ if (lastDigit === 1 && lastTwoDigits !== 11) {
156
+ return forms[0]
92
157
  }
93
158
 
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])
159
+ return forms[1]
160
+ }
161
+
162
+ // ============================================================================
163
+ // Conversion Functions
164
+ // ============================================================================
165
+
166
+ /**
167
+ * Converts a non-negative integer to Latvian words.
168
+ *
169
+ * @param {bigint} n - Non-negative integer to convert
170
+ * @param {Object} options - Conversion options
171
+ * @returns {string} Latvian words
172
+ */
173
+ function integerToWords (n, options = {}) {
174
+ if (n === 0n) return ZERO
175
+
176
+ // Fast path: numbers < 1000
177
+ if (n < 1000n) {
178
+ const num = Number(n)
179
+ return options.gender === 'feminine' ? buildSegmentFeminine(num) : buildSegment(num)
180
+ }
181
+
182
+ // For numbers >= 1000, feminine only applies to final segment if < 1000
183
+ // But we use masculine for all segments when n >= 1000
184
+ return buildLargeNumberWords(n, options)
185
+ }
186
+
187
+ /**
188
+ * Builds words for numbers >= 1000.
189
+ *
190
+ * @param {bigint} n - Number >= 1000
191
+ * @param {Object} options - Conversion options
192
+ * @returns {string} Latvian words
193
+ */
194
+ function buildLargeNumberWords (n, options) {
195
+ const numStr = n.toString()
196
+ const len = numStr.length
197
+
198
+ // Build segments of 3 digits from right to left
199
+ const segments = []
200
+ const segmentSize = 3
201
+
202
+ const remainderLen = len % segmentSize
203
+ let pos = 0
204
+ if (remainderLen > 0) {
205
+ segments.push(Number(numStr.slice(0, remainderLen)))
206
+ pos = remainderLen
207
+ }
208
+ while (pos < len) {
209
+ segments.push(Number(numStr.slice(pos, pos + segmentSize)))
210
+ pos += segmentSize
211
+ }
212
+
213
+ // Convert segments to words
214
+ const parts = []
215
+ let scaleIndex = segments.length - 1
216
+
217
+ for (let i = 0; i < segments.length; i++) {
218
+ const segment = segments[i]
219
+
220
+ if (segment !== 0) {
221
+ const segmentWord = buildSegment(segment)
222
+
223
+ if (scaleIndex === 0) {
224
+ // Units segment - use masculine (feminine doesn't apply when n >= 1000)
225
+ parts.push(segmentWord)
226
+ } else {
227
+ // Segment with scale word
228
+ const scaleForms = SCALE_FORMS[scaleIndex - 1]
229
+ const scaleWord = pluralize(segment, scaleForms)
230
+
231
+ // Latvian omits "one" before scale words
232
+ if (segment === 1) {
233
+ parts.push(scaleWord)
112
234
  } else {
113
- words.push(this.hundredsWords[0])
235
+ parts.push(segmentWord + ' ' + scaleWord)
114
236
  }
115
237
  }
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
238
  }
128
- return words.join(' ')
239
+
240
+ scaleIndex--
241
+ }
242
+
243
+ return parts.join(' ')
244
+ }
245
+
246
+ /**
247
+ * Converts decimal digits to Latvian words.
248
+ *
249
+ * @param {string} decimalPart - Decimal digits (without the point)
250
+ * @param {Object} options - Conversion options
251
+ * @returns {string} Latvian words for decimal part
252
+ */
253
+ function decimalPartToWords (decimalPart, options) {
254
+ let result = ''
255
+
256
+ // Handle leading zeros
257
+ let i = 0
258
+ while (i < decimalPart.length && decimalPart[i] === '0') {
259
+ if (result) result += ' '
260
+ result += ZERO
261
+ i++
262
+ }
263
+
264
+ // Convert remainder as a single number
265
+ const remainder = decimalPart.slice(i)
266
+ if (remainder) {
267
+ if (result) result += ' '
268
+ result += integerToWords(BigInt(remainder), options)
269
+ }
270
+
271
+ return result
272
+ }
273
+
274
+ /**
275
+ * Converts a numeric value to Latvian words.
276
+ *
277
+ * @param {number | string | bigint} value - The numeric value to convert
278
+ * @param {Object} [options] - Conversion options
279
+ * @param {string} [options.gender='masculine'] - Gender for numbers < 1000
280
+ * @returns {string} The number in Latvian words
281
+ * @throws {TypeError} If value is not a valid numeric type
282
+ * @throws {Error} If value is not a valid number format
283
+ *
284
+ * @example
285
+ * toWords(42) // 'četrdesmit divi'
286
+ * toWords(1, { gender: 'feminine' }) // 'viena'
287
+ * toWords(1000) // 'tūkstotis'
288
+ */
289
+ function toWords (value, options) {
290
+ options = validateOptions(options)
291
+ const { isNegative, integerPart, decimalPart } = parseNumericValue(value)
292
+
293
+ let result = ''
294
+
295
+ if (isNegative) {
296
+ result = NEGATIVE + ' '
129
297
  }
298
+
299
+ result += integerToWords(integerPart, options)
300
+
301
+ if (decimalPart) {
302
+ result += ' ' + DECIMAL_SEP + ' ' + decimalPartToWords(decimalPart, options)
303
+ }
304
+
305
+ return result
130
306
  }
307
+
308
+ // ============================================================================
309
+ // Public API
310
+ // ============================================================================
311
+
312
+ 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;