@digitaldefiance/i18n-lib 1.3.0 → 1.3.2

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 CHANGED
@@ -234,6 +234,17 @@ const displayNames = registry.getLanguageDisplayNames();
234
234
  // Get language codes for Mongoose enum
235
235
  const languageCodes = registry.getLanguageIds(); // ['en-US', 'fr', 'es']
236
236
  const isoCodes = registry.getLanguageCodes(); // ['en-US', 'fr', 'es']
237
+
238
+ // Get matching language code with fallback logic
239
+ const matchedCode = registry.getMatchingLanguageCode(
240
+ 'de-DE', // Requested code (not registered)
241
+ 'fr', // User default (registered)
242
+ // Falls back to site default if neither match
243
+ );
244
+ // Returns: 'fr' (user default)
245
+
246
+ const defaultCode = registry.getMatchingLanguageCode();
247
+ // Returns: 'en-US' (site default)
237
248
  ```
238
249
 
239
250
  **Key Features:**
@@ -243,6 +254,53 @@ const isoCodes = registry.getLanguageCodes(); // ['en-US', 'fr', 'es']
243
254
  - Default language management
244
255
  - Duplicate detection and validation
245
256
  - Extract language codes for schema definitions
257
+ - Intelligent language code matching with fallback chain
258
+
259
+ ### Language Code Resolution
260
+
261
+ The Language Registry provides intelligent language code matching with a fallback chain for handling user preferences and browser language headers:
262
+
263
+ ```typescript
264
+ import { LanguageRegistry } from '@digitaldefiance/i18n-lib';
265
+
266
+ const registry = new LanguageRegistry<'en-US' | 'fr' | 'es'>();
267
+ registry.registerLanguages([
268
+ createLanguageDefinition('en-US', 'English (US)', 'en-US', true),
269
+ createLanguageDefinition('fr', 'Français', 'fr'),
270
+ createLanguageDefinition('es', 'Español', 'es'),
271
+ ]);
272
+
273
+ // Fallback chain: requested → user default → site default
274
+ const languageCode = registry.getMatchingLanguageCode(
275
+ req.headers['accept-language'], // 1. Try requested code first
276
+ req.user?.siteLanguage, // 2. Fall back to user default
277
+ // 3. Falls back to site default if neither match
278
+ );
279
+
280
+ // Example scenarios:
281
+ registry.getMatchingLanguageCode('fr', 'es'); // Returns: 'fr' (requested exists)
282
+ registry.getMatchingLanguageCode('de', 'es'); // Returns: 'es' (user default exists)
283
+ registry.getMatchingLanguageCode('de', 'it'); // Returns: 'en-US' (site default)
284
+ registry.getMatchingLanguageCode(); // Returns: 'en-US' (site default)
285
+ registry.getMatchingLanguageCode('', ''); // Returns: 'en-US' (empty strings ignored)
286
+ ```
287
+
288
+ **Use Cases:**
289
+ - HTTP Accept-Language header processing
290
+ - User preference resolution
291
+ - Browser language detection with fallback
292
+ - Multi-tenant applications with per-user defaults
293
+
294
+ **Error Handling:**
295
+ ```typescript
296
+ try {
297
+ const emptyRegistry = new LanguageRegistry();
298
+ emptyRegistry.getMatchingLanguageCode('en-US');
299
+ } catch (error) {
300
+ // Throws RegistryError if no default language configured
301
+ console.error('No default language configured');
302
+ }
303
+ ```
246
304
 
247
305
  ### Enum Translation Registry
248
306
 
@@ -1391,6 +1449,7 @@ The core component provides 40+ system strings organized by category:
1391
1449
  - `hasLanguage(language)` - Check if language exists
1392
1450
  - `setLanguage(language)` - Set current language
1393
1451
  - `getLanguageByCode(code)` - Get language by ISO code
1452
+ - `getMatchingLanguageCode(requestedCode?, userDefaultCode?)` - Get matching language code with fallback logic
1394
1453
 
1395
1454
  **Validation**
1396
1455
 
@@ -2215,16 +2274,20 @@ For issues, questions, or contributions:
2215
2274
 
2216
2275
  ## ChangeLog
2217
2276
 
2218
- ### Version 1.3.0
2277
+ ### Version 1.3.2
2278
+
2279
+ - Add functionality to Language Registry for getMatchingLanguageCode
2280
+
2281
+ ### Version 1.3.1
2219
2282
 
2220
- - **Changed**: `CoreLanguageCode` now derived from `LanguageCodes` for type safety
2221
- - Type: `typeof LanguageCodes[keyof typeof LanguageCodes]`
2222
- - Maintains compile-time type safety while using registry as single source
2223
- - No breaking changes - existing code continues to work
2283
+ - **Changed**: `CoreLanguageCode` is now `string` - Language Registry is single source of truth
2284
+ - Use `engine.getLanguageRegistry().getLanguageIds()` for runtime validation
2285
+ - Use `getCoreLanguageCodes()` for static arrays (Mongoose schemas, etc.)
2286
+ - Runtime validation via registry, not compile-time types
2224
2287
  - **Added**: `getCoreLanguageCodes()` - Get core language codes as runtime array
2225
2288
  - **Added**: `getCoreLanguageDefinitions()` - Get core language definitions
2226
- - **Improved**: Language Registry is now the single source of truth
2227
- - **Benefit**: Type safety + runtime flexibility without duplication
2289
+ - **Philosophy**: Registry-based validation over hardcoded types
2290
+ - **Benefit**: Maximum flexibility - add languages without code changes
2228
2291
 
2229
2292
  ### Version 1.2.5
2230
2293
 
@@ -8,10 +8,16 @@ import { LanguageCodes } from './language-codes';
8
8
  import { LanguageDefinition } from './language-definition';
9
9
  import { PluginI18nEngine } from './plugin-i18n-engine';
10
10
  /**
11
- * Core language code type - derived from LanguageCodes for type safety
12
- * Use this for type parameters when you want to restrict to core languages only
11
+ * Core language code type - union of supported language codes
12
+ * Provides compile-time type safety for core languages
13
+ * For custom languages, extend this type or use string
13
14
  */
14
15
  export type CoreLanguageCode = typeof LanguageCodes[keyof typeof LanguageCodes];
16
+ /**
17
+ * Flexible language code type - use when you want runtime-only validation
18
+ * Alias for string to indicate it's a language code
19
+ */
20
+ export type FlexibleLanguageCode = string;
15
21
  /**
16
22
  * Create default language definitions
17
23
  */
@@ -24,11 +30,11 @@ export declare const CoreComponentDefinition: ComponentDefinition<CoreStringKey>
24
30
  /**
25
31
  * Core component strings for all default languages
26
32
  */
27
- export declare function createCoreComponentStrings(): import("./strict-types").CompleteComponentLanguageStrings<CoreStringKey, CoreLanguageCode>;
33
+ export declare function createCoreComponentStrings(): import("./strict-types").CompleteComponentLanguageStrings<CoreStringKey, string>;
28
34
  /**
29
35
  * Create core component registration
30
36
  */
31
- export declare function createCoreComponentRegistration(): ComponentRegistration<CoreStringKey, CoreLanguageCode>;
37
+ export declare function createCoreComponentRegistration(): ComponentRegistration<CoreStringKey, string>;
32
38
  /**
33
39
  * Get core language codes as array (for Mongoose enums, etc.)
34
40
  */
@@ -39,17 +45,18 @@ export declare function getCoreLanguageCodes(): string[];
39
45
  export declare function getCoreLanguageDefinitions(): LanguageDefinition[];
40
46
  /**
41
47
  * Create a pre-configured I18n engine with core components
48
+ * Returns engine with string type - use registry for language validation
42
49
  */
43
- export declare function createCoreI18nEngine(instanceKey?: string): PluginI18nEngine<CoreLanguageCode>;
50
+ export declare function createCoreI18nEngine(instanceKey?: string): PluginI18nEngine<string>;
44
51
  /**
45
52
  * Type alias for easier usage
46
53
  */
47
- export type CoreI18nEngine = PluginI18nEngine<CoreLanguageCode>;
54
+ export type CoreI18nEngine = PluginI18nEngine<string>;
48
55
  /**
49
56
  * Helper function to get core translation
50
57
  */
51
- export declare function getCoreTranslation(stringKey: CoreStringKey, variables?: Record<string, string | number>, language?: CoreLanguageCode, instanceKey?: string): string;
58
+ export declare function getCoreTranslation(stringKey: CoreStringKey, variables?: Record<string, string | number>, language?: string, instanceKey?: string): string;
52
59
  /**
53
60
  * Helper function to safely get core translation with fallback
54
61
  */
55
- export declare function safeCoreTranslation(stringKey: CoreStringKey, variables?: Record<string, string | number>, language?: CoreLanguageCode, instanceKey?: string): string;
62
+ export declare function safeCoreTranslation(stringKey: CoreStringKey, variables?: Record<string, string | number>, language?: string, instanceKey?: string): string;
package/dist/core-i18n.js CHANGED
@@ -449,6 +449,7 @@ function getCoreLanguageDefinitions() {
449
449
  }
450
450
  /**
451
451
  * Create a pre-configured I18n engine with core components
452
+ * Returns engine with string type - use registry for language validation
452
453
  */
453
454
  function createCoreI18nEngine(instanceKey = DefaultInstanceKey) {
454
455
  const languages = createDefaultLanguages();
@@ -54,6 +54,13 @@ export declare class LanguageRegistry<TLanguages extends string> {
54
54
  * Get the default language ID
55
55
  */
56
56
  getDefaultLanguageId(): TLanguages | null;
57
+ /**
58
+ * Get matching language code with fallback logic:
59
+ * 1. Try requested code
60
+ * 2. Fall back to user default
61
+ * 3. Fall back to site default
62
+ */
63
+ getMatchingLanguageCode(requestedCode?: string, userDefaultCode?: string): string;
57
64
  /**
58
65
  * Set the default language
59
66
  */
@@ -105,6 +105,28 @@ class LanguageRegistry {
105
105
  getDefaultLanguageId() {
106
106
  return this.defaultLanguageId;
107
107
  }
108
+ /**
109
+ * Get matching language code with fallback logic:
110
+ * 1. Try requested code
111
+ * 2. Fall back to user default
112
+ * 3. Fall back to site default
113
+ */
114
+ getMatchingLanguageCode(requestedCode, userDefaultCode) {
115
+ // Try requested code first
116
+ if (requestedCode && this.hasLanguageCode(requestedCode)) {
117
+ return requestedCode;
118
+ }
119
+ // Try user default
120
+ if (userDefaultCode && this.hasLanguageCode(userDefaultCode)) {
121
+ return userDefaultCode;
122
+ }
123
+ // Fall back to site default
124
+ const defaultLanguage = this.getDefaultLanguage();
125
+ if (!defaultLanguage) {
126
+ throw registry_error_1.RegistryError.createSimple(registry_error_type_1.RegistryErrorType.LanguageNotFound, 'No default language configured', {});
127
+ }
128
+ return defaultLanguage.code;
129
+ }
108
130
  /**
109
131
  * Set the default language
110
132
  */
@@ -1,4 +1,3 @@
1
- import { CoreLanguageCode } from './core-i18n';
2
1
  import { RegistryErrorType } from './registry-error-type';
3
2
  import { TranslationEngine } from './typed-error';
4
3
  /**
@@ -11,7 +10,7 @@ export declare class RegistryError extends Error {
11
10
  /**
12
11
  * Create a registry error with translation support
13
12
  */
14
- static createWithEngine(engine: TranslationEngine, type: RegistryErrorType, variables?: Record<string, string | number>, language?: CoreLanguageCode, metadata?: Record<string, any>): RegistryError;
13
+ static createWithEngine(engine: TranslationEngine, type: RegistryErrorType, variables?: Record<string, string | number>, language?: string, metadata?: Record<string, any>): RegistryError;
15
14
  /**
16
15
  * Create a simple RegistryError without engine dependency
17
16
  */
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RegistryError = void 0;
4
+ // CoreLanguageCode is deprecated - using string
4
5
  const core_string_key_1 = require("./core-string-key");
5
6
  const registry_error_type_1 = require("./registry-error-type");
6
7
  const typed_error_1 = require("./typed-error");
@@ -1,6 +1,5 @@
1
1
  import { Language, StringKey } from './default-config';
2
2
  import { I18nEngine } from './i18n-engine';
3
- import { CoreLanguageCode } from './core-i18n';
4
3
  import { CoreStringKey } from './core-string-key';
5
4
  import { PluginI18nEngine } from './plugin-i18n-engine';
6
5
  import { TranslationEngine } from './translation-engine';
@@ -52,9 +51,9 @@ export declare abstract class PluginTypedError<TEnum extends Record<string, stri
52
51
  export declare abstract class CoreTypedError<TEnum extends Record<string, string>> extends Error {
53
52
  readonly type: TEnum[keyof TEnum];
54
53
  readonly reasonMap: CompleteReasonMap<TEnum, CoreStringKey>;
55
- readonly language?: CoreLanguageCode | undefined;
54
+ readonly language?: string | undefined;
56
55
  readonly otherVars?: Record<string, string | number> | undefined;
57
- constructor(engine: PluginI18nEngine<CoreLanguageCode>, type: TEnum[keyof TEnum], reasonMap: CompleteReasonMap<TEnum, CoreStringKey>, language?: CoreLanguageCode | undefined, otherVars?: Record<string, string | number> | undefined);
56
+ constructor(engine: PluginI18nEngine<string>, type: TEnum[keyof TEnum], reasonMap: CompleteReasonMap<TEnum, CoreStringKey>, language?: string | undefined, otherVars?: Record<string, string | number> | undefined);
58
57
  }
59
58
  /**
60
59
  * Helper function to create a plugin-based TypedError with automatic engine detection
@@ -63,7 +62,7 @@ export declare function createPluginTypedError<TEnum extends Record<string, stri
63
62
  /**
64
63
  * Helper function to create a core system TypedError with automatic engine detection
65
64
  */
66
- export declare function createCoreTypedError<TEnum extends Record<string, string>>(type: TEnum[keyof TEnum], reasonMap: CompleteReasonMap<TEnum, CoreStringKey>, otherVars?: Record<string, string | number>, language?: CoreLanguageCode, instanceKey?: string): Error;
65
+ export declare function createCoreTypedError<TEnum extends Record<string, string>>(type: TEnum[keyof TEnum], reasonMap: CompleteReasonMap<TEnum, CoreStringKey>, otherVars?: Record<string, string | number>, language?: string, instanceKey?: string): Error;
67
66
  /**
68
67
  * Create a simple error with translation support (generalized pattern from RegistryError)
69
68
  */
@@ -6,6 +6,8 @@ exports.createCoreTypedError = createCoreTypedError;
6
6
  exports.createTranslatedError = createTranslatedError;
7
7
  // Legacy imports (for backward compatibility)
8
8
  const default_config_1 = require("./default-config");
9
+ // New plugin architecture imports
10
+ // CoreLanguageCode is deprecated - using string for flexibility
9
11
  const core_string_key_1 = require("./core-string-key");
10
12
  const plugin_i18n_engine_1 = require("./plugin-i18n-engine");
11
13
  /**
@@ -187,7 +189,7 @@ class DatabaseError extends CoreTypedError<typeof DatabaseErrorType> {
187
189
  }
188
190
 
189
191
  // Usage:
190
- // const engine = PluginI18nEngine.getInstance<CoreLanguageCode>();
192
+ // const engine = PluginI18nEngine.getInstance<string>();
191
193
  // throw new DatabaseError(engine, DatabaseErrorType.ConnectionFailed);
192
194
  */
193
195
  // Example 2: Custom component error with custom strings
@@ -210,19 +212,19 @@ const userErrorReasonMap: CompleteReasonMap<typeof UserErrorType, UserErrorStrin
210
212
  [UserErrorType.AccountLocked]: UserErrorStringKey.AccountLockedMessage
211
213
  };
212
214
 
213
- class UserError extends PluginTypedError<typeof UserErrorType, UserErrorStringKey, CoreLanguageCode> {
215
+ class UserError extends PluginTypedError<typeof UserErrorType, UserErrorStringKey, string> {
214
216
  constructor(
215
- engine: PluginI18nEngine<CoreLanguageCode>,
217
+ engine: PluginI18nEngine<string>,
216
218
  type: UserErrorType,
217
219
  otherVars?: Record<string, string | number>,
218
- language?: CoreLanguageCode
220
+ language?: string
219
221
  ) {
220
222
  super(engine, 'user-system', type, userErrorReasonMap, language, otherVars);
221
223
  }
222
224
  }
223
225
 
224
226
  // Usage:
225
- // const engine = PluginI18nEngine.getInstance<CoreLanguageCode>();
227
+ // const engine = PluginI18nEngine.getInstance<string>();
226
228
  // throw new UserError(engine, UserErrorType.UserNotFound, { username: 'john_doe' });
227
229
  */
228
230
  // Example 3: Using helper functions for simpler error creation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digitaldefiance/i18n-lib",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "description": "Generic i18n library with enum translation support",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",