@digitaldefiance/i18n-lib 1.3.11 → 1.3.13

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 (148) hide show
  1. package/README.md +8 -0
  2. package/package.json +12 -27
  3. package/src/active-context.ts +30 -0
  4. package/src/component-definition.ts +11 -0
  5. package/src/component-registration.ts +13 -0
  6. package/src/component-registry.ts +392 -0
  7. package/src/context-error-type.ts +3 -0
  8. package/src/context-error.ts +16 -0
  9. package/src/context-manager.ts +71 -0
  10. package/src/context.ts +90 -0
  11. package/src/core-i18n.ts +609 -0
  12. package/src/core-string-key.ts +49 -0
  13. package/src/create-translation-adapter.ts +47 -0
  14. package/src/currency-code.ts +35 -0
  15. package/{dist/currency-format.d.ts → src/currency-format.ts} +5 -4
  16. package/src/currency.ts +52 -0
  17. package/src/default-config.ts +199 -0
  18. package/src/enum-registry.ts +138 -0
  19. package/src/global-active-context.ts +255 -0
  20. package/src/handleable.ts +79 -0
  21. package/src/i-global-active-context.ts +59 -0
  22. package/src/i-handleable-error-options.ts +6 -0
  23. package/src/i-handleable.ts +5 -0
  24. package/src/i18n-config.ts +29 -0
  25. package/{dist/i18n-context.d.ts → src/i18n-context.ts} +7 -6
  26. package/src/i18n-engine.ts +491 -0
  27. package/{dist/index.d.ts → src/index.ts} +10 -1
  28. package/{dist/language-codes.d.ts → src/language-codes.ts} +23 -11
  29. package/src/language-definition.ts +13 -0
  30. package/src/language-registry.ts +292 -0
  31. package/src/plugin-i18n-engine.ts +520 -0
  32. package/src/plugin-translatable-generic-error.ts +106 -0
  33. package/src/plugin-translatable-handleable-generic.ts +60 -0
  34. package/src/plugin-typed-handleable.ts +77 -0
  35. package/src/registry-config.ts +15 -0
  36. package/src/registry-error-type.ts +12 -0
  37. package/src/registry-error.ts +74 -0
  38. package/src/strict-types.ts +35 -0
  39. package/src/template.ts +63 -0
  40. package/src/timezone.ts +20 -0
  41. package/src/translatable.ts +15 -0
  42. package/src/translation-engine.ts +8 -0
  43. package/src/translation-request.ts +12 -0
  44. package/src/translation-response.ts +8 -0
  45. package/src/typed-error.ts +384 -0
  46. package/src/typed-handleable.ts +70 -0
  47. package/{dist/types.d.ts → src/types.ts} +75 -20
  48. package/src/unified-translator.ts +96 -0
  49. package/src/utils.ts +213 -0
  50. package/src/validation-config.ts +11 -0
  51. package/src/validation-result.ts +12 -0
  52. package/dist/active-context.d.ts +0 -29
  53. package/dist/active-context.js +0 -2
  54. package/dist/component-definition.d.ts +0 -11
  55. package/dist/component-definition.js +0 -2
  56. package/dist/component-registration.d.ts +0 -9
  57. package/dist/component-registration.js +0 -2
  58. package/dist/component-registry.d.ts +0 -68
  59. package/dist/component-registry.js +0 -245
  60. package/dist/context-error-type.d.ts +0 -3
  61. package/dist/context-error-type.js +0 -7
  62. package/dist/context-error.d.ts +0 -6
  63. package/dist/context-error.js +0 -15
  64. package/dist/context-manager.d.ts +0 -33
  65. package/dist/context-manager.js +0 -61
  66. package/dist/context.d.ts +0 -44
  67. package/dist/context.js +0 -69
  68. package/dist/core-i18n.d.ts +0 -62
  69. package/dist/core-i18n.js +0 -477
  70. package/dist/core-string-key.d.ts +0 -42
  71. package/dist/core-string-key.js +0 -50
  72. package/dist/create-translation-adapter.d.ts +0 -20
  73. package/dist/create-translation-adapter.js +0 -36
  74. package/dist/currency-code.d.ts +0 -19
  75. package/dist/currency-code.js +0 -36
  76. package/dist/currency-format.js +0 -2
  77. package/dist/currency.d.ts +0 -11
  78. package/dist/currency.js +0 -48
  79. package/dist/default-config.d.ts +0 -32
  80. package/dist/default-config.js +0 -101
  81. package/dist/enum-registry.d.ts +0 -44
  82. package/dist/enum-registry.js +0 -100
  83. package/dist/global-active-context.d.ts +0 -50
  84. package/dist/global-active-context.js +0 -177
  85. package/dist/handleable.d.ts +0 -13
  86. package/dist/handleable.js +0 -56
  87. package/dist/i-global-active-context.d.ts +0 -22
  88. package/dist/i-global-active-context.js +0 -2
  89. package/dist/i-handleable-error-options.d.ts +0 -6
  90. package/dist/i-handleable-error-options.js +0 -2
  91. package/dist/i-handleable.d.ts +0 -5
  92. package/dist/i-handleable.js +0 -2
  93. package/dist/i18n-config.d.ts +0 -20
  94. package/dist/i18n-config.js +0 -2
  95. package/dist/i18n-context.js +0 -2
  96. package/dist/i18n-engine.d.ts +0 -178
  97. package/dist/i18n-engine.js +0 -338
  98. package/dist/index.js +0 -83
  99. package/dist/language-codes.js +0 -31
  100. package/dist/language-definition.d.ts +0 -13
  101. package/dist/language-definition.js +0 -2
  102. package/dist/language-registry.d.ts +0 -113
  103. package/dist/language-registry.js +0 -216
  104. package/dist/plugin-i18n-engine.d.ts +0 -146
  105. package/dist/plugin-i18n-engine.js +0 -360
  106. package/dist/plugin-translatable-generic-error.d.ts +0 -29
  107. package/dist/plugin-translatable-generic-error.js +0 -66
  108. package/dist/plugin-translatable-handleable-generic.d.ts +0 -28
  109. package/dist/plugin-translatable-handleable-generic.js +0 -40
  110. package/dist/plugin-typed-handleable.d.ts +0 -14
  111. package/dist/plugin-typed-handleable.js +0 -45
  112. package/dist/registry-config.d.ts +0 -14
  113. package/dist/registry-config.js +0 -2
  114. package/dist/registry-error-type.d.ts +0 -12
  115. package/dist/registry-error-type.js +0 -16
  116. package/dist/registry-error.d.ts +0 -18
  117. package/dist/registry-error.js +0 -45
  118. package/dist/strict-types.d.ts +0 -18
  119. package/dist/strict-types.js +0 -17
  120. package/dist/template.d.ts +0 -12
  121. package/dist/template.js +0 -30
  122. package/dist/timezone.d.ts +0 -11
  123. package/dist/timezone.js +0 -22
  124. package/dist/translatable-generic-error.d.ts +0 -29
  125. package/dist/translatable-generic-error.js +0 -66
  126. package/dist/translatable-handleable-generic.d.ts +0 -28
  127. package/dist/translatable-handleable-generic.js +0 -40
  128. package/dist/translatable.d.ts +0 -5
  129. package/dist/translatable.js +0 -11
  130. package/dist/translation-engine.d.ts +0 -8
  131. package/dist/translation-engine.js +0 -2
  132. package/dist/translation-request.d.ts +0 -9
  133. package/dist/translation-request.js +0 -2
  134. package/dist/translation-response.d.ts +0 -8
  135. package/dist/translation-response.js +0 -2
  136. package/dist/typed-error.d.ts +0 -72
  137. package/dist/typed-error.js +0 -251
  138. package/dist/typed-handleable.d.ts +0 -14
  139. package/dist/typed-handleable.js +0 -40
  140. package/dist/types.js +0 -18
  141. package/dist/unified-translator.d.ts +0 -30
  142. package/dist/unified-translator.js +0 -68
  143. package/dist/utils.d.ts +0 -64
  144. package/dist/utils.js +0 -130
  145. package/dist/validation-config.d.ts +0 -11
  146. package/dist/validation-config.js +0 -2
  147. package/dist/validation-result.d.ts +0 -12
  148. package/dist/validation-result.js +0 -2
@@ -0,0 +1,491 @@
1
+ import { createContext } from './context';
2
+ import { EnumTranslationRegistry } from './enum-registry';
3
+ import { I18nConfig } from './i18n-config';
4
+ import { I18nContext } from './i18n-context';
5
+ import { createTemplateProcessor } from './template';
6
+ import { EnumLanguageTranslation, LanguageContextSpace } from './types';
7
+ import { isTemplate, replaceVariables } from './utils';
8
+
9
+ /**
10
+ * Internationalization engine class
11
+ */
12
+ export class I18nEngine<
13
+ TStringKey extends string,
14
+ TLanguage extends string,
15
+ TConstants extends Record<string, any> = Record<string, any>,
16
+ TContext extends I18nContext<TLanguage> = I18nContext<
17
+ TLanguage
18
+ >,
19
+ > {
20
+ /**
21
+ * Registry for enum translations
22
+ */
23
+ protected _enumRegistry: EnumTranslationRegistry<TStringKey, TLanguage>;
24
+ /**
25
+ * Configuration for the i18n engine
26
+ */
27
+ public readonly config: I18nConfig<
28
+ TStringKey,
29
+ TLanguage,
30
+ TConstants
31
+ >;
32
+
33
+ /**
34
+ * Static instances for semi-singleton pattern
35
+ */
36
+ private static _instances = new Map<string, I18nEngine<any, any, any, any>>();
37
+ /**
38
+ * Default instance key (first created instance)
39
+ */
40
+ private static _defaultKey: string | null = null;
41
+ /**
42
+ * Default instance key if none is provided
43
+ */
44
+ protected static readonly DefaultInstanceKey = 'default';
45
+
46
+ /**
47
+ * Global context for translations (used if no context is provided) for this instance
48
+ */
49
+ private _context: TContext;
50
+
51
+ /**
52
+ * Default template processor instance
53
+ */
54
+ public readonly t: (
55
+ str: string,
56
+ language?: TLanguage,
57
+ ...otherVars: Record<string, string | number>[]
58
+ ) => string;
59
+
60
+ /**
61
+ * Creates a new I18nEngine instance
62
+ * @param config The i18n configuration
63
+ * @param key Optional instance key for the semi-singleton pattern
64
+ * @throws Error if an instance with the same key already exists
65
+ */
66
+ constructor(
67
+ config: I18nConfig<TStringKey, TLanguage, TConstants>,
68
+ key?: string,
69
+ newContext: () => TContext = () =>
70
+ createContext(
71
+ config.defaultLanguage,
72
+ config.defaultTranslationContext,
73
+ config.defaultCurrencyCode,
74
+ config.timezone,
75
+ config.adminTimezone,
76
+ ) as TContext,
77
+ ) {
78
+ this.validateConfig(config);
79
+ this.config = config;
80
+ this._enumRegistry = new EnumTranslationRegistry<TStringKey, TLanguage>(
81
+ Object.keys(config.strings) as TLanguage[],
82
+ (key: string, vars?: Record<string, any>) =>
83
+ this.safeTranslate(key as TStringKey, vars),
84
+ );
85
+ this._context = newContext();
86
+
87
+ const instanceKey = key || I18nEngine.DefaultInstanceKey;
88
+ if (I18nEngine._instances.has(instanceKey)) {
89
+ const existing = I18nEngine._instances.get(instanceKey)!;
90
+ throw new Error(
91
+ existing.translate('Error_InstanceAlreadyExistsTemplate' as any, {
92
+ key: instanceKey,
93
+ }),
94
+ );
95
+ }
96
+ I18nEngine._instances.set(instanceKey, this);
97
+ if (!I18nEngine._defaultKey) {
98
+ I18nEngine._defaultKey = instanceKey;
99
+ }
100
+
101
+ // Initialize the default template processor
102
+ this.t = createTemplateProcessor(
103
+ this.config.enumObj || ({} as Record<string, TStringKey>),
104
+ (
105
+ key: TStringKey,
106
+ vars?: Record<string, string | number>,
107
+ language?: TLanguage,
108
+ ) => this.translate(key, vars, language),
109
+ this.config.enumName || 'StringKey',
110
+ );
111
+ }
112
+
113
+ /**
114
+ * Gets an instance of the I18nEngine by key. If no key is provided, the default instance is returned.
115
+ * @param key The key of the instance to retrieve
116
+ * @returns The I18nEngine instance
117
+ * @throws Error if the instance with the provided key does not exist
118
+ */
119
+ public static getInstance<T extends I18nEngine<any, any, any, any>>(
120
+ key?: string,
121
+ ): T {
122
+ const instanceKey =
123
+ key || I18nEngine._defaultKey || I18nEngine.DefaultInstanceKey;
124
+ if (!instanceKey || !I18nEngine._instances.has(instanceKey)) {
125
+ throw new Error(
126
+ I18nEngine.getErrorMessage('Error_InstanceNotFoundTemplate', {
127
+ key: instanceKey,
128
+ }),
129
+ );
130
+ }
131
+ return I18nEngine._instances.get(instanceKey) as T;
132
+ }
133
+
134
+ /**
135
+ * Gets a translation for the provided error key using the specified instance (or default instance if none is provided).
136
+ * @param errorKey The error key to translate
137
+ * @param vars Variables to replace in the translation string
138
+ * @param instanceKey The key of the I18nEngine instance to use
139
+ * @param language The language to translate to
140
+ * @param fallbackLanguage The fallback language if the translation is not found
141
+ * @returns The translated error message
142
+ */
143
+ public static getErrorMessage(
144
+ errorKey: string,
145
+ vars?: Record<string, string | number>,
146
+ instanceKey?: string,
147
+ language?: string,
148
+ fallbackLanguage?: string,
149
+ ): string {
150
+ try {
151
+ const instance = I18nEngine.getInstance(instanceKey);
152
+ return instance.translate(
153
+ errorKey as any,
154
+ vars,
155
+ language,
156
+ fallbackLanguage,
157
+ );
158
+ } catch {
159
+ return `${errorKey}: ${JSON.stringify(vars || {})}`;
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Throws an error with a translated message using the specified instance (or default instance if none is provided).
165
+ * @param errorKey The error key to translate
166
+ * @param vars Variables to replace in the translation string
167
+ * @param instanceKey The key of the I18nEngine instance to use
168
+ * @throws Error with translated message
169
+ */
170
+ public static throwError(
171
+ errorKey: string,
172
+ vars?: Record<string, string | number>,
173
+ instanceKey?: string,
174
+ ): never {
175
+ throw new Error(I18nEngine.getErrorMessage(errorKey, vars, instanceKey));
176
+ }
177
+
178
+ /**
179
+ * Gets the global context for translations
180
+ * @returns The global context object
181
+ */
182
+ get context(): TContext {
183
+ return this._context;
184
+ }
185
+
186
+ /**
187
+ * Sets the global context for translations (used if no context is provided) for this instance
188
+ * @param context The context to set
189
+ */
190
+ set context(context: Partial<TContext>) {
191
+ this._context = { ...this._context, ...context } as TContext;
192
+ }
193
+
194
+ /**
195
+ * Gets the enum translation registry for this engine instance
196
+ * @returns The enum translation registry
197
+ */
198
+ get enumRegistry(): EnumTranslationRegistry<TStringKey, TLanguage> {
199
+ return this._enumRegistry;
200
+ }
201
+
202
+ /**
203
+ * Translates a string key into the specified language, replacing any variables as needed.
204
+ * @param key The string key to translate
205
+ * @param vars Variables to replace in the translation string
206
+ * @param language The language to translate to
207
+ * @param fallbackLanguage The fallback language if the translation is not found
208
+ * @returns The translated string
209
+ */
210
+ translate(
211
+ key: TStringKey,
212
+ vars?: Record<string, string | number>,
213
+ language?: TLanguage,
214
+ fallbackLanguage?: TLanguage,
215
+ ): string {
216
+ const lang =
217
+ language ??
218
+ (this._context.currentContext === 'admin'
219
+ ? this._context.adminLanguage
220
+ : this._context.language);
221
+ const fallback = fallbackLanguage ?? this.config.defaultLanguage;
222
+
223
+ try {
224
+ const stringValue = this.getString(lang, key);
225
+ let result = isTemplate(key)
226
+ ? replaceVariables(stringValue, vars, this.config.constants)
227
+ : stringValue;
228
+
229
+ // Ensure result is always a string
230
+ if (typeof result !== 'string') {
231
+ result = String(result);
232
+ }
233
+ return result;
234
+ } catch {
235
+ if (lang !== fallback) {
236
+ try {
237
+ const stringValue = this.getString(fallback, key);
238
+ let result = isTemplate(key)
239
+ ? replaceVariables(stringValue, vars, this.config.constants)
240
+ : stringValue;
241
+
242
+ // Ensure result is always a string
243
+ if (typeof result !== 'string') {
244
+ result = String(result);
245
+ }
246
+ return result;
247
+ } catch {
248
+ return String(key);
249
+ }
250
+ }
251
+ return String(key);
252
+ }
253
+ }
254
+
255
+ /**
256
+ * Translates an enumeration value into the specified language.
257
+ * @param enumObj The enumeration object
258
+ * @param value The enumeration value to translate
259
+ * @param language The language to translate to
260
+ * @returns The translated enumeration value
261
+ */
262
+ translateEnum<TEnum extends string | number>(
263
+ enumObj: Record<string, TEnum>,
264
+ value: TEnum,
265
+ language: TLanguage,
266
+ ): string {
267
+ return this._enumRegistry.translate(enumObj, value, language);
268
+ }
269
+
270
+ /**
271
+ * Registers an enumeration and its translations with the engine.
272
+ * @param enumObj The enumeration object
273
+ * @param translations The translations for the enumeration
274
+ * @param enumName The name of the enumeration (for error messages)
275
+ */
276
+ registerEnum<TEnum extends string | number>(
277
+ enumObj: Record<string, TEnum> | Record<string | number, string | number>,
278
+ translations: EnumLanguageTranslation<TEnum, TLanguage>,
279
+ enumName: string,
280
+ ): void {
281
+ this._enumRegistry.register(
282
+ enumObj as Record<string, TEnum>,
283
+ translations,
284
+ enumName,
285
+ );
286
+ }
287
+
288
+ /**
289
+ * Safe translation that prevents infinite recursion for error messages
290
+ * @param key The string key to translate
291
+ * @param vars Variables to replace in the translation string
292
+ * @param language The language to translate to
293
+ * @returns The translated string or the key if translation fails
294
+ */
295
+ public safeTranslate(
296
+ key: TStringKey,
297
+ vars?: Record<string, string | number>,
298
+ language?: TLanguage,
299
+ ): string {
300
+ try {
301
+ const lang = language ?? this.config.defaultLanguage;
302
+ const strings = this.config.strings[lang];
303
+ if (!strings?.[key]) return String(key);
304
+ const stringValue = strings[key];
305
+ let result = isTemplate(key)
306
+ ? replaceVariables(stringValue, vars, this.config.constants)
307
+ : stringValue;
308
+
309
+ // Ensure result is always a string
310
+ if (typeof result !== 'string') {
311
+ result = String(result);
312
+ }
313
+ return result;
314
+ } catch {
315
+ return String(key);
316
+ }
317
+ }
318
+
319
+ /**
320
+ * Retrieves the string for the given language and key, throwing an error if not found.
321
+ * @param language The language to get the string for
322
+ * @param key The string key to retrieve
323
+ * @returns The string value
324
+ * @throws Error if the language or string key is not found
325
+ */
326
+ private getString(language: TLanguage, key: TStringKey): string {
327
+ const strings = this.config.strings[language];
328
+ if (!strings) {
329
+ throw new Error(
330
+ this.safeTranslate('Error_LanguageNotFound' as any, { language }) ||
331
+ `Language not found: ${language}`,
332
+ );
333
+ }
334
+
335
+ const value = strings[key];
336
+ if (!value) {
337
+ throw new Error(
338
+ this.safeTranslate('Error_StringNotFound' as any, { key }) ||
339
+ `String not found: ${key}`,
340
+ );
341
+ }
342
+
343
+ return value;
344
+ }
345
+
346
+ /**
347
+ * Gets the language code for the specified language.
348
+ * @param language The language to get the code for
349
+ * @returns The language code
350
+ */
351
+ getLanguageCode(language: TLanguage): string {
352
+ return this.config.languageCodes[language] || language;
353
+ }
354
+
355
+ /**
356
+ * Gets the language for the specified language code.
357
+ * @param code The language code to look up
358
+ * @returns The language, or undefined if not found
359
+ */
360
+ getLanguageFromCode(code: string): TLanguage | undefined {
361
+ for (const [lang, langCode] of Object.entries(this.config.languageCodes)) {
362
+ if (langCode === code) {
363
+ return lang as TLanguage;
364
+ }
365
+ }
366
+ return undefined;
367
+ }
368
+
369
+ /**
370
+ * Gets all language codes.
371
+ * @returns A record of all language codes
372
+ */
373
+ getAllLanguageCodes(): Record<TLanguage, string> {
374
+ return this.config.languageCodes as Record<TLanguage, string>;
375
+ }
376
+
377
+ /**
378
+ * Gets all available languages.
379
+ * @returns An array of all available languages
380
+ */
381
+ getAvailableLanguages(): TLanguage[] {
382
+ return Object.keys(this.config.strings) as TLanguage[];
383
+ }
384
+
385
+ /**
386
+ * Checks if a language is available.
387
+ * @param language The language to check
388
+ * @returns True if the language is available, false otherwise
389
+ */
390
+ isLanguageAvailable(language: string): language is TLanguage {
391
+ return Object.keys(this.config.strings).includes(language);
392
+ }
393
+
394
+ /**
395
+ * Clears all instances (for testing purposes)
396
+ * @internal
397
+ */
398
+ public static clearInstances(): void {
399
+ I18nEngine._instances.clear();
400
+ I18nEngine._defaultKey = null;
401
+ }
402
+
403
+ /**
404
+ * Removes a specific instance by key
405
+ * @param key The key of the instance to remove
406
+ * @internal
407
+ */
408
+ public static removeInstance(key?: string): void {
409
+ const instanceKey = key || I18nEngine.DefaultInstanceKey;
410
+ I18nEngine._instances.delete(instanceKey);
411
+ if (I18nEngine._defaultKey === instanceKey) {
412
+ const nextKey = I18nEngine._instances.keys().next().value;
413
+ I18nEngine._defaultKey =
414
+ I18nEngine._instances.size > 0 && nextKey ? nextKey : null;
415
+ }
416
+ }
417
+
418
+ /**
419
+ * Static error message templates for validation
420
+ */
421
+ private static readonly ErrorTemplates = {
422
+ MissingStringCollection:
423
+ 'Missing string collection for language: {language}',
424
+ MissingTranslation:
425
+ "Missing translation for key '{key}' in language '{language}'",
426
+ DefaultLanguageNoCollection:
427
+ "Default language '{language}' has no string collection",
428
+ };
429
+
430
+ /**
431
+ * Validates the configuration to ensure all languages have string collections
432
+ * and all string keys are provided for each language
433
+ * @param config The configuration to validate
434
+ * @throws Error if validation fails
435
+ */
436
+ private validateConfig(
437
+ config: I18nConfig<TStringKey, TLanguage, TConstants>,
438
+ ): void {
439
+ // Check that default language exists
440
+ if (!config.strings[config.defaultLanguage]) {
441
+ throw new Error(
442
+ this.getValidationError(
443
+ 'Error_DefaultLanguageNoCollectionTemplate' as any,
444
+ { language: config.defaultLanguage },
445
+ config,
446
+ ),
447
+ );
448
+ }
449
+
450
+ // Check that all string keys are provided for each language that has strings
451
+ for (const language of Object.keys(config.strings) as TLanguage[]) {
452
+ const strings = config.strings[language]!;
453
+ for (const stringKey of config.stringNames) {
454
+ if (!strings[stringKey]) {
455
+ throw new Error(
456
+ this.getValidationError(
457
+ 'Error_MissingTranslationTemplate' as any,
458
+ { key: stringKey, language },
459
+ config,
460
+ ),
461
+ );
462
+ }
463
+ }
464
+ }
465
+ }
466
+
467
+ /**
468
+ * Gets validation error message, trying translation first, falling back to template
469
+ */
470
+ private getValidationError(
471
+ key: TStringKey,
472
+ vars: Record<string, any>,
473
+ config: I18nConfig<TStringKey, TLanguage, TConstants>,
474
+ ): string {
475
+ try {
476
+ const strings = config.strings[config.defaultLanguage];
477
+ if (strings?.[key]) {
478
+ return replaceVariables(strings[key], vars, config.constants);
479
+ }
480
+ } catch {}
481
+
482
+ // Fallback to static templates
483
+ const template = key.includes('MissingStringCollection')
484
+ ? I18nEngine.ErrorTemplates.MissingStringCollection
485
+ : key.includes('MissingTranslation')
486
+ ? I18nEngine.ErrorTemplates.MissingTranslation
487
+ : I18nEngine.ErrorTemplates.DefaultLanguageNoCollection;
488
+
489
+ return replaceVariables(template, vars);
490
+ }
491
+ }
@@ -1,3 +1,4 @@
1
+ // Legacy exports (for backwards compatibility)
1
2
  export * from './active-context';
2
3
  export * from './component-definition';
3
4
  export * from './component-registration';
@@ -46,11 +47,19 @@ export * from './translation-response';
46
47
  export * from './translatable';
47
48
  export * from './create-translation-adapter';
48
49
  export * from './unified-translator';
50
+
51
+ // Re-export for convenience
49
52
  export { createCoreI18nEngine as createCoreI18n } from './core-i18n';
50
53
  export { I18nEngine as I18n } from './i18n-engine';
51
54
  export { PluginI18nEngine as PluginI18n } from './plugin-i18n-engine';
55
+
56
+ // Testing utilities
57
+ import { PluginI18nEngine } from './plugin-i18n-engine';
58
+
52
59
  /**
53
60
  * Reset all I18n engines and clear component registrations
54
61
  * Useful for test cleanup
55
62
  */
56
- export declare function resetAllI18nEngines(): void;
63
+ export function resetAllI18nEngines(): void {
64
+ PluginI18nEngine.resetAll();
65
+ }
@@ -3,25 +3,37 @@
3
3
  * These are provided as constants for convenience, but any string can be used as a language code.
4
4
  * Site builders can use these or define their own custom language codes.
5
5
  */
6
- export declare const LanguageCodes: {
7
- readonly EN_US: "en-US";
8
- readonly EN_GB: "en-GB";
9
- readonly FR: "fr";
10
- readonly ES: "es";
11
- readonly DE: "de";
12
- readonly ZH_CN: "zh-CN";
13
- readonly JA: "ja";
14
- readonly UK: "uk";
15
- };
6
+ export const LanguageCodes = {
7
+ EN_US: 'en-US',
8
+ EN_GB: 'en-GB',
9
+ FR: 'fr',
10
+ ES: 'es',
11
+ DE: 'de',
12
+ ZH_CN: 'zh-CN',
13
+ JA: 'ja',
14
+ UK: 'uk',
15
+ } as const;
16
+
16
17
  /**
17
18
  * Type representing any language code (string)
18
19
  */
19
20
  export type LanguageCode = string;
21
+
20
22
  /**
21
23
  * Type representing the common language codes provided by this library
22
24
  */
23
25
  export type CommonLanguageCode = typeof LanguageCodes[keyof typeof LanguageCodes];
26
+
24
27
  /**
25
28
  * Helper to get display names for common language codes
26
29
  */
27
- export declare const LanguageDisplayNames: Record<CommonLanguageCode, string>;
30
+ export const LanguageDisplayNames: Record<CommonLanguageCode, string> = {
31
+ [LanguageCodes.EN_US]: 'English (US)',
32
+ [LanguageCodes.EN_GB]: 'English (UK)',
33
+ [LanguageCodes.FR]: 'Français',
34
+ [LanguageCodes.ES]: 'Español',
35
+ [LanguageCodes.DE]: 'Deutsch',
36
+ [LanguageCodes.ZH_CN]: '中文',
37
+ [LanguageCodes.JA]: '日本語',
38
+ [LanguageCodes.UK]: 'Українська',
39
+ };
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Language definition with its properties
3
+ */
4
+ export interface LanguageDefinition {
5
+ /** Unique identifier for the language */
6
+ readonly id: string;
7
+ /** Display name in the native language */
8
+ readonly name: string;
9
+ /** ISO language code (e.g., 'en', 'fr', 'zh-CN') */
10
+ readonly code: string;
11
+ /** Whether this is the fallback/default language */
12
+ readonly isDefault?: boolean;
13
+ }