@digitaldefiance/i18n-lib 1.0.32 → 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/enum-registry.d.ts +10 -1
- package/dist/enum-registry.js +31 -4
- 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 +9 -2
- package/dist/i18n-engine.js +16 -13
- 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
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Language registry for managing supported languages and their properties
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.LanguageRegistry = void 0;
|
|
7
|
+
exports.createLanguageDefinition = createLanguageDefinition;
|
|
8
|
+
exports.createLanguageDefinitions = createLanguageDefinitions;
|
|
9
|
+
const registry_error_1 = require("./registry-error");
|
|
10
|
+
const registry_error_type_1 = require("./registry-error-type");
|
|
11
|
+
/**
|
|
12
|
+
* Registry for managing supported languages
|
|
13
|
+
*/
|
|
14
|
+
class LanguageRegistry {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.languages = new Map();
|
|
17
|
+
this.languagesByCodes = new Map();
|
|
18
|
+
this.defaultLanguageId = null;
|
|
19
|
+
// Empty constructor - languages are registered via registerLanguage method
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Register a new language
|
|
23
|
+
*/
|
|
24
|
+
registerLanguage(language) {
|
|
25
|
+
const languageId = language.id;
|
|
26
|
+
// Check for duplicate language ID
|
|
27
|
+
if (this.languages.has(languageId)) {
|
|
28
|
+
throw registry_error_1.RegistryError.createSimple(registry_error_type_1.RegistryErrorType.DuplicateLanguage, `Language '${languageId}' is already registered`, { languageId });
|
|
29
|
+
}
|
|
30
|
+
// Check for duplicate language code
|
|
31
|
+
if (this.languagesByCodes.has(language.code)) {
|
|
32
|
+
const existingLanguageId = this.languagesByCodes.get(language.code);
|
|
33
|
+
throw registry_error_1.RegistryError.createSimple(registry_error_type_1.RegistryErrorType.DuplicateLanguage, `Language code '${language.code}' is already used by language '${existingLanguageId}'`, { languageId, code: language.code, existingLanguageId });
|
|
34
|
+
}
|
|
35
|
+
// Register the language
|
|
36
|
+
this.languages.set(languageId, language);
|
|
37
|
+
this.languagesByCodes.set(language.code, languageId);
|
|
38
|
+
// Set as default if specified or if it's the first language
|
|
39
|
+
if (language.isDefault || this.defaultLanguageId === null) {
|
|
40
|
+
this.defaultLanguageId = languageId;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Register multiple languages at once
|
|
45
|
+
*/
|
|
46
|
+
registerLanguages(languages) {
|
|
47
|
+
for (const language of languages) {
|
|
48
|
+
this.registerLanguage(language);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get a language by its ID
|
|
53
|
+
*/
|
|
54
|
+
getLanguage(languageId) {
|
|
55
|
+
return this.languages.get(languageId);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get a language by its code
|
|
59
|
+
*/
|
|
60
|
+
getLanguageByCode(code) {
|
|
61
|
+
const languageId = this.languagesByCodes.get(code);
|
|
62
|
+
return languageId ? this.languages.get(languageId) : undefined;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get all registered languages
|
|
66
|
+
*/
|
|
67
|
+
getAllLanguages() {
|
|
68
|
+
return Array.from(this.languages.values());
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get all language IDs
|
|
72
|
+
*/
|
|
73
|
+
getLanguageIds() {
|
|
74
|
+
return Array.from(this.languages.keys());
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Get all language codes
|
|
78
|
+
*/
|
|
79
|
+
getLanguageCodes() {
|
|
80
|
+
return Array.from(this.languagesByCodes.keys());
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Check if a language is registered
|
|
84
|
+
*/
|
|
85
|
+
hasLanguage(languageId) {
|
|
86
|
+
return this.languages.has(languageId);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Check if a language code is registered
|
|
90
|
+
*/
|
|
91
|
+
hasLanguageCode(code) {
|
|
92
|
+
return this.languagesByCodes.has(code);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get the default language
|
|
96
|
+
*/
|
|
97
|
+
getDefaultLanguage() {
|
|
98
|
+
return this.defaultLanguageId
|
|
99
|
+
? this.languages.get(this.defaultLanguageId) || null
|
|
100
|
+
: null;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Get the default language ID
|
|
104
|
+
*/
|
|
105
|
+
getDefaultLanguageId() {
|
|
106
|
+
return this.defaultLanguageId;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Set the default language
|
|
110
|
+
*/
|
|
111
|
+
setDefaultLanguage(languageId) {
|
|
112
|
+
if (!this.languages.has(languageId)) {
|
|
113
|
+
throw registry_error_1.RegistryError.createSimple(registry_error_type_1.RegistryErrorType.LanguageNotFound, `Language '${languageId}' not found`, { languageId });
|
|
114
|
+
}
|
|
115
|
+
this.defaultLanguageId = languageId;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Get the number of registered languages
|
|
119
|
+
*/
|
|
120
|
+
getLanguageCount() {
|
|
121
|
+
return this.languages.size;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Validate that all required languages are present
|
|
125
|
+
*/
|
|
126
|
+
validateRequiredLanguages(requiredLanguages) {
|
|
127
|
+
const missingLanguages = [];
|
|
128
|
+
const errors = [];
|
|
129
|
+
for (const languageId of requiredLanguages) {
|
|
130
|
+
if (!this.languages.has(languageId)) {
|
|
131
|
+
missingLanguages.push(languageId);
|
|
132
|
+
errors.push(`Required language '${languageId}' is not registered`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
isValid: missingLanguages.length === 0,
|
|
137
|
+
missingLanguages,
|
|
138
|
+
errors,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Create a mapping of language IDs to their display names
|
|
143
|
+
*/
|
|
144
|
+
getLanguageDisplayNames() {
|
|
145
|
+
const result = {};
|
|
146
|
+
for (const [languageId, language] of this.languages) {
|
|
147
|
+
result[languageId] = language.name;
|
|
148
|
+
}
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Create a mapping of language IDs to their codes
|
|
153
|
+
*/
|
|
154
|
+
getLanguageCodeMapping() {
|
|
155
|
+
const result = {};
|
|
156
|
+
for (const [languageId, language] of this.languages) {
|
|
157
|
+
result[languageId] = language.code;
|
|
158
|
+
}
|
|
159
|
+
return result;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Find languages by partial name match (case-insensitive)
|
|
163
|
+
*/
|
|
164
|
+
findLanguagesByName(partialName) {
|
|
165
|
+
const searchTerm = partialName.toLowerCase();
|
|
166
|
+
return Array.from(this.languages.values()).filter((language) => language.name.toLowerCase().includes(searchTerm));
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Clear all registered languages
|
|
170
|
+
*/
|
|
171
|
+
clear() {
|
|
172
|
+
this.languages.clear();
|
|
173
|
+
this.languagesByCodes.clear();
|
|
174
|
+
this.defaultLanguageId = null;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
exports.LanguageRegistry = LanguageRegistry;
|
|
178
|
+
/**
|
|
179
|
+
* Helper function to create language definitions with type safety
|
|
180
|
+
*/
|
|
181
|
+
function createLanguageDefinition(id, name, code, isDefault) {
|
|
182
|
+
return {
|
|
183
|
+
id,
|
|
184
|
+
name,
|
|
185
|
+
code,
|
|
186
|
+
isDefault: isDefault || false,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Helper function to create multiple language definitions
|
|
191
|
+
*/
|
|
192
|
+
function createLanguageDefinitions(languages) {
|
|
193
|
+
return languages.map((lang) => createLanguageDefinition(lang.id, lang.name, lang.code, lang.isDefault));
|
|
194
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin-based internationalization engine with component and language registration
|
|
3
|
+
*/
|
|
4
|
+
import { ComponentDefinition } from './component-definition';
|
|
5
|
+
import { ComponentRegistration } from './component-registration';
|
|
6
|
+
import { ComponentRegistry } from './component-registry';
|
|
7
|
+
import { EnumTranslationRegistry } from './enum-registry';
|
|
8
|
+
import { LanguageDefinition } from './language-definition';
|
|
9
|
+
import { LanguageRegistry } from './language-registry';
|
|
10
|
+
import { RegistryConfig } from './registry-config';
|
|
11
|
+
import { RegistryContext } from './registry-context';
|
|
12
|
+
import { TranslationResponse } from './translation-response';
|
|
13
|
+
import { EnumLanguageTranslation } from './types';
|
|
14
|
+
/**
|
|
15
|
+
* Plugin-based I18n Engine with registration capabilities
|
|
16
|
+
*/
|
|
17
|
+
export declare class PluginI18nEngine<TLanguages extends string> {
|
|
18
|
+
private readonly languageRegistry;
|
|
19
|
+
private readonly componentRegistry;
|
|
20
|
+
private readonly enumRegistry;
|
|
21
|
+
private readonly config;
|
|
22
|
+
private context;
|
|
23
|
+
/**
|
|
24
|
+
* Static instances for semi-singleton pattern
|
|
25
|
+
*/
|
|
26
|
+
private static _instances;
|
|
27
|
+
private static _defaultKey;
|
|
28
|
+
protected static readonly DefaultInstanceKey = "default";
|
|
29
|
+
constructor(initialLanguages: readonly LanguageDefinition[], config?: Partial<RegistryConfig<TLanguages>>);
|
|
30
|
+
/**
|
|
31
|
+
* Create a new instance with a specific key
|
|
32
|
+
*/
|
|
33
|
+
static createInstance<TLangs extends string>(key: string, initialLanguages: readonly LanguageDefinition[], config?: Partial<RegistryConfig<TLangs>>): PluginI18nEngine<TLangs>;
|
|
34
|
+
/**
|
|
35
|
+
* Get an existing instance by key
|
|
36
|
+
*/
|
|
37
|
+
static getInstance<TLangs extends string>(key?: string): PluginI18nEngine<TLangs>;
|
|
38
|
+
/**
|
|
39
|
+
* Register a new language
|
|
40
|
+
*/
|
|
41
|
+
registerLanguage(language: LanguageDefinition): void;
|
|
42
|
+
/**
|
|
43
|
+
* Register multiple languages
|
|
44
|
+
*/
|
|
45
|
+
registerLanguages(languages: readonly LanguageDefinition[]): void;
|
|
46
|
+
/**
|
|
47
|
+
* Register a component with its translations
|
|
48
|
+
*/
|
|
49
|
+
registerComponent<TStringKeys extends string>(registration: ComponentRegistration<TStringKeys, TLanguages>): import("./validation-result").ValidationResult;
|
|
50
|
+
/**
|
|
51
|
+
* Update strings for an existing component
|
|
52
|
+
*/
|
|
53
|
+
updateComponentStrings<TStringKeys extends string>(componentId: string, strings: Parameters<ComponentRegistry<TLanguages>['updateComponentStrings']>[1]): import("./validation-result").ValidationResult;
|
|
54
|
+
/**
|
|
55
|
+
* Register an enum with translations
|
|
56
|
+
*/
|
|
57
|
+
registerEnum<TEnum extends string | number>(enumObj: Record<string, TEnum>, translations: EnumLanguageTranslation<TEnum, TLanguages>, enumName: string): void;
|
|
58
|
+
/**
|
|
59
|
+
* Translate a string for a component
|
|
60
|
+
*/
|
|
61
|
+
translate<TStringKeys extends string>(componentId: string, stringKey: TStringKeys, variables?: Record<string, string | number>, language?: TLanguages): string;
|
|
62
|
+
/**
|
|
63
|
+
* Safe translate that returns a placeholder if translation fails
|
|
64
|
+
*/
|
|
65
|
+
safeTranslate(componentId: string, stringKey: string, variables?: Record<string, string | number>, language?: TLanguages): string;
|
|
66
|
+
/**
|
|
67
|
+
* Translate an enum value
|
|
68
|
+
*/
|
|
69
|
+
translateEnum<TEnum extends string | number>(enumObj: Record<string, TEnum>, value: TEnum, language?: TLanguages): string;
|
|
70
|
+
/**
|
|
71
|
+
* Get detailed translation response
|
|
72
|
+
*/
|
|
73
|
+
getTranslationDetails<TStringKeys extends string>(componentId: string, stringKey: TStringKeys, variables?: Record<string, string | number>, language?: TLanguages): TranslationResponse;
|
|
74
|
+
/**
|
|
75
|
+
* Get current context
|
|
76
|
+
*/
|
|
77
|
+
getContext(): RegistryContext<TLanguages>;
|
|
78
|
+
/**
|
|
79
|
+
* Update context
|
|
80
|
+
*/
|
|
81
|
+
updateContext(updates: Partial<RegistryContext<TLanguages>>): void;
|
|
82
|
+
/**
|
|
83
|
+
* Set current language
|
|
84
|
+
*/
|
|
85
|
+
setLanguage(language: TLanguages): void;
|
|
86
|
+
/**
|
|
87
|
+
* Get available languages
|
|
88
|
+
*/
|
|
89
|
+
getLanguages(): readonly LanguageDefinition[];
|
|
90
|
+
/**
|
|
91
|
+
* Get registered components
|
|
92
|
+
*/
|
|
93
|
+
getComponents(): ReadonlyArray<ComponentDefinition<any>>;
|
|
94
|
+
/**
|
|
95
|
+
* Check if a component is registered
|
|
96
|
+
*/
|
|
97
|
+
hasComponent(componentId: string): boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Check if a language is registered
|
|
100
|
+
*/
|
|
101
|
+
hasLanguage(language: TLanguages): boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Get language by code
|
|
104
|
+
*/
|
|
105
|
+
getLanguageByCode(code: string): LanguageDefinition | undefined;
|
|
106
|
+
/**
|
|
107
|
+
* Get language registry for direct access
|
|
108
|
+
*/
|
|
109
|
+
getLanguageRegistry(): LanguageRegistry<TLanguages>;
|
|
110
|
+
/**
|
|
111
|
+
* Get component registry for direct access
|
|
112
|
+
*/
|
|
113
|
+
getComponentRegistry(): ComponentRegistry<TLanguages>;
|
|
114
|
+
/**
|
|
115
|
+
* Get enum registry for direct access
|
|
116
|
+
*/
|
|
117
|
+
getEnumRegistry(): EnumTranslationRegistry<string, TLanguages>;
|
|
118
|
+
/**
|
|
119
|
+
* Validate that all components have complete translations
|
|
120
|
+
*/
|
|
121
|
+
validateAllComponents(): {
|
|
122
|
+
isValid: boolean;
|
|
123
|
+
errors: string[];
|
|
124
|
+
warnings: string[];
|
|
125
|
+
};
|
|
126
|
+
}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Plugin-based internationalization engine with component and language registration
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PluginI18nEngine = void 0;
|
|
7
|
+
const component_registry_1 = require("./component-registry");
|
|
8
|
+
const currency_code_1 = require("./currency-code");
|
|
9
|
+
const enum_registry_1 = require("./enum-registry");
|
|
10
|
+
const language_registry_1 = require("./language-registry");
|
|
11
|
+
const registry_error_1 = require("./registry-error");
|
|
12
|
+
const registry_error_type_1 = require("./registry-error-type");
|
|
13
|
+
const timezone_1 = require("./timezone");
|
|
14
|
+
/**
|
|
15
|
+
* Plugin-based I18n Engine with registration capabilities
|
|
16
|
+
*/
|
|
17
|
+
class PluginI18nEngine {
|
|
18
|
+
constructor(initialLanguages, config = {}) {
|
|
19
|
+
// Find default language from initialLanguages or use the first one
|
|
20
|
+
const defaultLang = initialLanguages.find((l) => l.isDefault) || initialLanguages[0];
|
|
21
|
+
if (!defaultLang) {
|
|
22
|
+
throw new Error('At least one language must be provided');
|
|
23
|
+
}
|
|
24
|
+
// Set up configuration with defaults
|
|
25
|
+
this.config = {
|
|
26
|
+
defaultLanguage: defaultLang.id,
|
|
27
|
+
fallbackLanguage: defaultLang.id,
|
|
28
|
+
defaultCurrencyCode: new currency_code_1.CurrencyCode('USD'),
|
|
29
|
+
timezone: new timezone_1.Timezone('UTC'),
|
|
30
|
+
adminTimezone: new timezone_1.Timezone('UTC'),
|
|
31
|
+
validation: {
|
|
32
|
+
requireCompleteStrings: false,
|
|
33
|
+
allowPartialRegistration: true,
|
|
34
|
+
fallbackLanguageId: defaultLang.id,
|
|
35
|
+
},
|
|
36
|
+
...config,
|
|
37
|
+
};
|
|
38
|
+
// Initialize registries
|
|
39
|
+
this.languageRegistry = new language_registry_1.LanguageRegistry();
|
|
40
|
+
this.componentRegistry = new component_registry_1.ComponentRegistry(initialLanguages.map((l) => l.id), this.config.validation);
|
|
41
|
+
this.enumRegistry = new enum_registry_1.EnumTranslationRegistry(initialLanguages.map((l) => l.id), (key, vars) => this.safeTranslate('core', key, vars));
|
|
42
|
+
// Register initial languages
|
|
43
|
+
this.languageRegistry.registerLanguages(initialLanguages);
|
|
44
|
+
// Initialize context
|
|
45
|
+
this.context = {
|
|
46
|
+
currentLanguage: this.config.defaultLanguage,
|
|
47
|
+
fallbackLanguage: this.config.fallbackLanguage,
|
|
48
|
+
currencyCode: this.config.defaultCurrencyCode,
|
|
49
|
+
timezone: this.config.timezone,
|
|
50
|
+
adminTimezone: this.config.adminTimezone,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Create a new instance with a specific key
|
|
55
|
+
*/
|
|
56
|
+
static createInstance(key, initialLanguages, config) {
|
|
57
|
+
if (PluginI18nEngine._instances.has(key)) {
|
|
58
|
+
throw registry_error_1.RegistryError.createSimple(registry_error_type_1.RegistryErrorType.DuplicateComponent, `I18n instance with key '${key}' already exists`, { key });
|
|
59
|
+
}
|
|
60
|
+
const instance = new PluginI18nEngine(initialLanguages, config);
|
|
61
|
+
PluginI18nEngine._instances.set(key, instance);
|
|
62
|
+
if (!PluginI18nEngine._defaultKey) {
|
|
63
|
+
PluginI18nEngine._defaultKey = key;
|
|
64
|
+
}
|
|
65
|
+
return instance;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get an existing instance by key
|
|
69
|
+
*/
|
|
70
|
+
static getInstance(key) {
|
|
71
|
+
const instanceKey = key ||
|
|
72
|
+
PluginI18nEngine._defaultKey ||
|
|
73
|
+
PluginI18nEngine.DefaultInstanceKey;
|
|
74
|
+
const instance = PluginI18nEngine._instances.get(instanceKey);
|
|
75
|
+
if (!instance) {
|
|
76
|
+
throw registry_error_1.RegistryError.createSimple(registry_error_type_1.RegistryErrorType.ComponentNotFound, `I18n instance with key '${instanceKey}' not found`, { key: instanceKey });
|
|
77
|
+
}
|
|
78
|
+
return instance;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Register a new language
|
|
82
|
+
*/
|
|
83
|
+
registerLanguage(language) {
|
|
84
|
+
this.languageRegistry.registerLanguage(language);
|
|
85
|
+
// Update component registry with new language
|
|
86
|
+
const newLanguages = this.languageRegistry.getLanguageIds();
|
|
87
|
+
this.componentRegistry.updateRegisteredLanguages(newLanguages);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Register multiple languages
|
|
91
|
+
*/
|
|
92
|
+
registerLanguages(languages) {
|
|
93
|
+
for (const language of languages) {
|
|
94
|
+
this.registerLanguage(language);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Register a component with its translations
|
|
99
|
+
*/
|
|
100
|
+
registerComponent(registration) {
|
|
101
|
+
return this.componentRegistry.registerComponent(registration);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Update strings for an existing component
|
|
105
|
+
*/
|
|
106
|
+
updateComponentStrings(componentId, strings) {
|
|
107
|
+
return this.componentRegistry.updateComponentStrings(componentId, strings);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Register an enum with translations
|
|
111
|
+
*/
|
|
112
|
+
registerEnum(enumObj, translations, enumName) {
|
|
113
|
+
this.enumRegistry.register(enumObj, translations, enumName);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Translate a string for a component
|
|
117
|
+
*/
|
|
118
|
+
translate(componentId, stringKey, variables, language) {
|
|
119
|
+
const request = {
|
|
120
|
+
componentId,
|
|
121
|
+
stringKey,
|
|
122
|
+
language: language || this.context.currentLanguage,
|
|
123
|
+
variables,
|
|
124
|
+
};
|
|
125
|
+
const response = this.componentRegistry.getTranslation(request);
|
|
126
|
+
return response.translation;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Safe translate that returns a placeholder if translation fails
|
|
130
|
+
*/
|
|
131
|
+
safeTranslate(componentId, stringKey, variables, language) {
|
|
132
|
+
try {
|
|
133
|
+
return this.translate(componentId, stringKey, variables, language);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
// Return a placeholder if translation fails
|
|
137
|
+
return `[${componentId}.${stringKey}]`;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Translate an enum value
|
|
142
|
+
*/
|
|
143
|
+
translateEnum(enumObj, value, language) {
|
|
144
|
+
return this.enumRegistry.translate(enumObj, value, language || this.context.currentLanguage);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get detailed translation response
|
|
148
|
+
*/
|
|
149
|
+
getTranslationDetails(componentId, stringKey, variables, language) {
|
|
150
|
+
const request = {
|
|
151
|
+
componentId,
|
|
152
|
+
stringKey,
|
|
153
|
+
language: language || this.context.currentLanguage,
|
|
154
|
+
variables,
|
|
155
|
+
};
|
|
156
|
+
return this.componentRegistry.getTranslation(request);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Get current context
|
|
160
|
+
*/
|
|
161
|
+
getContext() {
|
|
162
|
+
return { ...this.context };
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Update context
|
|
166
|
+
*/
|
|
167
|
+
updateContext(updates) {
|
|
168
|
+
this.context = { ...this.context, ...updates };
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Set current language
|
|
172
|
+
*/
|
|
173
|
+
setLanguage(language) {
|
|
174
|
+
if (!this.languageRegistry.hasLanguage(language)) {
|
|
175
|
+
throw registry_error_1.RegistryError.createSimple(registry_error_type_1.RegistryErrorType.LanguageNotFound, `Language '${language}' is not registered`, { language });
|
|
176
|
+
}
|
|
177
|
+
this.context.currentLanguage = language;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Get available languages
|
|
181
|
+
*/
|
|
182
|
+
getLanguages() {
|
|
183
|
+
return this.languageRegistry.getAllLanguages();
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Get registered components
|
|
187
|
+
*/
|
|
188
|
+
getComponents() {
|
|
189
|
+
return this.componentRegistry.getComponents();
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Check if a component is registered
|
|
193
|
+
*/
|
|
194
|
+
hasComponent(componentId) {
|
|
195
|
+
return this.componentRegistry.hasComponent(componentId);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Check if a language is registered
|
|
199
|
+
*/
|
|
200
|
+
hasLanguage(language) {
|
|
201
|
+
return this.languageRegistry.hasLanguage(language);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Get language by code
|
|
205
|
+
*/
|
|
206
|
+
getLanguageByCode(code) {
|
|
207
|
+
return this.languageRegistry.getLanguageByCode(code);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Get language registry for direct access
|
|
211
|
+
*/
|
|
212
|
+
getLanguageRegistry() {
|
|
213
|
+
return this.languageRegistry;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Get component registry for direct access
|
|
217
|
+
*/
|
|
218
|
+
getComponentRegistry() {
|
|
219
|
+
return this.componentRegistry;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Get enum registry for direct access
|
|
223
|
+
*/
|
|
224
|
+
getEnumRegistry() {
|
|
225
|
+
return this.enumRegistry;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Validate that all components have complete translations
|
|
229
|
+
*/
|
|
230
|
+
validateAllComponents() {
|
|
231
|
+
const errors = [];
|
|
232
|
+
const warnings = [];
|
|
233
|
+
let isValid = true;
|
|
234
|
+
const components = this.getComponents();
|
|
235
|
+
const languages = this.languageRegistry.getLanguageIds();
|
|
236
|
+
for (const component of components) {
|
|
237
|
+
const componentStrings = this.componentRegistry.getComponentStrings(component.id);
|
|
238
|
+
if (!componentStrings) {
|
|
239
|
+
errors.push(`Component '${component.id}' has no registered strings`);
|
|
240
|
+
isValid = false;
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
for (const language of languages) {
|
|
244
|
+
const languageStrings = componentStrings[language];
|
|
245
|
+
if (!languageStrings) {
|
|
246
|
+
errors.push(`Component '${component.id}' missing strings for language '${language}'`);
|
|
247
|
+
isValid = false;
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
for (const stringKey of component.stringKeys) {
|
|
251
|
+
if (!languageStrings[stringKey]) {
|
|
252
|
+
warnings.push(`Component '${component.id}' missing key '${stringKey}' for language '${language}'`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return { isValid, errors, warnings };
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
exports.PluginI18nEngine = PluginI18nEngine;
|
|
261
|
+
/**
|
|
262
|
+
* Static instances for semi-singleton pattern
|
|
263
|
+
*/
|
|
264
|
+
PluginI18nEngine._instances = new Map();
|
|
265
|
+
PluginI18nEngine._defaultKey = null;
|
|
266
|
+
PluginI18nEngine.DefaultInstanceKey = 'default';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CurrencyCode } from './currency-code';
|
|
2
|
+
import { Timezone } from './timezone';
|
|
3
|
+
import { ValidationConfig } from './validation-config';
|
|
4
|
+
/**
|
|
5
|
+
* Registry configuration
|
|
6
|
+
*/
|
|
7
|
+
export interface RegistryConfig<TLanguages extends string> {
|
|
8
|
+
readonly defaultLanguage: TLanguages;
|
|
9
|
+
readonly fallbackLanguage: TLanguages;
|
|
10
|
+
readonly defaultCurrencyCode: CurrencyCode;
|
|
11
|
+
readonly timezone: Timezone;
|
|
12
|
+
readonly adminTimezone: Timezone;
|
|
13
|
+
readonly validation: ValidationConfig;
|
|
14
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { CurrencyCode } from './currency-code';
|
|
2
|
+
import { Timezone } from './timezone';
|
|
3
|
+
/**
|
|
4
|
+
* Translation context similar to existing I18nContext
|
|
5
|
+
*/
|
|
6
|
+
export interface RegistryContext<TLanguages extends string> {
|
|
7
|
+
currentLanguage: TLanguages;
|
|
8
|
+
fallbackLanguage: TLanguages;
|
|
9
|
+
currencyCode: CurrencyCode;
|
|
10
|
+
timezone: Timezone;
|
|
11
|
+
adminTimezone: Timezone;
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error types for registry operations
|
|
3
|
+
*/
|
|
4
|
+
export declare enum RegistryErrorType {
|
|
5
|
+
ComponentNotFound = "COMPONENT_NOT_FOUND",
|
|
6
|
+
LanguageNotFound = "LANGUAGE_NOT_FOUND",
|
|
7
|
+
StringKeyNotFound = "STRING_KEY_NOT_FOUND",
|
|
8
|
+
IncompleteRegistration = "INCOMPLETE_REGISTRATION",
|
|
9
|
+
DuplicateComponent = "DUPLICATE_COMPONENT",
|
|
10
|
+
DuplicateLanguage = "DUPLICATE_LANGUAGE",
|
|
11
|
+
ValidationFailed = "VALIDATION_FAILED"
|
|
12
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RegistryErrorType = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Error types for registry operations
|
|
6
|
+
*/
|
|
7
|
+
var RegistryErrorType;
|
|
8
|
+
(function (RegistryErrorType) {
|
|
9
|
+
RegistryErrorType["ComponentNotFound"] = "COMPONENT_NOT_FOUND";
|
|
10
|
+
RegistryErrorType["LanguageNotFound"] = "LANGUAGE_NOT_FOUND";
|
|
11
|
+
RegistryErrorType["StringKeyNotFound"] = "STRING_KEY_NOT_FOUND";
|
|
12
|
+
RegistryErrorType["IncompleteRegistration"] = "INCOMPLETE_REGISTRATION";
|
|
13
|
+
RegistryErrorType["DuplicateComponent"] = "DUPLICATE_COMPONENT";
|
|
14
|
+
RegistryErrorType["DuplicateLanguage"] = "DUPLICATE_LANGUAGE";
|
|
15
|
+
RegistryErrorType["ValidationFailed"] = "VALIDATION_FAILED";
|
|
16
|
+
})(RegistryErrorType || (exports.RegistryErrorType = RegistryErrorType = {}));
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { CoreLanguage } from './core-language';
|
|
2
|
+
import { RegistryErrorType } from './registry-error-type';
|
|
3
|
+
import { TranslationEngine } from './typed-error';
|
|
4
|
+
/**
|
|
5
|
+
* Registry error class that can work with plugin engines
|
|
6
|
+
*/
|
|
7
|
+
export declare class RegistryError extends Error {
|
|
8
|
+
readonly type: RegistryErrorType;
|
|
9
|
+
readonly metadata?: Record<string, any> | undefined;
|
|
10
|
+
constructor(type: RegistryErrorType, message: string, metadata?: Record<string, any> | undefined);
|
|
11
|
+
/**
|
|
12
|
+
* Create a registry error with translation support
|
|
13
|
+
*/
|
|
14
|
+
static createWithEngine(engine: TranslationEngine, type: RegistryErrorType, variables?: Record<string, string | number>, language?: CoreLanguage, metadata?: Record<string, any>): RegistryError;
|
|
15
|
+
/**
|
|
16
|
+
* Create a simple RegistryError without engine dependency
|
|
17
|
+
*/
|
|
18
|
+
static createSimple(type: RegistryErrorType, message: string, metadata?: Record<string, any>): RegistryError;
|
|
19
|
+
}
|