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 AbstractLanguage from '../classes/abstract-language.js'
2
+
3
+ /**
4
+ * Persian (Farsi) language converter.
5
+ *
6
+ * Converts numbers to Persian words using Persian-Arabic numerals:
7
+ * - Right-to-left script orientation
8
+ * - Base-10 decimal system with Persian number words
9
+ * - Conjunction "و" (va/and) for compound numbers
10
+ * - Traditional Persian number naming conventions
11
+ *
12
+ * Key Features:
13
+ * - Named number lookup table (namedNumbers) for direct mapping 0-999
14
+ * - Group-based algorithm for numbers >= 1000:
15
+ * 1. Split into groups of 3 digits
16
+ * 2. Convert each group to words using named table or recursion
17
+ * 3. Append magnitude word (هزار/میلیون/میلیارد)
18
+ * 4. Join with "و" (and) conjunction
19
+ * - Special compound forms (دویست for 200, سیصد for 300)
20
+ * - Proper Persian grammatical structure
21
+ * - Support for large numbers (thousands, millions, billions, trillions)
22
+ *
23
+ * Features:
24
+ * - Native Persian digits and words
25
+ * - Special compound forms (e.g., دویست for 200, سیصد for 300)
26
+ * - Support for large numbers (thousands, millions)
27
+ * - Proper Persian grammatical structure
28
+ */
29
+ export class Farsi extends AbstractLanguage {
30
+ negativeWord = 'منفى'
31
+ decimalSeparatorWord = 'ممیّز'
32
+ zeroWord = 'صفر'
33
+ namedNumbers = {
34
+ 0: 'صفر',
35
+ 1: 'یک',
36
+ 2: 'دو',
37
+ 3: 'سه',
38
+ 4: 'چهار',
39
+ 5: 'پنج',
40
+ 6: 'شش',
41
+ 7: 'هفت',
42
+ 8: 'هشت',
43
+ 9: 'نه',
44
+ 10: 'ده',
45
+ 11: 'یازده',
46
+ 12: 'دوازده',
47
+ 13: 'سیزده',
48
+ 14: 'چهارده',
49
+ 15: 'پانزده',
50
+ 16: 'شانزده',
51
+ 17: 'هفده',
52
+ 18: 'هجده',
53
+ 19: 'نوزده',
54
+ 20: 'بیست',
55
+ 30: 'سی',
56
+ 40: 'چهل',
57
+ 50: 'پنجاه',
58
+ 60: 'شصت',
59
+ 70: 'هفتاد',
60
+ 80: 'هشتاد',
61
+ 90: 'نود',
62
+ 100: 'صد',
63
+ 200: 'دویست',
64
+ 300: 'سيصد',
65
+ 400: 'چهار صد',
66
+ 500: 'پانصد',
67
+ 600: 'ششصد',
68
+ 700: 'هفتصد',
69
+ 800: 'هشتصد',
70
+ 900: 'نهصد',
71
+ 1000: 'هزار',
72
+ 1_000_000: 'میلیون'
73
+ }
74
+
75
+ convertWholePart (number) {
76
+ if (this.namedNumbers[number] && number !== 1_000_000n) {
77
+ return this.namedNumbers[number]
78
+ }
79
+
80
+ if (number > 20n && number < 100n) {
81
+ const xone = number % 10n
82
+ const xten = number - xone
83
+ return `${this.namedNumbers[xten]} و ${this.namedNumbers[xone]}`
84
+ }
85
+
86
+ if (number > 100n && number < 1000n) {
87
+ const xhundred = 100n * (number / 100n)
88
+ const tail = this.convertWholePart(number - xhundred)
89
+ return `${this.namedNumbers[xhundred]} و ${tail}`
90
+ }
91
+
92
+ if (number > 1000n && number < 1_000_000n) {
93
+ const thousandMultiplier = number / 1000n
94
+ const namedThousandMultiplier =
95
+ (thousandMultiplier === 1n
96
+ ? ''
97
+ : this.convertWholePart(thousandMultiplier)) +
98
+ ' ' +
99
+ this.namedNumbers[1000]
100
+ const tailNumber = number - thousandMultiplier * 1000n
101
+ const tail = tailNumber === 0n ? '' : ' ' + this.convertWholePart(tailNumber)
102
+ return `${namedThousandMultiplier}${tail}`
103
+ }
104
+
105
+ if (number >= 1_000_000n) {
106
+ const millionMultiplier = number / 1_000_000n
107
+ const namedMillion =
108
+ this.convertWholePart(millionMultiplier) + ' ' + this.namedNumbers[1_000_000]
109
+ const tailNumber = number - millionMultiplier * 1_000_000n
110
+ const tail = tailNumber === 0n ? '' : ' و ' + this.convertWholePart(tailNumber)
111
+ return `${namedMillion}${tail}`
112
+ }
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Converts a number to Persian cardinal (written) form.
118
+ *
119
+ * @param {number|string|bigint} value The number to convert.
120
+ * @param {Object} [options={}] Configuration options.
121
+ * @returns {string} The number expressed in Persian words.
122
+ * @throws {TypeError} If value is NaN or invalid type.
123
+ * @throws {Error} If value is an invalid number string.
124
+ */
125
+ export default function convertToWords (value, options = {}) {
126
+ return new Farsi(options).convertToWords(value)
127
+ }
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Filipino (Tagalog) language implementation for n2words
3
+ *
4
+ * Uses scale-based system with irregular patterns for numbers 1-19.
5
+ * Filipino numbers follow patterns like: sampu (10), labinisa (11), dalawampu (20)
6
+ *
7
+ * @module lib/languages/tl
8
+ * @example
9
+ * import fil from './lib/languages/fil.js'
10
+ * tl(42) // 'apatnapu dalawa'
11
+ * tl(1000) // 'isang libo'
12
+ */
13
+
14
+ import GreedyScaleLanguage from '../classes/greedy-scale-language.js'
15
+
16
+ /**
17
+ * Filipino language implementation
18
+ * Extends GreedyScaleLanguage with scale-based number conversion
19
+ */
20
+ class FilipinoLanguage extends GreedyScaleLanguage {
21
+ negativeWord = 'negatibo'
22
+ decimalSeparatorWord = 'punto'
23
+ zeroWord = 'zero'
24
+ convertDecimalsPerDigit = true // Read decimals digit-by-digit
25
+
26
+ scaleWordPairs = [
27
+ [1000000000000n, 'trilyong'],
28
+ [1000000000n, 'milyong'],
29
+ [1000000n, 'milyong'],
30
+ [1000n, 'libong'],
31
+ [100n, 'daang'],
32
+
33
+ // Tens
34
+ [90n, 'siyamnapu'],
35
+ [80n, 'walumpu'],
36
+ [70n, 'pitumpu'],
37
+ [60n, 'animnapu'],
38
+ [50n, 'limampu'],
39
+ [40n, 'apatnapu'],
40
+ [30n, 'tatlumpu'],
41
+ [20n, 'dalawampu'],
42
+
43
+ // Teens (must come before 10 to be matched first)
44
+ [19n, 'labinsiyam'],
45
+ [18n, 'labingwalo'],
46
+ [17n, 'labimpito'],
47
+ [16n, 'labinanum'],
48
+ [15n, 'labinlima'],
49
+ [14n, 'labinapat'],
50
+ [13n, 'labintatlo'],
51
+ [12n, 'labindalawa'],
52
+ [11n, 'labinisa'],
53
+ [10n, 'sampu'],
54
+
55
+ // Ones
56
+ [9n, 'siyam'],
57
+ [8n, 'walo'],
58
+ [7n, 'pito'],
59
+ [6n, 'anim'],
60
+ [5n, 'lima'],
61
+ [4n, 'apat'],
62
+ [3n, 'tatlo'],
63
+ [2n, 'dalawa'],
64
+ [1n, 'isa'],
65
+ [0n, 'zero']
66
+ ]
67
+
68
+ /**
69
+ * Convert a whole number to Filipino words.
70
+ * Overrides parent to handle zero explicitly.
71
+ *
72
+ * @param {bigint} wholeNumber The whole number to convert.
73
+ * @returns {string} The Filipino representation.
74
+ */
75
+ convertWholePart (wholeNumber) {
76
+ // Handle zero explicitly
77
+ if (wholeNumber === 0n) {
78
+ return this.zeroWord
79
+ }
80
+ return super.convertWholePart(wholeNumber)
81
+ }
82
+
83
+ /**
84
+ * Merge two word-sets according to Filipino grammar rules.
85
+ *
86
+ * Features Filipino-specific rules:
87
+ * - "ng" connector between words
88
+ * - Consonant-ending words use "na" instead of "ng"
89
+ * - Implicit "one" omission ("isang daan" → "daan")
90
+ *
91
+ * @param {Object} leftWordSet Left word-set as `{ word: BigInt }`.
92
+ * @param {Object} rightWordSet Right word-set as `{ word: BigInt }`.
93
+ * @returns {Object} Merged word-set with combined text and value.
94
+ */
95
+ mergeScales (leftWordSet, rightWordSet) {
96
+ const leftWord = Object.keys(leftWordSet)[0]
97
+ const rightWord = Object.keys(rightWordSet)[0]
98
+ const leftValue = Object.values(leftWordSet)[0]
99
+ const rightValue = Object.values(rightWordSet)[0]
100
+
101
+ // Don't merge zero with anything - just return the non-zero value
102
+ if (leftValue === 0n) {
103
+ return rightWordSet
104
+ }
105
+ if (rightValue === 0n) {
106
+ return leftWordSet
107
+ }
108
+
109
+ // Implicit "one" - omit when adding with values < 100
110
+ if (leftValue === 1n && rightValue < 100n) {
111
+ return rightWordSet
112
+ }
113
+
114
+ // Multiply when right is a scale word AND right > left
115
+ // Use "ng" connector for Filipino, but consonant-ending words use " na "
116
+ if (rightValue > leftValue && rightValue >= 100n) {
117
+ // Words ending in consonants (not vowels) use " na " instead of "ng"
118
+ const vowels = ['a', 'e', 'i', 'o', 'u']
119
+ const lastChar = leftWord[leftWord.length - 1]
120
+ if (!vowels.includes(lastChar)) {
121
+ return {
122
+ [`${leftWord} na ${rightWord}`]: leftValue * rightValue
123
+ }
124
+ }
125
+ // Vowel-ending words add "ng"
126
+ return {
127
+ [`${leftWord}ng ${rightWord}`]: leftValue * rightValue
128
+ }
129
+ }
130
+
131
+ // Special Filipino rule: certain tens words take "-ng" linker when followed by ones
132
+ // Only limampu (50) confirmed to use this pattern
133
+ if (leftValue >= 10n && leftValue < 100n && rightValue >= 1n && rightValue < 10n) {
134
+ const tensWithNg = ['limampu']
135
+ if (tensWithNg.includes(leftWord)) {
136
+ return {
137
+ [`${leftWord}ng ${rightWord}`]: leftValue + rightValue
138
+ }
139
+ }
140
+ }
141
+
142
+ // Default: space for addition
143
+ return {
144
+ [`${leftWord} ${rightWord}`]: leftValue + rightValue
145
+ }
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Convert a number to Filipino words
151
+ *
152
+ * @param {number|string|bigint} value - The number to convert
153
+ * @param {Object} [options={}] - Conversion options
154
+ * @returns {string} The Filipino word representation
155
+ * @example
156
+ * convertToWords(42) // 'apatnapu dalawa'
157
+ * convertToWords(1000) // 'isang libo'
158
+ * convertToWords(123456) // 'isang daang dalawampung tatlong libong apat na daang limampung anim'
159
+ */
160
+ export default function convertToWords (value, options = {}) {
161
+ return new FilipinoLanguage(options).convertToWords(value)
162
+ }
@@ -0,0 +1,61 @@
1
+ import { French } from './fr.js'
2
+
3
+ /**
4
+ * @typedef {Object} BelgianFrenchOptions
5
+ * @property {boolean} [withHyphenSeparator=false] Use hyphens (true) instead of spaces (false) in compounds.
6
+ */
7
+
8
+ /**
9
+ * Belgian French language converter.
10
+ *
11
+ * Extends the French converter with Belgian French regional variant:
12
+ * - Uses "septante" (70) instead of "soixante-dix"
13
+ * - Uses "nonante" (90) instead of "quatre-vingt-dix"
14
+ * - Maintains standard French "quatre-vingts" for 80
15
+ * - More regular and logical number system than standard French
16
+ *
17
+ * Features:
18
+ * - Regional number word variations (septante, nonante)
19
+ * - Simplified tens naming (no complex arithmetic)
20
+ * - Inherits all other French grammar rules from FR class
21
+ * - Same pluralization and hyphenation patterns as standard French
22
+ */
23
+ export class BelgianFrench extends French {
24
+ /**
25
+ * Initializes the Belgian French converter.
26
+ *
27
+ * @param {BelgianFrenchOptions} [options={}] Configuration options.
28
+ */
29
+ constructor (options = {}) {
30
+ super(options)
31
+ // Fill the empty placeholder slots with Belgian variants
32
+ // First empty slot (index 10) is for 90n (between 100n and 80n)
33
+ // Second empty slot (index 12) is for 70n (between 80n and 60n)
34
+ this.scaleWordPairs = this.scaleWordPairs.map((pair, index) => {
35
+ if (Array.isArray(pair) && pair.length === 0) {
36
+ // Check next pair to determine which slot this is
37
+ const nextPair = this.scaleWordPairs[index + 1]
38
+ if (nextPair && nextPair[0] === 80n) {
39
+ return [90n, 'nonante']
40
+ } else if (nextPair && nextPair[0] === 60n) {
41
+ return [70n, 'septante']
42
+ }
43
+ }
44
+ return pair
45
+ })
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Converts a number to Belgian French cardinal (written) form.
51
+ *
52
+ * @param {number|string|bigint} value The number to convert.
53
+ * @param {Object} [options={}] Configuration options.
54
+ * @param {boolean} [options.withHyphenSeparator=false] Use hyphens (true) instead of spaces (false) in compounds.
55
+ * @returns {string} The number expressed in Belgian French words.
56
+ * @throws {TypeError} If value is NaN or invalid type.
57
+ * @throws {Error} If value is an invalid number string.
58
+ */
59
+ export default function convertToWords (value, options = {}) {
60
+ return new BelgianFrench(options).convertToWords(value)
61
+ }
@@ -0,0 +1,145 @@
1
+ import GreedyScaleLanguage from '../classes/greedy-scale-language.js'
2
+
3
+ /**
4
+ * @typedef {Object} FrenchOptions
5
+ * @property {boolean} [withHyphenSeparator=false] Use hyphens (true) instead of spaces (false) in compounds.
6
+ */
7
+
8
+ /**
9
+ * French language converter.
10
+ *
11
+ * Special handling:
12
+ * - Pluralization of "cent" (hundred) and other words
13
+ * - "et" (and) before odd numbers in tens place
14
+ * - Hyphenation for compound numbers
15
+ * - Regional number word variations
16
+ */
17
+ export class French extends GreedyScaleLanguage {
18
+ negativeWord = 'moins'
19
+ decimalSeparatorWord = 'virgule'
20
+ zeroWord = 'zéro'
21
+ scaleWordPairs = [
22
+ [1_000_000_000_000_000_000_000_000_000n, 'quadrilliard'],
23
+ [1_000_000_000_000_000_000_000_000n, 'quadrillion'],
24
+ [1_000_000_000_000_000_000_000n, 'trilliard'],
25
+ [1_000_000_000_000_000_000n, 'trillion'],
26
+ [1_000_000_000_000_000n, 'billiard'],
27
+ [1_000_000_000_000n, 'billion'],
28
+ [1_000_000_000n, 'milliard'],
29
+ [1_000_000n, 'million'],
30
+ [1000n, 'mille'],
31
+ [100n, 'cent'],
32
+ [],
33
+ [80n, 'quatre-vingts'],
34
+ [],
35
+ [60n, 'soixante'],
36
+ [50n, 'cinquante'],
37
+ [40n, 'quarante'],
38
+ [30n, 'trente'],
39
+ [20n, 'vingt'],
40
+ [19n, 'dix-neuf'],
41
+ [18n, 'dix-huit'],
42
+ [17n, 'dix-sept'],
43
+ [16n, 'seize'],
44
+ [15n, 'quinze'],
45
+ [14n, 'quatorze'],
46
+ [13n, 'treize'],
47
+ [12n, 'douze'],
48
+ [11n, 'onze'],
49
+ [10n, 'dix'],
50
+ [9n, 'neuf'],
51
+ [8n, 'huit'],
52
+ [7n, 'sept'],
53
+ [6n, 'six'],
54
+ [5n, 'cinq'],
55
+ [4n, 'quatre'],
56
+ [3n, 'trois'],
57
+ [2n, 'deux'],
58
+ [1n, 'un'],
59
+ [0n, 'zéro']
60
+ ]
61
+
62
+ /**
63
+ * Initializes the French converter with language-specific options.
64
+ *
65
+ * @param {FrenchOptions} [options={}] Configuration options.
66
+ */
67
+ constructor ({ withHyphenSeparator = false } = {}) {
68
+ super()
69
+
70
+ this.withHyphenSeparator = withHyphenSeparator
71
+
72
+ if (this.withHyphenSeparator) {
73
+ this.wordSeparator = '-'
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Merges two adjacent word-number pairs according to French grammar rules.
79
+ *
80
+ * French-specific rules:
81
+ * - Removes trailing 's' from multiples of 80 or 100 when followed by smaller numbers
82
+ * - Adds 's' to hundreds when appropriate
83
+ * - Uses "et" (and) when joining odd numbers to tens (e.g., "vingt et un")
84
+ * - Hyphens for compound tens (e.g., "vingt-deux")
85
+ *
86
+ * @param {Object} currentPair The left operand as `{ word: number }`.
87
+ * @param {Object} nextPair The right operand as `{ word: number }`.
88
+ * @returns {Object} Merged pair with combined word and resulting number.
89
+ */
90
+ mergeScales (currentPair, nextPair) {
91
+ let currentWord = Object.keys(currentPair)[0]
92
+ let nextWord = Object.keys(nextPair)[0]
93
+ const currentNumber = Object.values(currentPair)[0]
94
+ const nextNumber = Object.values(nextPair)[0]
95
+
96
+ if (currentNumber === 1n) {
97
+ if (nextNumber < 1_000_000n) {
98
+ return nextPair
99
+ }
100
+ } else {
101
+ if (
102
+ ((currentNumber - 80n) % 100n === 0n || (currentNumber % 100n === 0n && currentNumber < 1000n)) &&
103
+ nextNumber < 1_000_000n &&
104
+ currentWord.at(-1) === 's'
105
+ ) {
106
+ currentWord = currentWord.slice(0, -1)
107
+ }
108
+
109
+ if (
110
+ currentNumber < 1000n && nextNumber !== 1000n &&
111
+ nextWord.at(-1) !== 's' &&
112
+ nextNumber % 100n === 0n
113
+ ) {
114
+ nextWord += 's'
115
+ }
116
+ }
117
+
118
+ if (nextNumber < currentNumber && currentNumber < 100n) {
119
+ if (nextNumber % 10n === 1n && currentNumber !== 80n) {
120
+ return { [`${currentWord}${this.wordSeparator}et${this.wordSeparator}${nextWord}`]: currentNumber + nextNumber }
121
+ }
122
+ return { [`${currentWord}-${nextWord}`]: currentNumber + nextNumber }
123
+ }
124
+
125
+ if (nextNumber > currentNumber) return { [`${currentWord}${this.wordSeparator}${nextWord}`]: currentNumber * nextNumber }
126
+ return { [`${currentWord}${this.wordSeparator}${nextWord}`]: currentNumber + nextNumber }
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Converts a number to French cardinal (written) form.
132
+ *
133
+ * @param {number|string|bigint} value The number to convert.
134
+ * @param {Object} [options] Conversion options (see FR class).
135
+ * @returns {string} The number expressed in French words.
136
+ * @throws {TypeError} If value is NaN or invalid type.
137
+ * @throws {Error} If value is an invalid number string.
138
+ *
139
+ * @example
140
+ * convertToWords(42, { lang: 'fr' }); // 'quarante-deux'
141
+ * convertToWords(81, { lang: 'fr' }); // 'quatre-vingt-un'
142
+ */
143
+ export default function convertToWords (value, options = {}) {
144
+ return new French(options).convertToWords(value)
145
+ }
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Gujarati language implementation for n2words
3
+ *
4
+ * Gujarati uses Indian-style number grouping (3 digits, then 2-2 from right).
5
+ * Numbers: શૂન્ય (0), એક (1), બે (2), ત્રણ (3), ચાર (4), પાંચ (5)...
6
+ *
7
+ * @module lib/languages/gu
8
+ * @example
9
+ * import gu from './lib/languages/gu.js'
10
+ * gu(42) // 'બેતાળીસ'
11
+ * gu(1000) // 'એક હજાર'
12
+ */
13
+
14
+ import SouthAsianLanguage from '../classes/south-asian-language.js'
15
+
16
+ /**
17
+ * Gujarati language implementation
18
+ * Extends SouthAsianLanguage for Indian-style grouping
19
+ */
20
+ class GujaratiLanguage extends SouthAsianLanguage {
21
+ negativeWord = 'ઋણ'
22
+ decimalSeparatorWord = 'દશાંશ'
23
+ zeroWord = 'શૂન્ય'
24
+ hundredWord = 'સો'
25
+ convertDecimalsPerDigit = true
26
+
27
+ belowHundred = [
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
+ 'ત્યાસી',
112
+ 'ચોર્યાસી',
113
+ 'પંચાસી',
114
+ 'છ્યાસી',
115
+ 'સિત્યાસી',
116
+ 'અઠ્યાસી',
117
+ 'નેવ્યાસી',
118
+ 'નેવું',
119
+ 'એકાણું',
120
+ 'બાણું',
121
+ 'ત્રાણું',
122
+ 'ચોરાણું',
123
+ 'પંચાણું',
124
+ 'છન્નું',
125
+ 'સત્તાણું',
126
+ 'અઠ્ઠાણું',
127
+ 'નવ્વાણું'
128
+ ]
129
+
130
+ scaleWords = [
131
+ '',
132
+ 'હજાર',
133
+ 'લાખ',
134
+ 'કરોડ',
135
+ 'અબજ',
136
+ 'ખરબ',
137
+ 'નીલ',
138
+ 'પદ્મ',
139
+ 'શંખ'
140
+ ]
141
+ }
142
+
143
+ /**
144
+ * Convert a number to Gujarati words
145
+ *
146
+ * @param {number|string|bigint} value - The number to convert
147
+ * @param {Object} [options={}] - Conversion options
148
+ * @returns {string} The Gujarati word representation
149
+ * @example
150
+ * convertToWords(42) // 'બેતાળીસ'
151
+ * convertToWords(1000) // 'એક હજાર'
152
+ * convertToWords(100000) // 'એક લાખ'
153
+ */
154
+ export default function convertToWords (value, options = {}) {
155
+ return new GujaratiLanguage(options).convertToWords(value)
156
+ }