@digitaldefiance/i18n-lib 4.3.2 → 4.5.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.
Files changed (34) hide show
  1. package/README.md +422 -15
  2. package/package.json +2 -2
  3. package/src/core/i18n-engine.d.ts +29 -3
  4. package/src/core/i18n-engine.d.ts.map +1 -1
  5. package/src/core/i18n-engine.js +69 -9
  6. package/src/core/i18n-engine.js.map +1 -1
  7. package/src/core/string-key-enum-registry.d.ts +76 -1
  8. package/src/core/string-key-enum-registry.d.ts.map +1 -1
  9. package/src/core/string-key-enum-registry.js +147 -18
  10. package/src/core/string-key-enum-registry.js.map +1 -1
  11. package/src/create-i18n-setup.d.ts +11 -0
  12. package/src/create-i18n-setup.d.ts.map +1 -0
  13. package/src/create-i18n-setup.js +89 -0
  14. package/src/create-i18n-setup.js.map +1 -0
  15. package/src/index.d.ts +1 -0
  16. package/src/index.d.ts.map +1 -1
  17. package/src/index.js +4 -1
  18. package/src/index.js.map +1 -1
  19. package/src/interfaces/i18n-component-package.interface.d.ts +14 -0
  20. package/src/interfaces/i18n-component-package.interface.d.ts.map +1 -0
  21. package/src/interfaces/i18n-component-package.interface.js +3 -0
  22. package/src/interfaces/i18n-component-package.interface.js.map +1 -0
  23. package/src/interfaces/i18n-engine.interface.d.ts +3 -2
  24. package/src/interfaces/i18n-engine.interface.d.ts.map +1 -1
  25. package/src/interfaces/i18n-setup-config.interface.d.ts +25 -0
  26. package/src/interfaces/i18n-setup-config.interface.d.ts.map +1 -0
  27. package/src/interfaces/i18n-setup-config.interface.js +3 -0
  28. package/src/interfaces/i18n-setup-config.interface.js.map +1 -0
  29. package/src/interfaces/i18n-setup-result.interface.d.ts +31 -0
  30. package/src/interfaces/i18n-setup-result.interface.d.ts.map +1 -0
  31. package/src/interfaces/i18n-setup-result.interface.js +3 -0
  32. package/src/interfaces/i18n-setup-result.interface.js.map +1 -0
  33. package/src/interfaces/index.d.ts +3 -0
  34. package/src/interfaces/index.d.ts.map +1 -1
package/README.md CHANGED
@@ -1315,6 +1315,406 @@ function translateAnyValue<T extends string | number>(
1315
1315
  }
1316
1316
  ```
1317
1317
 
1318
+ ## Monorepo i18n-setup Guide
1319
+
1320
+ When building an application that consumes multiple Express Suite packages (e.g., `suite-core-lib`, `ecies-lib`), you need a single `i18n-setup.ts` file that initializes the engine, registers all components and their branded string key enums, sets up the global context, and exports translation helpers.
1321
+
1322
+ ### Recommended: Factory Approach (`createI18nSetup`)
1323
+
1324
+ The `createI18nSetup()` factory replaces ~200 lines of manual boilerplate with a single function call. It handles engine creation, core component registration, library component registration, branded enum registration, and context initialization automatically.
1325
+
1326
+ ```typescript
1327
+ // i18n-setup.ts — Application-level i18n initialization (factory approach)
1328
+
1329
+ import {
1330
+ createI18nSetup,
1331
+ createI18nStringKeys,
1332
+ LanguageCodes,
1333
+ } from '@digitaldefiance/i18n-lib';
1334
+ import { createSuiteCoreComponentPackage } from '@digitaldefiance/suite-core-lib';
1335
+ import { createEciesComponentPackage } from '@digitaldefiance/ecies-lib';
1336
+
1337
+ // 1. Define your application component
1338
+ export const AppComponentId = 'MyApp';
1339
+
1340
+ export const AppStringKey = createI18nStringKeys(AppComponentId, {
1341
+ SiteTitle: 'siteTitle',
1342
+ SiteDescription: 'siteDescription',
1343
+ WelcomeMessage: 'welcomeMessage',
1344
+ } as const);
1345
+
1346
+ const appStrings = {
1347
+ [LanguageCodes.EN_US]: {
1348
+ siteTitle: 'My Application',
1349
+ siteDescription: 'An Express Suite application',
1350
+ welcomeMessage: 'Welcome, {name}!',
1351
+ },
1352
+ [LanguageCodes.FR]: {
1353
+ siteTitle: 'Mon Application',
1354
+ siteDescription: 'Une application Express Suite',
1355
+ welcomeMessage: 'Bienvenue, {name} !',
1356
+ },
1357
+ };
1358
+
1359
+ // 2. Create the i18n setup — one call does everything
1360
+ const i18n = createI18nSetup({
1361
+ componentId: AppComponentId,
1362
+ stringKeyEnum: AppStringKey,
1363
+ strings: appStrings,
1364
+ aliases: ['AppStringKey'],
1365
+ libraryComponents: [
1366
+ createSuiteCoreComponentPackage(),
1367
+ createEciesComponentPackage(),
1368
+ ],
1369
+ });
1370
+
1371
+ // 3. Export the public API
1372
+ export const { engine: i18nEngine, translate, safeTranslate } = i18n;
1373
+ export const i18nContext = i18n.context;
1374
+ ```
1375
+
1376
+ The factory:
1377
+ - Creates or reuses an `I18nEngine` instance (idempotent via `instanceKey`, defaults to `'default'`)
1378
+ - Registers the Core i18n component automatically
1379
+ - Registers each library component's `ComponentConfig` and branded `stringKeyEnum` from the `I18nComponentPackage`
1380
+ - Registers your application component and its branded enum
1381
+ - Initializes `GlobalActiveContext` with the specified `defaultLanguage` (defaults to `'en-US'`)
1382
+ - Returns an `I18nSetupResult` with `engine`, `translate`, `safeTranslate`, `context`, `setLanguage`, `setAdminLanguage`, `setContext`, `getLanguage`, `getAdminLanguage`, and `reset`
1383
+
1384
+ Calling `createI18nSetup()` multiple times with the same `instanceKey` reuses the existing engine — safe for monorepos where a subset library and a superset API both call the factory.
1385
+
1386
+ ### I18nComponentPackage Interface
1387
+
1388
+ Library authors bundle a `ComponentConfig` with its branded string key enum in a single `I18nComponentPackage` object. This lets the factory auto-register both the component and its enum in one step.
1389
+
1390
+ ```typescript
1391
+ import type { AnyBrandedEnum } from '@digitaldefiance/branded-enum';
1392
+ import type { ComponentConfig } from '@digitaldefiance/i18n-lib';
1393
+
1394
+ interface I18nComponentPackage {
1395
+ readonly config: ComponentConfig;
1396
+ readonly stringKeyEnum?: AnyBrandedEnum;
1397
+ }
1398
+ ```
1399
+
1400
+ Each library exports a `createXxxComponentPackage()` function:
1401
+
1402
+ ```typescript
1403
+ // In suite-core-lib
1404
+ import { createSuiteCoreComponentPackage } from '@digitaldefiance/suite-core-lib';
1405
+ const pkg = createSuiteCoreComponentPackage();
1406
+ // pkg.config → SuiteCore ComponentConfig
1407
+ // pkg.stringKeyEnum → SuiteCoreStringKey branded enum
1408
+
1409
+ // In ecies-lib
1410
+ import { createEciesComponentPackage } from '@digitaldefiance/ecies-lib';
1411
+ const pkg = createEciesComponentPackage();
1412
+
1413
+ // In node-ecies-lib
1414
+ import { createNodeEciesComponentPackage } from '@digitaldefiance/node-ecies-lib';
1415
+ const pkg = createNodeEciesComponentPackage();
1416
+ ```
1417
+
1418
+ The existing `createSuiteCoreComponentConfig()` and `createEciesComponentConfig()` functions remain available for consumers that prefer the manual approach.
1419
+
1420
+ ### Browser-Safe Fallback
1421
+
1422
+ In browser environments, bundlers like Vite and webpack may create separate copies of `@digitaldefiance/branded-enum`, causing `isBrandedEnum()` to fail due to Symbol/WeakSet identity mismatch. This breaks `registerStringKeyEnum()` and `translateStringKey()`.
1423
+
1424
+ The engine now includes a transparent fallback: when the `StringKeyEnumRegistry` fails to resolve a component ID for a known string key value, the engine scans all registered components' string keys to find the matching component. The result is cached in a `ValueComponentLookupCache` for subsequent lookups, and the cache is invalidated whenever a new component is registered.
1425
+
1426
+ This means consumers do not need manual workarounds (like `safeRegisterStringKeyEnum` or `_componentLookup` maps) for bundler Symbol mismatch issues. Both `translateStringKey` and `safeTranslateStringKey` use the fallback automatically.
1427
+
1428
+ ### Advanced: Manual Setup
1429
+
1430
+ For advanced use cases where you need full control over engine creation, validation options, or custom registration order, you can use the manual approach:
1431
+
1432
+ <details>
1433
+ <summary>Click to expand manual i18n-setup.ts example</summary>
1434
+
1435
+ ```typescript
1436
+ // i18n-setup.ts — Manual approach (advanced)
1437
+
1438
+ import {
1439
+ I18nBuilder,
1440
+ I18nEngine,
1441
+ LanguageCodes,
1442
+ GlobalActiveContext,
1443
+ getCoreLanguageDefinitions,
1444
+ createCoreComponentRegistration,
1445
+ createI18nStringKeys,
1446
+ type CoreLanguageCode,
1447
+ type IActiveContext,
1448
+ type ComponentConfig,
1449
+ type LanguageContextSpace,
1450
+ } from '@digitaldefiance/i18n-lib';
1451
+ import type { BrandedEnumValue } from '@digitaldefiance/branded-enum';
1452
+ import {
1453
+ createSuiteCoreComponentConfig,
1454
+ SuiteCoreStringKey,
1455
+ } from '@digitaldefiance/suite-core-lib';
1456
+ import {
1457
+ createEciesComponentConfig,
1458
+ EciesStringKey,
1459
+ } from '@digitaldefiance/ecies-lib';
1460
+
1461
+ export const AppComponentId = 'MyApp';
1462
+
1463
+ export const AppStringKey = createI18nStringKeys(AppComponentId, {
1464
+ SiteTitle: 'siteTitle',
1465
+ SiteDescription: 'siteDescription',
1466
+ WelcomeMessage: 'welcomeMessage',
1467
+ } as const);
1468
+
1469
+ export type AppStringKeyValue = BrandedEnumValue<typeof AppStringKey>;
1470
+
1471
+ const appStrings: Record<string, Record<string, string>> = {
1472
+ [LanguageCodes.EN_US]: {
1473
+ siteTitle: 'My Application',
1474
+ siteDescription: 'An Express Suite application',
1475
+ welcomeMessage: 'Welcome, {name}!',
1476
+ },
1477
+ [LanguageCodes.FR]: {
1478
+ siteTitle: 'Mon Application',
1479
+ siteDescription: 'Une application Express Suite',
1480
+ welcomeMessage: 'Bienvenue, {name} !',
1481
+ },
1482
+ };
1483
+
1484
+ function createAppComponentConfig(): ComponentConfig {
1485
+ return { id: AppComponentId, strings: appStrings, aliases: ['AppStringKey'] };
1486
+ }
1487
+
1488
+ // Create or reuse engine
1489
+ let i18nEngine: I18nEngine;
1490
+ if (I18nEngine.hasInstance('default')) {
1491
+ i18nEngine = I18nEngine.getInstance('default');
1492
+ } else {
1493
+ i18nEngine = I18nBuilder.create()
1494
+ .withLanguages(getCoreLanguageDefinitions())
1495
+ .withDefaultLanguage(LanguageCodes.EN_US)
1496
+ .withFallbackLanguage(LanguageCodes.EN_US)
1497
+ .withInstanceKey('default')
1498
+ .build();
1499
+ }
1500
+
1501
+ // Register components
1502
+ const coreReg = createCoreComponentRegistration();
1503
+ i18nEngine.registerIfNotExists({
1504
+ id: coreReg.component.id,
1505
+ strings: coreReg.strings as Record<string, Record<string, string>>,
1506
+ });
1507
+ i18nEngine.registerIfNotExists(createSuiteCoreComponentConfig());
1508
+ i18nEngine.registerIfNotExists(createEciesComponentConfig());
1509
+ i18nEngine.registerIfNotExists(createAppComponentConfig());
1510
+
1511
+ // Register branded enums
1512
+ if (!i18nEngine.hasStringKeyEnum(SuiteCoreStringKey)) {
1513
+ i18nEngine.registerStringKeyEnum(SuiteCoreStringKey);
1514
+ }
1515
+ if (!i18nEngine.hasStringKeyEnum(EciesStringKey)) {
1516
+ i18nEngine.registerStringKeyEnum(EciesStringKey);
1517
+ }
1518
+ if (!i18nEngine.hasStringKeyEnum(AppStringKey)) {
1519
+ i18nEngine.registerStringKeyEnum(AppStringKey);
1520
+ }
1521
+
1522
+ // Initialize context
1523
+ const globalContext = GlobalActiveContext.getInstance<
1524
+ CoreLanguageCode,
1525
+ IActiveContext<CoreLanguageCode>
1526
+ >();
1527
+ globalContext.createContext(LanguageCodes.EN_US, LanguageCodes.EN_US, AppComponentId);
1528
+
1529
+ // Export helpers
1530
+ export { i18nEngine };
1531
+
1532
+ export const translate = (
1533
+ name: AppStringKeyValue,
1534
+ variables?: Record<string, string | number>,
1535
+ language?: CoreLanguageCode,
1536
+ context?: LanguageContextSpace,
1537
+ ): string => {
1538
+ const activeContext =
1539
+ context ?? globalContext.getContext(AppComponentId).currentContext;
1540
+ const lang =
1541
+ language ??
1542
+ (activeContext === 'admin'
1543
+ ? globalContext.getContext(AppComponentId).adminLanguage
1544
+ : globalContext.getContext(AppComponentId).language);
1545
+ return i18nEngine.translateStringKey(name, variables, lang);
1546
+ };
1547
+
1548
+ export const safeTranslate = (
1549
+ name: AppStringKeyValue,
1550
+ variables?: Record<string, string | number>,
1551
+ language?: CoreLanguageCode,
1552
+ context?: LanguageContextSpace,
1553
+ ): string => {
1554
+ const activeContext =
1555
+ context ?? globalContext.getContext(AppComponentId).currentContext;
1556
+ const lang =
1557
+ language ??
1558
+ (activeContext === 'admin'
1559
+ ? globalContext.getContext(AppComponentId).adminLanguage
1560
+ : globalContext.getContext(AppComponentId).language);
1561
+ return i18nEngine.safeTranslateStringKey(name, variables, lang);
1562
+ };
1563
+ ```
1564
+
1565
+ </details>
1566
+
1567
+ Key points for the manual approach:
1568
+
1569
+ - **Idempotent engine creation**: `I18nEngine.hasInstance('default')` checks for an existing engine before building a new one.
1570
+ - **Core component first**: Always register the Core component before other components — it provides error message translations used internally.
1571
+ - **`registerIfNotExists`**: All component registrations use the idempotent variant so multiple packages can safely register without conflicts.
1572
+ - **`hasStringKeyEnum` guard**: Prevents duplicate enum registration when multiple setup files run in the same process.
1573
+ - **Context-aware helpers**: The `translate` and `safeTranslate` functions resolve the active language from `GlobalActiveContext`, respecting user vs. admin context.
1574
+
1575
+ ### Migration Guide
1576
+
1577
+ Converting an existing manual `i18n-setup.ts` to the factory approach is straightforward. There are no breaking changes — the factory produces the same engine state as the manual approach.
1578
+
1579
+ #### Before (manual)
1580
+
1581
+ ```typescript
1582
+ import { I18nBuilder, I18nEngine, LanguageCodes, GlobalActiveContext, ... } from '@digitaldefiance/i18n-lib';
1583
+ import { createSuiteCoreComponentConfig, SuiteCoreStringKey } from '@digitaldefiance/suite-core-lib';
1584
+ import { createEciesComponentConfig, EciesStringKey } from '@digitaldefiance/ecies-lib';
1585
+
1586
+ // ~200 lines: engine creation, core registration, library registration,
1587
+ // enum registration, context initialization, translate helpers...
1588
+ ```
1589
+
1590
+ #### After (factory)
1591
+
1592
+ ```typescript
1593
+ import { createI18nSetup, createI18nStringKeys, LanguageCodes } from '@digitaldefiance/i18n-lib';
1594
+ import { createSuiteCoreComponentPackage } from '@digitaldefiance/suite-core-lib';
1595
+ import { createEciesComponentPackage } from '@digitaldefiance/ecies-lib';
1596
+
1597
+ const i18n = createI18nSetup({
1598
+ componentId: AppComponentId,
1599
+ stringKeyEnum: AppStringKey,
1600
+ strings: appStrings,
1601
+ libraryComponents: [
1602
+ createSuiteCoreComponentPackage(),
1603
+ createEciesComponentPackage(),
1604
+ ],
1605
+ });
1606
+
1607
+ export const { engine: i18nEngine, translate, safeTranslate } = i18n;
1608
+ ```
1609
+
1610
+ #### Migration steps
1611
+
1612
+ 1. Replace `createXxxComponentConfig` imports with `createXxxComponentPackage` imports
1613
+ 2. Replace manual engine creation (`I18nBuilder` / `I18nEngine.registerIfNotExists`) with `createI18nSetup()`
1614
+ 3. Move library component registrations into the `libraryComponents` array
1615
+ 4. Remove manual `registerStringKeyEnum` calls — the factory handles them
1616
+ 5. Remove manual `GlobalActiveContext` initialization — the factory handles it
1617
+ 6. Destructure the returned `I18nSetupResult` to get `engine`, `translate`, `safeTranslate`, etc.
1618
+
1619
+ #### Notes
1620
+
1621
+ - Existing `createXxxComponentConfig()` functions remain available for consumers that prefer the manual approach
1622
+ - The factory uses the same `registerIfNotExists` pattern internally, so it is safe to mix factory and manual consumers sharing the same engine instance
1623
+ - There are no breaking changes or behavioral differences between the manual and factory approaches
1624
+
1625
+ ### createI18nStringKeys vs createI18nStringKeysFromEnum
1626
+
1627
+ Both functions produce identical `BrandedStringKeys` output. Choose based on your starting point.
1628
+
1629
+ #### createI18nStringKeys — preferred for new code
1630
+
1631
+ Creates a branded enum directly from an `as const` object literal:
1632
+
1633
+ ```typescript
1634
+ import { createI18nStringKeys } from '@digitaldefiance/i18n-lib';
1635
+
1636
+ export const AppStringKey = createI18nStringKeys('my-app', {
1637
+ Welcome: 'welcome',
1638
+ Goodbye: 'goodbye',
1639
+ } as const);
1640
+ ```
1641
+
1642
+ Use this when writing a new component from scratch. The `as const` assertion preserves literal types so each key is fully type-safe.
1643
+
1644
+ #### createI18nStringKeysFromEnum — useful for migration
1645
+
1646
+ Wraps an existing TypeScript enum into a branded enum:
1647
+
1648
+ ```typescript
1649
+ import { createI18nStringKeysFromEnum } from '@digitaldefiance/i18n-lib';
1650
+
1651
+ // Existing traditional enum
1652
+ enum LegacyStringKeys {
1653
+ Welcome = 'welcome',
1654
+ Goodbye = 'goodbye',
1655
+ }
1656
+
1657
+ export const AppStringKey = createI18nStringKeysFromEnum(
1658
+ 'my-app',
1659
+ LegacyStringKeys,
1660
+ );
1661
+ ```
1662
+
1663
+ Use this when migrating code that already has a traditional `enum`. Internally, `createI18nStringKeysFromEnum` filters out TypeScript's reverse numeric mappings and then delegates to `createI18nStringKeys`.
1664
+
1665
+ #### Comparison
1666
+
1667
+ | Aspect | `createI18nStringKeys` | `createI18nStringKeysFromEnum` |
1668
+ |---|---|---|
1669
+ | Input | Object literal with `as const` | Existing TypeScript enum |
1670
+ | Use case | New code, fresh components | Migrating existing enum-based code |
1671
+ | Output | `BrandedStringKeys<T>` | `BrandedStringKeys<T>` |
1672
+ | Internal behavior | Calls `createBrandedEnum` directly | Filters reverse numeric mappings, then delegates to `createI18nStringKeys` |
1673
+
1674
+ ### Troubleshooting: Branded Enum Module Identity in Monorepos
1675
+
1676
+ #### Symptom
1677
+
1678
+ `registerStringKeyEnum()` throws or `hasStringKeyEnum()` returns `false` for a branded enum that was created with `createI18nStringKeys` or `createI18nStringKeysFromEnum`.
1679
+
1680
+ #### Root Cause
1681
+
1682
+ `isBrandedEnum()` returns `false` when the `@digitaldefiance/branded-enum` global registry holds a different module instance. This happens when multiple copies of the package are installed — each copy has its own `WeakSet` / `Symbol` registry, so enums created by one copy are not recognized by another.
1683
+
1684
+ #### Diagnosis
1685
+
1686
+ Check for duplicate installations:
1687
+
1688
+ ```bash
1689
+ # npm
1690
+ npm ls @digitaldefiance/branded-enum
1691
+
1692
+ # yarn
1693
+ yarn why @digitaldefiance/branded-enum
1694
+ ```
1695
+
1696
+ If you see more than one resolved version (or multiple paths), the registry is split.
1697
+
1698
+ #### Solutions
1699
+
1700
+ 1. **Single version via resolutions/overrides** — pin a single version in your root `package.json`:
1701
+
1702
+ ```jsonc
1703
+ // npm (package.json)
1704
+ "overrides": {
1705
+ "@digitaldefiance/branded-enum": "<version>"
1706
+ }
1707
+
1708
+ // yarn (package.json)
1709
+ "resolutions": {
1710
+ "@digitaldefiance/branded-enum": "<version>"
1711
+ }
1712
+ ```
1713
+
1714
+ 2. **Bundler deduplication** — if you use webpack, Rollup, or esbuild, ensure the `@digitaldefiance/branded-enum` module is resolved to a single path. For webpack, the `resolve.alias` or `resolve.dedupe` options can help.
1715
+
1716
+ 3. **Consistent package resolution** — in Nx or other monorepo tools, verify that all projects resolve the same physical copy. Running `nx graph` can help visualize dependency relationships.
1717
+
1318
1718
  ## Browser Support
1319
1719
 
1320
1720
  - Chrome/Edge: Latest 2 versions (minimum: Chrome 90, Edge 90)
@@ -1500,6 +1900,28 @@ Contributions welcome! Please:
1500
1900
 
1501
1901
  ## ChangeLog
1502
1902
 
1903
+ ### Version 4.4.0
1904
+
1905
+ **Factory-Based i18n Setup & Browser-Safe Fallback**
1906
+
1907
+ This release introduces `createI18nSetup()`, a factory function that replaces ~200 lines of boilerplate per consumer with a single function call. It also adds a browser-safe fallback for `translateStringKey` when bundler-duplicated packages break Symbol-based identity checks.
1908
+
1909
+ **New Features:**
1910
+
1911
+ - **`createI18nSetup()`**: Factory function that handles engine creation, core/library/app component registration, branded enum registration, and `GlobalActiveContext` initialization in one call
1912
+ - **`I18nComponentPackage`** interface: Bundles a `ComponentConfig` with its branded string key enum so the factory can auto-register both
1913
+ - **`I18nSetupConfig`** / **`I18nSetupResult`** interfaces: Typed config input and result output for the factory
1914
+ - **`createSuiteCoreComponentPackage()`**: New function in `suite-core-lib` returning an `I18nComponentPackage`
1915
+ - **`createEciesComponentPackage()`**: New function in `ecies-lib` returning an `I18nComponentPackage`
1916
+ - **`createNodeEciesComponentPackage()`**: New function in `node-ecies-lib` returning an `I18nComponentPackage`
1917
+ - **Browser-safe fallback**: `translateStringKey` and `safeTranslateStringKey` now fall back to scanning registered components when the `StringKeyEnumRegistry` fails (e.g., due to bundler Symbol mismatch), with a lazily-built `ValueComponentLookupCache` that invalidates on new component registration
1918
+ - **Updated starter template**: `express-suite-starter` scaffolding now uses `createI18nSetup()` for minimal boilerplate
1919
+
1920
+ **Backward Compatibility:**
1921
+
1922
+ - All existing APIs (`createSuiteCoreComponentConfig`, `createEciesComponentConfig`, `I18nBuilder`, manual registration) remain unchanged
1923
+ - The factory uses the same `registerIfNotExists` pattern internally, so factory and manual consumers can safely share the same engine instance
1924
+
1503
1925
  ### Version 4.3.0
1504
1926
 
1505
1927
  **String Key Enum Registration for Direct Translation**
@@ -2623,21 +3045,6 @@ const myEngine = PluginI18nEngine.createInstance<MyLanguageCodes>('custom', lang
2623
3045
 
2624
3046
  - Wed Sep 24 2025 15:20:07 GMT-0700 (Pacific Daylight Time)
2625
3047
  - Initial release of the TypeScript internationalization library with enum translation, template processing, context management, and currency formatting.
2626
- PluginI18nEngine.resetAll();
2627
- });
2628
-
2629
- afterEach(() => {
2630
- PluginI18nEngine.resetAll();
2631
- });
2632
-
2633
- it('should translate', () => {
2634
- const engine = PluginI18nEngine.createInstance('test', languages);
2635
- engine.registerComponent(registration);
2636
- expect(engine.translate('app', 'hello')).toBe('Hello');
2637
- });
2638
- });
2639
-
2640
- ```
2641
3048
 
2642
3049
  ## TypeScript Support
2643
3050
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digitaldefiance/i18n-lib",
3
- "version": "4.3.2",
3
+ "version": "4.5.0",
4
4
  "description": "i18n library with enum translation support",
5
5
  "homepage": "https://github.com/Digital-Defiance/i18n-lib",
6
6
  "repository": {
@@ -42,7 +42,7 @@
42
42
  "license": "MIT",
43
43
  "packageManager": "yarn@4.10.3",
44
44
  "dependencies": {
45
- "@digitaldefiance/branded-enum": "0.0.6",
45
+ "@digitaldefiance/branded-enum": "0.0.7",
46
46
  "currency-codes": "^2.2.0",
47
47
  "lru-cache": "^5.1.1",
48
48
  "moment": "^2.30.1",
@@ -19,6 +19,7 @@ export declare class I18nEngine implements II18nEngine {
19
19
  private readonly config;
20
20
  private readonly aliasToComponent;
21
21
  private readonly componentKeyLookup;
22
+ private valueComponentLookupCache;
22
23
  /**
23
24
  * Constructs an I18nEngine instance, registering languages, setting defaults,
24
25
  * and optionally registering and setting this instance as default.
@@ -53,6 +54,25 @@ export declare class I18nEngine implements II18nEngine {
53
54
  * @param config - Component configuration object.
54
55
  */
55
56
  private registerComponentMetadata;
57
+ /**
58
+ * Invalidates the value-to-component lookup cache.
59
+ * Called after component registration so new keys are discoverable.
60
+ */
61
+ private invalidateValueComponentLookupCache;
62
+ /**
63
+ * Builds a cache mapping string key values to component IDs
64
+ * by scanning all registered components.
65
+ */
66
+ private buildValueComponentLookupCache;
67
+ /**
68
+ * Resolves a string key value to its component ID, falling back to
69
+ * scanning registered components when the branded enum registry fails
70
+ * (e.g., due to bundler Symbol mismatch in browser environments).
71
+ * @param stringKeyValue - The string key value to resolve.
72
+ * @returns The component ID that owns this string key.
73
+ * @throws {I18nError} If the key is not found in any registered component.
74
+ */
75
+ private resolveComponentIdWithFallback;
56
76
  /**
57
77
  * Internal: Normalizes legacy keys into snake_case lowercased.
58
78
  * @param rawKey - The raw key string to normalize.
@@ -331,8 +351,9 @@ export declare class I18nEngine implements II18nEngine {
331
351
  * will cause an error to be thrown.
332
352
  *
333
353
  * @param stringKeyEnum - Branded enum created by createI18nStringKeys
334
- * @returns The extracted component ID
335
- * @throws {I18nError} If not a valid branded enum (INVALID_STRING_KEY_ENUM)
354
+ * @param componentId - Optional explicit component ID (escape hatch for cross-module scenarios)
355
+ * @returns The extracted or provided component ID
356
+ * @throws {I18nError} If not a valid branded enum and no fallback succeeds (INVALID_STRING_KEY_ENUM)
336
357
  *
337
358
  * @example Basic registration
338
359
  * ```typescript
@@ -345,6 +366,11 @@ export declare class I18nEngine implements II18nEngine {
345
366
  * console.log(componentId); // 'user'
346
367
  * ```
347
368
  *
369
+ * @example Explicit componentId escape hatch
370
+ * ```typescript
371
+ * engine.registerStringKeyEnum(plainObj, 'user'); // 'user'
372
+ * ```
373
+ *
348
374
  * @example Idempotent registration
349
375
  * ```typescript
350
376
  * engine.registerStringKeyEnum(UserKeys); // 'user'
@@ -354,7 +380,7 @@ export declare class I18nEngine implements II18nEngine {
354
380
  * @see {@link translateStringKey} - Translate registered string key values
355
381
  * @see {@link hasStringKeyEnum} - Check if an enum is registered
356
382
  */
357
- registerStringKeyEnum(stringKeyEnum: AnyBrandedEnum): string;
383
+ registerStringKeyEnum(stringKeyEnum: AnyBrandedEnum, componentId?: string): string;
358
384
  /**
359
385
  * Translates a branded string key value directly.
360
386
  *
@@ -1 +1 @@
1
- {"version":3,"file":"i18n-engine.d.ts","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-i18n-lib/src/core/i18n-engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"i18n-engine.d.ts","sourceRoot":"","sources":["../../../../../packages/digitaldefiance-i18n-lib/src/core/i18n-engine.ts"],"names":[],"mappings":"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"}