@digitaldefiance/i18n-lib 4.1.2 → 4.2.1
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 +170 -0
- package/package.json +1 -1
- package/src/branded-enum-utils.d.ts +226 -0
- package/src/branded-enum-utils.d.ts.map +1 -0
- package/src/branded-enum-utils.js +254 -0
- package/src/branded-enum-utils.js.map +1 -0
- package/src/core/enum-registry.d.ts +223 -8
- package/src/core/enum-registry.d.ts.map +1 -1
- package/src/core/enum-registry.js +231 -9
- package/src/core/enum-registry.js.map +1 -1
- package/src/core/i18n-engine.d.ts +126 -11
- package/src/core/i18n-engine.d.ts.map +1 -1
- package/src/core/i18n-engine.js +121 -11
- package/src/core/i18n-engine.js.map +1 -1
- package/src/enum-registry.d.ts +243 -21
- package/src/enum-registry.d.ts.map +1 -1
- package/src/enum-registry.js +255 -18
- package/src/enum-registry.js.map +1 -1
- package/src/index.d.ts +1 -0
- package/src/index.d.ts.map +1 -1
- package/src/index.js +2 -0
- package/src/index.js.map +1 -1
- package/src/plugin-i18n-engine.d.ts +101 -5
- package/src/plugin-i18n-engine.d.ts.map +1 -1
- package/src/plugin-i18n-engine.js +98 -2
- package/src/plugin-i18n-engine.js.map +1 -1
- package/src/types.d.ts +55 -0
- package/src/types.d.ts.map +1 -1
|
@@ -1,6 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enum translation registry (v2 - no generics)
|
|
3
|
+
*
|
|
4
|
+
* This module provides the `EnumRegistry` class for managing translations of enum
|
|
5
|
+
* values across multiple languages. It supports both traditional TypeScript enums
|
|
6
|
+
* and branded enums from `@digitaldefiance/branded-enum`.
|
|
7
|
+
*
|
|
8
|
+
* ## Overview
|
|
9
|
+
*
|
|
10
|
+
* The `EnumRegistry` is the v2 implementation of enum translation management,
|
|
11
|
+
* designed to work with the `I18nEngine`. It provides:
|
|
12
|
+
*
|
|
13
|
+
* - Registration of enums with their translations
|
|
14
|
+
* - Translation of enum values to localized strings
|
|
15
|
+
* - Automatic name inference for branded enums
|
|
16
|
+
* - Full backward compatibility with traditional enums
|
|
17
|
+
*
|
|
18
|
+
* ## Branded Enum Support
|
|
19
|
+
*
|
|
20
|
+
* When registering branded enums, the registry can automatically infer the enum
|
|
21
|
+
* name from the branded enum's component ID, eliminating the need to provide
|
|
22
|
+
* an explicit name parameter.
|
|
23
|
+
*
|
|
24
|
+
* @example Traditional enum usage
|
|
25
|
+
* ```typescript
|
|
26
|
+
* enum Status { Active = 'active', Inactive = 'inactive' }
|
|
27
|
+
*
|
|
28
|
+
* const registry = new EnumRegistry();
|
|
29
|
+
* registry.register(Status, {
|
|
30
|
+
* en: { active: 'Active', inactive: 'Inactive' },
|
|
31
|
+
* es: { active: 'Activo', inactive: 'Inactivo' },
|
|
32
|
+
* }, 'Status');
|
|
33
|
+
*
|
|
34
|
+
* registry.translate(Status, Status.Active, 'en'); // 'Active'
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @example Branded enum usage (name inferred)
|
|
38
|
+
* ```typescript
|
|
39
|
+
* import { createBrandedEnum } from '@digitaldefiance/branded-enum';
|
|
40
|
+
*
|
|
41
|
+
* const Status = createBrandedEnum('status', { Active: 'active', Inactive: 'inactive' });
|
|
42
|
+
*
|
|
43
|
+
* const registry = new EnumRegistry();
|
|
44
|
+
* registry.register(Status, {
|
|
45
|
+
* en: { active: 'Active', inactive: 'Inactive' },
|
|
46
|
+
* }); // Name 'status' is inferred from branded enum
|
|
47
|
+
*
|
|
48
|
+
* registry.translate(Status, Status.Active, 'en'); // 'Active'
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @module core/enum-registry
|
|
52
|
+
* @see {@link EnumTranslationRegistry} - Legacy registry with language validation
|
|
53
|
+
* @see {@link I18nEngine} - Main engine that uses this registry
|
|
54
|
+
*/
|
|
55
|
+
import type { AnyBrandedEnum, BrandedEnumValue } from '@digitaldefiance/branded-enum';
|
|
1
56
|
/**
|
|
2
57
|
* Registry for managing translations of enum values across multiple languages.
|
|
3
|
-
*
|
|
58
|
+
*
|
|
59
|
+
* Provides a centralized way to register and translate enum values with support
|
|
60
|
+
* for both traditional TypeScript enums and branded enums from
|
|
61
|
+
* `@digitaldefiance/branded-enum`.
|
|
62
|
+
*
|
|
63
|
+
* ## Key Features
|
|
64
|
+
*
|
|
65
|
+
* - **Dual Enum Support**: Works with both traditional and branded enums
|
|
66
|
+
* - **Automatic Name Inference**: Branded enums can have their name inferred from component ID
|
|
67
|
+
* - **Multi-Language**: Supports translations across any number of languages
|
|
68
|
+
* - **Type Safety**: Full TypeScript support with proper type inference
|
|
69
|
+
*
|
|
70
|
+
* ## Registration
|
|
71
|
+
*
|
|
72
|
+
* Use {@link register} to add an enum with its translations. For branded enums,
|
|
73
|
+
* the `enumName` parameter is optional and will be inferred from the component ID.
|
|
74
|
+
*
|
|
75
|
+
* ## Translation
|
|
76
|
+
*
|
|
77
|
+
* Use {@link translate} to get the localized string for an enum value. The method
|
|
78
|
+
* handles both traditional enum values and branded enum values.
|
|
79
|
+
*
|
|
80
|
+
* @example Complete workflow
|
|
81
|
+
* ```typescript
|
|
82
|
+
* import { createBrandedEnum } from '@digitaldefiance/branded-enum';
|
|
83
|
+
*
|
|
84
|
+
* // Create a branded enum
|
|
85
|
+
* const Priority = createBrandedEnum('priority', {
|
|
86
|
+
* High: 'high',
|
|
87
|
+
* Medium: 'medium',
|
|
88
|
+
* Low: 'low',
|
|
89
|
+
* });
|
|
90
|
+
*
|
|
91
|
+
* // Create registry and register enum
|
|
92
|
+
* const registry = new EnumRegistry();
|
|
93
|
+
* registry.register(Priority, {
|
|
94
|
+
* en: { high: 'High Priority', medium: 'Medium Priority', low: 'Low Priority' },
|
|
95
|
+
* es: { high: 'Alta Prioridad', medium: 'Prioridad Media', low: 'Baja Prioridad' },
|
|
96
|
+
* });
|
|
97
|
+
*
|
|
98
|
+
* // Check if registered
|
|
99
|
+
* registry.has(Priority); // true
|
|
100
|
+
*
|
|
101
|
+
* // Translate values
|
|
102
|
+
* registry.translate(Priority, Priority.High, 'en'); // 'High Priority'
|
|
103
|
+
* registry.translate(Priority, Priority.High, 'es'); // 'Alta Prioridad'
|
|
104
|
+
* ```
|
|
4
105
|
*/
|
|
5
106
|
export declare class EnumRegistry {
|
|
6
107
|
private translations;
|
|
@@ -10,29 +111,143 @@ export declare class EnumRegistry {
|
|
|
10
111
|
* Creates a new EnumRegistry instance.
|
|
11
112
|
* @param translateFn - Optional translation function for error messages
|
|
12
113
|
*/
|
|
13
|
-
constructor(translateFn?: (key: string, vars?: Record<string,
|
|
114
|
+
constructor(translateFn?: (key: string, vars?: Record<string, unknown>) => string);
|
|
14
115
|
/**
|
|
15
116
|
* Registers an enum with its translations for all languages.
|
|
117
|
+
*
|
|
118
|
+
* Supports both traditional TypeScript enums and branded enums from
|
|
119
|
+
* `@digitaldefiance/branded-enum`. For branded enums, the `enumName` parameter
|
|
120
|
+
* is optional and will be automatically inferred from the branded enum's
|
|
121
|
+
* component ID.
|
|
122
|
+
*
|
|
123
|
+
* ## Name Resolution
|
|
124
|
+
*
|
|
125
|
+
* The enum name is resolved in the following order:
|
|
126
|
+
* 1. Explicit `enumName` parameter (if provided)
|
|
127
|
+
* 2. Component ID from branded enum (if branded)
|
|
128
|
+
* 3. `'UnknownEnum'` (fallback for traditional enums without name)
|
|
129
|
+
*
|
|
130
|
+
* ## Translation Structure
|
|
131
|
+
*
|
|
132
|
+
* The `translations` object should map language codes to objects that map
|
|
133
|
+
* enum values to their translated strings:
|
|
134
|
+
*
|
|
135
|
+
* ```typescript
|
|
136
|
+
* {
|
|
137
|
+
* 'en': { 'value1': 'Translation 1', 'value2': 'Translation 2' },
|
|
138
|
+
* 'es': { 'value1': 'Traducción 1', 'value2': 'Traducción 2' },
|
|
139
|
+
* }
|
|
140
|
+
* ```
|
|
141
|
+
*
|
|
16
142
|
* @template TEnum - The enum value type (string or number)
|
|
17
|
-
* @param enumObj - The enum object to register
|
|
143
|
+
* @param enumObj - The enum object to register (traditional or branded)
|
|
18
144
|
* @param translations - Mapping of language codes to enum value translations
|
|
19
|
-
* @param enumName - Human-readable name for the enum (
|
|
145
|
+
* @param enumName - Human-readable name for the enum (optional for branded enums)
|
|
146
|
+
* @returns The registered translations object
|
|
147
|
+
*
|
|
148
|
+
* @example Traditional enum (name required)
|
|
149
|
+
* ```typescript
|
|
150
|
+
* enum Status { Active = 'active', Inactive = 'inactive' }
|
|
151
|
+
*
|
|
152
|
+
* registry.register(Status, {
|
|
153
|
+
* en: { active: 'Active', inactive: 'Inactive' },
|
|
154
|
+
* es: { active: 'Activo', inactive: 'Inactivo' },
|
|
155
|
+
* }, 'Status');
|
|
156
|
+
* ```
|
|
157
|
+
*
|
|
158
|
+
* @example Branded enum (name inferred)
|
|
159
|
+
* ```typescript
|
|
160
|
+
* const Status = createBrandedEnum('status', { Active: 'active', Inactive: 'inactive' });
|
|
161
|
+
*
|
|
162
|
+
* // Name 'status' is automatically inferred from the branded enum
|
|
163
|
+
* registry.register(Status, {
|
|
164
|
+
* en: { active: 'Active', inactive: 'Inactive' },
|
|
165
|
+
* });
|
|
166
|
+
* ```
|
|
167
|
+
*
|
|
168
|
+
* @example Branded enum with explicit name override
|
|
169
|
+
* ```typescript
|
|
170
|
+
* const Status = createBrandedEnum('status', { Active: 'active' });
|
|
171
|
+
*
|
|
172
|
+
* // Override the inferred name with a custom name
|
|
173
|
+
* registry.register(Status, {
|
|
174
|
+
* en: { active: 'Active' },
|
|
175
|
+
* }, 'UserStatus');
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
register<TEnum extends string | number>(enumObj: Record<string, TEnum> | AnyBrandedEnum | {
|
|
179
|
+
[key: string]: string | number;
|
|
180
|
+
}, translations: Record<string, Record<string, string>>, enumName?: string): Record<string, Record<string, string>>;
|
|
181
|
+
/**
|
|
182
|
+
* Resolves the enum name from a branded enum's component ID or returns default.
|
|
183
|
+
* @param enumObj - The enum object
|
|
184
|
+
* @returns The resolved enum name
|
|
20
185
|
*/
|
|
21
|
-
|
|
186
|
+
private resolveEnumName;
|
|
22
187
|
/**
|
|
23
188
|
* Translates an enum value to a specific language.
|
|
189
|
+
*
|
|
190
|
+
* Supports both traditional enum values and branded enum values. The method
|
|
191
|
+
* performs multiple lookup strategies to find the correct translation:
|
|
192
|
+
*
|
|
193
|
+
* ## Lookup Strategy
|
|
194
|
+
*
|
|
195
|
+
* 1. **Direct value lookup**: Try the string representation of the value
|
|
196
|
+
* 2. **Numeric enum reverse mapping**: For numeric enums, find the string key
|
|
197
|
+
* 3. **Branded enum key lookup**: For branded enums, find the enum key name
|
|
198
|
+
*
|
|
199
|
+
* ## Error Handling
|
|
200
|
+
*
|
|
201
|
+
* The method throws `I18nError` in the following cases:
|
|
202
|
+
* - Enum not registered: `I18nError.invalidConfig`
|
|
203
|
+
* - Language not found: `I18nError.languageNotFound`
|
|
204
|
+
* - Value not found: `I18nError.translationMissing`
|
|
205
|
+
*
|
|
24
206
|
* @template TEnum - The enum value type
|
|
25
|
-
* @param enumObj - The registered enum object
|
|
207
|
+
* @param enumObj - The registered enum object (traditional or branded)
|
|
26
208
|
* @param value - The enum value to translate
|
|
27
209
|
* @param language - The target language code
|
|
28
210
|
* @returns The translated string
|
|
29
211
|
* @throws {I18nError} If the enum, language, or value is not found
|
|
212
|
+
*
|
|
213
|
+
* @example Basic translation
|
|
214
|
+
* ```typescript
|
|
215
|
+
* const Status = createBrandedEnum('status', { Active: 'active' });
|
|
216
|
+
* registry.register(Status, { en: { active: 'Active' }, es: { active: 'Activo' } });
|
|
217
|
+
*
|
|
218
|
+
* registry.translate(Status, Status.Active, 'en'); // 'Active'
|
|
219
|
+
* registry.translate(Status, Status.Active, 'es'); // 'Activo'
|
|
220
|
+
* ```
|
|
221
|
+
*
|
|
222
|
+
* @example Error handling
|
|
223
|
+
* ```typescript
|
|
224
|
+
* try {
|
|
225
|
+
* registry.translate(UnregisteredEnum, 'value', 'en');
|
|
226
|
+
* } catch (error) {
|
|
227
|
+
* // I18nError: No translations found for enum: UnknownEnum
|
|
228
|
+
* }
|
|
229
|
+
* ```
|
|
30
230
|
*/
|
|
31
|
-
translate<TEnum extends string | number>(enumObj: Record<string, TEnum
|
|
231
|
+
translate<TEnum extends string | number>(enumObj: Record<string, TEnum> | AnyBrandedEnum | {
|
|
232
|
+
[key: string]: string | number;
|
|
233
|
+
}, value: TEnum | BrandedEnumValue<AnyBrandedEnum>, language: string): string;
|
|
32
234
|
/**
|
|
33
235
|
* Checks if an enum has been registered.
|
|
236
|
+
*
|
|
237
|
+
* Works with both traditional and branded enums. Uses object reference
|
|
238
|
+
* equality to check registration status.
|
|
239
|
+
*
|
|
34
240
|
* @param enumObj - The enum object to check
|
|
35
|
-
* @returns
|
|
241
|
+
* @returns `true` if the enum is registered, `false` otherwise
|
|
242
|
+
*
|
|
243
|
+
* @example
|
|
244
|
+
* ```typescript
|
|
245
|
+
* const Status = createBrandedEnum('status', { Active: 'active' });
|
|
246
|
+
*
|
|
247
|
+
* registry.has(Status); // false (not registered yet)
|
|
248
|
+
* registry.register(Status, { en: { active: 'Active' } });
|
|
249
|
+
* registry.has(Status); // true
|
|
250
|
+
* ```
|
|
36
251
|
*/
|
|
37
252
|
has(enumObj: object): boolean;
|
|
38
253
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enum-registry.d.ts","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-i18n-lib/src/core/enum-registry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"enum-registry.d.ts","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-i18n-lib/src/core/enum-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EACjB,MAAM,+BAA+B,CAAC;AAOvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,YAAY,CAGhB;IACJ,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,WAAW,CAAC,CAA0D;IAE9E;;;OAGG;gBAED,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM;IAKvE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8DG;IACH,QAAQ,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,EACpC,OAAO,EACH,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GACrB,cAAc,GACd;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;KAAE,EACtC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EACpD,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAOzC;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAQvB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2CG;IACH,SAAS,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,EACrC,OAAO,EACH,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GACrB,cAAc,GACd;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;KAAE,EACtC,KAAK,EAAE,KAAK,GAAG,gBAAgB,CAAC,cAAc,CAAC,EAC/C,QAAQ,EAAE,MAAM,GACf,MAAM;IA4CT;;;;;;;;;;;;;;;;;OAiBG;IACH,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAI7B;;;;OAIG;IACH,OAAO,CAAC,WAAW;CAGpB"}
|
|
@@ -1,14 +1,111 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-return */
|
|
3
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.EnumRegistry = void 0;
|
|
5
2
|
/**
|
|
6
3
|
* Enum translation registry (v2 - no generics)
|
|
4
|
+
*
|
|
5
|
+
* This module provides the `EnumRegistry` class for managing translations of enum
|
|
6
|
+
* values across multiple languages. It supports both traditional TypeScript enums
|
|
7
|
+
* and branded enums from `@digitaldefiance/branded-enum`.
|
|
8
|
+
*
|
|
9
|
+
* ## Overview
|
|
10
|
+
*
|
|
11
|
+
* The `EnumRegistry` is the v2 implementation of enum translation management,
|
|
12
|
+
* designed to work with the `I18nEngine`. It provides:
|
|
13
|
+
*
|
|
14
|
+
* - Registration of enums with their translations
|
|
15
|
+
* - Translation of enum values to localized strings
|
|
16
|
+
* - Automatic name inference for branded enums
|
|
17
|
+
* - Full backward compatibility with traditional enums
|
|
18
|
+
*
|
|
19
|
+
* ## Branded Enum Support
|
|
20
|
+
*
|
|
21
|
+
* When registering branded enums, the registry can automatically infer the enum
|
|
22
|
+
* name from the branded enum's component ID, eliminating the need to provide
|
|
23
|
+
* an explicit name parameter.
|
|
24
|
+
*
|
|
25
|
+
* @example Traditional enum usage
|
|
26
|
+
* ```typescript
|
|
27
|
+
* enum Status { Active = 'active', Inactive = 'inactive' }
|
|
28
|
+
*
|
|
29
|
+
* const registry = new EnumRegistry();
|
|
30
|
+
* registry.register(Status, {
|
|
31
|
+
* en: { active: 'Active', inactive: 'Inactive' },
|
|
32
|
+
* es: { active: 'Activo', inactive: 'Inactivo' },
|
|
33
|
+
* }, 'Status');
|
|
34
|
+
*
|
|
35
|
+
* registry.translate(Status, Status.Active, 'en'); // 'Active'
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @example Branded enum usage (name inferred)
|
|
39
|
+
* ```typescript
|
|
40
|
+
* import { createBrandedEnum } from '@digitaldefiance/branded-enum';
|
|
41
|
+
*
|
|
42
|
+
* const Status = createBrandedEnum('status', { Active: 'active', Inactive: 'inactive' });
|
|
43
|
+
*
|
|
44
|
+
* const registry = new EnumRegistry();
|
|
45
|
+
* registry.register(Status, {
|
|
46
|
+
* en: { active: 'Active', inactive: 'Inactive' },
|
|
47
|
+
* }); // Name 'status' is inferred from branded enum
|
|
48
|
+
*
|
|
49
|
+
* registry.translate(Status, Status.Active, 'en'); // 'Active'
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* @module core/enum-registry
|
|
53
|
+
* @see {@link EnumTranslationRegistry} - Legacy registry with language validation
|
|
54
|
+
* @see {@link I18nEngine} - Main engine that uses this registry
|
|
7
55
|
*/
|
|
56
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
57
|
+
exports.EnumRegistry = void 0;
|
|
58
|
+
const branded_enum_utils_1 = require("../branded-enum-utils");
|
|
8
59
|
const i18n_error_1 = require("../errors/i18n-error");
|
|
9
60
|
/**
|
|
10
61
|
* Registry for managing translations of enum values across multiple languages.
|
|
11
|
-
*
|
|
62
|
+
*
|
|
63
|
+
* Provides a centralized way to register and translate enum values with support
|
|
64
|
+
* for both traditional TypeScript enums and branded enums from
|
|
65
|
+
* `@digitaldefiance/branded-enum`.
|
|
66
|
+
*
|
|
67
|
+
* ## Key Features
|
|
68
|
+
*
|
|
69
|
+
* - **Dual Enum Support**: Works with both traditional and branded enums
|
|
70
|
+
* - **Automatic Name Inference**: Branded enums can have their name inferred from component ID
|
|
71
|
+
* - **Multi-Language**: Supports translations across any number of languages
|
|
72
|
+
* - **Type Safety**: Full TypeScript support with proper type inference
|
|
73
|
+
*
|
|
74
|
+
* ## Registration
|
|
75
|
+
*
|
|
76
|
+
* Use {@link register} to add an enum with its translations. For branded enums,
|
|
77
|
+
* the `enumName` parameter is optional and will be inferred from the component ID.
|
|
78
|
+
*
|
|
79
|
+
* ## Translation
|
|
80
|
+
*
|
|
81
|
+
* Use {@link translate} to get the localized string for an enum value. The method
|
|
82
|
+
* handles both traditional enum values and branded enum values.
|
|
83
|
+
*
|
|
84
|
+
* @example Complete workflow
|
|
85
|
+
* ```typescript
|
|
86
|
+
* import { createBrandedEnum } from '@digitaldefiance/branded-enum';
|
|
87
|
+
*
|
|
88
|
+
* // Create a branded enum
|
|
89
|
+
* const Priority = createBrandedEnum('priority', {
|
|
90
|
+
* High: 'high',
|
|
91
|
+
* Medium: 'medium',
|
|
92
|
+
* Low: 'low',
|
|
93
|
+
* });
|
|
94
|
+
*
|
|
95
|
+
* // Create registry and register enum
|
|
96
|
+
* const registry = new EnumRegistry();
|
|
97
|
+
* registry.register(Priority, {
|
|
98
|
+
* en: { high: 'High Priority', medium: 'Medium Priority', low: 'Low Priority' },
|
|
99
|
+
* es: { high: 'Alta Prioridad', medium: 'Prioridad Media', low: 'Baja Prioridad' },
|
|
100
|
+
* });
|
|
101
|
+
*
|
|
102
|
+
* // Check if registered
|
|
103
|
+
* registry.has(Priority); // true
|
|
104
|
+
*
|
|
105
|
+
* // Translate values
|
|
106
|
+
* registry.translate(Priority, Priority.High, 'en'); // 'High Priority'
|
|
107
|
+
* registry.translate(Priority, Priority.High, 'es'); // 'Alta Prioridad'
|
|
108
|
+
* ```
|
|
12
109
|
*/
|
|
13
110
|
class EnumRegistry {
|
|
14
111
|
translations = new Map();
|
|
@@ -23,23 +120,128 @@ class EnumRegistry {
|
|
|
23
120
|
}
|
|
24
121
|
/**
|
|
25
122
|
* Registers an enum with its translations for all languages.
|
|
123
|
+
*
|
|
124
|
+
* Supports both traditional TypeScript enums and branded enums from
|
|
125
|
+
* `@digitaldefiance/branded-enum`. For branded enums, the `enumName` parameter
|
|
126
|
+
* is optional and will be automatically inferred from the branded enum's
|
|
127
|
+
* component ID.
|
|
128
|
+
*
|
|
129
|
+
* ## Name Resolution
|
|
130
|
+
*
|
|
131
|
+
* The enum name is resolved in the following order:
|
|
132
|
+
* 1. Explicit `enumName` parameter (if provided)
|
|
133
|
+
* 2. Component ID from branded enum (if branded)
|
|
134
|
+
* 3. `'UnknownEnum'` (fallback for traditional enums without name)
|
|
135
|
+
*
|
|
136
|
+
* ## Translation Structure
|
|
137
|
+
*
|
|
138
|
+
* The `translations` object should map language codes to objects that map
|
|
139
|
+
* enum values to their translated strings:
|
|
140
|
+
*
|
|
141
|
+
* ```typescript
|
|
142
|
+
* {
|
|
143
|
+
* 'en': { 'value1': 'Translation 1', 'value2': 'Translation 2' },
|
|
144
|
+
* 'es': { 'value1': 'Traducción 1', 'value2': 'Traducción 2' },
|
|
145
|
+
* }
|
|
146
|
+
* ```
|
|
147
|
+
*
|
|
26
148
|
* @template TEnum - The enum value type (string or number)
|
|
27
|
-
* @param enumObj - The enum object to register
|
|
149
|
+
* @param enumObj - The enum object to register (traditional or branded)
|
|
28
150
|
* @param translations - Mapping of language codes to enum value translations
|
|
29
|
-
* @param enumName - Human-readable name for the enum (
|
|
151
|
+
* @param enumName - Human-readable name for the enum (optional for branded enums)
|
|
152
|
+
* @returns The registered translations object
|
|
153
|
+
*
|
|
154
|
+
* @example Traditional enum (name required)
|
|
155
|
+
* ```typescript
|
|
156
|
+
* enum Status { Active = 'active', Inactive = 'inactive' }
|
|
157
|
+
*
|
|
158
|
+
* registry.register(Status, {
|
|
159
|
+
* en: { active: 'Active', inactive: 'Inactive' },
|
|
160
|
+
* es: { active: 'Activo', inactive: 'Inactivo' },
|
|
161
|
+
* }, 'Status');
|
|
162
|
+
* ```
|
|
163
|
+
*
|
|
164
|
+
* @example Branded enum (name inferred)
|
|
165
|
+
* ```typescript
|
|
166
|
+
* const Status = createBrandedEnum('status', { Active: 'active', Inactive: 'inactive' });
|
|
167
|
+
*
|
|
168
|
+
* // Name 'status' is automatically inferred from the branded enum
|
|
169
|
+
* registry.register(Status, {
|
|
170
|
+
* en: { active: 'Active', inactive: 'Inactive' },
|
|
171
|
+
* });
|
|
172
|
+
* ```
|
|
173
|
+
*
|
|
174
|
+
* @example Branded enum with explicit name override
|
|
175
|
+
* ```typescript
|
|
176
|
+
* const Status = createBrandedEnum('status', { Active: 'active' });
|
|
177
|
+
*
|
|
178
|
+
* // Override the inferred name with a custom name
|
|
179
|
+
* registry.register(Status, {
|
|
180
|
+
* en: { active: 'Active' },
|
|
181
|
+
* }, 'UserStatus');
|
|
182
|
+
* ```
|
|
30
183
|
*/
|
|
31
184
|
register(enumObj, translations, enumName) {
|
|
185
|
+
const resolvedName = enumName ?? this.resolveEnumName(enumObj);
|
|
32
186
|
this.translations.set(enumObj, translations);
|
|
33
|
-
this.enumNames.set(enumObj,
|
|
187
|
+
this.enumNames.set(enumObj, resolvedName);
|
|
188
|
+
return translations;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Resolves the enum name from a branded enum's component ID or returns default.
|
|
192
|
+
* @param enumObj - The enum object
|
|
193
|
+
* @returns The resolved enum name
|
|
194
|
+
*/
|
|
195
|
+
resolveEnumName(enumObj) {
|
|
196
|
+
if ((0, branded_enum_utils_1.isBrandedEnum)(enumObj)) {
|
|
197
|
+
const componentId = (0, branded_enum_utils_1.getBrandedEnumComponentId)(enumObj);
|
|
198
|
+
return componentId ?? 'UnknownEnum';
|
|
199
|
+
}
|
|
200
|
+
return 'UnknownEnum';
|
|
34
201
|
}
|
|
35
202
|
/**
|
|
36
203
|
* Translates an enum value to a specific language.
|
|
204
|
+
*
|
|
205
|
+
* Supports both traditional enum values and branded enum values. The method
|
|
206
|
+
* performs multiple lookup strategies to find the correct translation:
|
|
207
|
+
*
|
|
208
|
+
* ## Lookup Strategy
|
|
209
|
+
*
|
|
210
|
+
* 1. **Direct value lookup**: Try the string representation of the value
|
|
211
|
+
* 2. **Numeric enum reverse mapping**: For numeric enums, find the string key
|
|
212
|
+
* 3. **Branded enum key lookup**: For branded enums, find the enum key name
|
|
213
|
+
*
|
|
214
|
+
* ## Error Handling
|
|
215
|
+
*
|
|
216
|
+
* The method throws `I18nError` in the following cases:
|
|
217
|
+
* - Enum not registered: `I18nError.invalidConfig`
|
|
218
|
+
* - Language not found: `I18nError.languageNotFound`
|
|
219
|
+
* - Value not found: `I18nError.translationMissing`
|
|
220
|
+
*
|
|
37
221
|
* @template TEnum - The enum value type
|
|
38
|
-
* @param enumObj - The registered enum object
|
|
222
|
+
* @param enumObj - The registered enum object (traditional or branded)
|
|
39
223
|
* @param value - The enum value to translate
|
|
40
224
|
* @param language - The target language code
|
|
41
225
|
* @returns The translated string
|
|
42
226
|
* @throws {I18nError} If the enum, language, or value is not found
|
|
227
|
+
*
|
|
228
|
+
* @example Basic translation
|
|
229
|
+
* ```typescript
|
|
230
|
+
* const Status = createBrandedEnum('status', { Active: 'active' });
|
|
231
|
+
* registry.register(Status, { en: { active: 'Active' }, es: { active: 'Activo' } });
|
|
232
|
+
*
|
|
233
|
+
* registry.translate(Status, Status.Active, 'en'); // 'Active'
|
|
234
|
+
* registry.translate(Status, Status.Active, 'es'); // 'Activo'
|
|
235
|
+
* ```
|
|
236
|
+
*
|
|
237
|
+
* @example Error handling
|
|
238
|
+
* ```typescript
|
|
239
|
+
* try {
|
|
240
|
+
* registry.translate(UnregisteredEnum, 'value', 'en');
|
|
241
|
+
* } catch (error) {
|
|
242
|
+
* // I18nError: No translations found for enum: UnknownEnum
|
|
243
|
+
* }
|
|
244
|
+
* ```
|
|
43
245
|
*/
|
|
44
246
|
translate(enumObj, value, language) {
|
|
45
247
|
const translations = this.translations.get(enumObj);
|
|
@@ -60,6 +262,13 @@ class EnumRegistry {
|
|
|
60
262
|
result = langTranslations[stringKey];
|
|
61
263
|
}
|
|
62
264
|
}
|
|
265
|
+
// For branded enums, try looking up by the enum key name
|
|
266
|
+
if (!result && (0, branded_enum_utils_1.isBrandedEnum)(enumObj)) {
|
|
267
|
+
const enumKey = Object.keys(enumObj).find((key) => enumObj[key] === value);
|
|
268
|
+
if (enumKey) {
|
|
269
|
+
result = langTranslations[enumKey];
|
|
270
|
+
}
|
|
271
|
+
}
|
|
63
272
|
if (!result) {
|
|
64
273
|
throw i18n_error_1.I18nError.translationMissing('enum', String(value), language);
|
|
65
274
|
}
|
|
@@ -67,8 +276,21 @@ class EnumRegistry {
|
|
|
67
276
|
}
|
|
68
277
|
/**
|
|
69
278
|
* Checks if an enum has been registered.
|
|
279
|
+
*
|
|
280
|
+
* Works with both traditional and branded enums. Uses object reference
|
|
281
|
+
* equality to check registration status.
|
|
282
|
+
*
|
|
70
283
|
* @param enumObj - The enum object to check
|
|
71
|
-
* @returns
|
|
284
|
+
* @returns `true` if the enum is registered, `false` otherwise
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* ```typescript
|
|
288
|
+
* const Status = createBrandedEnum('status', { Active: 'active' });
|
|
289
|
+
*
|
|
290
|
+
* registry.has(Status); // false (not registered yet)
|
|
291
|
+
* registry.register(Status, { en: { active: 'Active' } });
|
|
292
|
+
* registry.has(Status); // true
|
|
293
|
+
* ```
|
|
72
294
|
*/
|
|
73
295
|
has(enumObj) {
|
|
74
296
|
return this.translations.has(enumObj);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enum-registry.js","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-i18n-lib/src/core/enum-registry.ts"],"names":[],"mappings":";AAAA,
|
|
1
|
+
{"version":3,"file":"enum-registry.js","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-i18n-lib/src/core/enum-registry.ts"],"names":[],"mappings":"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"}
|