n2words 1.23.0 → 1.24.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 (317) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +182 -53
  3. package/dist/languages/ar.js +2 -0
  4. package/dist/languages/ar.js.map +1 -0
  5. package/dist/languages/az.js +2 -0
  6. package/dist/languages/az.js.map +1 -0
  7. package/dist/languages/bn.js +2 -0
  8. package/dist/languages/bn.js.map +1 -0
  9. package/dist/languages/cs.js +2 -0
  10. package/dist/languages/cs.js.map +1 -0
  11. package/dist/languages/da.js +2 -0
  12. package/dist/languages/da.js.map +1 -0
  13. package/dist/languages/de.js +2 -0
  14. package/dist/languages/de.js.map +1 -0
  15. package/dist/languages/el.js +2 -0
  16. package/dist/languages/el.js.map +1 -0
  17. package/dist/languages/en.js +2 -0
  18. package/dist/languages/en.js.map +1 -0
  19. package/dist/languages/es.js +2 -0
  20. package/dist/languages/es.js.map +1 -0
  21. package/dist/languages/fa.js +2 -0
  22. package/dist/languages/fa.js.map +1 -0
  23. package/dist/languages/fil.js +2 -0
  24. package/dist/languages/fil.js.map +1 -0
  25. package/dist/languages/fr-BE.js +2 -0
  26. package/dist/languages/fr-BE.js.map +1 -0
  27. package/dist/languages/fr.js +2 -0
  28. package/dist/languages/fr.js.map +1 -0
  29. package/dist/languages/gu.js +2 -0
  30. package/dist/languages/gu.js.map +1 -0
  31. package/dist/languages/he.js +2 -0
  32. package/dist/languages/he.js.map +1 -0
  33. package/dist/languages/hi.js +2 -0
  34. package/dist/languages/hi.js.map +1 -0
  35. package/dist/languages/hr.js +2 -0
  36. package/dist/languages/hr.js.map +1 -0
  37. package/dist/languages/hu.js +2 -0
  38. package/dist/languages/hu.js.map +1 -0
  39. package/dist/languages/id.js +2 -0
  40. package/dist/languages/id.js.map +1 -0
  41. package/dist/languages/it.js +2 -0
  42. package/dist/languages/it.js.map +1 -0
  43. package/dist/languages/ja.js +2 -0
  44. package/dist/languages/ja.js.map +1 -0
  45. package/dist/languages/kn.js +2 -0
  46. package/dist/languages/kn.js.map +1 -0
  47. package/dist/languages/ko.js +2 -0
  48. package/dist/languages/ko.js.map +1 -0
  49. package/dist/languages/lt.js +2 -0
  50. package/dist/languages/lt.js.map +1 -0
  51. package/dist/languages/lv.js +2 -0
  52. package/dist/languages/lv.js.map +1 -0
  53. package/dist/languages/mr.js +2 -0
  54. package/dist/languages/mr.js.map +1 -0
  55. package/dist/languages/ms.js +2 -0
  56. package/dist/languages/ms.js.map +1 -0
  57. package/dist/languages/nb.js +2 -0
  58. package/dist/languages/nb.js.map +1 -0
  59. package/dist/languages/nl.js +2 -0
  60. package/dist/languages/nl.js.map +1 -0
  61. package/dist/languages/pa-Guru.js +2 -0
  62. package/dist/languages/pa-Guru.js.map +1 -0
  63. package/dist/languages/pl.js +2 -0
  64. package/dist/languages/pl.js.map +1 -0
  65. package/dist/languages/pt.js +2 -0
  66. package/dist/languages/pt.js.map +1 -0
  67. package/dist/languages/ro.js +2 -0
  68. package/dist/languages/ro.js.map +1 -0
  69. package/dist/languages/ru.js +2 -0
  70. package/dist/languages/ru.js.map +1 -0
  71. package/dist/languages/sr-Latn.js +2 -0
  72. package/dist/languages/sr-Latn.js.map +1 -0
  73. package/dist/languages/sv.js +2 -0
  74. package/dist/languages/sv.js.map +1 -0
  75. package/dist/languages/sw.js +2 -0
  76. package/dist/languages/sw.js.map +1 -0
  77. package/dist/languages/ta.js +2 -0
  78. package/dist/languages/ta.js.map +1 -0
  79. package/dist/languages/te.js +2 -0
  80. package/dist/languages/te.js.map +1 -0
  81. package/dist/languages/th.js +2 -0
  82. package/dist/languages/th.js.map +1 -0
  83. package/dist/languages/tr.js +2 -0
  84. package/dist/languages/tr.js.map +1 -0
  85. package/dist/languages/uk.js +2 -0
  86. package/dist/languages/uk.js.map +1 -0
  87. package/dist/languages/ur.js +2 -0
  88. package/dist/languages/ur.js.map +1 -0
  89. package/dist/languages/vi.js +2 -0
  90. package/dist/languages/vi.js.map +1 -0
  91. package/dist/languages/zh-Hans.js +2 -0
  92. package/dist/languages/zh-Hans.js.map +1 -0
  93. package/dist/n2words.js +1 -1
  94. package/dist/n2words.js.map +1 -1
  95. package/lib/classes/abstract-language.js +211 -110
  96. package/lib/classes/greedy-scale-language.js +195 -0
  97. package/lib/classes/slavic-language.js +251 -0
  98. package/lib/classes/south-asian-language.js +161 -0
  99. package/lib/classes/turkic-language.js +63 -0
  100. package/lib/languages/ar.js +243 -0
  101. package/lib/languages/az.js +58 -0
  102. package/lib/languages/bn.js +126 -0
  103. package/lib/languages/cs.js +212 -0
  104. package/lib/languages/da.js +167 -0
  105. package/lib/languages/de.js +135 -0
  106. package/lib/languages/el.js +116 -0
  107. package/lib/languages/en.js +123 -0
  108. package/lib/languages/es.js +153 -0
  109. package/lib/languages/fa.js +127 -0
  110. package/lib/languages/fil.js +162 -0
  111. package/lib/languages/fr-BE.js +61 -0
  112. package/lib/languages/fr.js +145 -0
  113. package/lib/languages/gu.js +156 -0
  114. package/lib/languages/he.js +329 -0
  115. package/lib/languages/hi.js +126 -0
  116. package/lib/languages/hr.js +157 -0
  117. package/lib/languages/hu.js +155 -0
  118. package/lib/languages/id.js +174 -0
  119. package/lib/languages/it.js +148 -0
  120. package/lib/languages/ja.js +190 -0
  121. package/lib/languages/kn.js +71 -0
  122. package/lib/languages/ko.js +83 -0
  123. package/lib/languages/lt.js +171 -0
  124. package/lib/languages/lv.js +153 -0
  125. package/lib/languages/mr.js +156 -0
  126. package/lib/languages/ms.js +146 -0
  127. package/lib/languages/nb.js +120 -0
  128. package/lib/languages/nl.js +206 -0
  129. package/lib/languages/pa-Guru.js +126 -0
  130. package/lib/languages/pl.js +189 -0
  131. package/lib/languages/pt.js +147 -0
  132. package/lib/languages/ro.js +380 -0
  133. package/lib/languages/ru.js +116 -0
  134. package/lib/languages/sr-Latn.js +157 -0
  135. package/lib/languages/sv.js +127 -0
  136. package/lib/languages/sw.js +121 -0
  137. package/lib/languages/ta.js +226 -0
  138. package/lib/languages/te.js +229 -0
  139. package/lib/languages/th.js +123 -0
  140. package/lib/languages/tr.js +83 -0
  141. package/lib/{i18n → languages}/uk.js +50 -23
  142. package/lib/languages/ur.js +126 -0
  143. package/lib/languages/vi.js +193 -0
  144. package/lib/languages/zh-Hans.js +165 -0
  145. package/lib/n2words.js +246 -75
  146. package/package.json +80 -72
  147. package/typings/classes/abstract-language.d.ts +144 -0
  148. package/typings/classes/greedy-scale-language.d.ts +148 -0
  149. package/typings/classes/slavic-language.d.ts +145 -0
  150. package/typings/classes/south-asian-language.d.ts +101 -0
  151. package/typings/classes/turkic-language.d.ts +42 -0
  152. package/typings/languages/ar.d.ts +93 -0
  153. package/typings/languages/az.d.ts +25 -0
  154. package/typings/languages/bn.d.ts +1 -0
  155. package/typings/languages/cs.d.ts +120 -0
  156. package/typings/languages/da.d.ts +53 -0
  157. package/typings/languages/de.d.ts +26 -0
  158. package/typings/languages/el.d.ts +11 -0
  159. package/typings/languages/en.d.ts +30 -0
  160. package/typings/languages/es.d.ts +43 -0
  161. package/typings/languages/fa.d.ts +81 -0
  162. package/typings/languages/fil.d.ts +12 -0
  163. package/typings/languages/fr-BE.d.ts +41 -0
  164. package/typings/languages/fr.d.ts +43 -0
  165. package/typings/languages/gu.d.ts +12 -0
  166. package/typings/languages/he.d.ts +197 -0
  167. package/typings/languages/hi.d.ts +1 -0
  168. package/typings/languages/hr.d.ts +110 -0
  169. package/typings/languages/hu.d.ts +37 -0
  170. package/typings/languages/id.d.ts +69 -0
  171. package/typings/languages/it.d.ts +51 -0
  172. package/typings/languages/ja.d.ts +58 -0
  173. package/typings/languages/kn.d.ts +11 -0
  174. package/typings/languages/ko.d.ts +25 -0
  175. package/typings/languages/lt.d.ts +110 -0
  176. package/typings/languages/lv.d.ts +99 -0
  177. package/typings/languages/mr.d.ts +12 -0
  178. package/typings/languages/ms.d.ts +37 -0
  179. package/typings/languages/nb.d.ts +27 -0
  180. package/typings/languages/nl.d.ts +65 -0
  181. package/typings/languages/pa-Guru.d.ts +1 -0
  182. package/typings/languages/pl.d.ts +116 -0
  183. package/typings/languages/pt.d.ts +39 -0
  184. package/typings/languages/ro.d.ts +229 -0
  185. package/typings/languages/ru.d.ts +108 -0
  186. package/typings/languages/sr-Latn.d.ts +98 -0
  187. package/typings/languages/sv.d.ts +30 -0
  188. package/typings/languages/sw.d.ts +1 -0
  189. package/typings/languages/ta.d.ts +1 -0
  190. package/typings/languages/te.d.ts +1 -0
  191. package/typings/languages/th.d.ts +1 -0
  192. package/typings/languages/tr.d.ts +46 -0
  193. package/typings/languages/uk.d.ts +117 -0
  194. package/typings/languages/ur.d.ts +1 -0
  195. package/typings/languages/vi.d.ts +116 -0
  196. package/typings/languages/zh-Hans.d.ts +57 -0
  197. package/typings/n2words.d.ts +177 -0
  198. package/dist/ar.js +0 -2
  199. package/dist/ar.js.map +0 -1
  200. package/dist/az.js +0 -2
  201. package/dist/az.js.map +0 -1
  202. package/dist/cz.js +0 -2
  203. package/dist/cz.js.map +0 -1
  204. package/dist/de.js +0 -2
  205. package/dist/de.js.map +0 -1
  206. package/dist/dk.js +0 -2
  207. package/dist/dk.js.map +0 -1
  208. package/dist/en.js +0 -2
  209. package/dist/en.js.map +0 -1
  210. package/dist/es.js +0 -2
  211. package/dist/es.js.map +0 -1
  212. package/dist/fa.js +0 -2
  213. package/dist/fa.js.map +0 -1
  214. package/dist/fr-BE.js +0 -2
  215. package/dist/fr-BE.js.map +0 -1
  216. package/dist/fr.js +0 -2
  217. package/dist/fr.js.map +0 -1
  218. package/dist/he.js +0 -2
  219. package/dist/he.js.map +0 -1
  220. package/dist/hr.js +0 -2
  221. package/dist/hr.js.map +0 -1
  222. package/dist/hu.js +0 -2
  223. package/dist/hu.js.map +0 -1
  224. package/dist/id.js +0 -2
  225. package/dist/id.js.map +0 -1
  226. package/dist/it.js +0 -2
  227. package/dist/it.js.map +0 -1
  228. package/dist/ko.js +0 -2
  229. package/dist/ko.js.map +0 -1
  230. package/dist/lt.js +0 -2
  231. package/dist/lt.js.map +0 -1
  232. package/dist/lv.js +0 -2
  233. package/dist/lv.js.map +0 -1
  234. package/dist/n2words.d.ts +0 -2
  235. package/dist/nl.js +0 -2
  236. package/dist/nl.js.map +0 -1
  237. package/dist/no.js +0 -2
  238. package/dist/no.js.map +0 -1
  239. package/dist/pl.js +0 -2
  240. package/dist/pl.js.map +0 -1
  241. package/dist/pt.js +0 -2
  242. package/dist/pt.js.map +0 -1
  243. package/dist/ro.js +0 -2
  244. package/dist/ro.js.map +0 -1
  245. package/dist/ru.js +0 -2
  246. package/dist/ru.js.map +0 -1
  247. package/dist/sr.js +0 -2
  248. package/dist/sr.js.map +0 -1
  249. package/dist/tr.js +0 -2
  250. package/dist/tr.js.map +0 -1
  251. package/dist/uk.js +0 -2
  252. package/dist/uk.js.map +0 -1
  253. package/dist/vi.js +0 -2
  254. package/dist/vi.js.map +0 -1
  255. package/dist/zh.js +0 -2
  256. package/dist/zh.js.map +0 -1
  257. package/lib/classes/abstract-language.d.ts +0 -54
  258. package/lib/classes/base-language.d.ts +0 -58
  259. package/lib/classes/base-language.js +0 -172
  260. package/lib/i18n/ar.d.ts +0 -41
  261. package/lib/i18n/ar.js +0 -209
  262. package/lib/i18n/az.d.ts +0 -15
  263. package/lib/i18n/az.js +0 -66
  264. package/lib/i18n/cz.d.ts +0 -68
  265. package/lib/i18n/cz.js +0 -135
  266. package/lib/i18n/de.d.ts +0 -17
  267. package/lib/i18n/de.js +0 -103
  268. package/lib/i18n/dk.d.ts +0 -14
  269. package/lib/i18n/dk.js +0 -110
  270. package/lib/i18n/en.d.ts +0 -22
  271. package/lib/i18n/en.js +0 -86
  272. package/lib/i18n/es.d.ts +0 -16
  273. package/lib/i18n/es.js +0 -110
  274. package/lib/i18n/fa.d.ts +0 -54
  275. package/lib/i18n/fa.js +0 -106
  276. package/lib/i18n/fr-BE.d.ts +0 -11
  277. package/lib/i18n/fr-BE.js +0 -20
  278. package/lib/i18n/fr.d.ts +0 -15
  279. package/lib/i18n/fr.js +0 -99
  280. package/lib/i18n/he.d.ts +0 -61
  281. package/lib/i18n/he.js +0 -132
  282. package/lib/i18n/hr.d.ts +0 -68
  283. package/lib/i18n/hr.js +0 -129
  284. package/lib/i18n/hu.d.ts +0 -17
  285. package/lib/i18n/hu.js +0 -135
  286. package/lib/i18n/id.d.ts +0 -43
  287. package/lib/i18n/id.js +0 -156
  288. package/lib/i18n/it.d.ts +0 -29
  289. package/lib/i18n/it.js +0 -137
  290. package/lib/i18n/ko.d.ts +0 -15
  291. package/lib/i18n/ko.js +0 -56
  292. package/lib/i18n/lt.d.ts +0 -68
  293. package/lib/i18n/lt.js +0 -138
  294. package/lib/i18n/lv.d.ts +0 -57
  295. package/lib/i18n/lv.js +0 -120
  296. package/lib/i18n/nl.d.ts +0 -20
  297. package/lib/i18n/nl.js +0 -125
  298. package/lib/i18n/no.d.ts +0 -15
  299. package/lib/i18n/no.js +0 -77
  300. package/lib/i18n/pl.d.ts +0 -67
  301. package/lib/i18n/pl.js +0 -126
  302. package/lib/i18n/pt.d.ts +0 -26
  303. package/lib/i18n/pt.js +0 -118
  304. package/lib/i18n/ro.d.ts +0 -109
  305. package/lib/i18n/ro.js +0 -360
  306. package/lib/i18n/ru.d.ts +0 -30
  307. package/lib/i18n/ru.js +0 -198
  308. package/lib/i18n/sr.d.ts +0 -56
  309. package/lib/i18n/sr.js +0 -127
  310. package/lib/i18n/tr.d.ts +0 -15
  311. package/lib/i18n/tr.js +0 -64
  312. package/lib/i18n/uk.d.ts +0 -78
  313. package/lib/i18n/vi.d.ts +0 -70
  314. package/lib/i18n/vi.js +0 -151
  315. package/lib/i18n/zh.d.ts +0 -18
  316. package/lib/i18n/zh.js +0 -78
  317. package/lib/n2words.d.ts +0 -9
@@ -0,0 +1,127 @@
1
+ import GreedyScaleLanguage from '../classes/greedy-scale-language.js'
2
+
3
+ /**
4
+ * Swedish language converter.
5
+ *
6
+ * Converts numbers to Swedish words, supporting:
7
+ * - Negative numbers (prepended with "minus")
8
+ * - Decimal numbers (word "komma" between whole and fractional parts)
9
+ * - Numbers up to quadrillions
10
+ *
11
+ * Merge rules:
12
+ * - Hyphenated for compound tens (e.g., "tjugo-tre")
13
+ * - "och" (and) after hundreds (e.g., "hundra och ett")
14
+ * - Space-separated for larger composites (e.g., "en miljon")
15
+ */
16
+ export class Swedish extends GreedyScaleLanguage {
17
+ negativeWord = 'minus'
18
+ decimalSeparatorWord = 'komma'
19
+ zeroWord = 'noll'
20
+ wordSeparator = ' '
21
+ scaleWordPairs = [
22
+ [1_000_000_000_000_000_000_000_000_000n, 'kvadriljon'],
23
+ [1_000_000_000_000_000_000_000_000n, 'triljon'],
24
+ [1_000_000_000_000_000_000_000n, 'biljon'],
25
+ [1_000_000_000_000_000_000n, 'miljard'],
26
+ [1_000_000_000_000n, 'biljon'],
27
+ [1_000_000_000n, 'miljard'],
28
+ [1_000_000n, 'miljon'],
29
+ [1000n, 'tusen'],
30
+ [100n, 'hundra'],
31
+ [90n, 'nittio'],
32
+ [80n, 'åttio'],
33
+ [70n, 'sjuttio'],
34
+ [60n, 'sextio'],
35
+ [50n, 'femtio'],
36
+ [40n, 'fyrtio'],
37
+ [30n, 'trettio'],
38
+ [20n, 'tjugo'],
39
+ [19n, 'nitton'],
40
+ [18n, 'arton'],
41
+ [17n, 'sjutton'],
42
+ [16n, 'sexton'],
43
+ [15n, 'femton'],
44
+ [14n, 'fjorton'],
45
+ [13n, 'tretton'],
46
+ [12n, 'tolv'],
47
+ [11n, 'elva'],
48
+ [10n, 'tio'],
49
+ [9n, 'nio'],
50
+ [8n, 'åtta'],
51
+ [7n, 'sju'],
52
+ [6n, 'sex'],
53
+ [5n, 'fem'],
54
+ [4n, 'fyra'],
55
+ [3n, 'tre'],
56
+ [2n, 'två'],
57
+ [1n, 'ett'],
58
+ [0n, 'noll']
59
+ ]
60
+
61
+ /**
62
+ * Merges two adjacent word-number pairs according to Swedish grammar rules.
63
+ *
64
+ * Swedish-specific rules:
65
+ * - Implicit "ett": `mergeScales({ 'ett': 1n }, { 'hundra': 100n })` → `{ 'hundra': 100n }`
66
+ * - Hyphenated compounds: `mergeScales({ 'tjugo': 20n }, { 'tre': 3n })` → `{ 'tjugo-tre': 23n }`
67
+ * - "och" after hundreds: `mergeScales({ 'hundra': 100n }, { 'ett': 1n })` → `{ 'hundra och ett': 101n }`
68
+ * - "en" for millions: `mergeScales({ 'ett': 1n }, { 'miljon': 1000000n })` → `{ 'en miljon': 1000000n }`
69
+ *
70
+ * @param {Object} leftPair Left word-set as `{ word: BigInt }`.
71
+ * @param {Object} rightPair Right word-set as `{ word: BigInt }`.
72
+ * @returns {Object} Merged pair with combined word and resulting numeric value.
73
+ *
74
+ * @example
75
+ * mergeScales({ 'ett': 1n }, { 'hundra': 100n }); // { 'hundra': 100n }
76
+ * mergeScales({ 'tjugo': 20n }, { 'tre': 3n }); // { 'tjugo-tre': 23n }
77
+ */
78
+ mergeScales (leftPair, rightPair) {
79
+ const leftWord = Object.keys(leftPair)[0]
80
+ const rightWord = Object.keys(rightPair)[0]
81
+ const leftNumber = Object.values(leftPair)[0]
82
+ const rightNumber = Object.values(rightPair)[0]
83
+
84
+ if (leftNumber === 1n && rightNumber < 100n) {
85
+ return rightPair
86
+ }
87
+
88
+ // Omit 'ett' before 'hundra' and 'tusen'
89
+ if (leftNumber === 1n && (rightNumber === 100n || rightNumber === 1000n)) {
90
+ return rightPair
91
+ }
92
+
93
+ if (leftNumber < 100n && leftNumber > rightNumber) {
94
+ return { [`${leftWord}-${rightWord}`]: leftNumber + rightNumber }
95
+ }
96
+
97
+ if (leftNumber >= 100n && rightNumber < 100n) {
98
+ return { [`${leftWord} och ${rightWord}`]: leftNumber + rightNumber }
99
+ }
100
+
101
+ if (rightNumber > leftNumber) {
102
+ if (leftNumber === 1n && rightNumber >= 1_000_000n) {
103
+ return { [`en ${rightWord}`]: leftNumber * rightNumber }
104
+ }
105
+ return { [`${leftWord} ${rightWord}`]: leftNumber * rightNumber }
106
+ }
107
+
108
+ return { [`${leftWord} ${rightWord}`]: leftNumber + rightNumber }
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Converts a number to Swedish cardinal (written) form.
114
+ *
115
+ * @param {number|string|bigint} value The number to convert.
116
+ * @param {Object} [options] Conversion options (see Swedish class options).
117
+ * @returns {string} The number expressed in Swedish words.
118
+ * @throws {TypeError} If value is NaN or invalid type.
119
+ * @throws {Error} If value is an invalid number string.
120
+ *
121
+ * @example
122
+ * convertToWords(42); // 'fyrtio-två'
123
+ * convertToWords('1.5'); // 'ett komma fem'
124
+ */
125
+ export default function convertToWords (value, options = {}) {
126
+ return new Swedish(options).convertToWords(value)
127
+ }
@@ -0,0 +1,121 @@
1
+ import AbstractLanguage from '../classes/abstract-language.js'
2
+
3
+ class Swahili extends AbstractLanguage {
4
+ negativeWord = 'minus'
5
+ decimalSeparatorWord = 'nukta'
6
+ zeroWord = 'sifuri'
7
+ digits = {
8
+ 0: 'sifuri',
9
+ 1: 'moja',
10
+ 2: 'mbili',
11
+ 3: 'tatu',
12
+ 4: 'nne',
13
+ 5: 'tano',
14
+ 6: 'sita',
15
+ 7: 'saba',
16
+ 8: 'nane',
17
+ 9: 'tisa'
18
+ }
19
+
20
+ tens = {
21
+ 10: 'kumi',
22
+ 20: 'ishirini',
23
+ 30: 'thelathini',
24
+ 40: 'arobaini',
25
+ 50: 'hamsini',
26
+ 60: 'sitini',
27
+ 70: 'sabini',
28
+ 80: 'themanini',
29
+ 90: 'tisini'
30
+ }
31
+
32
+ scales = [
33
+ '',
34
+ 'elfu',
35
+ 'milioni',
36
+ 'bilioni',
37
+ 'trilioni'
38
+ ]
39
+
40
+ wordsUnder100 (n) {
41
+ if (n < 10) return this.digits[n]
42
+ if (n === 10) return this.tens[10]
43
+ if (n < 20) {
44
+ // 11-19: 'kumi na <digit>'
45
+ return this.tens[10] + ' na ' + this.digits[n - 10]
46
+ }
47
+ const tens = Math.trunc(n / 10) * 10
48
+ const ones = n % 10
49
+ if (ones === 0) return this.tens[tens]
50
+ return this.tens[tens] + ' na ' + this.digits[ones]
51
+ }
52
+
53
+ wordsUnder1000 (n) {
54
+ if (n < 100) return this.wordsUnder100(n)
55
+ if (n === 100) return 'mia moja'
56
+ const hundreds = Math.trunc(n / 100)
57
+ const rest = n % 100
58
+ const parts = []
59
+
60
+ // Hundreds: 'mia <digit>'
61
+ parts.push('mia ' + this.digits[hundreds])
62
+ if (rest > 0) {
63
+ if (rest < 10) {
64
+ parts.push('na ' + this.digits[rest])
65
+ } else {
66
+ parts.push(this.wordsUnder100(rest))
67
+ }
68
+ }
69
+
70
+ return parts.join(' ')
71
+ }
72
+
73
+ splitBy3 (number) {
74
+ const s = number.toString()
75
+ if (s.length <= 3) return [Number(s)]
76
+ const groups = []
77
+ const last3 = s.slice(-3)
78
+ groups.unshift(Number(last3))
79
+ let remaining = s.slice(0, -3)
80
+ while (remaining.length > 0) {
81
+ const group = remaining.slice(-3)
82
+ groups.unshift(Number(group))
83
+ remaining = remaining.slice(0, -3)
84
+ }
85
+ return groups
86
+ }
87
+
88
+ convertWholePart (number) {
89
+ if (number === 0n) return this.zeroWord
90
+
91
+ const groups = this.splitBy3(number)
92
+ const parts = []
93
+
94
+ for (let i = 0; i < groups.length; i++) {
95
+ const val = groups[i]
96
+ if (val === 0) continue
97
+ const scaleIndex = groups.length - i - 1
98
+ // scale word
99
+ if (scaleIndex === 0) {
100
+ if (val < 10 && parts.length > 0) {
101
+ parts.push('na ' + this.digits[val])
102
+ } else if (val === 100 && parts.length > 0) {
103
+ // In compound numbers (e.g., 1100 -> 'elfu moja mia'), use 'mia' not 'mia moja'
104
+ parts.push('mia')
105
+ } else {
106
+ parts.push(this.wordsUnder1000(val))
107
+ }
108
+ } else {
109
+ // e.g., 'elfu moja', 'milioni mbili'
110
+ const unit = (val === 1) ? 'moja' : this.wordsUnder1000(val)
111
+ parts.push(this.scales[scaleIndex] + ' ' + unit)
112
+ }
113
+ }
114
+
115
+ return parts.join(' ').trim()
116
+ }
117
+ }
118
+
119
+ export default function convertToWords (value, options = {}) {
120
+ return new Swahili(options).convertToWords(value)
121
+ }
@@ -0,0 +1,226 @@
1
+ import AbstractLanguage from '../classes/abstract-language.js'
2
+
3
+ class Tamil extends AbstractLanguage {
4
+ negativeWord = 'மைனஸ்'
5
+ decimalSeparatorWord = 'புள்ளி'
6
+ zeroWord = 'பூஜ்ஜியம்'
7
+ convertDecimalsPerDigit = true // Enable digit-by-digit decimal conversion
8
+ belowHundred = [
9
+ 'பூஜ்ஜியம்',
10
+ 'ஒன்று',
11
+ 'இரண்டு',
12
+ 'மூன்று',
13
+ 'நான்கு',
14
+ 'ஐந்து',
15
+ 'ஆறு',
16
+ 'ஏழு',
17
+ 'எட்டு',
18
+ 'ஒன்பது',
19
+ 'பத்து',
20
+ 'பதினொன்று',
21
+ 'பன்னிரண்டு',
22
+ 'பதிமூன்று',
23
+ 'பதினான்கு',
24
+ 'பதினைந்து',
25
+ 'பதினாறு',
26
+ 'பதினேழு',
27
+ 'பதினெட்டு',
28
+ 'பத்தொன்பது',
29
+ 'இருபது',
30
+ 'இருபத்தொன்று',
31
+ 'இருபத்திரண்டு',
32
+ 'இருபத்திமூன்று',
33
+ 'இருபத்திநான்கு',
34
+ 'இருபத்தைந்து',
35
+ 'இருபத்தாறு',
36
+ 'இருபத்தேழு',
37
+ 'இருபத்தெட்டு',
38
+ 'இருபத்தொன்பது',
39
+ 'முப்பது',
40
+ 'முப்பத்தொன்று',
41
+ 'முப்பத்திரண்டு',
42
+ 'முப்பத்திமூன்று',
43
+ 'முப்பத்திநான்கு',
44
+ 'முப்பத்தைந்து',
45
+ 'முப்பத்தாறு',
46
+ 'முப்பத்தேழு',
47
+ 'முப்பத்தெட்டு',
48
+ 'முப்பத்தொன்பது',
49
+ 'நாற்பது',
50
+ 'நாற்பத்தொன்று',
51
+ 'நாற்பத்திரண்டு',
52
+ 'நாற்பத்திமூன்று',
53
+ 'நாற்பத்திநான்கு',
54
+ 'நாற்பத்தைந்து',
55
+ 'நாற்பத்தாறு',
56
+ 'நாற்பத்தேழு',
57
+ 'நாற்பத்தெட்டு',
58
+ 'நாற்பத்தொன்பது',
59
+ 'ஐம்பது',
60
+ 'ஐம்பத்தொன்று',
61
+ 'ஐம்பத்திரண்டு',
62
+ 'ஐம்பத்திமூன்று',
63
+ 'ஐம்பத்திநான்கு',
64
+ 'ஐம்பத்தைந்து',
65
+ 'ஐம்பத்தாறு',
66
+ 'ஐம்பத்தேழு',
67
+ 'ஐம்பத்தெட்டு',
68
+ 'ஐம்பத்தொன்பது',
69
+ 'அறுபது',
70
+ 'அறுபத்தொன்று',
71
+ 'அறுபத்திரண்டு',
72
+ 'அறுபத்திமூன்று',
73
+ 'அறுபத்திநான்கு',
74
+ 'அறுபத்தைந்து',
75
+ 'அறுபத்தாறு',
76
+ 'அறுபத்தேழு',
77
+ 'அறுபத்தெட்டு',
78
+ 'அறுபத்தொன்பது',
79
+ 'எழுபது',
80
+ 'எழுபத்தொன்று',
81
+ 'எழுபத்திரண்டு',
82
+ 'எழுபத்திமூன்று',
83
+ 'எழுபத்திநான்கு',
84
+ 'எழுபத்தைந்து',
85
+ 'எழுபத்தாறு',
86
+ 'எழுபத்தேழு',
87
+ 'எழுபத்தெட்டு',
88
+ 'எழுபத்தொன்பது',
89
+ 'எண்பது',
90
+ 'எண்பத்தொன்று',
91
+ 'எண்பத்திரண்டு',
92
+ 'எண்பத்திமூன்று',
93
+ 'எண்பத்திநான்கு',
94
+ 'எண்பத்தைந்து',
95
+ 'எண்பத்தாறு',
96
+ 'எண்பத்தேழு',
97
+ 'எண்பத்தெட்டு',
98
+ 'எண்பத்தொன்பது',
99
+ 'தொண்ணூறு',
100
+ 'தொண்ணூற்று ஒன்று',
101
+ 'தொண்ணூற்று இரண்டு',
102
+ 'தொண்ணூற்று மூன்று',
103
+ 'தொண்ணூற்று நான்கு',
104
+ 'தொண்ணூற்று ஐந்து',
105
+ 'தொண்ணூற்று ஆறு',
106
+ 'தொண்ணூற்று ஏழு',
107
+ 'தொண்ணூற்று எட்டு',
108
+ 'தொண்ணூற்று ஒன்பது'
109
+ ]
110
+
111
+ hundreds = [
112
+ '',
113
+ 'நூறு',
114
+ 'இருநூறு',
115
+ 'முன்னூறு',
116
+ 'நானூறு',
117
+ 'ஐநூறு',
118
+ 'அறுநூறு',
119
+ 'எழுநூறு',
120
+ 'எண்நூறு',
121
+ 'தொள்ளாயிரம்'
122
+ ]
123
+
124
+ // Digits map 1–9 for decimal reading
125
+ digits = [
126
+ 'ஒன்று',
127
+ 'இரண்டு',
128
+ 'மூன்று',
129
+ 'நான்கு',
130
+ 'ஐந்து',
131
+ 'ஆறு',
132
+ 'ஏழு',
133
+ 'எட்டு',
134
+ 'ஒன்பது'
135
+ ]
136
+
137
+ scales = [
138
+ '',
139
+ 'ஆயிரம்',
140
+ 'லட்சம்',
141
+ 'கோடி',
142
+ 'அரபு',
143
+ 'கராபு',
144
+ 'நீல்',
145
+ 'பத்ம',
146
+ 'சங்கு'
147
+ ]
148
+
149
+ /**
150
+ * Convert numbers below 100 to Tamil words.
151
+ *
152
+ * @param {number} number The number to convert (0-99).
153
+ * @returns {string} The Tamil representation.
154
+ */
155
+ convertBelowHundred (number) {
156
+ return this.belowHundred[number]
157
+ }
158
+
159
+ convertBelowThousand (number) {
160
+ if (number === 0) return ''
161
+ if (number < 100) return this.convertBelowHundred(number)
162
+
163
+ const hundreds = Math.trunc(number / 100)
164
+ const remainder = number % 100
165
+ let hundredPart = this.hundreds[hundreds]
166
+
167
+ if (remainder > 0) {
168
+ if (hundredPart.endsWith('ம்')) {
169
+ hundredPart = hundredPart.replace(/ம்$/, 'த்து')
170
+ } else if (hundredPart.endsWith('று')) {
171
+ hundredPart = hundredPart.slice(0, -2) + 'ற்று'
172
+ }
173
+ }
174
+
175
+ const parts = [hundredPart]
176
+ if (remainder > 0) {
177
+ parts.push(this.convertBelowHundred(remainder))
178
+ }
179
+
180
+ return parts.join(' ').trim()
181
+ }
182
+
183
+ splitIndian (number) {
184
+ const numStr = number.toString()
185
+ if (numStr.length <= 3) return [Number(numStr)]
186
+
187
+ const groups = []
188
+ const last3 = numStr.slice(-3)
189
+ groups.unshift(Number(last3))
190
+
191
+ let remaining = numStr.slice(0, -3)
192
+ while (remaining.length > 0) {
193
+ const group = remaining.slice(-2)
194
+ groups.unshift(Number(group))
195
+ remaining = remaining.slice(0, -2)
196
+ }
197
+
198
+ return groups
199
+ }
200
+
201
+ convertWholePart (number) {
202
+ if (number === 0n) return this.zeroWord
203
+
204
+ const groups = this.splitIndian(number)
205
+ const groupCount = groups.length
206
+ const words = []
207
+
208
+ for (let i = 0; i < groupCount; i++) {
209
+ const groupValue = groups[i]
210
+ if (groupValue === 0) continue
211
+
212
+ const scaleIndex = groupCount - i - 1
213
+ const groupWords = (groupValue === 1 && scaleIndex > 0) ? 'ஒரு' : this.convertBelowThousand(groupValue)
214
+ words.push(groupWords)
215
+ if (scaleIndex > 0 && this.scales[scaleIndex]) {
216
+ words.push(this.scales[scaleIndex])
217
+ }
218
+ }
219
+
220
+ return words.join(' ').trim()
221
+ }
222
+ }
223
+
224
+ export default function convertToWords (value, options = {}) {
225
+ return new Tamil(options).convertToWords(value)
226
+ }
@@ -0,0 +1,229 @@
1
+ import AbstractLanguage from '../classes/abstract-language.js'
2
+
3
+ class Telugu extends AbstractLanguage {
4
+ negativeWord = 'మైనస్'
5
+ decimalSeparatorWord = 'పాయింట్'
6
+ zeroWord = 'సున్నా'
7
+ convertDecimalsPerDigit = true // Enable digit-by-digit decimal conversion
8
+ belowHundred = [
9
+ 'సున్నా',
10
+ 'ఒకటి',
11
+ 'రెండు',
12
+ 'మూడు',
13
+ 'నాలుగు',
14
+ 'ఐదు',
15
+ 'ఆరు',
16
+ 'ఏడు',
17
+ 'ఎనిమిది',
18
+ 'తొమ్మిది',
19
+ 'పది',
20
+ 'పదకొండు',
21
+ 'పన్నెండు',
22
+ 'పదమూడు',
23
+ 'పద్నాలుగు',
24
+ 'పదిహేను',
25
+ 'పదహారు',
26
+ 'పదిహేడు',
27
+ 'పద్దెనిమిది',
28
+ 'పంతొమ్మిది',
29
+ 'ఇరవై',
30
+ 'ఇరవై ఒక్కటి',
31
+ 'ఇరవై రెండు',
32
+ 'ఇరవై మూడు',
33
+ 'ఇరవై నాలుగు',
34
+ 'ఇరవై ఐదు',
35
+ 'ఇరవై ఆరు',
36
+ 'ఇరవై ఏడు',
37
+ 'ఇరవై ఎనిమిది',
38
+ 'ఇరవై తొమ్మిది',
39
+ 'ముప్పై',
40
+ 'ముప్పై ఒకటి',
41
+ 'ముప్పై రెండు',
42
+ 'ముప్పై మూడు',
43
+ 'ముప్పై నాలుగు',
44
+ 'ముప్పై ఐదు',
45
+ 'ముప్పై ఆరు',
46
+ 'ముప్పై ఏడు',
47
+ 'ముప్పై ఎనిమిది',
48
+ 'ముప్పై తొమ్మిది',
49
+ 'నలభై',
50
+ 'నలభై ఒకటి',
51
+ 'నలభై రెండు',
52
+ 'నలభై మూడు',
53
+ 'నలభై నాలుగు',
54
+ 'నలభై ఐదు',
55
+ 'నలభై ఆరు',
56
+ 'నలభై ఏడు',
57
+ 'నలభై ఎనిమిది',
58
+ 'నలభై తొమ్మిది',
59
+ 'యాభై',
60
+ 'యాభై ఒకటి',
61
+ 'యాభై రెండు',
62
+ 'యాభై మూడు',
63
+ 'యాభై నాలుగు',
64
+ 'యాభై ఐదు',
65
+ 'యాభై ఆరు',
66
+ 'యాభై ఏడు',
67
+ 'యాభై ఎనిమిది',
68
+ 'యాభై తొమ్మిది',
69
+ 'అరవై',
70
+ 'అరవై ఒకటి',
71
+ 'అరవై రెండు',
72
+ 'అరవై మూడు',
73
+ 'అరవై నాలుగు',
74
+ 'అరవై ఐదు',
75
+ 'అరవై ఆరు',
76
+ 'అరవై ఏడు',
77
+ 'అరవై ఎనిమిది',
78
+ 'అరవై తొమ్మిది',
79
+ 'డెబ్బై',
80
+ 'డెబ్బై ఒకటి',
81
+ 'డెబ్బై రెండు',
82
+ 'డెబ్బై మూడు',
83
+ 'డెబ్బై నాలుగు',
84
+ 'డెబ్బై ఐదు',
85
+ 'డెబ్బై ఆరు',
86
+ 'డెబ్బై ఏడు',
87
+ 'డెబ్బై ఎనిమిది',
88
+ 'డెబ్బై తొమ్మిది',
89
+ 'ఎనభై',
90
+ 'ఎనభై ఒకటి',
91
+ 'ఎనభై రెండు',
92
+ 'ఎనభై మూడు',
93
+ 'ఎనభై నాలుగు',
94
+ 'ఎనభై ఐదు',
95
+ 'ఎనభై ఆరు',
96
+ 'ఎనభై ఏడు',
97
+ 'ఎనభై ఎనిమిది',
98
+ 'ఎనభై తొమ్మిది',
99
+ 'తొంభై',
100
+ 'తొంభై ఒకటి',
101
+ 'తొంభై రెండు',
102
+ 'తొంభై మూడు',
103
+ 'తొంభై నాలుగు',
104
+ 'తొంభై ఐదు',
105
+ 'తొంభై ఆరు',
106
+ 'తొంభై ఏడు',
107
+ 'తొంభై ఎనిమిది',
108
+ 'తొంభై తొమ్మిది'
109
+ ]
110
+
111
+ hundreds = [
112
+ '',
113
+ 'వంద',
114
+ 'రెండు వందలు',
115
+ 'మూడు వందలు',
116
+ 'నాలుగు వందలు',
117
+ 'ఐదు వందలు',
118
+ 'ఆరు వందలు',
119
+ 'ఏడు వందలు',
120
+ 'ఎనిమిది వందలు',
121
+ 'తొమ్మిది వందలు'
122
+ ]
123
+
124
+ // Digits map 1–9 for decimal reading
125
+ digits = [
126
+ 'ఒకటి',
127
+ 'రెండు',
128
+ 'మూడు',
129
+ 'నాలుగు',
130
+ 'ఐదు',
131
+ 'ఆరు',
132
+ 'ఏడు',
133
+ 'ఎనిమిది',
134
+ 'తొమ్మిది'
135
+ ]
136
+
137
+ scales = [
138
+ '',
139
+ 'వెయ్యి',
140
+ 'లక్ష',
141
+ 'కోటి',
142
+ 'అరబ్',
143
+ 'ఖరబ్',
144
+ 'నిల్',
145
+ 'పడ్మ',
146
+ 'శంకు'
147
+ ]
148
+
149
+ /**
150
+ * Convert numbers below 100 to Telugu words.
151
+ *
152
+ * @param {number} number The number to convert (0-99).
153
+ * @returns {string} The Telugu representation.
154
+ */
155
+ convertBelowHundred (number) {
156
+ return this.belowHundred[number]
157
+ }
158
+
159
+ /**
160
+ * Convert numbers below 1000 to Telugu words.
161
+ *
162
+ * @param {number} number The number to convert (0-999).
163
+ * @returns {string} The Telugu representation.
164
+ */
165
+ convertBelowThousand (number) {
166
+ if (number === 0) return ''
167
+ if (number < 100) return this.convertBelowHundred(number)
168
+
169
+ const hundreds = Math.trunc(number / 100)
170
+ const remainder = number % 100
171
+ const parts = [this.hundreds[hundreds]]
172
+
173
+ if (remainder > 0) {
174
+ parts.push(this.convertBelowHundred(remainder))
175
+ }
176
+
177
+ return parts.join(' ').trim()
178
+ }
179
+
180
+ /**
181
+ * Split a number using Indian-style grouping (3-2-2 digits from right).
182
+ *
183
+ * @param {bigint} number The number to split.
184
+ * @returns {number[]} Array of number groups.
185
+ */
186
+ splitIndian (number) {
187
+ const numStr = number.toString()
188
+ if (numStr.length <= 3) return [Number(numStr)]
189
+
190
+ const groups = []
191
+ const last3 = numStr.slice(-3)
192
+ groups.unshift(Number(last3))
193
+
194
+ let remaining = numStr.slice(0, -3)
195
+ while (remaining.length > 0) {
196
+ const group = remaining.slice(-2)
197
+ groups.unshift(Number(group))
198
+ remaining = remaining.slice(0, -2)
199
+ }
200
+
201
+ return groups
202
+ }
203
+
204
+ convertWholePart (number) {
205
+ if (number === 0n) return this.zeroWord
206
+
207
+ const groups = this.splitIndian(number)
208
+ const groupCount = groups.length
209
+ const words = []
210
+
211
+ for (let i = 0; i < groupCount; i++) {
212
+ const groupValue = groups[i]
213
+ if (groupValue === 0) continue
214
+
215
+ const scaleIndex = groupCount - i - 1
216
+ const groupWords = (groupValue === 1 && scaleIndex > 0) ? 'ఒక' : this.convertBelowThousand(groupValue)
217
+ words.push(groupWords)
218
+ if (scaleIndex > 0 && this.scales[scaleIndex]) {
219
+ words.push(this.scales[scaleIndex])
220
+ }
221
+ }
222
+
223
+ return words.join(' ').trim()
224
+ }
225
+ }
226
+
227
+ export default function convertToWords (value, options = {}) {
228
+ return new Telugu(options).convertToWords(value)
229
+ }