@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.
- package/README.md +440 -4
- package/dist/component-definition.d.ts +11 -0
- package/dist/component-definition.js +2 -0
- package/dist/component-registration.d.ts +9 -0
- package/dist/component-registration.js +2 -0
- package/dist/component-registry.d.ts +64 -0
- package/dist/component-registry.js +238 -0
- package/dist/context.d.ts +2 -1
- package/dist/core-i18n.d.ts +330 -0
- package/dist/core-i18n.js +435 -0
- package/dist/core-language.d.ts +13 -0
- package/dist/core-language.js +17 -0
- package/dist/core-string-key.d.ts +39 -0
- package/dist/core-string-key.js +47 -0
- package/dist/default-config.d.ts +2 -1
- package/dist/default-config.js +24 -24
- package/dist/i18n-config.d.ts +20 -0
- package/dist/i18n-config.js +2 -0
- package/dist/i18n-context.d.ts +14 -0
- package/dist/i18n-context.js +2 -0
- package/dist/i18n-engine.d.ts +3 -1
- package/dist/index.d.ts +21 -1
- package/dist/index.js +25 -2
- package/dist/language-definition.d.ts +13 -0
- package/dist/language-definition.js +2 -0
- package/dist/language-registry.d.ts +106 -0
- package/dist/language-registry.js +194 -0
- package/dist/plugin-i18n-engine.d.ts +126 -0
- package/dist/plugin-i18n-engine.js +266 -0
- package/dist/registry-config.d.ts +14 -0
- package/dist/registry-config.js +2 -0
- package/dist/registry-context.d.ts +12 -0
- package/dist/registry-context.js +2 -0
- package/dist/registry-error-type.d.ts +12 -0
- package/dist/registry-error-type.js +16 -0
- package/dist/registry-error.d.ts +19 -0
- package/dist/registry-error.js +44 -0
- package/dist/translation-request.d.ts +9 -0
- package/dist/translation-request.js +2 -0
- package/dist/translation-response.d.ts +8 -0
- package/dist/translation-response.js +2 -0
- package/dist/typed-error.d.ts +63 -3
- package/dist/typed-error.js +230 -2
- package/dist/types.d.ts +42 -29
- package/dist/validation-config.d.ts +11 -0
- package/dist/validation-config.js +2 -0
- package/dist/validation-result.d.ts +12 -0
- package/dist/validation-result.js +2 -0
- package/package.json +2 -1
package/dist/typed-error.js
CHANGED
|
@@ -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
|
-
*
|
|
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 {
|
|
2
|
-
import {
|
|
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
|
-
*
|
|
37
|
-
*/
|
|
38
|
-
export
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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,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
|
+
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@digitaldefiance/i18n-lib",
|
|
3
|
-
"version": "1.0
|
|
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}'",
|