@digitaldefiance/i18n-lib 3.8.0 → 3.8.2

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 (503) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +182 -0
  3. package/package.json +12 -4
  4. package/src/{active-context.d.ts → active-context.ts} +0 -1
  5. package/src/builders/i18n-builder.ts +82 -0
  6. package/src/builders/{index.d.ts → index.ts} +1 -1
  7. package/src/component-definition.ts +11 -0
  8. package/src/component-registration.ts +29 -0
  9. package/src/component-registry.ts +432 -0
  10. package/src/context-error-type.ts +7 -0
  11. package/src/core/component-store.ts +241 -0
  12. package/src/core/context-manager.ts +113 -0
  13. package/src/core/enum-registry.ts +106 -0
  14. package/src/core/i18n-engine.ts +710 -0
  15. package/src/core/{index.d.ts → index.ts} +4 -1
  16. package/src/core/language-registry.ts +345 -0
  17. package/src/{core-component-id.d.ts → core-component-id.ts} +1 -2
  18. package/src/core-i18n.ts +270 -0
  19. package/src/core-plugin-factory.ts +111 -0
  20. package/src/core-string-key.ts +59 -0
  21. package/src/create-translation-adapter.ts +93 -0
  22. package/src/enum-registry.ts +152 -0
  23. package/src/errors/{base.d.ts → base.ts} +1 -1
  24. package/src/errors/context-error.ts +122 -0
  25. package/src/errors/enhanced-error-base.ts +260 -0
  26. package/src/errors/handleable.ts +152 -0
  27. package/src/errors/i18n-error.ts +494 -0
  28. package/src/errors/{index.d.ts → index.ts} +4 -1
  29. package/src/errors/simple-typed-error.ts +81 -0
  30. package/src/errors/{translatable-exports.d.ts → translatable-exports.ts} +1 -1
  31. package/src/errors/translatable-generic.ts +245 -0
  32. package/src/errors/translatable-handleable-generic.ts +222 -0
  33. package/src/errors/translatable.ts +138 -0
  34. package/src/errors/typed-handleable.ts +138 -0
  35. package/src/errors/typed.ts +617 -0
  36. package/src/gender/{gender-categories.d.ts → gender-categories.ts} +6 -2
  37. package/src/gender/gender-resolver.ts +40 -0
  38. package/src/gender/{index.d.ts → index.ts} +0 -1
  39. package/src/global-active-context.ts +266 -0
  40. package/src/icu/ast.ts +56 -0
  41. package/src/icu/compiler.ts +96 -0
  42. package/src/icu/formatter-registry.ts +36 -0
  43. package/src/icu/formatters/base-formatter.ts +8 -0
  44. package/src/icu/formatters/date-formatter.ts +30 -0
  45. package/src/icu/formatters/number-formatter.ts +32 -0
  46. package/src/icu/formatters/plural-formatter.ts +12 -0
  47. package/src/icu/formatters/select-formatter.ts +7 -0
  48. package/src/icu/formatters/selectordinal-formatter.ts +17 -0
  49. package/src/icu/formatters/time-formatter.ts +30 -0
  50. package/src/icu/helpers.ts +34 -0
  51. package/src/icu/parser.ts +242 -0
  52. package/src/icu/runtime.ts +37 -0
  53. package/src/icu/tokenizer.ts +212 -0
  54. package/src/icu/validator.ts +163 -0
  55. package/src/{index.d.ts → index.ts} +38 -6
  56. package/src/interfaces/active-context.interface.ts +41 -0
  57. package/src/interfaces/component-config.interface.ts +17 -0
  58. package/src/interfaces/engine-config.interface.ts +22 -0
  59. package/src/interfaces/global-active-context.ts +39 -0
  60. package/src/interfaces/handleable-error-options.ts +13 -0
  61. package/src/interfaces/handleable.ts +20 -0
  62. package/src/interfaces/i18n-engine.interface.ts +57 -0
  63. package/src/interfaces/{index.d.ts → index.ts} +1 -1
  64. package/src/interfaces/language-definition.interface.ts +17 -0
  65. package/src/interfaces/translation-options.interface.ts +15 -0
  66. package/src/interfaces/validation-result.interface.ts +24 -0
  67. package/src/language-codes.ts +40 -0
  68. package/src/language-definition.ts +13 -0
  69. package/src/plugin-i18n-engine.ts +707 -0
  70. package/src/pluralization/{index.d.ts → index.ts} +1 -1
  71. package/src/pluralization/language-plural-map.ts +186 -0
  72. package/src/pluralization/{plural-categories.d.ts → plural-categories.ts} +5 -3
  73. package/src/pluralization/plural-rules.ts +228 -0
  74. package/src/registry-config.ts +16 -0
  75. package/src/registry-error-type.ts +19 -0
  76. package/src/registry-error.ts +100 -0
  77. package/src/strict-types.ts +35 -0
  78. package/src/strings/de.ts +75 -0
  79. package/src/strings/en-GB.ts +74 -0
  80. package/src/strings/en-US.ts +74 -0
  81. package/src/strings/es.ts +74 -0
  82. package/src/strings/fr.ts +75 -0
  83. package/src/strings/ja.ts +73 -0
  84. package/src/strings/uk.ts +73 -0
  85. package/src/strings/zh-CN.ts +72 -0
  86. package/src/template.ts +72 -0
  87. package/src/translation-engine.ts +18 -0
  88. package/src/translation-request.ts +12 -0
  89. package/src/translation-response.ts +8 -0
  90. package/src/types/engine.ts +55 -0
  91. package/src/types/{index.d.ts → index.ts} +1 -1
  92. package/src/types/{plural-types.d.ts → plural-types.ts} +29 -3
  93. package/src/{types.d.ts → types.ts} +72 -21
  94. package/src/utils/currency.ts +141 -0
  95. package/src/utils/html-escape.ts +55 -0
  96. package/src/utils/{index.d.ts → index.ts} +0 -1
  97. package/src/utils/lru-cache.ts +76 -0
  98. package/src/utils/{plural-helpers.d.ts → plural-helpers.ts} +14 -4
  99. package/src/utils/{safe-object.js → safe-object.ts} +37 -34
  100. package/src/utils/string-utils.ts +77 -0
  101. package/src/utils/timezone.ts +76 -0
  102. package/src/utils/validation.ts +66 -0
  103. package/src/utils.ts +215 -0
  104. package/src/validation/{index.d.ts → index.ts} +0 -1
  105. package/src/validation/plural-validator.ts +168 -0
  106. package/src/validation-config.ts +11 -0
  107. package/src/validation-result.ts +12 -0
  108. package/src/active-context.d.ts.map +0 -1
  109. package/src/active-context.js +0 -3
  110. package/src/active-context.js.map +0 -1
  111. package/src/builders/i18n-builder.d.ts +0 -26
  112. package/src/builders/i18n-builder.d.ts.map +0 -1
  113. package/src/builders/i18n-builder.js +0 -70
  114. package/src/builders/i18n-builder.js.map +0 -1
  115. package/src/builders/index.d.ts.map +0 -1
  116. package/src/builders/index.js +0 -8
  117. package/src/builders/index.js.map +0 -1
  118. package/src/component-definition.d.ts +0 -12
  119. package/src/component-definition.d.ts.map +0 -1
  120. package/src/component-definition.js +0 -3
  121. package/src/component-definition.js.map +0 -1
  122. package/src/component-registration.d.ts +0 -22
  123. package/src/component-registration.d.ts.map +0 -1
  124. package/src/component-registration.js +0 -3
  125. package/src/component-registration.js.map +0 -1
  126. package/src/component-registry.d.ts +0 -102
  127. package/src/component-registry.d.ts.map +0 -1
  128. package/src/component-registry.js +0 -282
  129. package/src/component-registry.js.map +0 -1
  130. package/src/context-error-type.d.ts +0 -8
  131. package/src/context-error-type.d.ts.map +0 -1
  132. package/src/context-error-type.js +0 -12
  133. package/src/context-error-type.js.map +0 -1
  134. package/src/core/component-store.d.ts +0 -93
  135. package/src/core/component-store.d.ts.map +0 -1
  136. package/src/core/component-store.js +0 -198
  137. package/src/core/component-store.js.map +0 -1
  138. package/src/core/context-manager.d.ts +0 -72
  139. package/src/core/context-manager.d.ts.map +0 -1
  140. package/src/core/context-manager.js +0 -98
  141. package/src/core/context-manager.js.map +0 -1
  142. package/src/core/enum-registry.d.ts +0 -48
  143. package/src/core/enum-registry.d.ts.map +0 -1
  144. package/src/core/enum-registry.js +0 -85
  145. package/src/core/enum-registry.js.map +0 -1
  146. package/src/core/i18n-engine.d.ts +0 -241
  147. package/src/core/i18n-engine.d.ts.map +0 -1
  148. package/src/core/i18n-engine.js +0 -568
  149. package/src/core/i18n-engine.js.map +0 -1
  150. package/src/core/index.d.ts.map +0 -1
  151. package/src/core/index.js +0 -21
  152. package/src/core/index.js.map +0 -1
  153. package/src/core/language-registry.d.ts +0 -180
  154. package/src/core/language-registry.d.ts.map +0 -1
  155. package/src/core/language-registry.js +0 -298
  156. package/src/core/language-registry.js.map +0 -1
  157. package/src/core-component-id.d.ts.map +0 -1
  158. package/src/core-component-id.js +0 -9
  159. package/src/core-component-id.js.map +0 -1
  160. package/src/core-i18n.d.ts +0 -69
  161. package/src/core-i18n.d.ts.map +0 -1
  162. package/src/core-i18n.js +0 -219
  163. package/src/core-i18n.js.map +0 -1
  164. package/src/core-plugin-factory.d.ts +0 -28
  165. package/src/core-plugin-factory.d.ts.map +0 -1
  166. package/src/core-plugin-factory.js +0 -80
  167. package/src/core-plugin-factory.js.map +0 -1
  168. package/src/core-string-key.d.ts +0 -52
  169. package/src/core-string-key.d.ts.map +0 -1
  170. package/src/core-string-key.js +0 -61
  171. package/src/core-string-key.js.map +0 -1
  172. package/src/create-translation-adapter.d.ts +0 -33
  173. package/src/create-translation-adapter.d.ts.map +0 -1
  174. package/src/create-translation-adapter.js +0 -72
  175. package/src/create-translation-adapter.js.map +0 -1
  176. package/src/enum-registry.d.ts +0 -65
  177. package/src/enum-registry.d.ts.map +0 -1
  178. package/src/enum-registry.js +0 -123
  179. package/src/enum-registry.js.map +0 -1
  180. package/src/errors/base.d.ts.map +0 -1
  181. package/src/errors/base.js +0 -11
  182. package/src/errors/base.js.map +0 -1
  183. package/src/errors/context-error.d.ts +0 -50
  184. package/src/errors/context-error.d.ts.map +0 -1
  185. package/src/errors/context-error.js +0 -93
  186. package/src/errors/context-error.js.map +0 -1
  187. package/src/errors/enhanced-error-base.d.ts +0 -125
  188. package/src/errors/enhanced-error-base.d.ts.map +0 -1
  189. package/src/errors/enhanced-error-base.js +0 -165
  190. package/src/errors/enhanced-error-base.js.map +0 -1
  191. package/src/errors/handleable.d.ts +0 -83
  192. package/src/errors/handleable.d.ts.map +0 -1
  193. package/src/errors/handleable.js +0 -136
  194. package/src/errors/handleable.js.map +0 -1
  195. package/src/errors/i18n-error.d.ts +0 -211
  196. package/src/errors/i18n-error.d.ts.map +0 -1
  197. package/src/errors/i18n-error.js +0 -358
  198. package/src/errors/i18n-error.js.map +0 -1
  199. package/src/errors/index.d.ts.map +0 -1
  200. package/src/errors/index.js +0 -17
  201. package/src/errors/index.js.map +0 -1
  202. package/src/errors/simple-typed-error.d.ts +0 -53
  203. package/src/errors/simple-typed-error.d.ts.map +0 -1
  204. package/src/errors/simple-typed-error.js +0 -51
  205. package/src/errors/simple-typed-error.js.map +0 -1
  206. package/src/errors/translatable-exports.d.ts.map +0 -1
  207. package/src/errors/translatable-exports.js +0 -15
  208. package/src/errors/translatable-exports.js.map +0 -1
  209. package/src/errors/translatable-generic.d.ts +0 -87
  210. package/src/errors/translatable-generic.d.ts.map +0 -1
  211. package/src/errors/translatable-generic.js +0 -139
  212. package/src/errors/translatable-generic.js.map +0 -1
  213. package/src/errors/translatable-handleable-generic.d.ts +0 -116
  214. package/src/errors/translatable-handleable-generic.d.ts.map +0 -1
  215. package/src/errors/translatable-handleable-generic.js +0 -121
  216. package/src/errors/translatable-handleable-generic.js.map +0 -1
  217. package/src/errors/translatable.d.ts +0 -63
  218. package/src/errors/translatable.d.ts.map +0 -1
  219. package/src/errors/translatable.js +0 -85
  220. package/src/errors/translatable.js.map +0 -1
  221. package/src/errors/typed-handleable.d.ts +0 -62
  222. package/src/errors/typed-handleable.d.ts.map +0 -1
  223. package/src/errors/typed-handleable.js +0 -108
  224. package/src/errors/typed-handleable.js.map +0 -1
  225. package/src/errors/typed.d.ts +0 -206
  226. package/src/errors/typed.d.ts.map +0 -1
  227. package/src/errors/typed.js +0 -458
  228. package/src/errors/typed.js.map +0 -1
  229. package/src/gender/gender-categories.d.ts.map +0 -1
  230. package/src/gender/gender-categories.js +0 -15
  231. package/src/gender/gender-categories.js.map +0 -1
  232. package/src/gender/gender-resolver.d.ts +0 -14
  233. package/src/gender/gender-resolver.d.ts.map +0 -1
  234. package/src/gender/gender-resolver.js +0 -35
  235. package/src/gender/gender-resolver.js.map +0 -1
  236. package/src/gender/index.d.ts.map +0 -1
  237. package/src/gender/index.js +0 -6
  238. package/src/gender/index.js.map +0 -1
  239. package/src/global-active-context.d.ts +0 -50
  240. package/src/global-active-context.d.ts.map +0 -1
  241. package/src/global-active-context.js +0 -185
  242. package/src/global-active-context.js.map +0 -1
  243. package/src/icu/ast.d.ts +0 -48
  244. package/src/icu/ast.d.ts.map +0 -1
  245. package/src/icu/ast.js +0 -16
  246. package/src/icu/ast.js.map +0 -1
  247. package/src/icu/compiler.d.ts +0 -16
  248. package/src/icu/compiler.d.ts.map +0 -1
  249. package/src/icu/compiler.js +0 -87
  250. package/src/icu/compiler.js.map +0 -1
  251. package/src/icu/formatter-registry.d.ts +0 -10
  252. package/src/icu/formatter-registry.d.ts.map +0 -1
  253. package/src/icu/formatter-registry.js +0 -34
  254. package/src/icu/formatter-registry.js.map +0 -1
  255. package/src/icu/formatters/base-formatter.d.ts +0 -8
  256. package/src/icu/formatters/base-formatter.d.ts.map +0 -1
  257. package/src/icu/formatters/base-formatter.js +0 -3
  258. package/src/icu/formatters/base-formatter.js.map +0 -1
  259. package/src/icu/formatters/date-formatter.d.ts +0 -5
  260. package/src/icu/formatters/date-formatter.d.ts.map +0 -1
  261. package/src/icu/formatters/date-formatter.js +0 -31
  262. package/src/icu/formatters/date-formatter.js.map +0 -1
  263. package/src/icu/formatters/number-formatter.d.ts +0 -5
  264. package/src/icu/formatters/number-formatter.d.ts.map +0 -1
  265. package/src/icu/formatters/number-formatter.js +0 -33
  266. package/src/icu/formatters/number-formatter.js.map +0 -1
  267. package/src/icu/formatters/plural-formatter.d.ts +0 -5
  268. package/src/icu/formatters/plural-formatter.d.ts.map +0 -1
  269. package/src/icu/formatters/plural-formatter.js +0 -15
  270. package/src/icu/formatters/plural-formatter.js.map +0 -1
  271. package/src/icu/formatters/select-formatter.d.ts +0 -5
  272. package/src/icu/formatters/select-formatter.d.ts.map +0 -1
  273. package/src/icu/formatters/select-formatter.js +0 -10
  274. package/src/icu/formatters/select-formatter.js.map +0 -1
  275. package/src/icu/formatters/selectordinal-formatter.d.ts +0 -5
  276. package/src/icu/formatters/selectordinal-formatter.d.ts.map +0 -1
  277. package/src/icu/formatters/selectordinal-formatter.js +0 -22
  278. package/src/icu/formatters/selectordinal-formatter.js.map +0 -1
  279. package/src/icu/formatters/time-formatter.d.ts +0 -5
  280. package/src/icu/formatters/time-formatter.d.ts.map +0 -1
  281. package/src/icu/formatters/time-formatter.js +0 -31
  282. package/src/icu/formatters/time-formatter.js.map +0 -1
  283. package/src/icu/helpers.d.ts +0 -9
  284. package/src/icu/helpers.d.ts.map +0 -1
  285. package/src/icu/helpers.js +0 -31
  286. package/src/icu/helpers.js.map +0 -1
  287. package/src/icu/parser.d.ts +0 -31
  288. package/src/icu/parser.d.ts.map +0 -1
  289. package/src/icu/parser.js +0 -203
  290. package/src/icu/parser.js.map +0 -1
  291. package/src/icu/runtime.d.ts +0 -10
  292. package/src/icu/runtime.d.ts.map +0 -1
  293. package/src/icu/runtime.js +0 -33
  294. package/src/icu/runtime.js.map +0 -1
  295. package/src/icu/tokenizer.d.ts +0 -37
  296. package/src/icu/tokenizer.d.ts.map +0 -1
  297. package/src/icu/tokenizer.js +0 -187
  298. package/src/icu/tokenizer.js.map +0 -1
  299. package/src/icu/validator.d.ts +0 -11
  300. package/src/icu/validator.d.ts.map +0 -1
  301. package/src/icu/validator.js +0 -140
  302. package/src/icu/validator.js.map +0 -1
  303. package/src/index.d.ts.map +0 -1
  304. package/src/index.js +0 -76
  305. package/src/index.js.map +0 -1
  306. package/src/interfaces/active-context.interface.d.ts +0 -36
  307. package/src/interfaces/active-context.interface.d.ts.map +0 -1
  308. package/src/interfaces/active-context.interface.js +0 -3
  309. package/src/interfaces/active-context.interface.js.map +0 -1
  310. package/src/interfaces/component-config.interface.d.ts +0 -16
  311. package/src/interfaces/component-config.interface.d.ts.map +0 -1
  312. package/src/interfaces/component-config.interface.js +0 -6
  313. package/src/interfaces/component-config.interface.js.map +0 -1
  314. package/src/interfaces/engine-config.interface.d.ts +0 -22
  315. package/src/interfaces/engine-config.interface.d.ts.map +0 -1
  316. package/src/interfaces/engine-config.interface.js +0 -6
  317. package/src/interfaces/engine-config.interface.js.map +0 -1
  318. package/src/interfaces/global-active-context.d.ts +0 -23
  319. package/src/interfaces/global-active-context.d.ts.map +0 -1
  320. package/src/interfaces/global-active-context.js +0 -3
  321. package/src/interfaces/global-active-context.js.map +0 -1
  322. package/src/interfaces/handleable-error-options.d.ts +0 -14
  323. package/src/interfaces/handleable-error-options.d.ts.map +0 -1
  324. package/src/interfaces/handleable-error-options.js +0 -3
  325. package/src/interfaces/handleable-error-options.js.map +0 -1
  326. package/src/interfaces/handleable.d.ts +0 -21
  327. package/src/interfaces/handleable.d.ts.map +0 -1
  328. package/src/interfaces/handleable.js +0 -3
  329. package/src/interfaces/handleable.js.map +0 -1
  330. package/src/interfaces/i18n-engine.interface.d.ts +0 -46
  331. package/src/interfaces/i18n-engine.interface.d.ts.map +0 -1
  332. package/src/interfaces/i18n-engine.interface.js +0 -6
  333. package/src/interfaces/i18n-engine.interface.js.map +0 -1
  334. package/src/interfaces/index.d.ts.map +0 -1
  335. package/src/interfaces/index.js +0 -7
  336. package/src/interfaces/index.js.map +0 -1
  337. package/src/interfaces/language-definition.interface.d.ts +0 -17
  338. package/src/interfaces/language-definition.interface.d.ts.map +0 -1
  339. package/src/interfaces/language-definition.interface.js +0 -6
  340. package/src/interfaces/language-definition.interface.js.map +0 -1
  341. package/src/interfaces/translation-options.interface.d.ts +0 -15
  342. package/src/interfaces/translation-options.interface.d.ts.map +0 -1
  343. package/src/interfaces/translation-options.interface.js +0 -6
  344. package/src/interfaces/translation-options.interface.js.map +0 -1
  345. package/src/interfaces/validation-result.interface.d.ts +0 -24
  346. package/src/interfaces/validation-result.interface.d.ts.map +0 -1
  347. package/src/interfaces/validation-result.interface.js +0 -6
  348. package/src/interfaces/validation-result.interface.js.map +0 -1
  349. package/src/language-codes.d.ts +0 -28
  350. package/src/language-codes.d.ts.map +0 -1
  351. package/src/language-codes.js +0 -32
  352. package/src/language-codes.js.map +0 -1
  353. package/src/language-definition.d.ts +0 -14
  354. package/src/language-definition.d.ts.map +0 -1
  355. package/src/language-definition.js +0 -3
  356. package/src/language-definition.js.map +0 -1
  357. package/src/plugin-i18n-engine.d.ts +0 -164
  358. package/src/plugin-i18n-engine.d.ts.map +0 -1
  359. package/src/plugin-i18n-engine.js +0 -493
  360. package/src/plugin-i18n-engine.js.map +0 -1
  361. package/src/pluralization/index.d.ts.map +0 -1
  362. package/src/pluralization/index.js +0 -10
  363. package/src/pluralization/index.js.map +0 -1
  364. package/src/pluralization/language-plural-map.d.ts +0 -29
  365. package/src/pluralization/language-plural-map.d.ts.map +0 -1
  366. package/src/pluralization/language-plural-map.js +0 -155
  367. package/src/pluralization/language-plural-map.js.map +0 -1
  368. package/src/pluralization/plural-categories.d.ts.map +0 -1
  369. package/src/pluralization/plural-categories.js +0 -8
  370. package/src/pluralization/plural-categories.js.map +0 -1
  371. package/src/pluralization/plural-rules.d.ts +0 -102
  372. package/src/pluralization/plural-rules.d.ts.map +0 -1
  373. package/src/pluralization/plural-rules.js +0 -263
  374. package/src/pluralization/plural-rules.js.map +0 -1
  375. package/src/registry-config.d.ts +0 -16
  376. package/src/registry-config.d.ts.map +0 -1
  377. package/src/registry-config.js +0 -3
  378. package/src/registry-config.js.map +0 -1
  379. package/src/registry-error-type.d.ts +0 -20
  380. package/src/registry-error-type.d.ts.map +0 -1
  381. package/src/registry-error-type.js +0 -24
  382. package/src/registry-error-type.js.map +0 -1
  383. package/src/registry-error.d.ts +0 -25
  384. package/src/registry-error.d.ts.map +0 -1
  385. package/src/registry-error.js +0 -63
  386. package/src/registry-error.js.map +0 -1
  387. package/src/strict-types.d.ts +0 -19
  388. package/src/strict-types.d.ts.map +0 -1
  389. package/src/strict-types.js +0 -18
  390. package/src/strict-types.js.map +0 -1
  391. package/src/strings/de.d.ts +0 -3
  392. package/src/strings/de.d.ts.map +0 -1
  393. package/src/strings/de.js +0 -57
  394. package/src/strings/de.js.map +0 -1
  395. package/src/strings/en-GB.d.ts +0 -3
  396. package/src/strings/en-GB.d.ts.map +0 -1
  397. package/src/strings/en-GB.js +0 -57
  398. package/src/strings/en-GB.js.map +0 -1
  399. package/src/strings/en-US.d.ts +0 -3
  400. package/src/strings/en-US.d.ts.map +0 -1
  401. package/src/strings/en-US.js +0 -57
  402. package/src/strings/en-US.js.map +0 -1
  403. package/src/strings/es.d.ts +0 -3
  404. package/src/strings/es.d.ts.map +0 -1
  405. package/src/strings/es.js +0 -57
  406. package/src/strings/es.js.map +0 -1
  407. package/src/strings/fr.d.ts +0 -3
  408. package/src/strings/fr.d.ts.map +0 -1
  409. package/src/strings/fr.js +0 -57
  410. package/src/strings/fr.js.map +0 -1
  411. package/src/strings/ja.d.ts +0 -3
  412. package/src/strings/ja.d.ts.map +0 -1
  413. package/src/strings/ja.js +0 -57
  414. package/src/strings/ja.js.map +0 -1
  415. package/src/strings/uk.d.ts +0 -3
  416. package/src/strings/uk.d.ts.map +0 -1
  417. package/src/strings/uk.js +0 -57
  418. package/src/strings/uk.js.map +0 -1
  419. package/src/strings/zh-CN.d.ts +0 -3
  420. package/src/strings/zh-CN.d.ts.map +0 -1
  421. package/src/strings/zh-CN.js +0 -57
  422. package/src/strings/zh-CN.js.map +0 -1
  423. package/src/template.d.ts +0 -13
  424. package/src/template.d.ts.map +0 -1
  425. package/src/template.js +0 -40
  426. package/src/template.js.map +0 -1
  427. package/src/translation-engine.d.ts +0 -9
  428. package/src/translation-engine.d.ts.map +0 -1
  429. package/src/translation-engine.js +0 -3
  430. package/src/translation-engine.js.map +0 -1
  431. package/src/translation-request.d.ts +0 -10
  432. package/src/translation-request.d.ts.map +0 -1
  433. package/src/translation-request.js +0 -3
  434. package/src/translation-request.js.map +0 -1
  435. package/src/translation-response.d.ts +0 -9
  436. package/src/translation-response.d.ts.map +0 -1
  437. package/src/translation-response.js +0 -3
  438. package/src/translation-response.js.map +0 -1
  439. package/src/types/engine.d.ts +0 -47
  440. package/src/types/engine.d.ts.map +0 -1
  441. package/src/types/engine.js +0 -8
  442. package/src/types/engine.js.map +0 -1
  443. package/src/types/index.d.ts.map +0 -1
  444. package/src/types/index.js +0 -9
  445. package/src/types/index.js.map +0 -1
  446. package/src/types/plural-types.d.ts.map +0 -1
  447. package/src/types/plural-types.js +0 -39
  448. package/src/types/plural-types.js.map +0 -1
  449. package/src/types.d.ts.map +0 -1
  450. package/src/types.js +0 -23
  451. package/src/types.js.map +0 -1
  452. package/src/utils/currency.d.ts +0 -81
  453. package/src/utils/currency.d.ts.map +0 -1
  454. package/src/utils/currency.js +0 -99
  455. package/src/utils/currency.js.map +0 -1
  456. package/src/utils/html-escape.d.ts +0 -22
  457. package/src/utils/html-escape.d.ts.map +0 -1
  458. package/src/utils/html-escape.js +0 -53
  459. package/src/utils/html-escape.js.map +0 -1
  460. package/src/utils/index.d.ts.map +0 -1
  461. package/src/utils/index.js +0 -12
  462. package/src/utils/index.js.map +0 -1
  463. package/src/utils/lru-cache.d.ts +0 -42
  464. package/src/utils/lru-cache.d.ts.map +0 -1
  465. package/src/utils/lru-cache.js +0 -73
  466. package/src/utils/lru-cache.js.map +0 -1
  467. package/src/utils/plural-helpers.d.ts.map +0 -1
  468. package/src/utils/plural-helpers.js +0 -35
  469. package/src/utils/plural-helpers.js.map +0 -1
  470. package/src/utils/safe-object.d.ts +0 -39
  471. package/src/utils/safe-object.d.ts.map +0 -1
  472. package/src/utils/safe-object.js.map +0 -1
  473. package/src/utils/string-utils.d.ts +0 -28
  474. package/src/utils/string-utils.d.ts.map +0 -1
  475. package/src/utils/string-utils.js +0 -63
  476. package/src/utils/string-utils.js.map +0 -1
  477. package/src/utils/timezone.d.ts +0 -50
  478. package/src/utils/timezone.d.ts.map +0 -1
  479. package/src/utils/timezone.js +0 -74
  480. package/src/utils/timezone.js.map +0 -1
  481. package/src/utils/validation.d.ts +0 -40
  482. package/src/utils/validation.d.ts.map +0 -1
  483. package/src/utils/validation.js +0 -69
  484. package/src/utils/validation.js.map +0 -1
  485. package/src/utils.d.ts +0 -65
  486. package/src/utils.d.ts.map +0 -1
  487. package/src/utils.js +0 -129
  488. package/src/utils.js.map +0 -1
  489. package/src/validation/index.d.ts.map +0 -1
  490. package/src/validation/index.js +0 -5
  491. package/src/validation/index.js.map +0 -1
  492. package/src/validation/plural-validator.d.ts +0 -46
  493. package/src/validation/plural-validator.d.ts.map +0 -1
  494. package/src/validation/plural-validator.js +0 -123
  495. package/src/validation/plural-validator.js.map +0 -1
  496. package/src/validation-config.d.ts +0 -12
  497. package/src/validation-config.d.ts.map +0 -1
  498. package/src/validation-config.js +0 -3
  499. package/src/validation-config.js.map +0 -1
  500. package/src/validation-result.d.ts +0 -13
  501. package/src/validation-result.d.ts.map +0 -1
  502. package/src/validation-result.js +0 -3
  503. package/src/validation-result.js.map +0 -1
@@ -0,0 +1,432 @@
1
+ /**
2
+ * Component registry for managing internationalization components and their string translations
3
+ */
4
+
5
+ import { ComponentDefinition } from './component-definition';
6
+ import { ComponentRegistration } from './component-registration';
7
+ import { RegistryError } from './registry-error';
8
+ import { RegistryErrorType } from './registry-error-type';
9
+ import { TranslationRequest } from './translation-request';
10
+ import { TranslationResponse } from './translation-response';
11
+ import {
12
+ ComponentLanguageStrings,
13
+ ComponentStrings,
14
+ PartialComponentLanguageStrings,
15
+ PartialComponentStrings,
16
+ } from './types';
17
+ import { isTemplate, replaceVariables } from './utils';
18
+ import { ValidationConfig } from './validation-config';
19
+ import { ValidationResult } from './validation-result';
20
+
21
+ /**
22
+ * Registry for managing components and their translations
23
+ */
24
+ export class ComponentRegistry<TLanguages extends string> {
25
+ private readonly components = new Map<string, ComponentDefinition<any>>();
26
+ private readonly componentStrings = new Map<
27
+ string,
28
+ ComponentLanguageStrings<any, TLanguages>
29
+ >();
30
+ private readonly validationConfig: ValidationConfig;
31
+ private readonly registeredLanguages: Set<TLanguages>;
32
+ private readonly constants?: Record<string, any>;
33
+
34
+ /**
35
+ * Creates a new ComponentRegistry.
36
+ * @param languages - Array of supported language codes.
37
+ * @param validationConfig - Configuration for validation rules.
38
+ * @param constants - Optional constants for variable replacement in templates.
39
+ */
40
+ constructor(
41
+ languages: readonly TLanguages[],
42
+ validationConfig: ValidationConfig,
43
+ constants?: Record<string, any>,
44
+ ) {
45
+ this.registeredLanguages = new Set(languages);
46
+ this.validationConfig = validationConfig;
47
+ this.constants = constants;
48
+ }
49
+
50
+ /**
51
+ * Update the set of registered languages (for dynamic language addition).
52
+ * @param languages - Array of language codes to register.
53
+ */
54
+ public updateRegisteredLanguages(languages: readonly TLanguages[]): void {
55
+ this.registeredLanguages.clear();
56
+ languages.forEach((lang) => this.registeredLanguages.add(lang));
57
+ }
58
+
59
+ /**
60
+ * Register a new component with its translations.
61
+ * @param registration - Component registration payload.
62
+ * @returns ValidationResult indicating success or errors.
63
+ * @throws RegistryError if component is already registered or validation fails.
64
+ */
65
+ public registerComponent<TStringKeys extends string>(
66
+ registration: ComponentRegistration<TStringKeys, TLanguages>,
67
+ ): ValidationResult {
68
+ const { component, strings } = registration;
69
+
70
+ // Check for duplicate component
71
+ if (this.components.has(component.id)) {
72
+ throw RegistryError.createSimple(
73
+ RegistryErrorType.DuplicateComponent,
74
+ `Component '${component.id}' is already registered`,
75
+ { componentId: component.id },
76
+ );
77
+ }
78
+
79
+ // Validate the registration
80
+ const validationResult = this.validateComponentRegistration(registration);
81
+
82
+ if (
83
+ !validationResult.isValid &&
84
+ !this.validationConfig.allowPartialRegistration
85
+ ) {
86
+ throw RegistryError.createSimple(
87
+ RegistryErrorType.ValidationFailed,
88
+ `Component registration validation failed: ${validationResult.errors.join(
89
+ ', ',
90
+ )}`,
91
+ {
92
+ componentId: component.id,
93
+ missingKeys: validationResult.missingKeys,
94
+ errors: validationResult.errors,
95
+ },
96
+ );
97
+ }
98
+
99
+ // Complete missing strings with fallbacks if partial registration is allowed
100
+ const completeStrings = this.completeStringsWithFallbacks(
101
+ component,
102
+ strings,
103
+ );
104
+
105
+ // Register the component
106
+ this.components.set(component.id, component);
107
+ this.componentStrings.set(component.id, completeStrings);
108
+
109
+ return validationResult;
110
+ }
111
+
112
+ /**
113
+ * Update strings for an existing component.
114
+ * @param componentId - The ID of the component to update.
115
+ * @param strings - Partial strings to update.
116
+ * @returns ValidationResult indicating success or errors.
117
+ * @throws RegistryError if component is not found.
118
+ */
119
+ public updateComponentStrings<TStringKeys extends string>(
120
+ componentId: string,
121
+ strings: PartialComponentLanguageStrings<TStringKeys, TLanguages>,
122
+ ): ValidationResult {
123
+ const component = this.components.get(componentId);
124
+ if (!component) {
125
+ throw RegistryError.createSimple(
126
+ RegistryErrorType.ComponentNotFound,
127
+ `Component with ID '${componentId}' not found`,
128
+ { componentId },
129
+ );
130
+ }
131
+
132
+ const registration: ComponentRegistration<TStringKeys, TLanguages> = {
133
+ component: component as ComponentDefinition<TStringKeys>,
134
+ strings,
135
+ };
136
+
137
+ const validationResult = this.validateComponentRegistration(registration);
138
+
139
+ if (
140
+ validationResult.isValid ||
141
+ this.validationConfig.allowPartialRegistration
142
+ ) {
143
+ const existingStrings =
144
+ this.componentStrings.get(componentId) ||
145
+ ({} as ComponentLanguageStrings<TStringKeys, TLanguages>);
146
+ const updatedStrings = this.mergeStrings(existingStrings, strings);
147
+ const completeStrings = this.completeStringsWithFallbacks(
148
+ component,
149
+ updatedStrings,
150
+ );
151
+
152
+ this.componentStrings.set(componentId, completeStrings);
153
+ }
154
+
155
+ return validationResult;
156
+ }
157
+
158
+ /**
159
+ * Get a translation for a specific component, string key, and language.
160
+ * @param request - Translation request containing componentId, stringKey, language, and variables.
161
+ * @returns TranslationResponse with the translated string and metadata.
162
+ * @throws RegistryError if component, language, or string key is not found.
163
+ */
164
+ public getTranslation<TStringKeys extends string>(
165
+ request: TranslationRequest<TStringKeys, TLanguages>,
166
+ ): TranslationResponse {
167
+ const { componentId, stringKey, language, variables } = request;
168
+
169
+ // Check if component exists
170
+ if (!this.components.has(componentId)) {
171
+ throw RegistryError.createSimple(
172
+ RegistryErrorType.ComponentNotFound,
173
+ `Component '${componentId}' not found`,
174
+ { componentId },
175
+ );
176
+ }
177
+
178
+ const componentStrings = this.componentStrings.get(componentId);
179
+ if (!componentStrings) {
180
+ throw RegistryError.createSimple(
181
+ RegistryErrorType.StringKeyNotFound,
182
+ `No strings registered for component '${componentId}'`,
183
+ { componentId },
184
+ );
185
+ }
186
+
187
+ const targetLanguage =
188
+ language || (this.validationConfig.fallbackLanguageId as TLanguages);
189
+ let actualLanguage = targetLanguage;
190
+ let wasFallback = false;
191
+
192
+ // Try to get the string in the requested language
193
+ let languageStrings = componentStrings[targetLanguage];
194
+
195
+ // If not found and different from fallback, try fallback language
196
+ if (
197
+ !languageStrings &&
198
+ targetLanguage !== this.validationConfig.fallbackLanguageId
199
+ ) {
200
+ languageStrings =
201
+ componentStrings[
202
+ this.validationConfig.fallbackLanguageId as TLanguages
203
+ ];
204
+ actualLanguage = this.validationConfig.fallbackLanguageId as TLanguages;
205
+ wasFallback = true;
206
+ }
207
+
208
+ if (!languageStrings) {
209
+ throw RegistryError.createSimple(
210
+ RegistryErrorType.LanguageNotFound,
211
+ `No strings found for language '${targetLanguage}' in component '${componentId}'`,
212
+ { componentId, language: targetLanguage },
213
+ );
214
+ }
215
+
216
+ const translation = languageStrings[stringKey];
217
+ if (!translation) {
218
+ throw RegistryError.createSimple(
219
+ RegistryErrorType.StringKeyNotFound,
220
+ `String key '${stringKey}' not found for component '${componentId}' in language '${actualLanguage}'`,
221
+ { componentId, stringKey, language: actualLanguage },
222
+ );
223
+ }
224
+
225
+ // Process variables if the string key indicates it's a template
226
+ let processedTranslation: string = translation;
227
+ if (isTemplate(stringKey)) {
228
+ processedTranslation = replaceVariables(
229
+ translation,
230
+ variables,
231
+ this.constants,
232
+ );
233
+ }
234
+
235
+ return {
236
+ translation: processedTranslation,
237
+ actualLanguage,
238
+ wasFallback,
239
+ };
240
+ }
241
+
242
+ /**
243
+ * Get all registered components.
244
+ * @returns Array of all registered ComponentDefinition objects.
245
+ */
246
+ public getComponents(): ReadonlyArray<ComponentDefinition<any>> {
247
+ return Array.from(this.components.values());
248
+ }
249
+
250
+ /**
251
+ * Get a specific component by ID.
252
+ * @param componentId - The ID of the component to retrieve.
253
+ * @returns The ComponentDefinition or undefined if not found.
254
+ */
255
+ public getComponent<TStringKeys extends string>(
256
+ componentId: string,
257
+ ): ComponentDefinition<TStringKeys> | undefined {
258
+ return this.components.get(componentId) as
259
+ | ComponentDefinition<TStringKeys>
260
+ | undefined;
261
+ }
262
+
263
+ /**
264
+ * Check if a component is registered.
265
+ * @param componentId - The ID of the component to check.
266
+ * @returns True if the component is registered, false otherwise.
267
+ */
268
+ public hasComponent(componentId: string): boolean {
269
+ return this.components.has(componentId);
270
+ }
271
+
272
+ /**
273
+ * Get all strings for a component in all languages.
274
+ * @param componentId - The ID of the component.
275
+ * @returns ComponentLanguageStrings or undefined if not found.
276
+ */
277
+ public getComponentStrings<TStringKeys extends string>(
278
+ componentId: string,
279
+ ): ComponentLanguageStrings<TStringKeys, TLanguages> | undefined {
280
+ return this.componentStrings.get(componentId) as
281
+ | ComponentLanguageStrings<TStringKeys, TLanguages>
282
+ | undefined;
283
+ }
284
+
285
+ /**
286
+ * Validate a component registration.
287
+ * @param registration - Component registration to validate.
288
+ * @returns ValidationResult with details of missing keys and errors.
289
+ */
290
+ private validateComponentRegistration<TStringKeys extends string>(
291
+ registration: ComponentRegistration<TStringKeys, TLanguages>,
292
+ ): ValidationResult {
293
+ const { component, strings } = registration;
294
+ const missingKeys: Array<{
295
+ languageId: string;
296
+ componentId: string;
297
+ stringKey: string;
298
+ }> = [];
299
+ const errors: string[] = [];
300
+
301
+ // Check if all required string keys are provided for each language
302
+ for (const languageId of this.registeredLanguages) {
303
+ const languageStrings = strings[languageId];
304
+
305
+ if (!languageStrings) {
306
+ if (this.validationConfig.requireCompleteStrings) {
307
+ errors.push(
308
+ `Missing all strings for language '${languageId}' in component '${component.id}'`,
309
+ );
310
+ }
311
+ // Add all missing keys for this language
312
+ for (const stringKey of component.stringKeys) {
313
+ missingKeys.push({
314
+ languageId,
315
+ componentId: component.id,
316
+ stringKey,
317
+ });
318
+ }
319
+ continue;
320
+ }
321
+
322
+ // Check individual string keys
323
+ for (const stringKey of component.stringKeys) {
324
+ if (!languageStrings[stringKey]) {
325
+ missingKeys.push({
326
+ languageId,
327
+ componentId: component.id,
328
+ stringKey,
329
+ });
330
+
331
+ if (this.validationConfig.requireCompleteStrings) {
332
+ errors.push(
333
+ `Missing string key '${stringKey}' for language '${languageId}' in component '${component.id}'`,
334
+ );
335
+ }
336
+ }
337
+ }
338
+ }
339
+
340
+ return {
341
+ isValid: missingKeys.length === 0,
342
+ missingKeys,
343
+ errors,
344
+ };
345
+ }
346
+
347
+ /**
348
+ * Complete missing strings with fallbacks.
349
+ * @param component - The component definition.
350
+ * @param strings - Partial strings provided.
351
+ * @returns Complete strings with fallbacks filled in.
352
+ */
353
+ private completeStringsWithFallbacks<TStringKeys extends string>(
354
+ component: ComponentDefinition<TStringKeys>,
355
+ strings: PartialComponentLanguageStrings<TStringKeys, TLanguages>,
356
+ ): ComponentLanguageStrings<TStringKeys, TLanguages> {
357
+ const result: Partial<{
358
+ [L in TLanguages]: ComponentStrings<TStringKeys>;
359
+ }> = {};
360
+ const fallbackLanguage = this.validationConfig
361
+ .fallbackLanguageId as TLanguages;
362
+ const fallbackStrings = strings[fallbackLanguage];
363
+
364
+ // Ensure all languages have all required keys
365
+ for (const languageId of this.registeredLanguages) {
366
+ const existingLanguageStrings =
367
+ strings[languageId] || ({} as PartialComponentStrings<TStringKeys>);
368
+ const languageStrings: Partial<{ [K in TStringKeys]: string }> = {};
369
+
370
+ for (const stringKey of component.stringKeys) {
371
+ if (existingLanguageStrings[stringKey]) {
372
+ languageStrings[stringKey] = existingLanguageStrings[stringKey]!;
373
+ } else if (fallbackStrings && fallbackStrings[stringKey]) {
374
+ // Try to use fallback language
375
+ languageStrings[stringKey] = fallbackStrings[stringKey]!;
376
+ } else {
377
+ // Last resort: use a placeholder
378
+ languageStrings[stringKey] = `[${component.id}.${stringKey}]`;
379
+ }
380
+ }
381
+
382
+ result[languageId] = languageStrings as ComponentStrings<TStringKeys>;
383
+ }
384
+
385
+ return result as ComponentLanguageStrings<TStringKeys, TLanguages>;
386
+ }
387
+
388
+ /**
389
+ * Merge existing strings with new strings.
390
+ * @param existing - Existing complete strings.
391
+ * @param updates - Partial updates to apply.
392
+ * @returns Merged partial strings.
393
+ */
394
+ private mergeStrings<TStringKeys extends string>(
395
+ existing: ComponentLanguageStrings<TStringKeys, TLanguages>,
396
+ updates: PartialComponentLanguageStrings<TStringKeys, TLanguages>,
397
+ ): PartialComponentLanguageStrings<TStringKeys, TLanguages> {
398
+ const result: { [L in TLanguages]?: PartialComponentStrings<TStringKeys> } =
399
+ {};
400
+
401
+ // Copy existing strings
402
+ for (const [languageId, languageStrings] of Object.entries(existing) as [
403
+ TLanguages,
404
+ ComponentStrings<TStringKeys>,
405
+ ][]) {
406
+ result[languageId] = { ...languageStrings };
407
+ }
408
+
409
+ // Apply updates
410
+ for (const [languageId, languageStrings] of Object.entries(updates) as [
411
+ TLanguages,
412
+ PartialComponentStrings<TStringKeys> | undefined,
413
+ ][]) {
414
+ if (languageStrings) {
415
+ result[languageId] = {
416
+ ...result[languageId],
417
+ ...languageStrings,
418
+ };
419
+ }
420
+ }
421
+
422
+ return result;
423
+ }
424
+
425
+ /**
426
+ * Clear all components and their strings (useful for testing).
427
+ */
428
+ public clearAllComponents(): void {
429
+ this.components.clear();
430
+ this.componentStrings.clear();
431
+ }
432
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Types of context-related errors
3
+ */
4
+ export enum ContextErrorType {
5
+ /** Error indicating an invalid or non-existent context */
6
+ InvalidContext = 'InvalidContext',
7
+ }
@@ -0,0 +1,241 @@
1
+ /**
2
+ * Component storage (no generics)
3
+ */
4
+
5
+ import { I18nError } from '../errors/i18n-error';
6
+ import { ComponentConfig, ValidationResult } from '../interfaces';
7
+ import { getPluralCategory } from '../pluralization/language-plural-map';
8
+ import { PluralString, resolvePluralString } from '../types/plural-types';
9
+ import { replaceVariables } from '../utils';
10
+
11
+ /**
12
+ * Class representing a storage for component configurations and translations.
13
+ */
14
+ export class ComponentStore {
15
+ private components = new Map<string, ComponentConfig>();
16
+ private aliasMap = new Map<string, string>();
17
+ private constants?: Record<string, any>;
18
+
19
+ /**
20
+ * Creates a new ComponentStore instance.
21
+ * @param constants - Optional constants to be used in variable replacement.
22
+ */
23
+ constructor(constants?: Record<string, any>) {
24
+ this.constants = constants;
25
+ }
26
+
27
+ /**
28
+ * Registers a new component configuration.
29
+ * @param config - The component configuration to register.
30
+ * @returns ValidationResult indicating the result of the registration.
31
+ * @throws {I18nError} If the component ID is already registered.
32
+ */
33
+ register(config: ComponentConfig): ValidationResult {
34
+ if (this.components.has(config.id)) {
35
+ throw I18nError.duplicateComponent(config.id);
36
+ }
37
+
38
+ const validation = this.validate(config);
39
+ this.components.set(config.id, config);
40
+
41
+ // Register aliases
42
+ if (config.aliases) {
43
+ for (const alias of config.aliases) {
44
+ this.aliasMap.set(alias, config.id);
45
+ }
46
+ }
47
+
48
+ return validation;
49
+ }
50
+
51
+ /**
52
+ * Updates an existing component's strings.
53
+ * @param componentId - The ID of the component to update.
54
+ * @param strings - The new strings to merge into the component.
55
+ * @returns ValidationResult indicating the result of the update.
56
+ * @throws {I18nError} If the component is not found.
57
+ */
58
+ update(
59
+ componentId: string,
60
+ strings: Record<string, Record<string, string>>,
61
+ ): ValidationResult {
62
+ const existing = this.components.get(componentId);
63
+ if (!existing) {
64
+ throw I18nError.componentNotFound(componentId);
65
+ }
66
+
67
+ const updated: ComponentConfig = {
68
+ ...existing,
69
+ strings: { ...existing.strings, ...strings },
70
+ };
71
+
72
+ this.components.set(componentId, updated);
73
+ return this.validate(updated);
74
+ }
75
+
76
+ /**
77
+ * Checks if a component or alias is registered.
78
+ * @param componentId - The component ID or alias to check.
79
+ * @returns True if the component or alias is registered, false otherwise.
80
+ */
81
+ has(componentId: string): boolean {
82
+ return this.components.has(componentId) || this.aliasMap.has(componentId);
83
+ }
84
+
85
+ /**
86
+ * Retrieves a component configuration by ID or alias.
87
+ * @param componentId - The component ID or alias to retrieve.
88
+ * @returns The component configuration.
89
+ * @throws {I18nError} If the component is not found.
90
+ */
91
+ get(componentId: string): ComponentConfig {
92
+ const id = this.aliasMap.get(componentId) || componentId;
93
+ const component = this.components.get(id);
94
+ if (!component) {
95
+ throw I18nError.componentNotFound(componentId);
96
+ }
97
+ return component;
98
+ }
99
+
100
+ /**
101
+ * Retrieves all registered component configurations.
102
+ * @returns An array of all component configurations.
103
+ */
104
+ getAll(): readonly ComponentConfig[] {
105
+ return Array.from(this.components.values());
106
+ }
107
+
108
+ /**
109
+ * Translates a key for a component in a given language, replacing variables.
110
+ * @param componentId - The component ID.
111
+ * @param key - The translation key.
112
+ * @param variables - Optional variables for replacement.
113
+ * @param language - Optional language code (default is 'en-US').
114
+ * @returns The translated string.
115
+ * @throws {I18nError} If the language or translation key is not found.
116
+ */
117
+ translate(
118
+ componentId: string,
119
+ key: string,
120
+ variables?: Record<string, any>,
121
+ language?: string,
122
+ ): string {
123
+ const component = this.get(componentId);
124
+ const lang = language || 'en-US';
125
+ const langStrings = component.strings[lang];
126
+
127
+ if (!langStrings) {
128
+ throw I18nError.languageNotFound(lang);
129
+ }
130
+
131
+ const value = langStrings[key];
132
+ if (!value) {
133
+ throw I18nError.translationMissing(componentId, key, lang);
134
+ }
135
+
136
+ // Resolve plural form if needed
137
+ const translation = this.resolvePluralForm(value, variables?.count, lang);
138
+
139
+ return replaceVariables(translation, variables, this.constants);
140
+ }
141
+
142
+ /**
143
+ * Resolve plural form from a PluralString based on count variable.
144
+ * @param value - The string or PluralString to resolve.
145
+ * @param count - The count for pluralization.
146
+ * @param language - The language code.
147
+ * @returns The resolved plural form string.
148
+ */
149
+ private resolvePluralForm(
150
+ value: string | PluralString,
151
+ count: number | undefined,
152
+ language: string,
153
+ ): string {
154
+ // If it's a simple string, return as-is
155
+ if (typeof value === 'string') {
156
+ return value;
157
+ }
158
+
159
+ // If no count provided, use 'other' form or first available
160
+ if (count === undefined) {
161
+ return resolvePluralString(value, 'other') || '';
162
+ }
163
+
164
+ // Get the appropriate plural category for this count and language
165
+ const category = getPluralCategory(language, count);
166
+
167
+ // Resolve the plural form with fallback logic
168
+ return resolvePluralString(value, category) || '';
169
+ }
170
+
171
+ /**
172
+ * Safely translates a key for a component, returning a fallback string on error.
173
+ * @param componentId - The component ID.
174
+ * @param key - The translation key.
175
+ * @param variables - Optional variables for replacement.
176
+ * @param language - Optional language code.
177
+ * @returns The translated string or a fallback string if translation fails.
178
+ */
179
+ safeTranslate(
180
+ componentId: string,
181
+ key: string,
182
+ variables?: Record<string, any>,
183
+ language?: string,
184
+ ): string {
185
+ try {
186
+ return this.translate(componentId, key, variables, language);
187
+ } catch {
188
+ return `[${componentId}.${key}]`;
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Validates a component configuration for missing keys across languages.
194
+ * @param config - The component configuration to validate.
195
+ * @returns ValidationResult containing errors and warnings.
196
+ */
197
+ private validate(config: ComponentConfig): ValidationResult {
198
+ const errors: string[] = [];
199
+ const warnings: string[] = [];
200
+
201
+ // Check if all languages have all keys
202
+ const allKeys = new Set<string>();
203
+ for (const langStrings of Object.values(config.strings)) {
204
+ for (const key of Object.keys(langStrings)) {
205
+ allKeys.add(key);
206
+ }
207
+ }
208
+
209
+ for (const [lang, langStrings] of Object.entries(config.strings)) {
210
+ for (const key of allKeys) {
211
+ if (!langStrings[key]) {
212
+ warnings.push(
213
+ `Missing key '${key}' for language '${lang}' in component '${config.id}'`,
214
+ );
215
+ }
216
+ }
217
+ }
218
+
219
+ return {
220
+ isValid: errors.length === 0,
221
+ errors,
222
+ warnings,
223
+ };
224
+ }
225
+
226
+ /**
227
+ * Sets constants for variable replacement.
228
+ * @param constants - The constants to set.
229
+ */
230
+ setConstants(constants: Record<string, any>): void {
231
+ this.constants = constants;
232
+ }
233
+
234
+ /**
235
+ * Clears all registered components and aliases.
236
+ */
237
+ clear(): void {
238
+ this.components.clear();
239
+ this.aliasMap.clear();
240
+ }
241
+ }