@digitaldefiance/i18n-lib 1.3.12 → 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 +4 -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
@@ -1,56 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HandleableError = void 0;
4
- class HandleableError extends Error {
5
- constructor(source, options) {
6
- super(source.message);
7
- this.name = this.constructor.name;
8
- this.cause = options?.cause ?? source;
9
- this.statusCode = options?.statusCode ?? 500;
10
- this._handled = options?.handled ?? false;
11
- this.sourceData = options?.sourceData;
12
- // Capture stack trace - prioritize source stack, then capture new one
13
- if (source.stack) {
14
- this.stack = source.stack;
15
- }
16
- else if (Error.captureStackTrace) {
17
- Error.captureStackTrace(this, this.constructor);
18
- }
19
- else {
20
- this.stack = new Error().stack;
21
- }
22
- }
23
- get handled() {
24
- return this._handled;
25
- }
26
- set handled(value) {
27
- this._handled = value;
28
- }
29
- serializeValue(value) {
30
- if (value && typeof value === 'object' && 'toJSON' in value && typeof value.toJSON === 'function') {
31
- return value.toJSON();
32
- }
33
- if (value instanceof Error) {
34
- return value.message;
35
- }
36
- if (Array.isArray(value)) {
37
- return value.map(item => this.serializeValue(item));
38
- }
39
- if (value && typeof value === 'object') {
40
- return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, this.serializeValue(v)]));
41
- }
42
- return value;
43
- }
44
- toJSON() {
45
- return {
46
- name: this.name,
47
- message: this.message,
48
- statusCode: this.statusCode,
49
- handled: this.handled,
50
- stack: this.stack,
51
- cause: this.serializeValue(this.cause),
52
- ...(this.sourceData ? { sourceData: this.serializeValue(this.sourceData) } : {}),
53
- };
54
- }
55
- }
56
- exports.HandleableError = HandleableError;
@@ -1,22 +0,0 @@
1
- import { IActiveContext } from './active-context';
2
- import { CurrencyCode } from './currency-code';
3
- import { Timezone } from './timezone';
4
- import { LanguageContextSpace } from './types';
5
- export interface IGlobalActiveContext<TLanguage extends string, TActiveContext extends IActiveContext<TLanguage>> {
6
- context: TActiveContext;
7
- userLanguage: TLanguage;
8
- currencyCode: CurrencyCode;
9
- adminLanguage: TLanguage;
10
- languageContextSpace: LanguageContextSpace;
11
- userTimezone: Timezone;
12
- adminTimezone: Timezone;
13
- createContext(defaultLanguage: TLanguage, defaultAdminLanguage?: TLanguage, key?: string): TActiveContext;
14
- getContext(key?: string): TActiveContext;
15
- setUserLanguage(language: TLanguage, key?: string): void;
16
- setCurrencyCode(code: CurrencyCode, key?: string): void;
17
- setAdminLanguage(language: TLanguage, key?: string): void;
18
- setLanguageContextSpace(context: LanguageContextSpace, key?: string): void;
19
- getLanguageContextSpace(key?: string): LanguageContextSpace;
20
- setUserTimezone(tz: Timezone, key?: string): void;
21
- setAdminTimezone(tz: Timezone, key?: string): void;
22
- }
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,6 +0,0 @@
1
- export interface HandleableErrorOptions {
2
- cause?: Error;
3
- handled?: boolean;
4
- statusCode?: number;
5
- sourceData?: unknown;
6
- }
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,5 +0,0 @@
1
- export interface IHandleable {
2
- toJSON(): Record<string, unknown>;
3
- get handled(): boolean;
4
- set handled(value: boolean);
5
- }
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,20 +0,0 @@
1
- import { CurrencyCode } from './currency-code';
2
- import { Timezone } from './timezone';
3
- import { LanguageCodeCollection, LanguageContextSpace, MasterStringsCollection } from './types';
4
- /**
5
- * I18n configuration interface
6
- */
7
- export interface I18nConfig<TStringKey extends string, TLanguage extends string, TConstants extends Record<string, any> = Record<string, any>> {
8
- stringNames: TStringKey[];
9
- strings: MasterStringsCollection<TStringKey, TLanguage>;
10
- defaultLanguage: TLanguage;
11
- defaultTranslationContext: LanguageContextSpace;
12
- defaultCurrencyCode: CurrencyCode;
13
- languageCodes: LanguageCodeCollection<TLanguage>;
14
- languages: TLanguage[];
15
- constants?: TConstants;
16
- enumName?: string;
17
- enumObj?: Record<string, TStringKey>;
18
- timezone: Timezone;
19
- adminTimezone: Timezone;
20
- }
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,178 +0,0 @@
1
- import { EnumTranslationRegistry } from './enum-registry';
2
- import { I18nConfig } from './i18n-config';
3
- import { I18nContext } from './i18n-context';
4
- import { EnumLanguageTranslation } from './types';
5
- /**
6
- * Internationalization engine class
7
- */
8
- export declare class I18nEngine<TStringKey extends string, TLanguage extends string, TConstants extends Record<string, any> = Record<string, any>, TContext extends I18nContext<TLanguage> = I18nContext<TLanguage>> {
9
- /**
10
- * Registry for enum translations
11
- */
12
- protected _enumRegistry: EnumTranslationRegistry<TStringKey, TLanguage>;
13
- /**
14
- * Configuration for the i18n engine
15
- */
16
- readonly config: I18nConfig<TStringKey, TLanguage, TConstants>;
17
- /**
18
- * Static instances for semi-singleton pattern
19
- */
20
- private static _instances;
21
- /**
22
- * Default instance key (first created instance)
23
- */
24
- private static _defaultKey;
25
- /**
26
- * Default instance key if none is provided
27
- */
28
- protected static readonly DefaultInstanceKey = "default";
29
- /**
30
- * Global context for translations (used if no context is provided) for this instance
31
- */
32
- private _context;
33
- /**
34
- * Default template processor instance
35
- */
36
- readonly t: (str: string, language?: TLanguage, ...otherVars: Record<string, string | number>[]) => string;
37
- /**
38
- * Creates a new I18nEngine instance
39
- * @param config The i18n configuration
40
- * @param key Optional instance key for the semi-singleton pattern
41
- * @throws Error if an instance with the same key already exists
42
- */
43
- constructor(config: I18nConfig<TStringKey, TLanguage, TConstants>, key?: string, newContext?: () => TContext);
44
- /**
45
- * Gets an instance of the I18nEngine by key. If no key is provided, the default instance is returned.
46
- * @param key The key of the instance to retrieve
47
- * @returns The I18nEngine instance
48
- * @throws Error if the instance with the provided key does not exist
49
- */
50
- static getInstance<T extends I18nEngine<any, any, any, any>>(key?: string): T;
51
- /**
52
- * Gets a translation for the provided error key using the specified instance (or default instance if none is provided).
53
- * @param errorKey The error key to translate
54
- * @param vars Variables to replace in the translation string
55
- * @param instanceKey The key of the I18nEngine instance to use
56
- * @param language The language to translate to
57
- * @param fallbackLanguage The fallback language if the translation is not found
58
- * @returns The translated error message
59
- */
60
- static getErrorMessage(errorKey: string, vars?: Record<string, string | number>, instanceKey?: string, language?: string, fallbackLanguage?: string): string;
61
- /**
62
- * Throws an error with a translated message using the specified instance (or default instance if none is provided).
63
- * @param errorKey The error key to translate
64
- * @param vars Variables to replace in the translation string
65
- * @param instanceKey The key of the I18nEngine instance to use
66
- * @throws Error with translated message
67
- */
68
- static throwError(errorKey: string, vars?: Record<string, string | number>, instanceKey?: string): never;
69
- /**
70
- * Gets the global context for translations
71
- * @returns The global context object
72
- */
73
- get context(): TContext;
74
- /**
75
- * Sets the global context for translations (used if no context is provided) for this instance
76
- * @param context The context to set
77
- */
78
- set context(context: Partial<TContext>);
79
- /**
80
- * Gets the enum translation registry for this engine instance
81
- * @returns The enum translation registry
82
- */
83
- get enumRegistry(): EnumTranslationRegistry<TStringKey, TLanguage>;
84
- /**
85
- * Translates a string key into the specified language, replacing any variables as needed.
86
- * @param key The string key to translate
87
- * @param vars Variables to replace in the translation string
88
- * @param language The language to translate to
89
- * @param fallbackLanguage The fallback language if the translation is not found
90
- * @returns The translated string
91
- */
92
- translate(key: TStringKey, vars?: Record<string, string | number>, language?: TLanguage, fallbackLanguage?: TLanguage): string;
93
- /**
94
- * Translates an enumeration value into the specified language.
95
- * @param enumObj The enumeration object
96
- * @param value The enumeration value to translate
97
- * @param language The language to translate to
98
- * @returns The translated enumeration value
99
- */
100
- translateEnum<TEnum extends string | number>(enumObj: Record<string, TEnum>, value: TEnum, language: TLanguage): string;
101
- /**
102
- * Registers an enumeration and its translations with the engine.
103
- * @param enumObj The enumeration object
104
- * @param translations The translations for the enumeration
105
- * @param enumName The name of the enumeration (for error messages)
106
- */
107
- registerEnum<TEnum extends string | number>(enumObj: Record<string, TEnum> | Record<string | number, string | number>, translations: EnumLanguageTranslation<TEnum, TLanguage>, enumName: string): void;
108
- /**
109
- * Safe translation that prevents infinite recursion for error messages
110
- * @param key The string key to translate
111
- * @param vars Variables to replace in the translation string
112
- * @param language The language to translate to
113
- * @returns The translated string or the key if translation fails
114
- */
115
- safeTranslate(key: TStringKey, vars?: Record<string, string | number>, language?: TLanguage): string;
116
- /**
117
- * Retrieves the string for the given language and key, throwing an error if not found.
118
- * @param language The language to get the string for
119
- * @param key The string key to retrieve
120
- * @returns The string value
121
- * @throws Error if the language or string key is not found
122
- */
123
- private getString;
124
- /**
125
- * Gets the language code for the specified language.
126
- * @param language The language to get the code for
127
- * @returns The language code
128
- */
129
- getLanguageCode(language: TLanguage): string;
130
- /**
131
- * Gets the language for the specified language code.
132
- * @param code The language code to look up
133
- * @returns The language, or undefined if not found
134
- */
135
- getLanguageFromCode(code: string): TLanguage | undefined;
136
- /**
137
- * Gets all language codes.
138
- * @returns A record of all language codes
139
- */
140
- getAllLanguageCodes(): Record<TLanguage, string>;
141
- /**
142
- * Gets all available languages.
143
- * @returns An array of all available languages
144
- */
145
- getAvailableLanguages(): TLanguage[];
146
- /**
147
- * Checks if a language is available.
148
- * @param language The language to check
149
- * @returns True if the language is available, false otherwise
150
- */
151
- isLanguageAvailable(language: string): language is TLanguage;
152
- /**
153
- * Clears all instances (for testing purposes)
154
- * @internal
155
- */
156
- static clearInstances(): void;
157
- /**
158
- * Removes a specific instance by key
159
- * @param key The key of the instance to remove
160
- * @internal
161
- */
162
- static removeInstance(key?: string): void;
163
- /**
164
- * Static error message templates for validation
165
- */
166
- private static readonly ErrorTemplates;
167
- /**
168
- * Validates the configuration to ensure all languages have string collections
169
- * and all string keys are provided for each language
170
- * @param config The configuration to validate
171
- * @throws Error if validation fails
172
- */
173
- private validateConfig;
174
- /**
175
- * Gets validation error message, trying translation first, falling back to template
176
- */
177
- private getValidationError;
178
- }
@@ -1,338 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.I18nEngine = void 0;
4
- const context_1 = require("./context");
5
- const enum_registry_1 = require("./enum-registry");
6
- const template_1 = require("./template");
7
- const utils_1 = require("./utils");
8
- /**
9
- * Internationalization engine class
10
- */
11
- class I18nEngine {
12
- /**
13
- * Creates a new I18nEngine instance
14
- * @param config The i18n configuration
15
- * @param key Optional instance key for the semi-singleton pattern
16
- * @throws Error if an instance with the same key already exists
17
- */
18
- constructor(config, key, newContext = () => (0, context_1.createContext)(config.defaultLanguage, config.defaultTranslationContext, config.defaultCurrencyCode, config.timezone, config.adminTimezone)) {
19
- this.validateConfig(config);
20
- this.config = config;
21
- this._enumRegistry = new enum_registry_1.EnumTranslationRegistry(Object.keys(config.strings), (key, vars) => this.safeTranslate(key, vars));
22
- this._context = newContext();
23
- const instanceKey = key || I18nEngine.DefaultInstanceKey;
24
- if (I18nEngine._instances.has(instanceKey)) {
25
- const existing = I18nEngine._instances.get(instanceKey);
26
- throw new Error(existing.translate('Error_InstanceAlreadyExistsTemplate', {
27
- key: instanceKey,
28
- }));
29
- }
30
- I18nEngine._instances.set(instanceKey, this);
31
- if (!I18nEngine._defaultKey) {
32
- I18nEngine._defaultKey = instanceKey;
33
- }
34
- // Initialize the default template processor
35
- this.t = (0, template_1.createTemplateProcessor)(this.config.enumObj || {}, (key, vars, language) => this.translate(key, vars, language), this.config.enumName || 'StringKey');
36
- }
37
- /**
38
- * Gets an instance of the I18nEngine by key. If no key is provided, the default instance is returned.
39
- * @param key The key of the instance to retrieve
40
- * @returns The I18nEngine instance
41
- * @throws Error if the instance with the provided key does not exist
42
- */
43
- static getInstance(key) {
44
- const instanceKey = key || I18nEngine._defaultKey || I18nEngine.DefaultInstanceKey;
45
- if (!instanceKey || !I18nEngine._instances.has(instanceKey)) {
46
- throw new Error(I18nEngine.getErrorMessage('Error_InstanceNotFoundTemplate', {
47
- key: instanceKey,
48
- }));
49
- }
50
- return I18nEngine._instances.get(instanceKey);
51
- }
52
- /**
53
- * Gets a translation for the provided error key using the specified instance (or default instance if none is provided).
54
- * @param errorKey The error key to translate
55
- * @param vars Variables to replace in the translation string
56
- * @param instanceKey The key of the I18nEngine instance to use
57
- * @param language The language to translate to
58
- * @param fallbackLanguage The fallback language if the translation is not found
59
- * @returns The translated error message
60
- */
61
- static getErrorMessage(errorKey, vars, instanceKey, language, fallbackLanguage) {
62
- try {
63
- const instance = I18nEngine.getInstance(instanceKey);
64
- return instance.translate(errorKey, vars, language, fallbackLanguage);
65
- }
66
- catch {
67
- return `${errorKey}: ${JSON.stringify(vars || {})}`;
68
- }
69
- }
70
- /**
71
- * Throws an error with a translated message using the specified instance (or default instance if none is provided).
72
- * @param errorKey The error key to translate
73
- * @param vars Variables to replace in the translation string
74
- * @param instanceKey The key of the I18nEngine instance to use
75
- * @throws Error with translated message
76
- */
77
- static throwError(errorKey, vars, instanceKey) {
78
- throw new Error(I18nEngine.getErrorMessage(errorKey, vars, instanceKey));
79
- }
80
- /**
81
- * Gets the global context for translations
82
- * @returns The global context object
83
- */
84
- get context() {
85
- return this._context;
86
- }
87
- /**
88
- * Sets the global context for translations (used if no context is provided) for this instance
89
- * @param context The context to set
90
- */
91
- set context(context) {
92
- this._context = { ...this._context, ...context };
93
- }
94
- /**
95
- * Gets the enum translation registry for this engine instance
96
- * @returns The enum translation registry
97
- */
98
- get enumRegistry() {
99
- return this._enumRegistry;
100
- }
101
- /**
102
- * Translates a string key into the specified language, replacing any variables as needed.
103
- * @param key The string key to translate
104
- * @param vars Variables to replace in the translation string
105
- * @param language The language to translate to
106
- * @param fallbackLanguage The fallback language if the translation is not found
107
- * @returns The translated string
108
- */
109
- translate(key, vars, language, fallbackLanguage) {
110
- const lang = language ??
111
- (this._context.currentContext === 'admin'
112
- ? this._context.adminLanguage
113
- : this._context.language);
114
- const fallback = fallbackLanguage ?? this.config.defaultLanguage;
115
- try {
116
- const stringValue = this.getString(lang, key);
117
- let result = (0, utils_1.isTemplate)(key)
118
- ? (0, utils_1.replaceVariables)(stringValue, vars, this.config.constants)
119
- : stringValue;
120
- // Ensure result is always a string
121
- if (typeof result !== 'string') {
122
- result = String(result);
123
- }
124
- return result;
125
- }
126
- catch {
127
- if (lang !== fallback) {
128
- try {
129
- const stringValue = this.getString(fallback, key);
130
- let result = (0, utils_1.isTemplate)(key)
131
- ? (0, utils_1.replaceVariables)(stringValue, vars, this.config.constants)
132
- : stringValue;
133
- // Ensure result is always a string
134
- if (typeof result !== 'string') {
135
- result = String(result);
136
- }
137
- return result;
138
- }
139
- catch {
140
- return String(key);
141
- }
142
- }
143
- return String(key);
144
- }
145
- }
146
- /**
147
- * Translates an enumeration value into the specified language.
148
- * @param enumObj The enumeration object
149
- * @param value The enumeration value to translate
150
- * @param language The language to translate to
151
- * @returns The translated enumeration value
152
- */
153
- translateEnum(enumObj, value, language) {
154
- return this._enumRegistry.translate(enumObj, value, language);
155
- }
156
- /**
157
- * Registers an enumeration and its translations with the engine.
158
- * @param enumObj The enumeration object
159
- * @param translations The translations for the enumeration
160
- * @param enumName The name of the enumeration (for error messages)
161
- */
162
- registerEnum(enumObj, translations, enumName) {
163
- this._enumRegistry.register(enumObj, translations, enumName);
164
- }
165
- /**
166
- * Safe translation that prevents infinite recursion for error messages
167
- * @param key The string key to translate
168
- * @param vars Variables to replace in the translation string
169
- * @param language The language to translate to
170
- * @returns The translated string or the key if translation fails
171
- */
172
- safeTranslate(key, vars, language) {
173
- try {
174
- const lang = language ?? this.config.defaultLanguage;
175
- const strings = this.config.strings[lang];
176
- if (!strings?.[key])
177
- return String(key);
178
- const stringValue = strings[key];
179
- let result = (0, utils_1.isTemplate)(key)
180
- ? (0, utils_1.replaceVariables)(stringValue, vars, this.config.constants)
181
- : stringValue;
182
- // Ensure result is always a string
183
- if (typeof result !== 'string') {
184
- result = String(result);
185
- }
186
- return result;
187
- }
188
- catch {
189
- return String(key);
190
- }
191
- }
192
- /**
193
- * Retrieves the string for the given language and key, throwing an error if not found.
194
- * @param language The language to get the string for
195
- * @param key The string key to retrieve
196
- * @returns The string value
197
- * @throws Error if the language or string key is not found
198
- */
199
- getString(language, key) {
200
- const strings = this.config.strings[language];
201
- if (!strings) {
202
- throw new Error(this.safeTranslate('Error_LanguageNotFound', { language }) ||
203
- `Language not found: ${language}`);
204
- }
205
- const value = strings[key];
206
- if (!value) {
207
- throw new Error(this.safeTranslate('Error_StringNotFound', { key }) ||
208
- `String not found: ${key}`);
209
- }
210
- return value;
211
- }
212
- /**
213
- * Gets the language code for the specified language.
214
- * @param language The language to get the code for
215
- * @returns The language code
216
- */
217
- getLanguageCode(language) {
218
- return this.config.languageCodes[language] || language;
219
- }
220
- /**
221
- * Gets the language for the specified language code.
222
- * @param code The language code to look up
223
- * @returns The language, or undefined if not found
224
- */
225
- getLanguageFromCode(code) {
226
- for (const [lang, langCode] of Object.entries(this.config.languageCodes)) {
227
- if (langCode === code) {
228
- return lang;
229
- }
230
- }
231
- return undefined;
232
- }
233
- /**
234
- * Gets all language codes.
235
- * @returns A record of all language codes
236
- */
237
- getAllLanguageCodes() {
238
- return this.config.languageCodes;
239
- }
240
- /**
241
- * Gets all available languages.
242
- * @returns An array of all available languages
243
- */
244
- getAvailableLanguages() {
245
- return Object.keys(this.config.strings);
246
- }
247
- /**
248
- * Checks if a language is available.
249
- * @param language The language to check
250
- * @returns True if the language is available, false otherwise
251
- */
252
- isLanguageAvailable(language) {
253
- return Object.keys(this.config.strings).includes(language);
254
- }
255
- /**
256
- * Clears all instances (for testing purposes)
257
- * @internal
258
- */
259
- static clearInstances() {
260
- I18nEngine._instances.clear();
261
- I18nEngine._defaultKey = null;
262
- }
263
- /**
264
- * Removes a specific instance by key
265
- * @param key The key of the instance to remove
266
- * @internal
267
- */
268
- static removeInstance(key) {
269
- const instanceKey = key || I18nEngine.DefaultInstanceKey;
270
- I18nEngine._instances.delete(instanceKey);
271
- if (I18nEngine._defaultKey === instanceKey) {
272
- const nextKey = I18nEngine._instances.keys().next().value;
273
- I18nEngine._defaultKey =
274
- I18nEngine._instances.size > 0 && nextKey ? nextKey : null;
275
- }
276
- }
277
- /**
278
- * Validates the configuration to ensure all languages have string collections
279
- * and all string keys are provided for each language
280
- * @param config The configuration to validate
281
- * @throws Error if validation fails
282
- */
283
- validateConfig(config) {
284
- // Check that default language exists
285
- if (!config.strings[config.defaultLanguage]) {
286
- throw new Error(this.getValidationError('Error_DefaultLanguageNoCollectionTemplate', { language: config.defaultLanguage }, config));
287
- }
288
- // Check that all string keys are provided for each language that has strings
289
- for (const language of Object.keys(config.strings)) {
290
- const strings = config.strings[language];
291
- for (const stringKey of config.stringNames) {
292
- if (!strings[stringKey]) {
293
- throw new Error(this.getValidationError('Error_MissingTranslationTemplate', { key: stringKey, language }, config));
294
- }
295
- }
296
- }
297
- }
298
- /**
299
- * Gets validation error message, trying translation first, falling back to template
300
- */
301
- getValidationError(key, vars, config) {
302
- try {
303
- const strings = config.strings[config.defaultLanguage];
304
- if (strings?.[key]) {
305
- return (0, utils_1.replaceVariables)(strings[key], vars, config.constants);
306
- }
307
- }
308
- catch { }
309
- // Fallback to static templates
310
- const template = key.includes('MissingStringCollection')
311
- ? I18nEngine.ErrorTemplates.MissingStringCollection
312
- : key.includes('MissingTranslation')
313
- ? I18nEngine.ErrorTemplates.MissingTranslation
314
- : I18nEngine.ErrorTemplates.DefaultLanguageNoCollection;
315
- return (0, utils_1.replaceVariables)(template, vars);
316
- }
317
- }
318
- exports.I18nEngine = I18nEngine;
319
- /**
320
- * Static instances for semi-singleton pattern
321
- */
322
- I18nEngine._instances = new Map();
323
- /**
324
- * Default instance key (first created instance)
325
- */
326
- I18nEngine._defaultKey = null;
327
- /**
328
- * Default instance key if none is provided
329
- */
330
- I18nEngine.DefaultInstanceKey = 'default';
331
- /**
332
- * Static error message templates for validation
333
- */
334
- I18nEngine.ErrorTemplates = {
335
- MissingStringCollection: 'Missing string collection for language: {language}',
336
- MissingTranslation: "Missing translation for key '{key}' in language '{language}'",
337
- DefaultLanguageNoCollection: "Default language '{language}' has no string collection",
338
- };