@digitaldefiance/i18n-lib 1.2.5 → 1.3.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 CHANGED
@@ -1,49 +1,127 @@
1
1
  # @digitaldefiance/i18n-lib
2
2
 
3
- A comprehensive TypeScript internationalization library with plugin-based component registration, enum translation support, template processing, and context management.
3
+ A comprehensive, production-ready TypeScript internationalization (i18n) library featuring plugin-based architecture, compile-time type safety, component registration, enum translation, template processing, and advanced context management. Built for enterprise applications requiring robust multilingual support with zero-knowledge security patterns.
4
4
 
5
- ## 🚀 New Plugin-Based Architecture
5
+ ## 🚀 Plugin-Based Architecture
6
6
 
7
- **Version 1.1.0** introduces a revolutionary plugin-based architecture with component registration and rigid compile-time type safety:
7
+ **Version 1.1.0+** introduces a revolutionary plugin-based architecture with component registration and rigid compile-time type safety:
8
8
 
9
- - **Component Registration System**: Register translation components with their own string keys
10
- - **Language Plugin Support**: Add new languages dynamically with validation
11
- - **Compile-Time Type Safety**: TypeScript ensures all strings are complete for all languages
12
- - **Automatic Validation**: Comprehensive validation with detailed error reporting
13
- - **Fallback System**: Intelligent fallback to default languages with missing translation detection
14
- - **Multi-Instance Support**: Named instances for different application contexts
9
+ - **Component Registration System**: Register translation components with their own isolated string keys
10
+ - **Language Plugin Support**: Add new languages dynamically with automatic validation
11
+ - **Compile-Time Type Safety**: TypeScript ensures all strings are complete for all languages at build time
12
+ - **Automatic Validation**: Comprehensive validation with detailed error reporting and missing key detection
13
+ - **Intelligent Fallback System**: Graceful degradation to default languages with missing translation tracking
14
+ - **Multi-Instance Support**: Named instances for different application contexts (admin, user, API, etc.)
15
+ - **Global Context Management**: Centralized context with per-instance language, currency, and timezone settings
16
+ - **Translation Adapters**: Generic adapter utilities for seamless integration with error classes and other components
15
17
 
16
18
  ## Features
17
19
 
18
- ### Core Features
20
+ ### Core Translation Features
19
21
 
20
- - **Type-Safe Translations**: Full TypeScript support with generic types for strings and languages
21
- - **Plugin Architecture**: Register components and languages dynamically with full type safety
22
+ - **Type-Safe Translations**: Full TypeScript support with generic types for strings, languages, and contexts
23
+ - **Plugin Architecture**: Register components and languages dynamically with full compile-time type safety
22
24
  - **Configuration Validation**: Automatic validation ensures all languages have complete string collections
23
- - **Localized Error Messages**: Error messages can be translated using the engine's own translation system
24
- - **Enum Translation Registry**: Translate enum values with complete type safety
25
- - **Template Processing**: Advanced template system with `{{EnumName.EnumKey}}` patterns and variable replacement
26
- - **Context Management**: Admin vs user translation contexts with automatic language switching
27
- - **Singleton Pattern**: Efficient instance management with named instances
28
- - **Currency Formatting**: Built-in currency formatting utilities with locale support
29
- - **Fallback System**: Graceful degradation when translations are missing
25
+ - **Localized Error Messages**: Error messages translated using the engine's own translation system
26
+ - **Enum Translation Registry**: Translate enum values with complete type safety and automatic validation
27
+ - **Advanced Template Processing**:
28
+ - Component-based patterns: `{{componentId.stringKey}}`
29
+ - Legacy enum patterns: `{{EnumName.EnumKey}}`
30
+ - Variable replacement: `{variableName}`
31
+ - Nested template support with multiple variable objects
32
+ - **Context Management**:
33
+ - Admin vs user translation contexts
34
+ - Automatic language switching based on context
35
+ - Per-instance context isolation
36
+ - Global context with named instance support
37
+ - **Currency Formatting**: Built-in currency formatting utilities with locale-aware symbol positioning
38
+ - **Timezone Support**: Validated timezone handling with moment-timezone integration
39
+ - **Intelligent Fallback System**:
40
+ - Graceful degradation when translations are missing
41
+ - Fallback to default language with tracking
42
+ - Placeholder generation for missing keys: `[componentId.stringKey]`
30
43
  - **Extensible Configuration**: Module augmentation support for layered library extension
31
- - **Backward Compatibility**: Legacy I18nEngine remains fully supported
32
-
33
- ### New Plugin Features
34
-
35
- - **Component Registry**: Manage translation components with validation
36
- - **Language Registry**: Dynamic language registration with metadata
37
- - **Type-Safe Registration**: Compile-time guarantees for translation completeness
38
- - **Validation Reporting**: Detailed missing translation reports
39
- - **Plugin System**: Modular component architecture
44
+ - **Backward Compatibility**: Legacy I18nEngine remains fully supported for migration paths
45
+
46
+ ### Plugin System Features
47
+
48
+ - **Component Registry**:
49
+ - Manage translation components with automatic validation
50
+ - Component isolation with independent string key namespaces
51
+ - Dynamic component registration and updates
52
+ - Comprehensive validation reporting
53
+ - **Language Registry**:
54
+ - Dynamic language registration with metadata (name, code, default flag)
55
+ - BCP 47 language code support
56
+ - Language lookup by ID or ISO code
57
+ - Display name mapping for UI rendering
58
+ - **Type-Safe Registration**:
59
+ - Compile-time guarantees for translation completeness
60
+ - Strict type helpers for enforcing complete translations
61
+ - Partial registration support with fallback generation
62
+ - **Validation System**:
63
+ - Detailed missing translation reports
64
+ - Per-component validation results
65
+ - Global validation across all components
66
+ - Configurable validation strictness
67
+ - **Instance Management**:
68
+ - Named instances for different application contexts
69
+ - Singleton pattern with automatic default instance
70
+ - Instance cleanup utilities for testing
71
+ - Per-instance context and configuration
72
+
73
+ ### Advanced Features
74
+
75
+ - **Translatable Errors**:
76
+ - Generic translatable error class for any component
77
+ - Automatic translation with fallback support
78
+ - Error retranslation for dynamic language switching
79
+ - Metadata attachment for debugging
80
+ - **Translation Adapters**:
81
+ - Generic adapter creation for PluginI18nEngine
82
+ - Seamless integration with error classes
83
+ - Zero-overhead delegation pattern
84
+ - **Context Change Monitoring**:
85
+ - Reactive context proxies with change listeners
86
+ - Property-level change notifications
87
+ - Error-safe listener execution
88
+ - **Strict Type Enforcement**:
89
+ - Compile-time completeness checking
90
+ - Helper functions for strict translation maps
91
+ - Type utilities for extracting string keys and languages
92
+ - **Testing Utilities**:
93
+ - Instance cleanup methods
94
+ - Component registry reset
95
+ - Global engine reset for test isolation
96
+
97
+ ## Table of Contents
98
+
99
+ - [Installation](#installation)
100
+ - [Quick Start](#quick-start)
101
+ - [Plugin-Based Architecture](#plugin-based-architecture)
102
+ - [Core Components](#core-components)
103
+ - [Advanced Features](#advanced-features)
104
+ - [API Reference](#api-reference)
105
+ - [Type Definitions](#type-definitions)
106
+ - [Testing](#testing)
107
+ - [Best Practices](#best-practices)
108
+ - [Migration Guide](#migration-guide)
109
+ - [Changelog](#changelog)
40
110
 
41
111
  ## Installation
42
112
 
43
113
  ```bash
44
114
  npm install @digitaldefiance/i18n-lib
115
+ # or
116
+ yarn add @digitaldefiance/i18n-lib
45
117
  ```
46
118
 
119
+ ### Dependencies
120
+
121
+ - `currency-codes`: Currency code validation
122
+ - `moment-timezone`: Timezone validation and handling
123
+ - TypeScript 4.5+ recommended for full type safety
124
+
47
125
  ## Quick Start
48
126
 
49
127
  ```typescript
@@ -99,6 +177,174 @@ const spanishGreeting = i18n.translate(MyStrings.UserGreetingTemplate, { name: '
99
177
  // "¡Hola, Juan!"
100
178
  ```
101
179
 
180
+ ## Core Components
181
+
182
+ The library is built around several key components that work together to provide comprehensive i18n support:
183
+
184
+ ### Component Registry
185
+
186
+ Manages translation components with automatic validation:
187
+
188
+ ```typescript
189
+ import { ComponentRegistry, ComponentDefinition, ComponentRegistration } from '@digitaldefiance/i18n-lib';
190
+
191
+ // Define component
192
+ const myComponent: ComponentDefinition<MyStringKeys> = {
193
+ id: 'my-component',
194
+ name: 'My Component',
195
+ stringKeys: Object.values(MyStringKeys)
196
+ };
197
+
198
+ // Register with translations
199
+ const registration: ComponentRegistration<MyStringKeys, Languages> = {
200
+ component: myComponent,
201
+ strings: {
202
+ 'en-US': { /* translations */ },
203
+ 'fr': { /* translations */ }
204
+ }
205
+ };
206
+ ```
207
+
208
+ **Key Features:**
209
+ - Component isolation with independent string key namespaces
210
+ - Automatic validation of translation completeness
211
+ - Dynamic component registration and updates
212
+ - Fallback generation for missing translations
213
+ - Detailed validation reporting
214
+
215
+ ### Language Registry
216
+
217
+ Manages supported languages with metadata:
218
+
219
+ ```typescript
220
+ import { LanguageRegistry, LanguageDefinition, createLanguageDefinition } from '@digitaldefiance/i18n-lib';
221
+
222
+ const registry = new LanguageRegistry<'en-US' | 'fr' | 'es'>();
223
+
224
+ // Register languages
225
+ registry.registerLanguage(createLanguageDefinition('en-US', 'English (US)', 'en-US', true));
226
+ registry.registerLanguage(createLanguageDefinition('fr', 'Français', 'fr'));
227
+
228
+ // Query languages
229
+ const language = registry.getLanguage('en-US');
230
+ const byCode = registry.getLanguageByCode('fr');
231
+ const allLanguages = registry.getAllLanguages();
232
+ const displayNames = registry.getLanguageDisplayNames();
233
+
234
+ // Get language codes for Mongoose enum
235
+ const languageCodes = registry.getLanguageIds(); // ['en-US', 'fr', 'es']
236
+ const isoCodes = registry.getLanguageCodes(); // ['en-US', 'fr', 'es']
237
+ ```
238
+
239
+ **Key Features:**
240
+ - BCP 47 language code support
241
+ - Language lookup by ID or ISO code
242
+ - Display name mapping for UI rendering
243
+ - Default language management
244
+ - Duplicate detection and validation
245
+ - Extract language codes for schema definitions
246
+
247
+ ### Enum Translation Registry
248
+
249
+ Translates enum values with type safety:
250
+
251
+ ```typescript
252
+ import { EnumTranslationRegistry } from '@digitaldefiance/i18n-lib';
253
+
254
+ enum Status {
255
+ Active = 'active',
256
+ Inactive = 'inactive'
257
+ }
258
+
259
+ const enumRegistry = new EnumTranslationRegistry<string, 'en-US' | 'fr'>(
260
+ ['en-US', 'fr'],
261
+ (key, vars) => engine.translate('core', key, vars)
262
+ );
263
+
264
+ enumRegistry.register(Status, {
265
+ 'en-US': {
266
+ [Status.Active]: 'Active',
267
+ [Status.Inactive]: 'Inactive'
268
+ },
269
+ 'fr': {
270
+ [Status.Active]: 'Actif',
271
+ [Status.Inactive]: 'Inactif'
272
+ }
273
+ }, 'Status');
274
+
275
+ const translated = enumRegistry.translate(Status, Status.Active, 'fr'); // 'Actif'
276
+ ```
277
+
278
+ **Key Features:**
279
+ - Complete enum coverage validation
280
+ - Numeric and string enum support
281
+ - Automatic key resolution for numeric enums
282
+ - Localized error messages
283
+
284
+ ### Global Active Context
285
+
286
+ Centralized context management for all engine instances:
287
+
288
+ ```typescript
289
+ import { GlobalActiveContext, IActiveContext } from '@digitaldefiance/i18n-lib';
290
+
291
+ const globalContext = GlobalActiveContext.getInstance<'en-US' | 'fr', IActiveContext<'en-US' | 'fr'>>();
292
+
293
+ // Create context for an instance
294
+ globalContext.createContext('en-US', 'en-US', 'my-app');
295
+
296
+ // Update context properties
297
+ globalContext.setUserLanguage('fr', 'my-app');
298
+ globalContext.setAdminLanguage('en-US', 'my-app');
299
+ globalContext.setCurrencyCode(new CurrencyCode('EUR'), 'my-app');
300
+ globalContext.setUserTimezone(new Timezone('Europe/Paris'), 'my-app');
301
+
302
+ // Get context
303
+ const context = globalContext.getContext('my-app');
304
+ console.log(context.language); // 'fr'
305
+ console.log(context.adminLanguage); // 'en-US'
306
+ ```
307
+
308
+ **Key Features:**
309
+ - Per-instance context isolation
310
+ - User and admin language separation
311
+ - Currency code management
312
+ - Timezone handling
313
+ - Context space management (admin, user, system, api)
314
+
315
+ ### Context Manager
316
+
317
+ Reactive context with change listeners:
318
+
319
+ ```typescript
320
+ import { ContextManager } from '@digitaldefiance/i18n-lib';
321
+
322
+ interface AppContext {
323
+ language: string;
324
+ theme: string;
325
+ }
326
+
327
+ const manager = new ContextManager<AppContext>();
328
+
329
+ // Add change listener
330
+ manager.addListener((property, oldValue, newValue) => {
331
+ console.log(`${property} changed from ${oldValue} to ${newValue}`);
332
+ });
333
+
334
+ // Create reactive proxy
335
+ const context = { language: 'en', theme: 'dark' };
336
+ const reactiveContext = manager.createProxy(context);
337
+
338
+ // Changes trigger listeners
339
+ reactiveContext.language = 'fr'; // Logs: "language changed from en to fr"
340
+ ```
341
+
342
+ **Key Features:**
343
+ - Property-level change notifications
344
+ - Multiple listener support
345
+ - Error-safe listener execution
346
+ - Proxy-based reactivity
347
+
102
348
  ## 🆕 Plugin-Based Architecture (New in v1.1.0)
103
349
 
104
350
  The new plugin-based architecture provides a component registration system with rigid compile-time type safety.
@@ -108,9 +354,10 @@ The new plugin-based architecture provides a component registration system with
108
354
  ```typescript
109
355
  import {
110
356
  createCoreI18nEngine,
111
- CoreStringKey,
357
+ CoreStringKey,
112
358
  CoreLanguageCode,
113
359
  LanguageCodes,
360
+ getCoreLanguageCodes,
114
361
  ComponentDefinition,
115
362
  ComponentRegistration
116
363
  } from '@digitaldefiance/i18n-lib';
@@ -118,8 +365,15 @@ import {
118
365
  // Create engine with default languages and core strings
119
366
  const i18n = createCoreI18nEngine('myapp');
120
367
 
121
- // Use core translations
122
- const welcomeMessage = i18n.translate('core', CoreStringKey.System_Welcome);
368
+ // Type-safe language parameter
369
+ const lang: CoreLanguageCode = LanguageCodes.FR; // Type-checked!
370
+
371
+ // Get supported language codes from registry (runtime)
372
+ const supportedLanguages = i18n.getLanguageRegistry().getLanguageIds();
373
+ // ['en-US', 'en-GB', 'fr', 'es', 'de', 'zh-CN', 'ja', 'uk']
374
+
375
+ // Use core translations with type safety
376
+ const welcomeMessage = i18n.translate('core', CoreStringKey.System_Welcome, undefined, lang);
123
377
  const errorMessage = i18n.translate('core', CoreStringKey.Error_ValidationFailed);
124
378
 
125
379
  // Define your own component with type safety
@@ -260,6 +514,296 @@ const userNotFound = i18n.translate(
260
514
  );
261
515
  ```
262
516
 
517
+ ## Advanced Features
518
+
519
+ ### Translation Adapters
520
+
521
+ Create adapters to use PluginI18nEngine with components expecting the TranslationEngine interface:
522
+
523
+ ```typescript
524
+ import { createTranslationAdapter, PluginI18nEngine, TranslationEngine } from '@digitaldefiance/i18n-lib';
525
+
526
+ const pluginEngine = PluginI18nEngine.getInstance<'en-US' | 'fr'>();
527
+
528
+ // Create adapter for a specific component
529
+ const adapter: TranslationEngine<MyStringKey> = createTranslationAdapter(
530
+ pluginEngine,
531
+ 'my-component'
532
+ );
533
+
534
+ // Use with error classes or other components
535
+ class MyError extends Error {
536
+ constructor(
537
+ type: ErrorType,
538
+ engine: TranslationEngine<ErrorStringKey>
539
+ ) {
540
+ const message = engine.translate(type);
541
+ super(message);
542
+ }
543
+ }
544
+
545
+ const error = new MyError(ErrorType.NotFound, adapter);
546
+ ```
547
+
548
+ **Key Features:**
549
+ - Zero-overhead delegation to PluginI18nEngine
550
+ - Maintains full type safety
551
+ - Graceful error handling with fallback to key strings
552
+ - Seamless integration with existing code
553
+
554
+ ### Translatable Errors
555
+
556
+ Generic error class with automatic translation:
557
+
558
+ ```typescript
559
+ import { TranslatableGenericError, PluginI18nEngine } from '@digitaldefiance/i18n-lib';
560
+
561
+ enum UserErrorKey {
562
+ UserNotFound = 'userNotFound',
563
+ InvalidCredentials = 'invalidCredentials'
564
+ }
565
+
566
+ // Throw translatable error
567
+ throw new TranslatableGenericError(
568
+ 'user-errors',
569
+ UserErrorKey.UserNotFound,
570
+ { username: 'john_doe' },
571
+ 'en-US',
572
+ { userId: 123 },
573
+ 'myapp'
574
+ );
575
+
576
+ // Create with explicit engine
577
+ const engine = PluginI18nEngine.getInstance<'en-US' | 'fr'>();
578
+ const error = TranslatableGenericError.withEngine(
579
+ engine,
580
+ 'user-errors',
581
+ UserErrorKey.InvalidCredentials,
582
+ undefined,
583
+ 'fr'
584
+ );
585
+
586
+ // Retranslate dynamically
587
+ try {
588
+ // ... code that throws TranslatableGenericError
589
+ } catch (error) {
590
+ if (error instanceof TranslatableGenericError) {
591
+ const localizedMessage = error.retranslate('fr', 'myapp');
592
+ sendToUser(localizedMessage);
593
+ }
594
+ }
595
+ ```
596
+
597
+ **Key Features:**
598
+ - Works with any registered component
599
+ - Uses safeTranslate for consistent fallback behavior
600
+ - Stores error context for retranslation
601
+ - Never throws during construction
602
+ - Metadata attachment for debugging
603
+
604
+ ### Typed Errors
605
+
606
+ Base classes for creating strongly-typed error hierarchies:
607
+
608
+ ```typescript
609
+ import { BaseTypedError, CompleteReasonMap, TranslationEngine } from '@digitaldefiance/i18n-lib';
610
+
611
+ enum DatabaseErrorType {
612
+ ConnectionFailed = 'connectionFailed',
613
+ QueryTimeout = 'queryTimeout'
614
+ }
615
+
616
+ enum DatabaseErrorKey {
617
+ ConnectionFailedMessage = 'connectionFailedMessage',
618
+ QueryTimeoutMessage = 'queryTimeoutMessage'
619
+ }
620
+
621
+ const reasonMap: CompleteReasonMap<typeof DatabaseErrorType, DatabaseErrorKey> = {
622
+ [DatabaseErrorType.ConnectionFailed]: DatabaseErrorKey.ConnectionFailedMessage,
623
+ [DatabaseErrorType.QueryTimeout]: DatabaseErrorKey.QueryTimeoutMessage
624
+ };
625
+
626
+ class DatabaseError extends BaseTypedError<typeof DatabaseErrorType, DatabaseErrorKey> {
627
+ static create(
628
+ engine: TranslationEngine<DatabaseErrorKey>,
629
+ type: DatabaseErrorType,
630
+ metadata?: Record<string, any>
631
+ ): DatabaseError {
632
+ return DatabaseError.createTranslated(
633
+ engine,
634
+ 'database',
635
+ type,
636
+ reasonMap,
637
+ undefined,
638
+ undefined,
639
+ metadata
640
+ );
641
+ }
642
+ }
643
+ ```
644
+
645
+ **Key Features:**
646
+ - Complete enum coverage enforcement
647
+ - Translation engine integration
648
+ - Simple and translated error creation
649
+ - Metadata support
650
+
651
+ ### Template Processing
652
+
653
+ Advanced template system with multiple pattern types:
654
+
655
+ ```typescript
656
+ import { PluginI18nEngine } from '@digitaldefiance/i18n-lib';
657
+
658
+ const engine = PluginI18nEngine.getInstance<'en-US'>();
659
+
660
+ // Component-based patterns
661
+ const message1 = engine.t(
662
+ '{{core.Common_Welcome}} {{user.UserGreetingTemplate}}',
663
+ 'en-US',
664
+ { name: 'John' }
665
+ );
666
+ // "Welcome Hello, John!"
667
+
668
+ // Variable replacement
669
+ const message2 = engine.t(
670
+ 'User {username} has {count} messages',
671
+ 'en-US',
672
+ { username: 'john_doe', count: 5 }
673
+ );
674
+ // "User john_doe has 5 messages"
675
+
676
+ // Mixed patterns
677
+ const message3 = engine.t(
678
+ '{{core.System_Welcome}}, {name}! {{core.System_PleaseWait}}',
679
+ 'en-US',
680
+ { name: 'Alice' }
681
+ );
682
+ // "Welcome, Alice! Please wait..."
683
+ ```
684
+
685
+ **Pattern Types:**
686
+ - `{{componentId.stringKey}}`: Component-based translation
687
+ - `{variableName}`: Variable replacement
688
+ - Template strings automatically use first variable object
689
+ - Multiple variable objects merged for replacement
690
+
691
+ ### Currency Formatting
692
+
693
+ Locale-aware currency formatting:
694
+
695
+ ```typescript
696
+ import { getCurrencyFormat, CurrencyCode } from '@digitaldefiance/i18n-lib';
697
+
698
+ // Get format details
699
+ const usdFormat = getCurrencyFormat('en-US', 'USD');
700
+ console.log(usdFormat);
701
+ // {
702
+ // symbol: '$',
703
+ // position: 'prefix',
704
+ // groupSeparator: ',',
705
+ // decimalSeparator: '.'
706
+ // }
707
+
708
+ const eurFormat = getCurrencyFormat('de-DE', 'EUR');
709
+ console.log(eurFormat);
710
+ // {
711
+ // symbol: '€',
712
+ // position: 'postfix',
713
+ // groupSeparator: '.',
714
+ // decimalSeparator: ','
715
+ // }
716
+
717
+ // Validate currency codes
718
+ const currencyCode = new CurrencyCode('USD');
719
+ console.log(currencyCode.value); // 'USD'
720
+ console.log(CurrencyCode.values); // Array of all valid ISO 4217 codes
721
+ ```
722
+
723
+ **Key Features:**
724
+ - ISO 4217 currency code validation
725
+ - Locale-aware symbol positioning
726
+ - Group and decimal separator detection
727
+ - Intl.NumberFormat integration
728
+
729
+ ### Timezone Handling
730
+
731
+ Validated timezone management:
732
+
733
+ ```typescript
734
+ import { Timezone, isValidTimezone } from '@digitaldefiance/i18n-lib';
735
+
736
+ // Create validated timezone
737
+ const tz = new Timezone('America/New_York');
738
+ console.log(tz.value); // 'America/New_York'
739
+
740
+ // Validate timezone strings
741
+ if (isValidTimezone('Europe/Paris')) {
742
+ const parisTz = new Timezone('Europe/Paris');
743
+ }
744
+
745
+ // Invalid timezone throws error
746
+ try {
747
+ new Timezone('Invalid/Timezone');
748
+ } catch (error) {
749
+ console.error('Invalid timezone');
750
+ }
751
+ ```
752
+
753
+ **Key Features:**
754
+ - Moment-timezone validation
755
+ - Immutable timezone values
756
+ - Validation utilities
757
+ - IANA timezone database support
758
+
759
+ ### Utility Functions
760
+
761
+ Helper functions for common operations:
762
+
763
+ ```typescript
764
+ import {
765
+ replaceVariables,
766
+ isTemplate,
767
+ toStringKey,
768
+ buildReasonMap,
769
+ validateReasonMap,
770
+ createCompleteReasonMap
771
+ } from '@digitaldefiance/i18n-lib';
772
+
773
+ // Variable replacement
774
+ const result = replaceVariables(
775
+ 'Hello, {name}! You have {count} messages.',
776
+ { name: 'John', count: 5 }
777
+ );
778
+ // "Hello, John! You have 5 messages."
779
+
780
+ // Template detection
781
+ if (isTemplate('userGreetingTemplate')) {
782
+ // Handle as template
783
+ }
784
+
785
+ // String key construction
786
+ const key = toStringKey('error', 'validation', 'failed');
787
+ // 'error_validation_failed'
788
+
789
+ // Reason map building
790
+ enum ErrorType {
791
+ NotFound = 'notFound',
792
+ AccessDenied = 'accessDenied'
793
+ }
794
+
795
+ const reasonMap = buildReasonMap(ErrorType, ['error']);
796
+ // {
797
+ // notFound: 'error_notFound',
798
+ // accessDenied: 'error_accessDenied'
799
+ // }
800
+
801
+ // Validate reason map completeness
802
+ if (validateReasonMap(ErrorType, reasonMap)) {
803
+ // All enum values are mapped
804
+ }
805
+ ```
806
+
263
807
  ### Advanced Plugin Usage
264
808
 
265
809
  #### Compile-Time Completeness Enforcement (Strict Mode)
@@ -676,6 +1220,144 @@ I18nEngine.clearInstances();
676
1220
  I18nEngine.removeInstance('main');
677
1221
  ```
678
1222
 
1223
+ ## Supported Languages
1224
+
1225
+ The library includes pre-built translations for 8 languages in the core component:
1226
+
1227
+ | Language Code | Display Name | ISO Code |
1228
+ |--------------|--------------|----------|
1229
+ | `en-US` | English (US) | en-US |
1230
+ | `en-GB` | English (UK) | en-GB |
1231
+ | `fr` | Français | fr |
1232
+ | `es` | Español | es |
1233
+ | `de` | Deutsch | de |
1234
+ | `zh-CN` | 中文 (简体) | zh-CN |
1235
+ | `ja` | 日本語 | ja |
1236
+ | `uk` | Українська | uk |
1237
+
1238
+ ### Language Code Constants
1239
+
1240
+ ```typescript
1241
+ import { LanguageCodes, LanguageDisplayNames, getCoreLanguageCodes } from '@digitaldefiance/i18n-lib';
1242
+
1243
+ // Use constants for type safety
1244
+ const lang = LanguageCodes.FR; // 'fr'
1245
+ const displayName = LanguageDisplayNames[LanguageCodes.FR]; // 'Français'
1246
+
1247
+ // Get all core language codes as array (for Mongoose enums, etc.)
1248
+ const coreLanguageCodes = getCoreLanguageCodes();
1249
+ // ['en-US', 'en-GB', 'fr', 'es', 'de', 'zh-CN', 'ja', 'uk']
1250
+
1251
+ // All available codes
1252
+ const codes = {
1253
+ EN_US: 'en-US',
1254
+ EN_GB: 'en-GB',
1255
+ FR: 'fr',
1256
+ ES: 'es',
1257
+ DE: 'de',
1258
+ ZH_CN: 'zh-CN',
1259
+ JA: 'ja',
1260
+ UK: 'uk'
1261
+ };
1262
+ ```
1263
+
1264
+ ### Custom Language Codes
1265
+
1266
+ Extend core languages with custom ones while maintaining type safety:
1267
+
1268
+ ```typescript
1269
+ import {
1270
+ CoreLanguageCode,
1271
+ getCoreLanguageDefinitions,
1272
+ createLanguageDefinition,
1273
+ PluginI18nEngine
1274
+ } from '@digitaldefiance/i18n-lib';
1275
+
1276
+ // Define custom language type extending core
1277
+ type MyLanguageCode = CoreLanguageCode | 'pt-BR' | 'it';
1278
+
1279
+ // Create engine with extended languages
1280
+ const engine = PluginI18nEngine.createInstance<MyLanguageCode>(
1281
+ 'myapp',
1282
+ [
1283
+ ...getCoreLanguageDefinitions(),
1284
+ createLanguageDefinition('pt-BR', 'Português (Brasil)', 'pt-BR'),
1285
+ createLanguageDefinition('it', 'Italiano', 'it')
1286
+ ]
1287
+ );
1288
+
1289
+ // Type-safe language usage
1290
+ const lang1: MyLanguageCode = 'en-US'; // ✓ Core language
1291
+ const lang2: MyLanguageCode = 'pt-BR'; // ✓ Custom language
1292
+ const lang3: MyLanguageCode = 'invalid'; // ✗ Type error!
1293
+ ```
1294
+
1295
+ ### Helper Functions for Mongoose Schemas
1296
+
1297
+ Extract language codes from the registry (single source of truth):
1298
+
1299
+ ```typescript
1300
+ import { PluginI18nEngine, getCoreLanguageCodes, LanguageCodes } from '@digitaldefiance/i18n-lib';
1301
+ import { Schema } from 'mongoose';
1302
+
1303
+ // Static approach: Get core language codes as array
1304
+ const coreLanguageCodes = getCoreLanguageCodes();
1305
+ // ['en-US', 'en-GB', 'fr', 'es', 'de', 'zh-CN', 'ja', 'uk']
1306
+
1307
+ // Dynamic approach: Get from engine instance (includes custom languages)
1308
+ const engine = PluginI18nEngine.getInstance<string>();
1309
+ const languageIds = engine.getLanguageRegistry().getLanguageIds();
1310
+ const isoCodes = engine.getLanguageRegistry().getLanguageCodes();
1311
+
1312
+ // Use in Mongoose schema
1313
+ const userSchema = new Schema({
1314
+ language: {
1315
+ type: String,
1316
+ enum: coreLanguageCodes, // Static core languages
1317
+ default: LanguageCodes.EN_US
1318
+ },
1319
+ adminLanguage: {
1320
+ type: String,
1321
+ enum: languageIds, // Dynamic from registry
1322
+ default: LanguageCodes.EN_US
1323
+ }
1324
+ });
1325
+
1326
+ // Get display names for validation messages
1327
+ const displayNames = engine.getLanguageRegistry().getLanguageDisplayNames();
1328
+ // { 'en-US': 'English (US)', 'fr': 'Français', ... }
1329
+ ```
1330
+
1331
+ ## Core String Keys
1332
+
1333
+ The core component provides 40+ system strings organized by category:
1334
+
1335
+ ### Common Strings
1336
+ - `Common_Yes`, `Common_No`, `Common_Cancel`, `Common_OK`
1337
+ - `Common_Save`, `Common_Delete`, `Common_Edit`, `Common_Create`, `Common_Update`
1338
+ - `Common_Loading`, `Common_Error`, `Common_Success`, `Common_Warning`, `Common_Info`
1339
+ - `Common_Disposed`
1340
+
1341
+ ### Error Messages
1342
+ - `Error_InvalidInput`, `Error_NetworkError`, `Error_NotFound`
1343
+ - `Error_AccessDenied`, `Error_InternalServer`, `Error_ValidationFailed`
1344
+ - `Error_RequiredField`, `Error_InvalidContextTemplate`
1345
+ - `Error_MissingTranslationKeyTemplate`
1346
+
1347
+ ### Registry Error Templates
1348
+ - `Error_ComponentNotFoundTemplate`
1349
+ - `Error_LanguageNotFoundTemplate`
1350
+ - `Error_StringKeyNotFoundTemplate`
1351
+ - `Error_IncompleteRegistrationTemplate`
1352
+ - `Error_DuplicateComponentTemplate`
1353
+ - `Error_DuplicateLanguageTemplate`
1354
+ - `Error_ValidationFailedTemplate`
1355
+
1356
+ ### System Messages
1357
+ - `System_Welcome`, `System_Goodbye`, `System_PleaseWait`
1358
+ - `System_ProcessingRequest`, `System_OperationComplete`
1359
+ - `System_NoDataAvailable`
1360
+
679
1361
  ## API Reference
680
1362
 
681
1363
  ### Plugin Architecture API
@@ -1008,6 +1690,133 @@ If localized error messages aren't provided, the engine falls back to English te
1008
1690
  - `Missing translation for key '{key}' in language '{language}'`
1009
1691
  - `Default language '{language}' has no string collection`
1010
1692
 
1693
+ ## Error Handling
1694
+
1695
+ The library provides comprehensive error handling with localized error messages:
1696
+
1697
+ ### Registry Errors
1698
+
1699
+ ```typescript
1700
+ import { RegistryError, RegistryErrorType } from '@digitaldefiance/i18n-lib';
1701
+
1702
+ try {
1703
+ engine.registerComponent(invalidRegistration);
1704
+ } catch (error) {
1705
+ if (error instanceof RegistryError) {
1706
+ console.error(`Error type: ${error.type}`);
1707
+ console.error(`Metadata:`, error.metadata);
1708
+
1709
+ switch (error.type) {
1710
+ case RegistryErrorType.ComponentNotFound:
1711
+ // Handle missing component
1712
+ break;
1713
+ case RegistryErrorType.DuplicateComponent:
1714
+ // Handle duplicate registration
1715
+ break;
1716
+ case RegistryErrorType.ValidationFailed:
1717
+ // Handle validation failure
1718
+ break;
1719
+ }
1720
+ }
1721
+ }
1722
+ ```
1723
+
1724
+ **Error Types:**
1725
+ - `ComponentNotFound`: Component ID not registered
1726
+ - `LanguageNotFound`: Language not registered
1727
+ - `StringKeyNotFound`: Translation key not found
1728
+ - `IncompleteRegistration`: Missing translations detected
1729
+ - `DuplicateComponent`: Component already registered
1730
+ - `DuplicateLanguage`: Language already registered
1731
+ - `ValidationFailed`: Validation check failed
1732
+
1733
+ ### Context Errors
1734
+
1735
+ ```typescript
1736
+ import { ContextError, ContextErrorType } from '@digitaldefiance/i18n-lib';
1737
+
1738
+ try {
1739
+ const context = globalContext.getContext('invalid-key');
1740
+ } catch (error) {
1741
+ if (error instanceof ContextError) {
1742
+ console.error(`Invalid context: ${error.contextKey}`);
1743
+ }
1744
+ }
1745
+ ```
1746
+
1747
+ ### Safe Translation
1748
+
1749
+ Use `safeTranslate` to prevent errors:
1750
+
1751
+ ```typescript
1752
+ // Regular translate throws on missing key
1753
+ try {
1754
+ const text = engine.translate('component', 'missingKey');
1755
+ } catch (error) {
1756
+ // Handle error
1757
+ }
1758
+
1759
+ // Safe translate returns placeholder
1760
+ const text = engine.safeTranslate('component', 'missingKey');
1761
+ // Returns: "[component.missingKey]"
1762
+ ```
1763
+
1764
+ ## Validation
1765
+
1766
+ ### Component Validation
1767
+
1768
+ ```typescript
1769
+ // Validate during registration
1770
+ const result = engine.registerComponent(registration);
1771
+
1772
+ if (!result.isValid) {
1773
+ console.error('Validation errors:', result.errors);
1774
+ console.warn('Missing keys:', result.missingKeys);
1775
+
1776
+ result.missingKeys.forEach(missing => {
1777
+ console.log(`Missing: ${missing.stringKey} for ${missing.languageId} in ${missing.componentId}`);
1778
+ });
1779
+ }
1780
+ ```
1781
+
1782
+ ### Global Validation
1783
+
1784
+ ```typescript
1785
+ // Validate all components
1786
+ const validation = engine.validateAllComponents();
1787
+
1788
+ if (!validation.isValid) {
1789
+ console.error('Errors:', validation.errors);
1790
+ console.warn('Warnings:', validation.warnings);
1791
+ }
1792
+
1793
+ // Example output:
1794
+ // Errors: ["Component 'user' missing strings for language 'de'"]
1795
+ // Warnings: ["Component 'user' missing key 'greeting' for language 'fr'"]
1796
+ ```
1797
+
1798
+ ### Validation Configuration
1799
+
1800
+ ```typescript
1801
+ import { ValidationConfig } from '@digitaldefiance/i18n-lib';
1802
+
1803
+ const strictConfig: ValidationConfig = {
1804
+ requireCompleteStrings: true,
1805
+ allowPartialRegistration: false,
1806
+ fallbackLanguageId: 'en-US'
1807
+ };
1808
+
1809
+ const lenientConfig: ValidationConfig = {
1810
+ requireCompleteStrings: false,
1811
+ allowPartialRegistration: true,
1812
+ fallbackLanguageId: 'en-US'
1813
+ };
1814
+
1815
+ const engine = new PluginI18nEngine(languages, {
1816
+ validation: strictConfig
1817
+ });
1818
+ ```
1819
+
1011
1820
  ## Best Practices
1012
1821
 
1013
1822
  ### Plugin Architecture (Recommended for New Projects)
@@ -1049,16 +1858,374 @@ const text = modern.translate('my-component', MyStrings.Welcome);
1049
1858
 
1050
1859
  Both systems can coexist in the same application during migration.
1051
1860
 
1861
+ ## Performance Considerations
1862
+
1863
+ ### Instance Management
1864
+
1865
+ - Use named instances to isolate different application contexts
1866
+ - Reuse instances rather than creating new ones
1867
+ - Clean up instances in tests to prevent memory leaks
1868
+
1869
+ ### Translation Caching
1870
+
1871
+ - Translations are stored in memory for fast access
1872
+ - Component strings are validated once during registration
1873
+ - Fallback translations are generated during registration, not at runtime
1874
+
1875
+ ### Type Safety Overhead
1876
+
1877
+ - Compile-time type checking has zero runtime cost
1878
+ - Generic types are erased during compilation
1879
+ - Validation runs only during registration, not translation
1880
+
1881
+ ## Security Considerations
1882
+
1883
+ ### Zero-Knowledge Patterns
1884
+
1885
+ The library is designed to support zero-knowledge security patterns:
1886
+
1887
+ - No translation data is sent to external services
1888
+ - All translations are stored locally
1889
+ - No telemetry or analytics
1890
+ - Suitable for sensitive applications
1891
+
1892
+ ### Input Sanitization
1893
+
1894
+ Always sanitize user input before using in translations:
1895
+
1896
+ ```typescript
1897
+ import { replaceVariables } from '@digitaldefiance/i18n-lib';
1898
+
1899
+ // BAD: Direct user input
1900
+ const message = engine.translate('component', 'template', {
1901
+ userInput: req.body.unsafeInput
1902
+ });
1903
+
1904
+ // GOOD: Sanitized input
1905
+ const message = engine.translate('component', 'template', {
1906
+ userInput: sanitize(req.body.unsafeInput)
1907
+ });
1908
+ ```
1909
+
1910
+ ### Error Message Exposure
1911
+
1912
+ Be careful not to expose sensitive information in error messages:
1913
+
1914
+ ```typescript
1915
+ // BAD: Exposes internal details
1916
+ throw new TranslatableGenericError(
1917
+ 'auth',
1918
+ 'loginFailed',
1919
+ { password: user.password }, // Don't include sensitive data
1920
+ language
1921
+ );
1922
+
1923
+ // GOOD: Safe error message
1924
+ throw new TranslatableGenericError(
1925
+ 'auth',
1926
+ 'loginFailed',
1927
+ { username: user.username },
1928
+ language,
1929
+ { userId: user.id } // Metadata for logging only
1930
+ );
1931
+ ```
1932
+
1933
+ ## Mongoose Integration
1934
+
1935
+ ### Schema Definition with Language Enums
1936
+
1937
+ ```typescript
1938
+ import { Schema, model } from 'mongoose';
1939
+ import { LanguageCodes, getCoreLanguageCodes } from '@digitaldefiance/i18n-lib';
1940
+
1941
+ // Get core language codes from helper (single source of truth)
1942
+ const supportedLanguages = getCoreLanguageCodes();
1943
+ // ['en-US', 'en-GB', 'fr', 'es', 'de', 'zh-CN', 'ja', 'uk']
1944
+
1945
+ const userSchema = new Schema({
1946
+ language: {
1947
+ type: String,
1948
+ enum: supportedLanguages,
1949
+ default: LanguageCodes.EN_US,
1950
+ required: true
1951
+ },
1952
+ adminLanguage: {
1953
+ type: String,
1954
+ enum: supportedLanguages,
1955
+ default: LanguageCodes.EN_US
1956
+ }
1957
+ });
1958
+
1959
+ export const User = model('User', userSchema);
1960
+ ```
1961
+
1962
+ ### Dynamic Language Enum from Engine
1963
+
1964
+ ```typescript
1965
+ import { PluginI18nEngine } from '@digitaldefiance/i18n-lib';
1966
+
1967
+ // Get languages from engine instance
1968
+ const engine = PluginI18nEngine.getInstance();
1969
+ const registry = engine.getLanguageRegistry();
1970
+
1971
+ // Extract for Mongoose
1972
+ const languageEnum = registry.getLanguageIds();
1973
+ const defaultLanguage = registry.getDefaultLanguageId();
1974
+
1975
+ const contentSchema = new Schema({
1976
+ language: {
1977
+ type: String,
1978
+ enum: languageEnum,
1979
+ default: defaultLanguage
1980
+ }
1981
+ });
1982
+ ```
1983
+
1984
+ ### Validation with Display Names
1985
+
1986
+ ```typescript
1987
+ import { PluginI18nEngine } from '@digitaldefiance/i18n-lib';
1988
+
1989
+ const engine = PluginI18nEngine.getInstance();
1990
+ const displayNames = engine.getLanguageRegistry().getLanguageDisplayNames();
1991
+
1992
+ const settingsSchema = new Schema({
1993
+ language: {
1994
+ type: String,
1995
+ enum: Object.keys(displayNames),
1996
+ validate: {
1997
+ validator: (v: string) => v in displayNames,
1998
+ message: (props) => {
1999
+ const validLanguages = Object.entries(displayNames)
2000
+ .map(([code, name]) => `${name} (${code})`)
2001
+ .join(', ');
2002
+ return `${props.value} is not a valid language. Valid options: ${validLanguages}`;
2003
+ }
2004
+ }
2005
+ }
2006
+ });
2007
+ ```
2008
+
2009
+ ## Integration Examples
2010
+
2011
+ ### Express.js Middleware
2012
+
2013
+ ```typescript
2014
+ import { PluginI18nEngine, CoreLanguageCode } from '@digitaldefiance/i18n-lib';
2015
+ import { Request, Response, NextFunction } from 'express';
2016
+
2017
+ const engine = PluginI18nEngine.getInstance<CoreLanguageCode>();
2018
+
2019
+ function i18nMiddleware(req: Request, res: Response, next: NextFunction) {
2020
+ // Get language from header, query, or cookie
2021
+ const language = (req.headers['accept-language'] ||
2022
+ req.query.lang ||
2023
+ req.cookies.language ||
2024
+ 'en-US') as CoreLanguageCode;
2025
+
2026
+ // Set language for this request (type-safe)
2027
+ engine.setLanguage(language);
2028
+
2029
+ // Add translation helper to response locals
2030
+ res.locals.t = (componentId: string, key: string, vars?: any) => {
2031
+ return engine.translate(componentId, key, vars, language);
2032
+ };
2033
+
2034
+ next();
2035
+ }
2036
+
2037
+ app.use(i18nMiddleware);
2038
+ ```
2039
+
2040
+ ### React Integration
2041
+
2042
+ ```typescript
2043
+ import React, { createContext, useContext, useState } from 'react';
2044
+ import { PluginI18nEngine, CoreLanguageCode, LanguageCodes } from '@digitaldefiance/i18n-lib';
2045
+
2046
+ const I18nContext = createContext<{
2047
+ engine: PluginI18nEngine<CoreLanguageCode>;
2048
+ language: CoreLanguageCode;
2049
+ setLanguage: (lang: CoreLanguageCode) => void;
2050
+ } | null>(null);
2051
+
2052
+ export function I18nProvider({ children }: { children: React.ReactNode }) {
2053
+ const [engine] = useState(() => PluginI18nEngine.getInstance<CoreLanguageCode>());
2054
+ const [language, setLanguageState] = useState<CoreLanguageCode>(LanguageCodes.EN_US);
2055
+
2056
+ const setLanguage = (lang: CoreLanguageCode) => {
2057
+ engine.setLanguage(lang);
2058
+ setLanguageState(lang);
2059
+ };
2060
+
2061
+ return (
2062
+ <I18nContext.Provider value={{ engine, language, setLanguage }}>
2063
+ {children}
2064
+ </I18nContext.Provider>
2065
+ );
2066
+ }
2067
+
2068
+ export function useI18n() {
2069
+ const context = useContext(I18nContext);
2070
+ if (!context) throw new Error('useI18n must be used within I18nProvider');
2071
+
2072
+ const t = (componentId: string, key: string, vars?: any) => {
2073
+ return context.engine.translate(componentId, key, vars, context.language);
2074
+ };
2075
+
2076
+ return { ...context, t };
2077
+ }
2078
+
2079
+ // Usage in component
2080
+ function MyComponent() {
2081
+ const { t, language, setLanguage } = useI18n();
2082
+
2083
+ return (
2084
+ <div>
2085
+ <h1>{t('core', CoreStringKey.System_Welcome)}</h1>
2086
+ <button onClick={() => setLanguage('fr')}>
2087
+ Switch to French
2088
+ </button>
2089
+ </div>
2090
+ );
2091
+ }
2092
+ ```
2093
+
2094
+ ### Vue.js Plugin
2095
+
2096
+ ```typescript
2097
+ import { Plugin } from 'vue';
2098
+ import { PluginI18nEngine, CoreLanguageCode } from '@digitaldefiance/i18n-lib';
2099
+
2100
+ const i18nPlugin: Plugin = {
2101
+ install(app, options) {
2102
+ const engine = PluginI18nEngine.getInstance<CoreLanguageCode>();
2103
+
2104
+ app.config.globalProperties.$t = (
2105
+ componentId: string,
2106
+ key: string,
2107
+ vars?: any
2108
+ ) => {
2109
+ return engine.translate(componentId, key, vars);
2110
+ };
2111
+
2112
+ app.config.globalProperties.$i18n = engine;
2113
+ }
2114
+ };
2115
+
2116
+ export default i18nPlugin;
2117
+
2118
+ // Usage in component
2119
+ // <template>
2120
+ // <div>{{ $t('core', 'System_Welcome') }}</div>
2121
+ // </template>
2122
+ ```
2123
+
2124
+ ## Troubleshooting
2125
+
2126
+ ### Common Issues
2127
+
2128
+ **Issue: "Instance with key 'X' not found"**
2129
+ ```typescript
2130
+ // Solution: Create instance before using
2131
+ const engine = PluginI18nEngine.createInstance('myapp', languages);
2132
+ // Or use default instance
2133
+ const engine = PluginI18nEngine.getInstance(); // Uses 'default' key
2134
+ ```
2135
+
2136
+ **Issue: "Component 'X' not found"**
2137
+ ```typescript
2138
+ // Solution: Register component before translating
2139
+ engine.registerComponent(myComponentRegistration);
2140
+ const text = engine.translate('my-component', 'key');
2141
+ ```
2142
+
2143
+ **Issue: "Language 'X' not found"**
2144
+ ```typescript
2145
+ // Solution: Register language before using
2146
+ engine.registerLanguage(createLanguageDefinition('fr', 'Français', 'fr'));
2147
+ engine.setLanguage('fr');
2148
+ ```
2149
+
2150
+ **Issue: Missing translations in production**
2151
+ ```typescript
2152
+ // Solution: Use validation to catch missing translations
2153
+ const validation = engine.validateAllComponents();
2154
+ if (!validation.isValid) {
2155
+ console.error('Missing translations:', validation.errors);
2156
+ // Fix translations before deploying
2157
+ }
2158
+ ```
2159
+
2160
+ **Issue: Type errors with string keys**
2161
+ ```typescript
2162
+ // Solution: Use enum values, not strings
2163
+ enum MyKeys {
2164
+ Welcome = 'welcome'
2165
+ }
2166
+
2167
+ // BAD
2168
+ engine.translate('component', 'welcome'); // Type error
2169
+
2170
+ // GOOD
2171
+ engine.translate('component', MyKeys.Welcome);
2172
+ ```
2173
+
1052
2174
  ## License
1053
2175
 
1054
- MIT
2176
+ MIT License - See LICENSE file for details
1055
2177
 
1056
2178
  ## Repository
1057
2179
 
1058
- Part of the DigitalBurnbag project - a secure file sharing and automated protocol system.
2180
+ Part of the [DigitalBurnbag](https://github.com/Digital-Defiance/DigitalBurnbag) project - a secure file sharing and automated protocol system with zero-knowledge encryption.
2181
+
2182
+ ## Contributing
2183
+
2184
+ Contributions are welcome! Please:
2185
+
2186
+ 1. Fork the repository
2187
+ 2. Create a feature branch
2188
+ 3. Add tests for new functionality
2189
+ 4. Ensure all tests pass
2190
+ 5. Submit a pull request
2191
+
2192
+ ### Development Setup
2193
+
2194
+ ```bash
2195
+ # Clone repository
2196
+ git clone https://github.com/Digital-Defiance/DigitalBurnbag.git
2197
+ cd DigitalBurnbag/packages/digitaldefiance-i18n-lib
2198
+
2199
+ # Install dependencies
2200
+ yarn install
2201
+
2202
+ # Run tests
2203
+ yarn test
2204
+
2205
+ # Build
2206
+ yarn build
2207
+ ```
2208
+
2209
+ ## Support
2210
+
2211
+ For issues, questions, or contributions:
2212
+ - GitHub Issues: https://github.com/Digital-Defiance/DigitalBurnbag/issues
2213
+ - Documentation: See README.md and inline code documentation
2214
+ - Examples: See `examples/` directory in repository
1059
2215
 
1060
2216
  ## ChangeLog
1061
2217
 
2218
+ ### Version 1.3.0
2219
+
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
2224
+ - **Added**: `getCoreLanguageCodes()` - Get core language codes as runtime array
2225
+ - **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
2228
+
1062
2229
  ### Version 1.2.5
1063
2230
 
1064
2231
  - Sat Oct 25 2025 15:0100 GMT-0700 (Pacific Daylight Time)
@@ -7,7 +7,11 @@ import { CoreStringKey } from './core-string-key';
7
7
  import { LanguageCodes } from './language-codes';
8
8
  import { LanguageDefinition } from './language-definition';
9
9
  import { PluginI18nEngine } from './plugin-i18n-engine';
10
- export type CoreLanguageCode = typeof LanguageCodes.EN_US | typeof LanguageCodes.EN_GB | typeof LanguageCodes.FR | typeof LanguageCodes.ES | typeof LanguageCodes.DE | typeof LanguageCodes.ZH_CN | typeof LanguageCodes.JA | typeof LanguageCodes.UK;
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
13
+ */
14
+ export type CoreLanguageCode = typeof LanguageCodes[keyof typeof LanguageCodes];
11
15
  /**
12
16
  * Create default language definitions
13
17
  */
@@ -25,6 +29,14 @@ export declare function createCoreComponentStrings(): import("./strict-types").C
25
29
  * Create core component registration
26
30
  */
27
31
  export declare function createCoreComponentRegistration(): ComponentRegistration<CoreStringKey, CoreLanguageCode>;
32
+ /**
33
+ * Get core language codes as array (for Mongoose enums, etc.)
34
+ */
35
+ export declare function getCoreLanguageCodes(): string[];
36
+ /**
37
+ * Get core language definitions
38
+ */
39
+ export declare function getCoreLanguageDefinitions(): LanguageDefinition[];
28
40
  /**
29
41
  * Create a pre-configured I18n engine with core components
30
42
  */
package/dist/core-i18n.js CHANGED
@@ -7,6 +7,8 @@ exports.CoreComponentDefinition = exports.CoreI18nComponentId = void 0;
7
7
  exports.createDefaultLanguages = createDefaultLanguages;
8
8
  exports.createCoreComponentStrings = createCoreComponentStrings;
9
9
  exports.createCoreComponentRegistration = createCoreComponentRegistration;
10
+ exports.getCoreLanguageCodes = getCoreLanguageCodes;
11
+ exports.getCoreLanguageDefinitions = getCoreLanguageDefinitions;
10
12
  exports.createCoreI18nEngine = createCoreI18nEngine;
11
13
  exports.getCoreTranslation = getCoreTranslation;
12
14
  exports.safeCoreTranslation = safeCoreTranslation;
@@ -433,6 +435,18 @@ function createCoreComponentRegistration() {
433
435
  strings: createCoreComponentStrings(),
434
436
  };
435
437
  }
438
+ /**
439
+ * Get core language codes as array (for Mongoose enums, etc.)
440
+ */
441
+ function getCoreLanguageCodes() {
442
+ return Object.values(language_codes_1.LanguageCodes);
443
+ }
444
+ /**
445
+ * Get core language definitions
446
+ */
447
+ function getCoreLanguageDefinitions() {
448
+ return createDefaultLanguages();
449
+ }
436
450
  /**
437
451
  * Create a pre-configured I18n engine with core components
438
452
  */
@@ -215,7 +215,7 @@ class UserError extends PluginTypedError<typeof UserErrorType, UserErrorStringKe
215
215
  engine: PluginI18nEngine<CoreLanguageCode>,
216
216
  type: UserErrorType,
217
217
  otherVars?: Record<string, string | number>,
218
- language?: CoreLanguage
218
+ language?: CoreLanguageCode
219
219
  ) {
220
220
  super(engine, 'user-system', type, userErrorReasonMap, language, otherVars);
221
221
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digitaldefiance/i18n-lib",
3
- "version": "1.2.5",
3
+ "version": "1.3.0",
4
4
  "description": "Generic i18n library with enum translation support",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",