n2words 1.24.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (349) hide show
  1. package/README.md +285 -156
  2. package/dist/ArabicConverter.js +3 -0
  3. package/dist/ArabicConverter.js.map +1 -0
  4. package/dist/AzerbaijaniConverter.js +3 -0
  5. package/dist/AzerbaijaniConverter.js.map +1 -0
  6. package/dist/BanglaConverter.js +3 -0
  7. package/dist/BanglaConverter.js.map +1 -0
  8. package/dist/BiblicalHebrewConverter.js +3 -0
  9. package/dist/BiblicalHebrewConverter.js.map +1 -0
  10. package/dist/CroatianConverter.js +3 -0
  11. package/dist/CroatianConverter.js.map +1 -0
  12. package/dist/CzechConverter.js +3 -0
  13. package/dist/CzechConverter.js.map +1 -0
  14. package/dist/DanishConverter.js +3 -0
  15. package/dist/DanishConverter.js.map +1 -0
  16. package/dist/DutchConverter.js +3 -0
  17. package/dist/DutchConverter.js.map +1 -0
  18. package/dist/EnglishConverter.js +3 -0
  19. package/dist/EnglishConverter.js.map +1 -0
  20. package/dist/FilipinoConverter.js +3 -0
  21. package/dist/FilipinoConverter.js.map +1 -0
  22. package/dist/FrenchBelgiumConverter.js +3 -0
  23. package/dist/FrenchBelgiumConverter.js.map +1 -0
  24. package/dist/FrenchConverter.js +3 -0
  25. package/dist/FrenchConverter.js.map +1 -0
  26. package/dist/GermanConverter.js +3 -0
  27. package/dist/GermanConverter.js.map +1 -0
  28. package/dist/GreekConverter.js +3 -0
  29. package/dist/GreekConverter.js.map +1 -0
  30. package/dist/GujaratiConverter.js +3 -0
  31. package/dist/GujaratiConverter.js.map +1 -0
  32. package/dist/HebrewConverter.js +3 -0
  33. package/dist/HebrewConverter.js.map +1 -0
  34. package/dist/HindiConverter.js +3 -0
  35. package/dist/HindiConverter.js.map +1 -0
  36. package/dist/HungarianConverter.js +3 -0
  37. package/dist/HungarianConverter.js.map +1 -0
  38. package/dist/IndonesianConverter.js +3 -0
  39. package/dist/IndonesianConverter.js.map +1 -0
  40. package/dist/ItalianConverter.js +3 -0
  41. package/dist/ItalianConverter.js.map +1 -0
  42. package/dist/JapaneseConverter.js +3 -0
  43. package/dist/JapaneseConverter.js.map +1 -0
  44. package/dist/KannadaConverter.js +3 -0
  45. package/dist/KannadaConverter.js.map +1 -0
  46. package/dist/KoreanConverter.js +3 -0
  47. package/dist/KoreanConverter.js.map +1 -0
  48. package/dist/LatvianConverter.js +3 -0
  49. package/dist/LatvianConverter.js.map +1 -0
  50. package/dist/LithuanianConverter.js +3 -0
  51. package/dist/LithuanianConverter.js.map +1 -0
  52. package/dist/MalayConverter.js +3 -0
  53. package/dist/MalayConverter.js.map +1 -0
  54. package/dist/MarathiConverter.js +3 -0
  55. package/dist/MarathiConverter.js.map +1 -0
  56. package/dist/NorwegianBokmalConverter.js +3 -0
  57. package/dist/NorwegianBokmalConverter.js.map +1 -0
  58. package/dist/PersianConverter.js +3 -0
  59. package/dist/PersianConverter.js.map +1 -0
  60. package/dist/PolishConverter.js +3 -0
  61. package/dist/PolishConverter.js.map +1 -0
  62. package/dist/PortugueseConverter.js +3 -0
  63. package/dist/PortugueseConverter.js.map +1 -0
  64. package/dist/PunjabiConverter.js +3 -0
  65. package/dist/PunjabiConverter.js.map +1 -0
  66. package/dist/RomanianConverter.js +3 -0
  67. package/dist/RomanianConverter.js.map +1 -0
  68. package/dist/RussianConverter.js +3 -0
  69. package/dist/RussianConverter.js.map +1 -0
  70. package/dist/SerbianCyrillicConverter.js +3 -0
  71. package/dist/SerbianCyrillicConverter.js.map +1 -0
  72. package/dist/SerbianLatinConverter.js +3 -0
  73. package/dist/SerbianLatinConverter.js.map +1 -0
  74. package/dist/SimplifiedChineseConverter.js +3 -0
  75. package/dist/SimplifiedChineseConverter.js.map +1 -0
  76. package/dist/SpanishConverter.js +3 -0
  77. package/dist/SpanishConverter.js.map +1 -0
  78. package/dist/SwahiliConverter.js +3 -0
  79. package/dist/SwahiliConverter.js.map +1 -0
  80. package/dist/SwedishConverter.js +3 -0
  81. package/dist/SwedishConverter.js.map +1 -0
  82. package/dist/TamilConverter.js +3 -0
  83. package/dist/TamilConverter.js.map +1 -0
  84. package/dist/TeluguConverter.js +3 -0
  85. package/dist/TeluguConverter.js.map +1 -0
  86. package/dist/ThaiConverter.js +3 -0
  87. package/dist/ThaiConverter.js.map +1 -0
  88. package/dist/TraditionalChineseConverter.js +3 -0
  89. package/dist/TraditionalChineseConverter.js.map +1 -0
  90. package/dist/TurkishConverter.js +3 -0
  91. package/dist/TurkishConverter.js.map +1 -0
  92. package/dist/UkrainianConverter.js +3 -0
  93. package/dist/UkrainianConverter.js.map +1 -0
  94. package/dist/UrduConverter.js +3 -0
  95. package/dist/UrduConverter.js.map +1 -0
  96. package/dist/VietnameseConverter.js +3 -0
  97. package/dist/VietnameseConverter.js.map +1 -0
  98. package/dist/n2words.js +3 -2
  99. package/dist/n2words.js.map +1 -1
  100. package/lib/classes/abstract-language.d.ts +178 -0
  101. package/lib/classes/abstract-language.js +192 -185
  102. package/lib/classes/greedy-scale-language.d.ts +109 -0
  103. package/lib/classes/greedy-scale-language.js +96 -90
  104. package/lib/classes/slavic-language.d.ts +148 -0
  105. package/lib/classes/slavic-language.js +136 -106
  106. package/lib/classes/south-asian-language.d.ts +70 -0
  107. package/lib/classes/south-asian-language.js +58 -65
  108. package/lib/classes/turkic-language.d.ts +26 -0
  109. package/lib/classes/turkic-language.js +22 -26
  110. package/lib/languages/ar.d.ts +30 -0
  111. package/lib/languages/ar.js +49 -133
  112. package/lib/languages/az.d.ts +12 -0
  113. package/lib/languages/az.js +7 -23
  114. package/lib/languages/bn.d.ts +11 -0
  115. package/lib/languages/bn.js +12 -7
  116. package/lib/languages/cs.d.ts +88 -0
  117. package/lib/languages/cs.js +44 -113
  118. package/lib/languages/da.d.ts +15 -0
  119. package/lib/languages/da.js +40 -87
  120. package/lib/languages/de.d.ts +14 -0
  121. package/lib/languages/de.js +34 -68
  122. package/lib/languages/el.d.ts +14 -0
  123. package/lib/languages/el.js +22 -48
  124. package/lib/languages/en.d.ts +16 -0
  125. package/lib/languages/en.js +22 -59
  126. package/lib/languages/es.d.ts +15 -0
  127. package/lib/languages/es.js +49 -81
  128. package/lib/languages/fa.d.ts +47 -0
  129. package/lib/languages/fa.js +90 -73
  130. package/lib/languages/fil.d.ts +16 -0
  131. package/lib/languages/fil.js +35 -76
  132. package/lib/languages/fr-BE.d.ts +11 -0
  133. package/lib/languages/fr-BE.js +15 -51
  134. package/lib/languages/fr.d.ts +15 -0
  135. package/lib/languages/fr.js +33 -72
  136. package/lib/languages/gu.d.ts +11 -0
  137. package/lib/languages/gu.js +10 -34
  138. package/lib/languages/hbo.d.ts +113 -0
  139. package/lib/languages/hbo.js +251 -0
  140. package/lib/languages/he.d.ts +80 -0
  141. package/lib/languages/he.js +41 -164
  142. package/lib/languages/hi.d.ts +11 -0
  143. package/lib/languages/hi.js +12 -7
  144. package/lib/languages/hr.d.ts +80 -0
  145. package/lib/languages/hr.js +51 -95
  146. package/lib/languages/hu.d.ts +22 -0
  147. package/lib/languages/hu.js +35 -53
  148. package/lib/languages/id.d.ts +37 -0
  149. package/lib/languages/id.js +29 -44
  150. package/lib/languages/it.d.ts +37 -0
  151. package/lib/languages/it.js +36 -52
  152. package/lib/languages/ja.d.ts +17 -0
  153. package/lib/languages/ja.js +22 -75
  154. package/lib/languages/kn.d.ts +11 -0
  155. package/lib/languages/kn.js +10 -39
  156. package/lib/languages/ko.d.ts +14 -0
  157. package/lib/languages/ko.js +17 -45
  158. package/lib/languages/lt.d.ts +70 -0
  159. package/lib/languages/lt.js +28 -63
  160. package/lib/languages/lv.d.ts +70 -0
  161. package/lib/languages/lv.js +35 -58
  162. package/lib/languages/mr.d.ts +11 -0
  163. package/lib/languages/mr.js +10 -34
  164. package/lib/languages/ms.d.ts +31 -0
  165. package/lib/languages/ms.js +24 -20
  166. package/lib/languages/nb.d.ts +12 -0
  167. package/lib/languages/nb.js +36 -56
  168. package/lib/languages/nl.d.ts +16 -0
  169. package/lib/languages/nl.js +58 -109
  170. package/lib/languages/pa.d.ts +11 -0
  171. package/lib/languages/{pa-Guru.js → pa.js} +12 -7
  172. package/lib/languages/pl.d.ts +80 -0
  173. package/lib/languages/pl.js +26 -105
  174. package/lib/languages/pt.d.ts +29 -0
  175. package/lib/languages/pt.js +29 -64
  176. package/lib/languages/ro.d.ts +158 -0
  177. package/lib/languages/ro.js +60 -167
  178. package/lib/languages/ru.d.ts +85 -0
  179. package/lib/languages/ru.js +17 -37
  180. package/lib/languages/sr-Cyrl.d.ts +80 -0
  181. package/lib/languages/sr-Cyrl.js +113 -0
  182. package/lib/languages/sr-Latn.d.ts +80 -0
  183. package/lib/languages/sr-Latn.js +54 -98
  184. package/lib/languages/sv.d.ts +14 -0
  185. package/lib/languages/sv.js +26 -63
  186. package/lib/languages/sw.d.ts +39 -0
  187. package/lib/languages/sw.js +26 -21
  188. package/lib/languages/ta.d.ts +20 -0
  189. package/lib/languages/ta.js +26 -26
  190. package/lib/languages/te.d.ts +22 -0
  191. package/lib/languages/te.js +28 -38
  192. package/lib/languages/th.d.ts +17 -0
  193. package/lib/languages/th.js +25 -31
  194. package/lib/languages/tr.d.ts +12 -0
  195. package/lib/languages/tr.js +11 -38
  196. package/lib/languages/uk.d.ts +85 -0
  197. package/lib/languages/uk.js +18 -44
  198. package/lib/languages/ur.d.ts +11 -0
  199. package/lib/languages/ur.js +12 -7
  200. package/lib/languages/vi.d.ts +72 -0
  201. package/lib/languages/vi.js +25 -71
  202. package/lib/languages/zh-Hans.d.ts +21 -0
  203. package/lib/languages/zh-Hans.js +33 -87
  204. package/lib/languages/zh-Hant.d.ts +21 -0
  205. package/lib/languages/zh-Hant.js +111 -0
  206. package/lib/n2words.d.ts +209 -0
  207. package/lib/n2words.js +474 -191
  208. package/package.json +106 -67
  209. package/dist/languages/ar.js +0 -2
  210. package/dist/languages/ar.js.map +0 -1
  211. package/dist/languages/az.js +0 -2
  212. package/dist/languages/az.js.map +0 -1
  213. package/dist/languages/bn.js +0 -2
  214. package/dist/languages/bn.js.map +0 -1
  215. package/dist/languages/cs.js +0 -2
  216. package/dist/languages/cs.js.map +0 -1
  217. package/dist/languages/da.js +0 -2
  218. package/dist/languages/da.js.map +0 -1
  219. package/dist/languages/de.js +0 -2
  220. package/dist/languages/de.js.map +0 -1
  221. package/dist/languages/el.js +0 -2
  222. package/dist/languages/el.js.map +0 -1
  223. package/dist/languages/en.js +0 -2
  224. package/dist/languages/en.js.map +0 -1
  225. package/dist/languages/es.js +0 -2
  226. package/dist/languages/es.js.map +0 -1
  227. package/dist/languages/fa.js +0 -2
  228. package/dist/languages/fa.js.map +0 -1
  229. package/dist/languages/fil.js +0 -2
  230. package/dist/languages/fil.js.map +0 -1
  231. package/dist/languages/fr-BE.js +0 -2
  232. package/dist/languages/fr-BE.js.map +0 -1
  233. package/dist/languages/fr.js +0 -2
  234. package/dist/languages/fr.js.map +0 -1
  235. package/dist/languages/gu.js +0 -2
  236. package/dist/languages/gu.js.map +0 -1
  237. package/dist/languages/he.js +0 -2
  238. package/dist/languages/he.js.map +0 -1
  239. package/dist/languages/hi.js +0 -2
  240. package/dist/languages/hi.js.map +0 -1
  241. package/dist/languages/hr.js +0 -2
  242. package/dist/languages/hr.js.map +0 -1
  243. package/dist/languages/hu.js +0 -2
  244. package/dist/languages/hu.js.map +0 -1
  245. package/dist/languages/id.js +0 -2
  246. package/dist/languages/id.js.map +0 -1
  247. package/dist/languages/it.js +0 -2
  248. package/dist/languages/it.js.map +0 -1
  249. package/dist/languages/ja.js +0 -2
  250. package/dist/languages/ja.js.map +0 -1
  251. package/dist/languages/kn.js +0 -2
  252. package/dist/languages/kn.js.map +0 -1
  253. package/dist/languages/ko.js +0 -2
  254. package/dist/languages/ko.js.map +0 -1
  255. package/dist/languages/lt.js +0 -2
  256. package/dist/languages/lt.js.map +0 -1
  257. package/dist/languages/lv.js +0 -2
  258. package/dist/languages/lv.js.map +0 -1
  259. package/dist/languages/mr.js +0 -2
  260. package/dist/languages/mr.js.map +0 -1
  261. package/dist/languages/ms.js +0 -2
  262. package/dist/languages/ms.js.map +0 -1
  263. package/dist/languages/nb.js +0 -2
  264. package/dist/languages/nb.js.map +0 -1
  265. package/dist/languages/nl.js +0 -2
  266. package/dist/languages/nl.js.map +0 -1
  267. package/dist/languages/pa-Guru.js +0 -2
  268. package/dist/languages/pa-Guru.js.map +0 -1
  269. package/dist/languages/pl.js +0 -2
  270. package/dist/languages/pl.js.map +0 -1
  271. package/dist/languages/pt.js +0 -2
  272. package/dist/languages/pt.js.map +0 -1
  273. package/dist/languages/ro.js +0 -2
  274. package/dist/languages/ro.js.map +0 -1
  275. package/dist/languages/ru.js +0 -2
  276. package/dist/languages/ru.js.map +0 -1
  277. package/dist/languages/sr-Latn.js +0 -2
  278. package/dist/languages/sr-Latn.js.map +0 -1
  279. package/dist/languages/sv.js +0 -2
  280. package/dist/languages/sv.js.map +0 -1
  281. package/dist/languages/sw.js +0 -2
  282. package/dist/languages/sw.js.map +0 -1
  283. package/dist/languages/ta.js +0 -2
  284. package/dist/languages/ta.js.map +0 -1
  285. package/dist/languages/te.js +0 -2
  286. package/dist/languages/te.js.map +0 -1
  287. package/dist/languages/th.js +0 -2
  288. package/dist/languages/th.js.map +0 -1
  289. package/dist/languages/tr.js +0 -2
  290. package/dist/languages/tr.js.map +0 -1
  291. package/dist/languages/uk.js +0 -2
  292. package/dist/languages/uk.js.map +0 -1
  293. package/dist/languages/ur.js +0 -2
  294. package/dist/languages/ur.js.map +0 -1
  295. package/dist/languages/vi.js +0 -2
  296. package/dist/languages/vi.js.map +0 -1
  297. package/dist/languages/zh-Hans.js +0 -2
  298. package/dist/languages/zh-Hans.js.map +0 -1
  299. package/typings/classes/abstract-language.d.ts +0 -144
  300. package/typings/classes/greedy-scale-language.d.ts +0 -148
  301. package/typings/classes/slavic-language.d.ts +0 -145
  302. package/typings/classes/south-asian-language.d.ts +0 -101
  303. package/typings/classes/turkic-language.d.ts +0 -42
  304. package/typings/languages/ar.d.ts +0 -93
  305. package/typings/languages/az.d.ts +0 -25
  306. package/typings/languages/bn.d.ts +0 -1
  307. package/typings/languages/cs.d.ts +0 -120
  308. package/typings/languages/da.d.ts +0 -53
  309. package/typings/languages/de.d.ts +0 -26
  310. package/typings/languages/el.d.ts +0 -11
  311. package/typings/languages/en.d.ts +0 -30
  312. package/typings/languages/es.d.ts +0 -43
  313. package/typings/languages/fa.d.ts +0 -81
  314. package/typings/languages/fil.d.ts +0 -12
  315. package/typings/languages/fr-BE.d.ts +0 -41
  316. package/typings/languages/fr.d.ts +0 -43
  317. package/typings/languages/gu.d.ts +0 -12
  318. package/typings/languages/he.d.ts +0 -197
  319. package/typings/languages/hi.d.ts +0 -1
  320. package/typings/languages/hr.d.ts +0 -110
  321. package/typings/languages/hu.d.ts +0 -37
  322. package/typings/languages/id.d.ts +0 -69
  323. package/typings/languages/it.d.ts +0 -51
  324. package/typings/languages/ja.d.ts +0 -58
  325. package/typings/languages/kn.d.ts +0 -11
  326. package/typings/languages/ko.d.ts +0 -25
  327. package/typings/languages/lt.d.ts +0 -110
  328. package/typings/languages/lv.d.ts +0 -99
  329. package/typings/languages/mr.d.ts +0 -12
  330. package/typings/languages/ms.d.ts +0 -37
  331. package/typings/languages/nb.d.ts +0 -27
  332. package/typings/languages/nl.d.ts +0 -65
  333. package/typings/languages/pa-Guru.d.ts +0 -1
  334. package/typings/languages/pl.d.ts +0 -116
  335. package/typings/languages/pt.d.ts +0 -39
  336. package/typings/languages/ro.d.ts +0 -229
  337. package/typings/languages/ru.d.ts +0 -108
  338. package/typings/languages/sr-Latn.d.ts +0 -98
  339. package/typings/languages/sv.d.ts +0 -30
  340. package/typings/languages/sw.d.ts +0 -1
  341. package/typings/languages/ta.d.ts +0 -1
  342. package/typings/languages/te.d.ts +0 -1
  343. package/typings/languages/th.d.ts +0 -1
  344. package/typings/languages/tr.d.ts +0 -46
  345. package/typings/languages/uk.d.ts +0 -117
  346. package/typings/languages/ur.d.ts +0 -1
  347. package/typings/languages/vi.d.ts +0 -116
  348. package/typings/languages/zh-Hans.d.ts +0 -57
  349. package/typings/n2words.d.ts +0 -177
@@ -1,37 +1,22 @@
1
- import AbstractLanguage from '../classes/abstract-language.js'
1
+ import { AbstractLanguage } from '../classes/abstract-language.js'
2
2
 
3
3
  /**
4
- * Persian (Farsi) language converter.
4
+ * Persian language converter.
5
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
6
+ * Supports:
7
+ * - "و" (and) conjunction for compound numbers
8
+ * - Recursive conversion for larger numbers
28
9
  */
29
- export class Farsi extends AbstractLanguage {
10
+ export class Persian extends AbstractLanguage {
30
11
  negativeWord = 'منفى'
31
12
  decimalSeparatorWord = 'ممیّز'
32
13
  zeroWord = 'صفر'
33
- namedNumbers = {
34
- 0: 'صفر',
14
+
15
+ /**
16
+ * Words for digits 1-9.
17
+ * @type {Object.<number, string>}
18
+ */
19
+ onesWords = {
35
20
  1: 'یک',
36
21
  2: 'دو',
37
22
  3: 'سه',
@@ -40,7 +25,14 @@ export class Farsi extends AbstractLanguage {
40
25
  6: 'شش',
41
26
  7: 'هفت',
42
27
  8: 'هشت',
43
- 9: 'نه',
28
+ 9: 'نه'
29
+ }
30
+
31
+ /**
32
+ * Words for teen numbers (10-19).
33
+ * @type {Object.<number, string>}
34
+ */
35
+ teensWords = {
44
36
  10: 'ده',
45
37
  11: 'یازده',
46
38
  12: 'دوازده',
@@ -50,7 +42,14 @@ export class Farsi extends AbstractLanguage {
50
42
  16: 'شانزده',
51
43
  17: 'هفده',
52
44
  18: 'هجده',
53
- 19: 'نوزده',
45
+ 19: 'نوزده'
46
+ }
47
+
48
+ /**
49
+ * Words for multiples of ten (20-90).
50
+ * @type {Object.<number, string>}
51
+ */
52
+ tensWords = {
54
53
  20: 'بیست',
55
54
  30: 'سی',
56
55
  40: 'چهل',
@@ -58,7 +57,14 @@ export class Farsi extends AbstractLanguage {
58
57
  60: 'شصت',
59
58
  70: 'هفتاد',
60
59
  80: 'هشتاد',
61
- 90: 'نود',
60
+ 90: 'نود'
61
+ }
62
+
63
+ /**
64
+ * Words for hundreds (100-900).
65
+ * @type {Object.<number, string>}
66
+ */
67
+ hundredsWords = {
62
68
  100: 'صد',
63
69
  200: 'دویست',
64
70
  300: 'سيصد',
@@ -67,61 +73,72 @@ export class Farsi extends AbstractLanguage {
67
73
  600: 'ششصد',
68
74
  700: 'هفتصد',
69
75
  800: 'هشتصد',
70
- 900: 'نهصد',
76
+ 900: 'نهصد'
77
+ }
78
+
79
+ /**
80
+ * Scale magnitude words.
81
+ * @type {Object.<number, string>}
82
+ */
83
+ scaleWords = {
71
84
  1000: 'هزار',
72
85
  1_000_000: 'میلیون'
73
86
  }
74
87
 
75
- convertWholePart (number) {
76
- if (this.namedNumbers[number] && number !== 1_000_000n) {
77
- return this.namedNumbers[number]
88
+ /** Converts integer part using categorized word tables. */
89
+ integerToWords (integerPart) {
90
+ // Zero
91
+ if (integerPart === 0n) {
92
+ return this.zeroWord
78
93
  }
79
94
 
80
- if (number > 20n && number < 100n) {
81
- const xone = number % 10n
82
- const xten = number - xone
83
- return `${this.namedNumbers[xten]} و ${this.namedNumbers[xone]}`
95
+ // 1-9
96
+ if (integerPart <= 9n) {
97
+ return this.onesWords[integerPart]
84
98
  }
85
99
 
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}`
100
+ // 10-19
101
+ if (integerPart <= 19n) {
102
+ return this.teensWords[integerPart]
90
103
  }
91
104
 
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}`
105
+ // 20-99
106
+ if (integerPart < 100n) {
107
+ const ones = integerPart % 10n
108
+ const tens = integerPart - ones
109
+ if (ones === 0n) {
110
+ return this.tensWords[tens]
111
+ }
112
+ return `${this.tensWords[tens]} و ${this.onesWords[ones]}`
103
113
  }
104
114
 
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}`
115
+ // 100-999
116
+ if (integerPart < 1000n) {
117
+ const hundreds = 100n * (integerPart / 100n)
118
+ const remainder = integerPart - hundreds
119
+ if (remainder === 0n) {
120
+ return this.hundredsWords[hundreds]
121
+ }
122
+ return `${this.hundredsWords[hundreds]} و ${this.integerToWords(remainder)}`
112
123
  }
113
- }
114
- }
115
124
 
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)
125
+ // 1000-999999
126
+ if (integerPart < 1_000_000n) {
127
+ const thousandMultiplier = integerPart / 1000n
128
+ // Persian omits "one" before thousand: 1000 is just "هزار", not "یک هزار"
129
+ const thousandPrefix = thousandMultiplier === 1n
130
+ ? ''
131
+ : this.integerToWords(thousandMultiplier) + ' '
132
+ const remainder = integerPart % 1000n
133
+ const suffix = remainder === 0n ? '' : ' ' + this.integerToWords(remainder)
134
+ return `${thousandPrefix}${this.scaleWords[1000]}${suffix}`
135
+ }
136
+
137
+ // 1000000+
138
+ const millionMultiplier = integerPart / 1_000_000n
139
+ const millionPrefix = this.integerToWords(millionMultiplier) + ' ' + this.scaleWords[1_000_000]
140
+ const remainder = integerPart % 1_000_000n
141
+ const suffix = remainder === 0n ? '' : ' و ' + this.integerToWords(remainder)
142
+ return `${millionPrefix}${suffix}`
143
+ }
127
144
  }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Filipino language converter.
3
+ *
4
+ * Supports:
5
+ * - "ng" connectors between words
6
+ * - Implicit "one" omission
7
+ * - Special linkers for certain tens (e.g., "limampung")
8
+ */
9
+ export class Filipino extends GreedyScaleLanguage {
10
+ scaleWords: (string | bigint)[][];
11
+ /** Converts integer part with explicit zero handling. */
12
+ integerToWords(integerPart: any): string;
13
+ /** Combines two word-sets with Filipino connector and linker rules. */
14
+ combineWordSets(preceding: any, following: any): any;
15
+ }
16
+ import { GreedyScaleLanguage } from '../classes/greedy-scale-language.js';
@@ -1,29 +1,20 @@
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'
1
+ import { GreedyScaleLanguage } from '../classes/greedy-scale-language.js'
15
2
 
16
3
  /**
17
- * Filipino language implementation
18
- * Extends GreedyScaleLanguage with scale-based number conversion
4
+ * Filipino language converter.
5
+ *
6
+ * Supports:
7
+ * - "ng" connectors between words
8
+ * - Implicit "one" omission
9
+ * - Special linkers for certain tens (e.g., "limampung")
19
10
  */
20
- class FilipinoLanguage extends GreedyScaleLanguage {
11
+ export class Filipino extends GreedyScaleLanguage {
21
12
  negativeWord = 'negatibo'
22
13
  decimalSeparatorWord = 'punto'
23
14
  zeroWord = 'zero'
24
- convertDecimalsPerDigit = true // Read decimals digit-by-digit
15
+ usePerDigitDecimals = true // Read decimals digit-by-digit
25
16
 
26
- scaleWordPairs = [
17
+ scaleWords = [
27
18
  [1000000000000n, 'trilyong'],
28
19
  [1000000000n, 'milyong'],
29
20
  [1000000n, 'milyong'],
@@ -65,98 +56,66 @@ class FilipinoLanguage extends GreedyScaleLanguage {
65
56
  [0n, 'zero']
66
57
  ]
67
58
 
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) {
59
+ /** Converts integer part with explicit zero handling. */
60
+ integerToWords (integerPart) {
76
61
  // Handle zero explicitly
77
- if (wholeNumber === 0n) {
62
+ if (integerPart === 0n) {
78
63
  return this.zeroWord
79
64
  }
80
- return super.convertWholePart(wholeNumber)
65
+ return super.integerToWords(integerPart)
81
66
  }
82
67
 
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]
68
+ /** Combines two word-sets with Filipino connector and linker rules. */
69
+ combineWordSets (preceding, following) {
70
+ const precedingWord = Object.keys(preceding)[0]
71
+ const followingWord = Object.keys(following)[0]
72
+ const precedingValue = Object.values(preceding)[0]
73
+ const followingValue = Object.values(following)[0]
100
74
 
101
75
  // Don't merge zero with anything - just return the non-zero value
102
- if (leftValue === 0n) {
103
- return rightWordSet
76
+ if (precedingValue === 0n) {
77
+ return following
104
78
  }
105
- if (rightValue === 0n) {
106
- return leftWordSet
79
+ if (followingValue === 0n) {
80
+ return preceding
107
81
  }
108
82
 
109
83
  // Implicit "one" - omit when adding with values < 100
110
- if (leftValue === 1n && rightValue < 100n) {
111
- return rightWordSet
84
+ if (precedingValue === 1n && followingValue < 100n) {
85
+ return following
112
86
  }
113
87
 
114
- // Multiply when right is a scale word AND right > left
88
+ // Multiply when following is a scale word AND following > preceding
115
89
  // Use "ng" connector for Filipino, but consonant-ending words use " na "
116
- if (rightValue > leftValue && rightValue >= 100n) {
90
+ if (followingValue > precedingValue && followingValue >= 100n) {
117
91
  // Words ending in consonants (not vowels) use " na " instead of "ng"
118
92
  const vowels = ['a', 'e', 'i', 'o', 'u']
119
- const lastChar = leftWord[leftWord.length - 1]
93
+ const lastChar = precedingWord[precedingWord.length - 1]
120
94
  if (!vowels.includes(lastChar)) {
121
95
  return {
122
- [`${leftWord} na ${rightWord}`]: leftValue * rightValue
96
+ [`${precedingWord} na ${followingWord}`]: precedingValue * followingValue
123
97
  }
124
98
  }
125
99
  // Vowel-ending words add "ng"
126
100
  return {
127
- [`${leftWord}ng ${rightWord}`]: leftValue * rightValue
101
+ [`${precedingWord}ng ${followingWord}`]: precedingValue * followingValue
128
102
  }
129
103
  }
130
104
 
131
105
  // Special Filipino rule: certain tens words take "-ng" linker when followed by ones
132
106
  // Only limampu (50) confirmed to use this pattern
133
- if (leftValue >= 10n && leftValue < 100n && rightValue >= 1n && rightValue < 10n) {
107
+ if (precedingValue >= 10n && precedingValue < 100n && followingValue >= 1n && followingValue < 10n) {
134
108
  const tensWithNg = ['limampu']
135
- if (tensWithNg.includes(leftWord)) {
109
+ if (tensWithNg.includes(precedingWord)) {
136
110
  return {
137
- [`${leftWord}ng ${rightWord}`]: leftValue + rightValue
111
+ [`${precedingWord}ng ${followingWord}`]: precedingValue + followingValue
138
112
  }
139
113
  }
140
114
  }
141
115
 
142
116
  // Default: space for addition
143
117
  return {
144
- [`${leftWord} ${rightWord}`]: leftValue + rightValue
118
+ [`${precedingWord} ${followingWord}`]: precedingValue + followingValue
145
119
  }
146
120
  }
147
121
  }
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,11 @@
1
+ /**
2
+ * French (Belgium) language converter.
3
+ *
4
+ * Supports:
5
+ * - Belgian regional variants: "septante" (70) and "nonante" (90)
6
+ * - Simplified tens naming (no complex arithmetic)
7
+ * - Inherits all other French grammar rules
8
+ */
9
+ export class FrenchBelgium extends French {
10
+ }
11
+ import { French } from './fr.js';
@@ -1,61 +1,25 @@
1
1
  import { French } from './fr.js'
2
2
 
3
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.
4
+ * French (Belgium) language converter.
10
5
  *
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)
6
+ * Supports:
7
+ * - Belgian regional variants: "septante" (70) and "nonante" (90)
19
8
  * - 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
9
+ * - Inherits all other French grammar rules
22
10
  */
23
- export class BelgianFrench extends French {
24
- /**
25
- * Initializes the Belgian French converter.
26
- *
27
- * @param {BelgianFrenchOptions} [options={}] Configuration options.
28
- */
11
+ export class FrenchBelgium extends French {
29
12
  constructor (options = {}) {
30
13
  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
14
 
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)
15
+ // Insert 90n ('nonante') after 80n and 70n ('septante') after 60n
16
+ const tuples = [...this.scaleWords]
17
+ // Find index of 80n and insert 90n after it
18
+ const idx80 = tuples.findIndex(tuple => tuple[0] === 80n)
19
+ if (idx80 !== -1) tuples.splice(idx80, 0, [90n, 'nonante'])
20
+ // Find index of 60n and insert 70n after it
21
+ const idx60 = tuples.findIndex(tuple => tuple[0] === 60n)
22
+ if (idx60 !== -1) tuples.splice(idx60, 0, [70n, 'septante'])
23
+ this.scaleWords = tuples
24
+ }
61
25
  }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * French language converter.
3
+ *
4
+ * Supports:
5
+ * - Pluralization of "cent" (hundred) and other words
6
+ * - "et" (and) before odd numbers in tens place
7
+ * - Optional hyphenation for compound numbers
8
+ */
9
+ export class French extends GreedyScaleLanguage {
10
+ constructor(options?: {});
11
+ scaleWords: (string | bigint)[][];
12
+ /** Combines two word-sets with French pluralization and hyphenation rules. */
13
+ combineWordSets(preceding: any, following: any): any;
14
+ }
15
+ import { GreedyScaleLanguage } from '../classes/greedy-scale-language.js';
@@ -1,24 +1,19 @@
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
- */
1
+ import { GreedyScaleLanguage } from '../classes/greedy-scale-language.js'
7
2
 
8
3
  /**
9
4
  * French language converter.
10
5
  *
11
- * Special handling:
6
+ * Supports:
12
7
  * - Pluralization of "cent" (hundred) and other words
13
8
  * - "et" (and) before odd numbers in tens place
14
- * - Hyphenation for compound numbers
15
- * - Regional number word variations
9
+ * - Optional hyphenation for compound numbers
16
10
  */
17
11
  export class French extends GreedyScaleLanguage {
18
12
  negativeWord = 'moins'
19
13
  decimalSeparatorWord = 'virgule'
20
14
  zeroWord = 'zéro'
21
- scaleWordPairs = [
15
+
16
+ scaleWords = [
22
17
  [1_000_000_000_000_000_000_000_000_000n, 'quadrilliard'],
23
18
  [1_000_000_000_000_000_000_000_000n, 'quadrillion'],
24
19
  [1_000_000_000_000_000_000_000n, 'trilliard'],
@@ -29,9 +24,7 @@ export class French extends GreedyScaleLanguage {
29
24
  [1_000_000n, 'million'],
30
25
  [1000n, 'mille'],
31
26
  [100n, 'cent'],
32
- [],
33
27
  [80n, 'quatre-vingts'],
34
- [],
35
28
  [60n, 'soixante'],
36
29
  [50n, 'cinquante'],
37
30
  [40n, 'quarante'],
@@ -59,87 +52,55 @@ export class French extends GreedyScaleLanguage {
59
52
  [0n, 'zéro']
60
53
  ]
61
54
 
62
- /**
63
- * Initializes the French converter with language-specific options.
64
- *
65
- * @param {FrenchOptions} [options={}] Configuration options.
66
- */
67
- constructor ({ withHyphenSeparator = false } = {}) {
55
+ constructor (options = {}) {
68
56
  super()
69
57
 
70
- this.withHyphenSeparator = withHyphenSeparator
58
+ this.setOptions({
59
+ withHyphenSeparator: false
60
+ }, options)
71
61
 
72
- if (this.withHyphenSeparator) {
62
+ if (options.withHyphenSeparator) {
73
63
  this.wordSeparator = '-'
74
64
  }
75
65
  }
76
66
 
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]
67
+ /** Combines two word-sets with French pluralization and hyphenation rules. */
68
+ combineWordSets (preceding, following) {
69
+ let precedingWord = Object.keys(preceding)[0]
70
+ let followingWord = Object.keys(following)[0]
71
+ const precedingValue = Object.values(preceding)[0]
72
+ const followingValue = Object.values(following)[0]
95
73
 
96
- if (currentNumber === 1n) {
97
- if (nextNumber < 1_000_000n) {
98
- return nextPair
74
+ if (precedingValue === 1n) {
75
+ if (followingValue < 1_000_000n) {
76
+ return following
99
77
  }
100
78
  } else {
101
79
  if (
102
- ((currentNumber - 80n) % 100n === 0n || (currentNumber % 100n === 0n && currentNumber < 1000n)) &&
103
- nextNumber < 1_000_000n &&
104
- currentWord.at(-1) === 's'
80
+ ((precedingValue - 80n) % 100n === 0n || (precedingValue % 100n === 0n && precedingValue < 1000n)) &&
81
+ followingValue < 1_000_000n &&
82
+ precedingWord.at(-1) === 's'
105
83
  ) {
106
- currentWord = currentWord.slice(0, -1)
84
+ precedingWord = precedingWord.slice(0, -1)
107
85
  }
108
86
 
109
87
  if (
110
- currentNumber < 1000n && nextNumber !== 1000n &&
111
- nextWord.at(-1) !== 's' &&
112
- nextNumber % 100n === 0n
88
+ precedingValue < 1000n && followingValue !== 1000n &&
89
+ followingWord.at(-1) !== 's' &&
90
+ followingValue % 100n === 0n
113
91
  ) {
114
- nextWord += 's'
92
+ followingWord += 's'
115
93
  }
116
94
  }
117
95
 
118
- if (nextNumber < currentNumber && currentNumber < 100n) {
119
- if (nextNumber % 10n === 1n && currentNumber !== 80n) {
120
- return { [`${currentWord}${this.wordSeparator}et${this.wordSeparator}${nextWord}`]: currentNumber + nextNumber }
96
+ if (followingValue < precedingValue && precedingValue < 100n) {
97
+ if (followingValue % 10n === 1n && precedingValue !== 80n) {
98
+ return { [`${precedingWord}${this.wordSeparator}et${this.wordSeparator}${followingWord}`]: precedingValue + followingValue }
121
99
  }
122
- return { [`${currentWord}-${nextWord}`]: currentNumber + nextNumber }
100
+ return { [`${precedingWord}-${followingWord}`]: precedingValue + followingValue }
123
101
  }
124
102
 
125
- if (nextNumber > currentNumber) return { [`${currentWord}${this.wordSeparator}${nextWord}`]: currentNumber * nextNumber }
126
- return { [`${currentWord}${this.wordSeparator}${nextWord}`]: currentNumber + nextNumber }
103
+ if (followingValue > precedingValue) return { [`${precedingWord}${this.wordSeparator}${followingWord}`]: precedingValue * followingValue }
104
+ return { [`${precedingWord}${this.wordSeparator}${followingWord}`]: precedingValue + followingValue }
127
105
  }
128
106
  }
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
- }