@digitaldefiance/i18n-lib 1.0.33 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +440 -4
  2. package/dist/component-definition.d.ts +11 -0
  3. package/dist/component-definition.js +2 -0
  4. package/dist/component-registration.d.ts +9 -0
  5. package/dist/component-registration.js +2 -0
  6. package/dist/component-registry.d.ts +64 -0
  7. package/dist/component-registry.js +238 -0
  8. package/dist/context.d.ts +2 -1
  9. package/dist/core-i18n.d.ts +330 -0
  10. package/dist/core-i18n.js +435 -0
  11. package/dist/core-language.d.ts +13 -0
  12. package/dist/core-language.js +17 -0
  13. package/dist/core-string-key.d.ts +39 -0
  14. package/dist/core-string-key.js +47 -0
  15. package/dist/default-config.d.ts +2 -1
  16. package/dist/default-config.js +24 -24
  17. package/dist/i18n-config.d.ts +20 -0
  18. package/dist/i18n-config.js +2 -0
  19. package/dist/i18n-context.d.ts +14 -0
  20. package/dist/i18n-context.js +2 -0
  21. package/dist/i18n-engine.d.ts +3 -1
  22. package/dist/index.d.ts +21 -1
  23. package/dist/index.js +25 -2
  24. package/dist/language-definition.d.ts +13 -0
  25. package/dist/language-definition.js +2 -0
  26. package/dist/language-registry.d.ts +106 -0
  27. package/dist/language-registry.js +194 -0
  28. package/dist/plugin-i18n-engine.d.ts +126 -0
  29. package/dist/plugin-i18n-engine.js +266 -0
  30. package/dist/registry-config.d.ts +14 -0
  31. package/dist/registry-config.js +2 -0
  32. package/dist/registry-context.d.ts +12 -0
  33. package/dist/registry-context.js +2 -0
  34. package/dist/registry-error-type.d.ts +12 -0
  35. package/dist/registry-error-type.js +16 -0
  36. package/dist/registry-error.d.ts +19 -0
  37. package/dist/registry-error.js +44 -0
  38. package/dist/translation-request.d.ts +9 -0
  39. package/dist/translation-request.js +2 -0
  40. package/dist/translation-response.d.ts +8 -0
  41. package/dist/translation-response.js +2 -0
  42. package/dist/typed-error.d.ts +63 -3
  43. package/dist/typed-error.js +230 -2
  44. package/dist/types.d.ts +42 -29
  45. package/dist/validation-config.d.ts +11 -0
  46. package/dist/validation-config.js +2 -0
  47. package/dist/validation-result.d.ts +12 -0
  48. package/dist/validation-result.js +2 -0
  49. package/package.json +2 -1
@@ -1,9 +1,49 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TypedError = void 0;
3
+ exports.CoreTypedError = exports.PluginTypedError = exports.TypedError = exports.BaseTypedError = void 0;
4
+ exports.createPluginTypedError = createPluginTypedError;
5
+ exports.createCoreTypedError = createCoreTypedError;
6
+ exports.createTranslatedError = createTranslatedError;
7
+ // Legacy imports (for backward compatibility)
4
8
  const default_config_1 = require("./default-config");
9
+ const core_string_key_1 = require("./core-string-key");
10
+ const plugin_i18n_engine_1 = require("./plugin-i18n-engine");
5
11
  /**
6
- * Type-safe TypedError that ensures complete enum coverage
12
+ * Base typed error class with common patterns
13
+ */
14
+ class BaseTypedError extends Error {
15
+ constructor(type, message, metadata) {
16
+ super(message);
17
+ this.type = type;
18
+ this.metadata = metadata;
19
+ this.name = this.constructor.name;
20
+ }
21
+ /**
22
+ * Create a simple typed error without engine dependency
23
+ */
24
+ static createSimple(type, message, metadata) {
25
+ return new this(type, message, metadata);
26
+ }
27
+ /**
28
+ * Create a typed error with translation support
29
+ */
30
+ static createTranslated(engine, componentId, type, reasonMap, variables, language, metadata) {
31
+ const key = reasonMap[type];
32
+ let message;
33
+ if (key && engine) {
34
+ // Try to translate the error message using the engine
35
+ message = engine.safeTranslate(componentId, key, variables, language);
36
+ }
37
+ else {
38
+ // Fallback to a basic English message
39
+ message = `Error: ${type}${metadata ? ` - ${JSON.stringify(metadata)}` : ''}`;
40
+ }
41
+ return new this(type, message, metadata);
42
+ }
43
+ }
44
+ exports.BaseTypedError = BaseTypedError;
45
+ /**
46
+ * Legacy TypedError that ensures complete enum coverage (for backward compatibility)
7
47
  */
8
48
  class TypedError extends Error {
9
49
  constructor(engine, type, reasonMap, language, otherVars) {
@@ -19,3 +59,191 @@ class TypedError extends Error {
19
59
  }
20
60
  }
21
61
  exports.TypedError = TypedError;
62
+ /**
63
+ * Plugin-based TypedError that works with the new component registration system
64
+ */
65
+ class PluginTypedError extends Error {
66
+ constructor(engine, componentId, type, reasonMap, language, otherVars) {
67
+ const key = reasonMap[type];
68
+ // If key is not found in the reason map, use core error message
69
+ if (!key) {
70
+ const errorMsg = engine.safeTranslate('core', core_string_key_1.CoreStringKey.Error_StringKeyNotFoundTemplate, {
71
+ stringKey: String(type),
72
+ componentId: componentId,
73
+ }, language);
74
+ throw new Error(errorMsg);
75
+ }
76
+ // Translate the error message using the component and string key
77
+ const translatedMessage = engine.safeTranslate(componentId, key, otherVars, language);
78
+ super(translatedMessage);
79
+ this.componentId = componentId;
80
+ this.type = type;
81
+ this.reasonMap = reasonMap;
82
+ this.language = language;
83
+ this.otherVars = otherVars;
84
+ this.name = this.constructor.name;
85
+ }
86
+ }
87
+ exports.PluginTypedError = PluginTypedError;
88
+ /**
89
+ * Core system TypedError using the core component strings
90
+ */
91
+ class CoreTypedError extends Error {
92
+ constructor(engine, type, reasonMap, language, otherVars) {
93
+ const key = reasonMap[type];
94
+ // If key is not found in the reason map, use a fallback error
95
+ if (!key) {
96
+ const errorMsg = engine.safeTranslate('core', core_string_key_1.CoreStringKey.Error_StringKeyNotFoundTemplate, {
97
+ stringKey: String(type),
98
+ componentId: 'core',
99
+ }, language);
100
+ throw new Error(errorMsg);
101
+ }
102
+ // Translate the error message using the core component
103
+ const translatedMessage = engine.safeTranslate('core', key, otherVars, language);
104
+ super(translatedMessage);
105
+ this.type = type;
106
+ this.reasonMap = reasonMap;
107
+ this.language = language;
108
+ this.otherVars = otherVars;
109
+ this.name = this.constructor.name;
110
+ }
111
+ }
112
+ exports.CoreTypedError = CoreTypedError;
113
+ /**
114
+ * Helper function to create a plugin-based TypedError with automatic engine detection
115
+ */
116
+ function createPluginTypedError(componentId, type, reasonMap, otherVars, language, instanceKey) {
117
+ const engine = plugin_i18n_engine_1.PluginI18nEngine.getInstance(instanceKey);
118
+ return new (class extends PluginTypedError {
119
+ constructor() {
120
+ super(engine, componentId, type, reasonMap, language, otherVars);
121
+ }
122
+ })();
123
+ }
124
+ /**
125
+ * Helper function to create a core system TypedError with automatic engine detection
126
+ */
127
+ function createCoreTypedError(type, reasonMap, otherVars, language, instanceKey) {
128
+ const engine = plugin_i18n_engine_1.PluginI18nEngine.getInstance(instanceKey);
129
+ return new (class extends CoreTypedError {
130
+ constructor() {
131
+ super(engine, type, reasonMap, language, otherVars);
132
+ }
133
+ })();
134
+ }
135
+ /**
136
+ * Create a simple error with translation support (generalized pattern from RegistryError)
137
+ */
138
+ function createTranslatedError(engine, componentId, type, reasonMap, variables, language, metadata, errorName) {
139
+ const key = reasonMap[type];
140
+ let message;
141
+ if (key && engine) {
142
+ try {
143
+ // Try to translate the error message using the engine
144
+ message = engine.safeTranslate(componentId, key, variables, language);
145
+ }
146
+ catch (translationError) {
147
+ // Fallback if translation fails
148
+ message = `Error: ${type}${metadata ? ` - ${JSON.stringify(metadata)}` : ''}`;
149
+ }
150
+ }
151
+ else {
152
+ // Fallback to a basic English message
153
+ message = `Error: ${type}${metadata ? ` - ${JSON.stringify(metadata)}` : ''}`;
154
+ }
155
+ const error = new Error(message);
156
+ error.name = errorName || 'TranslatedError';
157
+ error.type = type;
158
+ error.metadata = metadata;
159
+ return error;
160
+ }
161
+ /**
162
+ * Example usage of the new plugin-based TypedError system
163
+ */
164
+ // Example 1: Core system error using CoreStringKey
165
+ /*
166
+ enum DatabaseErrorType {
167
+ ConnectionFailed = 'connectionFailed',
168
+ QueryTimeout = 'queryTimeout',
169
+ AccessDenied = 'accessDenied'
170
+ }
171
+
172
+ const coreErrorReasonMap: CompleteReasonMap<typeof DatabaseErrorType, CoreStringKey> = {
173
+ [DatabaseErrorType.ConnectionFailed]: CoreStringKey.Error_NetworkError,
174
+ [DatabaseErrorType.QueryTimeout]: CoreStringKey.Error_InternalServer,
175
+ [DatabaseErrorType.AccessDenied]: CoreStringKey.Error_AccessDenied
176
+ };
177
+
178
+ class DatabaseError extends CoreTypedError<typeof DatabaseErrorType> {
179
+ constructor(
180
+ engine: PluginI18nEngine<CoreLanguage>,
181
+ type: DatabaseErrorType,
182
+ otherVars?: Record<string, string | number>,
183
+ language?: CoreLanguage
184
+ ) {
185
+ super(engine, type, coreErrorReasonMap, language, otherVars);
186
+ }
187
+ }
188
+
189
+ // Usage:
190
+ // const engine = PluginI18nEngine.getInstance<CoreLanguage>();
191
+ // throw new DatabaseError(engine, DatabaseErrorType.ConnectionFailed);
192
+ */
193
+ // Example 2: Custom component error with custom strings
194
+ /*
195
+ enum UserErrorType {
196
+ UserNotFound = 'userNotFound',
197
+ InvalidCredentials = 'invalidCredentials',
198
+ AccountLocked = 'accountLocked'
199
+ }
200
+
201
+ enum UserErrorStringKey {
202
+ UserNotFoundMessage = 'userNotFoundMessage',
203
+ InvalidCredentialsMessage = 'invalidCredentialsMessage',
204
+ AccountLockedMessage = 'accountLockedMessage'
205
+ }
206
+
207
+ const userErrorReasonMap: CompleteReasonMap<typeof UserErrorType, UserErrorStringKey> = {
208
+ [UserErrorType.UserNotFound]: UserErrorStringKey.UserNotFoundMessage,
209
+ [UserErrorType.InvalidCredentials]: UserErrorStringKey.InvalidCredentialsMessage,
210
+ [UserErrorType.AccountLocked]: UserErrorStringKey.AccountLockedMessage
211
+ };
212
+
213
+ class UserError extends PluginTypedError<typeof UserErrorType, UserErrorStringKey, CoreLanguage> {
214
+ constructor(
215
+ engine: PluginI18nEngine<CoreLanguage>,
216
+ type: UserErrorType,
217
+ otherVars?: Record<string, string | number>,
218
+ language?: CoreLanguage
219
+ ) {
220
+ super(engine, 'user-system', type, userErrorReasonMap, language, otherVars);
221
+ }
222
+ }
223
+
224
+ // Usage:
225
+ // const engine = PluginI18nEngine.getInstance<CoreLanguage>();
226
+ // throw new UserError(engine, UserErrorType.UserNotFound, { username: 'john_doe' });
227
+ */
228
+ // Example 3: Using helper functions for simpler error creation
229
+ /*
230
+ // Define your error types and mappings
231
+ enum ApiErrorType {
232
+ Timeout = 'timeout',
233
+ NotFound = 'notFound'
234
+ }
235
+
236
+ const apiErrorMap: CompleteReasonMap<typeof ApiErrorType, CoreStringKey> = {
237
+ [ApiErrorType.Timeout]: CoreStringKey.Error_NetworkError,
238
+ [ApiErrorType.NotFound]: CoreStringKey.Error_NotFound
239
+ };
240
+
241
+ // Create errors using helper functions
242
+ function throwApiError(type: ApiErrorType, vars?: Record<string, string | number>) {
243
+ throw createCoreTypedError(type, apiErrorMap, vars);
244
+ }
245
+
246
+ // Usage:
247
+ // throwApiError(ApiErrorType.NotFound, { resource: 'user' });
248
+ */
249
+ // Export the type for external use (already exported above)
package/dist/types.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { CurrencyCode } from './currency-code';
2
- import { Timezone } from './timezone';
1
+ import { ComponentDefinition } from './component-definition';
2
+ import { ComponentRegistration } from './component-registration';
3
+ import { LanguageDefinition } from './language-definition';
3
4
  /**
4
5
  * Standard language contexts
5
6
  */
@@ -33,33 +34,29 @@ export type LanguageCodeCollection<TLanguage extends string> = Partial<Record<TL
33
34
  */
34
35
  export type EnumTranslationMap<TEnum extends string | number, TLanguage extends string> = Partial<Record<TLanguage, Partial<Record<TEnum, string>>>>;
35
36
  /**
36
- * I18n configuration interface
37
- */
38
- export interface I18nConfig<TStringKey extends string, TLanguage extends string, TConstants extends Record<string, any> = Record<string, any>, TTranslationContext extends string = LanguageContext> {
39
- stringNames: TStringKey[];
40
- strings: MasterStringsCollection<TStringKey, TLanguage>;
41
- defaultLanguage: TLanguage;
42
- defaultTranslationContext: TTranslationContext;
43
- defaultCurrencyCode: CurrencyCode;
44
- languageCodes: LanguageCodeCollection<TLanguage>;
45
- languages: TLanguage[];
46
- constants?: TConstants;
47
- enumName?: string;
48
- enumObj?: Record<string, TStringKey>;
49
- timezone: Timezone;
50
- adminTimezone: Timezone;
51
- }
52
- /**
53
- * I18n context interface
54
- */
55
- export interface I18nContext<TLanguage extends string, TTranslationContext extends string = LanguageContext> {
56
- language: TLanguage;
57
- adminLanguage: TLanguage;
58
- currencyCode: CurrencyCode;
59
- currentContext: TTranslationContext;
60
- timezone: Timezone;
61
- adminTimezone: Timezone;
62
- }
37
+ * String collection for a specific language and component
38
+ */
39
+ export type ComponentStrings<TStringKeys extends string> = {
40
+ [K in TStringKeys]: string;
41
+ };
42
+ /**
43
+ * Partial string collection (used during registration before validation)
44
+ */
45
+ export type PartialComponentStrings<TStringKeys extends string> = {
46
+ [K in TStringKeys]?: string;
47
+ };
48
+ /**
49
+ * Language strings for a component across all registered languages
50
+ */
51
+ export type ComponentLanguageStrings<TStringKeys extends string, TLanguages extends string> = {
52
+ [L in TLanguages]: ComponentStrings<TStringKeys>;
53
+ };
54
+ /**
55
+ * Partial language strings (used during registration before validation)
56
+ */
57
+ export type PartialComponentLanguageStrings<TStringKeys extends string, TLanguages extends string> = {
58
+ [L in TLanguages]?: PartialComponentStrings<TStringKeys>;
59
+ };
63
60
  /**
64
61
  * Generic translation type for any enumeration
65
62
  */
@@ -72,6 +69,22 @@ export type EnumTranslation<T extends string | number> = {
72
69
  export type EnumLanguageTranslation<T extends string | number, TLanguage extends string = string> = Partial<{
73
70
  [L in TLanguage]: EnumTranslation<T>;
74
71
  }>;
72
+ /**
73
+ * Type utility to extract string keys from a component definition
74
+ */
75
+ export type ExtractStringKeys<T> = T extends ComponentDefinition<infer K> ? K : never;
76
+ /**
77
+ * Type utility to extract languages from registry
78
+ */
79
+ export type ExtractLanguages<T> = T extends LanguageDefinition ? T['id'] : never;
80
+ /**
81
+ * Type utility to create a strongly typed component registration
82
+ */
83
+ export type CreateComponentRegistration<TComponent extends ComponentDefinition<any>, TLanguages extends string> = ComponentRegistration<ExtractStringKeys<TComponent>, TLanguages>;
84
+ /**
85
+ * Utility type to ensure all string keys are provided for all languages
86
+ */
87
+ export type CompleteComponentStrings<TStringKeys extends string, TLanguages extends string> = ComponentLanguageStrings<TStringKeys, TLanguages>;
75
88
  /**
76
89
  * Helper function to create typed translations for an enumeration
77
90
  */
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Configuration for component registration validation
3
+ */
4
+ export interface ValidationConfig {
5
+ /** Whether to require all languages to have all strings */
6
+ readonly requireCompleteStrings: boolean;
7
+ /** Whether to allow registration with missing strings (will use fallbacks) */
8
+ readonly allowPartialRegistration: boolean;
9
+ /** Default language to fall back to for missing strings */
10
+ readonly fallbackLanguageId: string;
11
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Validation result for component registration
3
+ */
4
+ export interface ValidationResult {
5
+ readonly isValid: boolean;
6
+ readonly missingKeys: ReadonlyArray<{
7
+ readonly languageId: string;
8
+ readonly componentId: string;
9
+ readonly stringKey: string;
10
+ }>;
11
+ readonly errors: readonly string[];
12
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@digitaldefiance/i18n-lib",
3
- "version": "1.0.33",
3
+ "version": "1.1.0",
4
4
  "description": "Generic i18n library with enum translation support",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "scripts": {
8
8
  "build": "yarn tsc",
9
9
  "test": "yarn jest --detectOpenHandles",
10
+ "test:stream": "yarn jest --detectOpenHandles --runInBand --outputStyle=stream",
10
11
  "lint": "eslint src/**/*.ts tests/**/*.ts",
11
12
  "lint:fix": "eslint src/**/*.ts tests/**/*.ts --fix",
12
13
  "prettier:check": "prettier --check 'src/**/*.{ts,tsx}' 'tests/**/*.{ts,tsx}'",