Skip to content

Digital-Defiance/i18n-lib

Repository files navigation

@digitaldefiance/i18n-lib

A production-ready TypeScript internationalization library with component-based architecture, type-safe translations, and comprehensive error handling.

Part of Express Suite

Features

  • Production-Grade Security: Comprehensive protection against common attacks
    • Prototype pollution prevention
    • ReDoS (Regular Expression Denial of Service) mitigation
    • XSS (Cross-Site Scripting) protection with HTML escaping
    • Input validation with configurable limits
    • Bounded resource usage (cache, recursion, input length)
  • ICU MessageFormat: Industry-standard message formatting with plural, select, date/time/number formatting
  • Component-Based Architecture: Register translation components with full type safety
  • 37 Supported Languages: CLDR-compliant plural rules for world's most complex languages
  • Pluralization Support: Automatic plural form selection based on count (one/few/many/other)
  • Gender Support: Gender-aware translations (male/female/neutral/other)
  • Advanced Number Formatting: Thousand separators, currency, percent with decimal precision
  • 8 Built-in Languages: English (US/UK), French, Spanish, German, Chinese, Japanese, Ukrainian
  • Advanced Template Processing:
    • Component references: {{Component.key}}
    • Alias resolution: {{Alias.key}}
    • Enum name resolution: {{EnumName.value}}
    • Variable substitution: {variable}
    • Context variables: {currency}, {timezone}, {language}
  • Context Integration: Automatic injection of currency, timezone, and language from GlobalActiveContext
  • Smart Object Handling: CurrencyCode and Timezone objects automatically extract values
  • Multiple Instances: Create isolated i18n engines for different contexts
  • Fluent Builder: I18nBuilder for clean, chainable engine configuration
  • Core System Strings: Pre-built translations for common UI elements and errors
  • Type Safety: Full TypeScript support with generic types
  • Error Handling: Comprehensive error classes with translation support and ICU formatting
  • 93.22% Test Coverage: 1,738 tests covering all features
  • Security Hardened: See SECURITY.md for details

Installation

npm install @digitaldefiance/i18n-lib
# or
yarn add @digitaldefiance/i18n-lib

Quick Start

import { PluginI18nEngine, LanguageCodes } from '@digitaldefiance/i18n-lib';

// Create engine with languages
const engine = PluginI18nEngine.createInstance('myapp', [
  { id: LanguageCodes.EN_US, name: 'English (US)', code: 'en-US', isDefault: true },
  { id: LanguageCodes.FR, name: 'Français', code: 'fr' }
]);

// Register component with translations
engine.registerComponent({
  component: {
    id: 'app',
    name: 'Application',
    stringKeys: ['welcome', 'goodbye']
  },
  strings: {
    [LanguageCodes.EN_US]: {
      welcome: 'Welcome to {appName}!',
      goodbye: 'Goodbye!'
    },
    [LanguageCodes.FR]: {
      welcome: 'Bienvenue sur {appName}!',
      goodbye: 'Au revoir!'
    }
  }
});

// Translate
console.log(engine.translate('app', 'welcome', { appName: 'MyApp' }));
// Output: "Welcome to MyApp!"

// Switch language
engine.setLanguage(LanguageCodes.FR);
console.log(engine.translate('app', 'welcome', { appName: 'MyApp' }));
// Output: "Bienvenue sur MyApp!"

// Pluralization (automatic form selection)
engine.register({
  id: 'cart',
  strings: {
    'en-US': {
      items: {
        one: '1 item',
        other: '{count} items'
      }
    }
  }
});

console.log(engine.translate('cart', 'items', { count: 1 }));
// Output: "1 item"
console.log(engine.translate('cart', 'items', { count: 5 }));
// Output: "5 items"

ICU MessageFormat

Industry-standard message formatting with powerful features. See @docs/ICU_MESSAGEFORMAT.md for complete guide.

Quick Example

import { formatICUMessage } from '@digitaldefiance/i18n-lib';

// Simple variable
formatICUMessage('Hello {name}', { name: 'Alice' });
// → "Hello Alice"

// Plural
formatICUMessage('{count, plural, one {# item} other {# items}}', { count: 1 });
// → "1 item"

// Select
formatICUMessage('{gender, select, male {He} female {She} other {They}}', { gender: 'male' });
// → "He"

// Number formatting
formatICUMessage('{price, number, currency}', { price: 99.99 }, 'en-US');
// → "$99.99"

// Complex nested
formatICUMessage(
  '{gender, select, male {He has} female {She has}} {count, plural, one {# item} other {# items}}',
  { gender: 'female', count: 2 }
);
// → "She has 2 items"

Features

  • Full ICU Syntax: Variables, plural, select, selectordinal
  • Formatters: Number (integer, currency, percent), Date, Time
  • 37 Languages: CLDR plural rules for all supported languages
  • Nested Messages: Up to 4 levels deep
  • Performance: <1ms per format, message caching
  • Specification Compliant: Unicode ICU, CLDR, FormatJS compatible

Documentation

API

import { 
  formatICUMessage,      // One-line formatting
  isICUMessage,          // Detect ICU format
  parseICUMessage,       // Parse to AST
  compileICUMessage,     // Compile to function
  validateICUMessage,    // Validate syntax
  Runtime                // Advanced usage
} from '@digitaldefiance/i18n-lib';

Pluralization & Gender

Pluralization

Automatic plural form selection based on count with CLDR-compliant rules for 37 languages:

import { createPluralString } from '@digitaldefiance/i18n-lib';

// English (one/other)
engine.register({
  id: 'shop',
  strings: {
    'en-US': {
      items: createPluralString({
        one: '{count} item',
        other: '{count} items'
      })
    }
  }
});

// Russian (one/few/many)
engine.register({
  id: 'shop',
  strings: {
    'ru': {
      items: createPluralString({
        one: '{count} товар',
        few: '{count} товара',
        many: '{count} товаров'
      })
    }
  }
});

// Arabic (zero/one/two/few/many/other)
engine.register({
  id: 'shop',
  strings: {
    'ar': {
      items: createPluralString({
        zero: 'لا عناصر',
        one: 'عنصر واحد',
        two: 'عنصران',
        few: '{count} عناصر',
        many: '{count} عنصرًا',
        other: '{count} عنصر'
      })
    }
  }
});

// Automatic form selection
engine.translate('shop', 'items', { count: 1 });  // "1 item"
engine.translate('shop', 'items', { count: 5 });  // "5 items"
engine.translate('shop', 'items', { count: 21 }, 'ru'); // "21 товар"

Supported Languages (37 total):

  • Simple (other only): Japanese, Chinese, Korean, Turkish, Vietnamese, Thai, Indonesian, Malay
  • Two forms (one/other): English, German, Spanish, Italian, Portuguese, Dutch, Swedish, Norwegian, Danish, Finnish, Greek, Hebrew, Hindi
  • Three forms (one/few/many): Russian, Ukrainian, Romanian, Latvian
  • Four forms: Polish, Czech, Lithuanian, Slovenian, Scottish Gaelic
  • Five forms: Irish, Breton
  • Six forms: Arabic, Welsh

See PLURALIZATION_SUPPORT.md for complete language matrix.

Gender Support

Gender-aware translations with intelligent fallback:

import { createGenderedString } from '@digitaldefiance/i18n-lib';

engine.register({
  id: 'profile',
  strings: {
    'en-US': {
      greeting: createGenderedString({
        male: 'Welcome, Mr. {name}',
        female: 'Welcome, Ms. {name}',
        neutral: 'Welcome, {name}'
      })
    }
  }
});

engine.translate('profile', 'greeting', { name: 'Smith', gender: 'male' });
// Output: "Welcome, Mr. Smith"

Combined Plural + Gender

Nested plural and gender forms:

// Plural → Gender
const pluralGender = {
  one: {
    male: 'He has {count} item',
    female: 'She has {count} item'
  },
  other: {
    male: 'He has {count} items',
    female: 'She has {count} items'
  }
};

// Gender → Plural
const genderPlural = {
  male: {
    one: 'He has {count} item',
    other: 'He has {count} items'
  },
  female: {
    one: 'She has {count} item',
    other: 'She has {count} items'
  }
};

Helper Functions

import { 
  createPluralString, 
  createGenderedString, 
  getRequiredPluralForms 
} from '@digitaldefiance/i18n-lib';

// Get required forms for a language
const forms = getRequiredPluralForms('ru');
// Returns: ['one', 'few', 'many']

// Type-safe plural string creation
const plural = createPluralString({
  one: '1 item',
  other: '{count} items'
});

// Type-safe gender string creation
const gender = createGenderedString({
  male: 'He',
  female: 'She',
  neutral: 'They'
});

Validation

import { validatePluralForms } from '@digitaldefiance/i18n-lib';

// Validate plural forms for a language
const result = validatePluralForms(
  { one: 'item', other: 'items' },
  'en',
  'items',
  { strict: true, checkUnused: true, checkVariables: true }
);

if (!result.isValid) {
  console.error('Errors:', result.errors);
}
if (result.warnings.length > 0) {
  console.warn('Warnings:', result.warnings);
}

Core Concepts

PluginI18nEngine

The main engine class that manages translations, languages, and components.

import { PluginI18nEngine, LanguageCodes } from '@digitaldefiance/i18n-lib';

// Create instance
const engine = PluginI18nEngine.createInstance('myapp', languages);

// Or use constructor
const engine = new PluginI18nEngine(languages, config);

Component Registration

Components group related translations together:

engine.registerComponent({
  component: {
    id: 'auth',
    name: 'Authentication',
    stringKeys: ['login', 'logout', 'error']
  },
  strings: {
    [LanguageCodes.EN_US]: {
      login: 'Login',
      logout: 'Logout',
      error: 'Authentication failed'
    },
    [LanguageCodes.FR]: {
      login: 'Connexion',
      logout: 'Déconnexion',
      error: 'Échec de l\'authentification'
    }
  },
  aliases: ['authentication'] // Optional aliases
});

// Safe registration (won't error if already registered)
engine.registerComponentIfNotExists({
  component: { id: 'auth', /* ... */ },
  strings: { /* ... */ }
});

Translation

// Simple translation
const text = engine.translate('auth', 'login');

// With variables
const greeting = engine.translate('app', 'welcome', { name: 'John' });

// Specific language
const french = engine.translate('auth', 'login', {}, LanguageCodes.FR);

// Safe translation (returns fallback on error)
const safe = engine.safeTranslate('missing', 'key'); // Returns "[missing.key]"

Template Processing

// Component references: {{componentId.stringKey}}
engine.t('Click {{auth.login}} to continue');

// Alias resolution: {{alias.stringKey}}
engine.registerComponent({
  component: { id: 'authentication', /* ... */ },
  aliases: ['auth', 'AuthModule']
});
engine.t('{{auth.login}}'); // Resolves via alias

// Variables: {variableName}
engine.t('Hello, {username}!', { username: 'Alice' });

// Context variables (automatic injection)
engine.t('Price in {currency}'); // Uses context currency
engine.t('Time: {timezone}'); // Uses context timezone
engine.t('Language: {language}'); // Uses current language

// CurrencyCode and Timezone objects
const currency = new CurrencyCode('EUR');
const timezone = new Timezone('America/New_York');
engine.t('Price: {amount} {currency}', { amount: 100, currency });
// Output: "Price: 100 EUR"

// Variable priority: provided > context > constants
engine.t('{AppName}'); // Uses constant
engine.t('{currency}'); // Uses context
engine.t('{currency}', { currency: 'GBP' }); // Uses provided (overrides context)

// Mixed patterns
engine.t('{{auth.login}}: {username} ({currency})', { username: 'admin' });

Builder Pattern

import { I18nBuilder } from '@digitaldefiance/i18n-lib';

const engine = I18nBuilder.create()
  .withLanguages([
    { id: 'en-US', name: 'English', code: 'en-US', isDefault: true },
    { id: 'fr', name: 'French', code: 'fr' }
  ])
  .withDefaultLanguage('en-US')
  .withFallbackLanguage('en-US')
  .withConstants({
    AppName: 'MyApp',
    Version: '1.0.0'
  })
  .withValidation({
    requireCompleteStrings: false,
    allowPartialRegistration: true
  })
  .withInstanceKey('myapp')
  .withRegisterInstance(true)
  .withSetAsDefault(true)
  .build();

Context Integration

import { GlobalActiveContext, CurrencyCode, Timezone } from '@digitaldefiance/i18n-lib';

// Set context variables
const context = GlobalActiveContext.getInstance();
context.setCurrencyCode(new CurrencyCode('EUR'));
context.setUserTimezone(new Timezone('Europe/Paris'));
context.setUserLanguage('fr');

// Context variables automatically available in translations
engine.t('Price in {currency}'); // "Price in EUR"
engine.t('Timezone: {timezone}'); // "Timezone: Europe/Paris"
engine.t('Language: {language}'); // "Language: fr"

// Override context with provided variables
engine.t('Price in {currency}', { currency: 'USD' }); // "Price in USD"

Constants Management

// Merge constants (adds/overwrites specific keys)
engine.mergeConstants({ Version: '2.0', NewKey: 'value' });
// Existing constants preserved, specified ones added/updated

// Update all constants (replaces everything)
engine.updateConstants({ Site: 'NewSite', Version: '2.0' });
// All previous constants removed, only these remain

Language Management

// Set current language
engine.setLanguage(LanguageCodes.FR);

// Get current language
const lang = engine.getCurrentLanguage();

// Check if language exists
if (engine.hasLanguage(LanguageCodes.ES)) {
  engine.setLanguage(LanguageCodes.ES);
}

// Get all languages
const languages = engine.getLanguages();

Admin Context

Separate language for admin interfaces:

// Set admin language
engine.setAdminLanguage(LanguageCodes.EN_US);

// Switch to admin context
engine.switchToAdmin();

// Switch back to user context
engine.switchToUser();

Core System Strings

Pre-built translations for common UI elements:

import { getCoreI18nEngine, CoreStringKey, CoreI18nComponentId } from '@digitaldefiance/i18n-lib';

const coreEngine = getCoreI18nEngine();

// Use core strings
const yes = coreEngine.translate(CoreI18nComponentId, CoreStringKey.Common_Yes);
const error = coreEngine.translate(CoreI18nComponentId, CoreStringKey.Error_NotFound);

Available core string categories:

  • Common: Yes, No, Cancel, OK, Save, Delete, Edit, Create, Update, Loading, etc.
  • Errors: InvalidInput, NetworkError, NotFound, AccessDenied, ValidationFailed, etc.
  • System: Welcome, Goodbye, PleaseWait, ProcessingRequest, OperationComplete, etc.

Multiple Instances

Create isolated engines for different parts of your application:

// Admin engine
const adminEngine = PluginI18nEngine.createInstance('admin', adminLanguages);

// User engine
const userEngine = PluginI18nEngine.createInstance('user', userLanguages);

// Get instance by key
const admin = PluginI18nEngine.getInstance('admin');

// Check if instance exists
if (PluginI18nEngine.hasInstance('admin')) {
  // ...
}

// Remove instance
PluginI18nEngine.removeInstance('admin');

// Reset all instances
PluginI18nEngine.resetAll();

Error Handling

RegistryError

Errors related to component/language registration:

import { RegistryError, RegistryErrorType } from '@digitaldefiance/i18n-lib';

try {
  engine.translate('missing', 'key');
} catch (error) {
  if (error instanceof RegistryError) {
    console.log(error.type);     // RegistryErrorType.COMPONENT_NOT_FOUND
    console.log(error.message);  // "Component 'missing' not found"
    console.log(error.metadata); // { componentId: 'missing' }
  }
}

TranslatableError

Base class for errors with translated messages:

import { TranslatableError, CoreStringKey, CoreI18nComponentId } from '@digitaldefiance/i18n-lib';

class MyError extends TranslatableError {
  constructor(language?: string) {
    super(
      CoreI18nComponentId,
      CoreStringKey.Error_AccessDenied,
      {},
      language
    );
  }
}

throw new MyError(LanguageCodes.FR); // Throws with French error message

Translation Adapter

Adapt PluginI18nEngine to simpler TranslationEngine interface:

import { createTranslationAdapter } from '@digitaldefiance/i18n-lib';

const adapter = createTranslationAdapter(engine, 'componentId');

// Use adapter where TranslationEngine is expected
const message = adapter.translate('key', { var: 'value' });

Language Codes

Built-in language codes following BCP 47 standard:

import { LanguageCodes } from '@digitaldefiance/i18n-lib';

LanguageCodes.EN_US  // 'en-US'
LanguageCodes.EN_GB  // 'en-GB'
LanguageCodes.FR     // 'fr'
LanguageCodes.ES     // 'es'
LanguageCodes.DE     // 'de'
LanguageCodes.ZH_CN  // 'zh-CN'
LanguageCodes.JA     // 'ja'
LanguageCodes.UK     // 'uk'

API Reference

PluginI18nEngine

Static Methods

  • createInstance<TLanguage>(key: string, languages: LanguageDefinition[], config?: RegistryConfig) - Create named instance
  • getInstance<TLanguage>(key?: string) - Get instance by key
  • hasInstance(key?: string) - Check if instance exists
  • removeInstance(key?: string) - Remove instance
  • resetAll() - Reset all instances

Instance Methods

  • registerComponent(registration: ComponentRegistration) - Register component
  • translate(componentId: string, key: string, variables?, language?) - Translate string
  • safeTranslate(componentId: string, key: string, variables?, language?) - Safe translate with fallback
  • t(template: string, variables?, language?) - Process template string
  • setLanguage(language: TLanguage) - Set current language
  • setAdminLanguage(language: TLanguage) - Set admin language
  • getCurrentLanguage() - Get current language
  • getLanguages() - Get all languages
  • hasLanguage(language: TLanguage) - Check if language exists
  • switchToAdmin() - Switch to admin context
  • switchToUser() - Switch to user context
  • validate() - Validate all components

Core Functions

  • getCoreI18nEngine() - Get core engine with system strings
  • createCoreI18nEngine(instanceKey?) - Create core engine instance
  • getCoreTranslation(stringKey, variables?, language?, instanceKey?) - Get core translation
  • safeCoreTranslation(stringKey, variables?, language?, instanceKey?) - Safe core translation
  • getCoreLanguageCodes() - Get array of core language codes
  • getCoreLanguageDefinitions() - Get core language definitions

Testing

import { PluginI18nEngine } from '@digitaldefiance/i18n-lib';

describe('My Tests', () => {
  beforeEach(() => {
    PluginI18nEngine.resetAll();
  });

  afterEach(() => {
    PluginI18nEngine.resetAll();
  });

  it('should translate', () => {
    const engine = PluginI18nEngine.createInstance('test', languages);
    engine.registerComponent(registration);
    expect(engine.translate('app', 'hello')).toBe('Hello');
  });
});

TypeScript Support

Full TypeScript support with generic types:

// Type-safe language codes
type MyLanguages = 'en-US' | 'fr' | 'es';
const engine = PluginI18nEngine.createInstance<MyLanguages>('app', languages);

// Type-safe string keys
enum MyStringKeys {
  Welcome = 'welcome',
  Goodbye = 'goodbye'
}

// Type-safe component registration
const registration: ComponentRegistration<MyStringKeys, MyLanguages> = {
  component: {
    id: 'app',
    name: 'App',
    stringKeys: Object.values(MyStringKeys)
  },
  strings: {
    'en-US': {
      [MyStringKeys.Welcome]: 'Welcome',
      [MyStringKeys.Goodbye]: 'Goodbye'
    },
    'fr': {
      [MyStringKeys.Welcome]: 'Bienvenue',
      [MyStringKeys.Goodbye]: 'Au revoir'
    }
  }
};

Browser Support

  • Chrome/Edge: Latest 2 versions
  • Firefox: Latest 2 versions
  • Safari: Latest 2 versions
  • Node.js: 18+

License

MIT License - See LICENSE file for details

Contributing

Contributions welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass (npm test)
  5. Submit a pull request

Support

ChangeLog

Version 3.7.5

Type Safety Improvements Release

This release eliminates all unsafe type casts from the production codebase, improving type safety and maintainability.

Type Safety Enhancements:

  • New SimpleTypedError Class: Introduced a type-safe error class (simple-typed-error.ts) that properly extends Error without using type casts

    • Supports type, componentId, reasonMap, metadata properties with full type safety
    • Includes error cause chaining (ES2022 standard)
    • Provides isTypedError() type guard and fromError() conversion utility
    • Maintains proper prototype chain for instanceof checks
  • Refactored Error Helper Functions: Updated all error creation helpers to use SimpleTypedError

    • createComponentTypedError() - Now returns SimpleTypedError instead of casting properties
    • createCoreTypedError() - Type-safe error creation for core system errors
    • createTranslatedError() - Type-safe translated error creation
    • All functions now have proper return types without as any casts
  • Fixed Empty Object Initializations: Replaced {} as any with proper Partial<T> types

    • buildTypeSafeReasonMap() in utils.ts now uses proper partial types
    • ensureAllLanguagesHaveAllKeys() in component-registry.ts uses type-safe initialization
  • Improved Enum Translation Type Safety: Enhanced type safety in enum registry and plural handling

    • Enum registry now uses String() conversion instead of as any casts
    • Added type guards for PluralCategory validation in hasPluralForm()
    • Fixed getPluralCategory() return type to properly return PluralCategory
    • Removed unsafe casts in plural category handling
  • Global Context Type Safety: Leveraged ambient type declarations for global objects

    • Removed (globalThis as any).GlobalActiveContext casts
    • Uses ambient declarations from types/global.d.ts for type-safe global access
    • Fixed Proxy pattern in core-i18n.ts to use proper keyof access
  • Enhanced I18n Engine Interface: Created comprehensive engine type definitions

    • New src/types/engine.ts with generic II18nEngine<TStringKeys> interface
    • Proper generic constraints for type-safe string key handling
    • Re-exports main II18nEngine interface for centralized imports
  • Renamed for Clarity: Improved naming to avoid confusion

    • Renamed abstract TypedError to AbstractTypedError (with deprecation notice)
    • New SimpleTypedError class is the recommended type-safe implementation
    • Maintains backward compatibility with existing code

Code Quality:

  • Zero Type Casts: Eliminated approximately 20 instances of as any and as unknown casts from production code
  • Improved Type Inference: Better TypeScript type inference throughout the codebase
  • Enhanced Maintainability: Clearer code structure with explicit types instead of casts

Testing:

  • Added comprehensive unit tests for SimpleTypedError class
  • Added property-based tests using fast-check for error property preservation
  • Created type-safety-fixes.spec.ts with tests for all improvements
  • All existing tests continue to pass with enhanced type safety

Documentation:

  • Updated JSDoc comments with proper type information
  • Added deprecation notices for legacy patterns
  • Improved code examples in documentation

Migration Notes:

This release is fully backward compatible. Existing code will continue to work unchanged. To use the new type-safe patterns:

// New: Use SimpleTypedError directly
import { TypedError } from '@digitaldefiance/i18n-lib/errors/simple-typed-error';

const error = new TypedError('Error message', {
  type: 'validation',
  componentId: 'my-component',
  metadata: { field: 'email' }
});

// Old abstract classes still work (now called AbstractTypedError)
// Helper functions automatically use the new SimpleTypedError internally

Breaking Changes:

None - This release maintains full backward compatibility while improving internal type safety.

Version 3.8.0

Internal Refactoring Release - Circular Dependency Elimination

This release eliminates all circular dependencies from the codebase through internal architectural improvements. All changes are non-breaking and maintain full backward compatibility.

Internal Improvements:

  • Zero Circular Dependencies: Eliminated all 15 circular dependencies that existed in the codebase

    • Broke core/i18n-engine ↔ core-i18n cycle
    • Broke errors/translatable → core/i18n-engine → errors/index cycle
    • Broke core-i18n ↔ plugin-i18n-engine cycle
    • Broke context-related cycles
    • Broke registry-error cycles
    • Optimized barrel exports with type-only exports
  • Lazy Initialization Pattern: Error classes and core modules now use lazy initialization to avoid circular dependencies

    • TranslatableError uses getInstance() at construction time instead of module load
    • TypedError and related classes use lazy engine lookup
    • Registry errors use lazy initialization for core dependencies
    • Fallback behavior if engine not initialized
  • Factory Pattern: Introduced core-plugin-factory.ts to break plugin engine cycles

    • createCorePluginI18nEngine() moved to factory file
    • Factory imports both core-i18n and plugin-i18n-engine
    • Breaks circular dependency between these modules
  • Type-Only Exports: Optimized barrel exports to eliminate runtime dependencies

    • src/interfaces/index.ts uses export type for all type exports
    • src/errors/index.ts split into base.ts and translatable-exports.ts
    • src/core/index.ts uses type-only exports where appropriate
  • Module Organization: Established clear dependency hierarchy

    • Interfaces & Types (no implementation dependencies)
    • Error Classes (lazy initialization for i18n)
    • Core Modules (clear hierarchy, no cycles)
    • High-Level Modules (core-i18n, plugin-i18n-engine)

Testing & Quality:

  • Automated Circular Dependency Detection: Added test that fails if circular dependencies are introduced
  • Module Independence Tests: Verify modules can be imported independently
  • All Tests Passing: 1,779 tests passing with no regressions
  • Zero Breaking Changes: Public API remains completely unchanged

Documentation:

  • CIRCULAR_DEPENDENCY_FIXES.md - Comprehensive internal documentation
    • Detailed explanation of all patterns used
    • Best practices for maintaining zero circular dependencies
    • Examples of lazy initialization, factory pattern, and type-only exports
    • Guidelines for adding new modules without creating cycles

Files Modified:

  • src/core-plugin-factory.ts - New factory file for plugin engine creation
  • src/core-i18n.ts - Lazy initialization with Proxy pattern
  • src/errors/*.ts - Lazy initialization in error constructors
  • src/errors/index.ts - Split into separate barrel files
  • src/interfaces/index.ts - Type-only exports
  • src/core/index.ts - Optimized barrel exports
  • src/registry-error.ts - Lazy initialization for core dependencies
  • tests/circular-dependencies.spec.ts - Automated detection test

Breaking Changes:

None - This release is fully backward compatible. All changes are internal refactoring only.

Migration:

No migration required! Your existing code works unchanged. The improvements are entirely internal.

Benefits:

  • Improved Maintainability: Clearer module structure and dependencies
  • Better Tree-Shaking: Reduced runtime dependencies improve bundle optimization
  • Predictable Initialization: No more initialization order issues
  • Future-Proof: Established patterns prevent circular dependencies from being reintroduced

Version 3.7.2

  • Minor version bump to fix an export

Version 3.7.1

  • Minor version bump to fix an export

Version 3.7.0

Comprehensive ICU Integration & Number Formatting Enhancements

Enhanced all I18nError methods and core ICU infrastructure to fully leverage 3.5.0 advanced ICU MessageFormat features:

Core Infrastructure Improvements:

  • ICU Compiler Enhancements:

    • Fixed # placeholder in plural/selectordinal to use Intl.NumberFormat with thousand separators
    • Numbers in plural messages now properly formatted (1,500 instead of 1500)
    • Locale-aware formatting respects regional preferences
  • Number Formatter Upgrades:

    • Percent formatting now shows decimal precision (0-2 places): 5.67% instead of 5%
    • Integer formatting maintains thousand separators automatically
    • Currency formatting preserves decimal places with locale-specific symbols

Enhanced Error Methods (13 existing + 4 new):

Enhanced Existing Methods:

  • componentNotFound() - ICU select for namespaced components
  • stringKeyNotFound() - SelectOrdinal for nested depth levels
  • duplicateComponent() - Nested select for namespace context
  • instanceNotFound() - Select for default vs named instances
  • instanceExists() - Nested select with detailed messages
  • translationMissing() - Nested select detecting key paths
  • duplicateLanguage() - Template literal with proper quoting
  • pluralFormNotFound() - Nested select + plural + number formatting (form count)
  • invalidPluralCategory() - Nested plural + number formatting (category count)
  • And 4 more existing methods with ICU enhancements...

New Advanced Methods:

  • validationThresholdExceeded() - Number formatting: Currency ($1,500.50), Percent (5.67%), Integer (1,500)
  • operationStepFailed() - SelectOrdinal: 1st, 2nd, 3rd, 4th, 21st, 22nd, 23rd...
  • rateLimitExceeded() - 4-level nested messages: Plural + number + select with thousand separators
  • nestedValidationError() - Complex nesting: Multiple select + plural for validation context

ICU Features Fully Integrated:

  • Number Formatters: Currency ($1,500.50), percent (5.67%), integer (1,500) with thousand separators

  • SelectOrdinal: Ordinal formatting (1st, 2nd, 3rd, 21st, 22nd, 23rd)

  • Nested Messages: Up to 4 levels deep with combined plural, select, and number formatting

  • ICU Plural: # placeholder now formats with thousand separators

  • ICU Select: Nested within plural messages for complex conditional logic

  • Decimal Precision: Percent values show up to 2 decimal places

  • Locale-Aware: All formatting respects target language/locale

  • Real-World Use Cases:

    • Validation threshold errors with formatted currency/percentages
    • Multi-step operation failures with ordinal step numbers
    • Rate limiting with nested request counts and retry timing
    • Complex nested field validation with severity levels

Testing & Quality:

  • 1,738 total tests passing (93.22% coverage)
  • 250+ new tests for advanced ICU features:
    • Currency formatting: $1,500.50, €1.500,50, ¥1,500
    • Percent precision: 5.67%, 0.5%, 100%
    • SelectOrdinal: 1st-100th with edge cases (11th, 21st, 22nd, 23rd)
    • Nested messages: 4 levels deep validation
    • Thousand separators: 1,000, 10,000, 1,000,000
    • Multilingual: 8+ languages tested
    • Real-world scenarios: API rate limits, validation thresholds, multi-step operations

Documentation:

  • All error methods include comprehensive JSDoc with ICU pattern examples
  • EnhancedErrorHelper base class with static utility methods
  • Integration patterns for all error class types
  • Migration guide showing before/after message formats

New Error Codes:

  • VALIDATION_THRESHOLD_EXCEEDED - Numeric threshold violations with formatted values
  • OPERATION_STEP_FAILED - Step-based operation failures with ordinal formatting
  • RATE_LIMIT_EXCEEDED - Rate limiting with nested plural/number formatting
  • NESTED_VALIDATION_ERROR - Complex nested validation with 4-level messages

Files Modified:

  • src/icu/compiler.ts - Enhanced # placeholder with Intl.NumberFormat
  • src/icu/formatters/number-formatter.ts - Added percent decimal precision (0-2 places)
  • src/errors/i18n-error.ts - Enhanced all 17 error methods with ICU patterns
  • src/errors/enhanced-error-base.ts - New base class with static helper methods
  • src/errors/*.ts - Enhanced 8 error classes with comprehensive JSDoc
  • tests/errors/*.spec.ts - 250+ new tests, updated expectations

Breaking Changes:

None - Fully backward compatible! All changes are enhancements:

  • Enhanced error message formats (more detailed, better formatted)
  • Metadata structure extended (formCount, count added where useful)
  • New optional parameters for advanced error methods
  • All existing code continues to work unchanged

Migration:

No migration required! Your existing code works as-is. To use new features:

// Use new number formatting in errors
const error = I18nError.validationThresholdExceeded(
  'price', 99.99, 50.00, 'currency', 'en-US'
);
// Message: "Validation failed for price: value $99.99 exceeds maximum threshold of $50.00"

// Use selectordinal for steps
const error = I18nError.operationStepFailed(3, 'deployment', 'Connection timeout');
// Message: "Operation 'deployment' failed at 3rd step: Connection timeout"

// Numbers in plural messages now have thousand separators automatically
const error = I18nError.rateLimitExceeded(1500, 1000, 3600, 300);
// Message: "Rate limit exceeded: 1,500 requests made, exceeding limit of 1,000..."

Version 3.6.4

  • Add DefaultLanguageCode

Version 3.6.3

  • make getCodeLabelMap() not readonly

Version 3.6.2

  • Add getCodeLabelMap() for use with react components
  • Add documentation jsdocs

Version 3.6.1

  • Upgrade currency-codes

Version 3.6.0

Security Hardening Release

  • Prototype Pollution Prevention: Validates all object keys, filters dangerous properties
  • ReDoS Mitigation: Limited regex patterns, input length validation
  • XSS Protection: HTML escaping option, safe type coercion
  • Input Validation: Length limits, character whitelisting
  • Resource Limits: LRU cache (1000 entries), recursion depth (10), message length (10000)
  • 101 New Tests: Comprehensive security test coverage
  • New Utilities: safe-object, html-escape, validation, lru-cache
  • Documentation: SECURITY.md, SECURITY_AUDIT.md, SECURITY_FIXES_COMPLETE.md

Version 3.5.0

Major Feature Release - ICU MessageFormat Support

New Features:

  • ICU MessageFormat: Full industry-standard message formatting

    • Parser with 6 AST node types (MESSAGE, LITERAL, ARGUMENT, PLURAL, SELECT, SELECTORDINAL)
    • Tokenizer with sophisticated depth tracking
    • Semantic validator with configurable options
    • Message compiler (AST → executable function)
    • Runtime with message caching
    • 304 tests passing (100%)
  • Formatters: 6 built-in formatters

    • NumberFormatter (integer, currency, percent)
    • DateFormatter (short, medium, long, full)
    • TimeFormatter (short, medium, long, full)
    • PluralFormatter (37 languages via CLDR)
    • SelectFormatter
    • SelectOrdinalFormatter
    • FormatterRegistry (pluggable system)
  • Helper Functions: Easy-to-use utilities

    • formatICUMessage() - One-line formatting
    • isICUMessage() - Detect ICU format
    • parseICUMessage() - Parse to AST
    • compileICUMessage() - Compile to function
    • validateICUMessage() - Validate syntax
  • Advanced Features:

    • Nested messages (4 levels tested)
    • Missing value handling
    • Performance optimization (<1ms/format)
    • Memory-efficient caching
    • Multilingual validation (12 languages, 6 writing systems)

Documentation:

Testing:

  • 304 ICU tests passing (100%)
  • Specification compliance (Unicode ICU, CLDR)
  • Industry compatibility (React Intl, Vue I18n, Angular)
  • Edge case coverage (nesting, Unicode, RTL, special chars)
  • Performance validation (<1ms, 1000 formats in <100ms)

Migration:

// Use ICU MessageFormat
import { formatICUMessage } from '@digitaldefiance/i18n-lib';

formatICUMessage('Hello {name}', { name: 'Alice' });
formatICUMessage('{count, plural, one {# item} other {# items}}', { count: 1 });

Version 3.0.0

Major Feature Release - Pluralization & Gender Support

New Features:

  • CLDR Pluralization: Full support for 37 languages with automatic plural form selection

    • 19 unique plural rule implementations (English, Russian, Arabic, Polish, French, Spanish, Japanese, Ukrainian, Chinese, German, Scottish Gaelic, Welsh, Breton, Slovenian, Czech, Lithuanian, Latvian, Irish, Romanian)
    • 18 additional languages reusing existing rules
    • Handles world's most complex plural systems (Arabic 6 forms, Welsh 6 forms, Breton 5 forms)
    • Intelligent fallback: requested form → 'other' → first available
    • Type-safe PluralString type with backward compatibility
  • Gender Support: Gender-aware translations with 4 categories

    • Gender categories: male, female, neutral, other
    • GenderedString type for type-safe gender forms
    • Intelligent fallback: requested → neutral → other → first available
    • Works seamlessly with pluralization
  • Combined Plural + Gender: Nested plural and gender resolution

    • Supports both plural→gender and gender→plural nesting
    • Full fallback support for missing forms
    • Works with all 37 supported languages
  • Validation System: Comprehensive plural form validation

    • validatePluralForms() - Validates required forms per language
    • validateCountVariable() - Ensures count variable exists
    • Strict and lenient modes
    • Variable consistency checking
    • Unused form detection
  • Helper Functions: Utilities for easy plural/gender string creation

    • createPluralString() - Type-safe plural object creation
    • createGenderedString() - Type-safe gender object creation
    • getRequiredPluralForms() - Get required forms for any language
  • Error Handling: New error codes for pluralization

    • PLURAL_FORM_NOT_FOUND - Missing plural form with suggestions
    • INVALID_PLURAL_CATEGORY - Invalid category with valid options
    • MISSING_COUNT_VARIABLE - Count variable missing when plurals used

Documentation:

Testing:

  • 348 tests passing (92% of roadmap target)
  • 100% coverage on pluralization, gender, and validation code
  • Comprehensive edge case testing
  • Integration tests for complex scenarios

Migration:

// Simple strings continue to work unchanged
engine.register({
  id: 'app',
  strings: {
    'en-US': {
      title: 'My App'  // Still works
    }
  }
});

// Add pluralization
import { createPluralString } from '@digitaldefiance/i18n-lib';

engine.register({
  id: 'cart',
  strings: {
    'en-US': {
      items: createPluralString({
        one: '{count} item',
        other: '{count} items'
      })
    }
  }
});

// Use with count variable
engine.translate('cart', 'items', { count: 5 });
// Output: "5 items"

Version 2.1.40

  • Alignment

Version 2.1.32

  • Expose config instead of constants

Version 2.1.31

  • Add constants param to i18n creation

Version 2.1.30

  • Version alignment bump

Version 2.1.25

  • Improve test coverage

Version 2.1.16

  • Add static registerIfNotExists to i8nengine

Version 2.1.15

  • Add registerIfNotExists() method to I18nEngine for safe component registration
  • Add registerComponentIfNotExists() method to PluginI18nEngine
  • Prevents "Component already registered" errors when reusing engine instances

Version 2.1.12

  • Add constants updateConstants mergeConstants functions to engine

Version 2.1.10

  • Convergence bump

Version 2.1.6

  • Minor update to expose core keys via V2 engine

Version 2.1.5

  • Minor timezone/currency export fix

Version 2.1.4

  • Version bump

Version 2.1.1

  • Minor fix, set this.name in errors

Version 2.1.0 (December 2025)

Moderate Feature Release - Enhanced I18nEngine with context variables, comprehensive testing, and improved architecture

New Features:

  • Context Variable Injection: Automatic injection of timezone, currency, and language from GlobalActiveContext
    • t() function now supports {currency}, {timezone}, {language}, {adminLanguage}, etc.
    • CurrencyCode and Timezone objects automatically extract their values
    • Variable priority: provided variables > context variables > constants
  • Enhanced t() Function: Complete template processing with multiple resolution strategies
    • {{Component.key}} - Component reference resolution
    • {{Alias.key}} - Alias resolution for components
    • {{EnumName.key}} - Enum name resolution
    • {variable} - Variable substitution with context awareness
    • Mixed patterns supported in single template
  • Object Value Extraction: Smart handling of wrapper objects
    • CurrencyCode objects: .value and .code getters
    • Timezone objects: .value and .name getters
    • Generic objects with .value property automatically extracted
  • I18nBuilder: Fluent builder pattern for engine creation
    • withLanguages(), withConstants(), withValidation()
    • withInstanceKey(), withRegisterInstance(), withSetAsDefault()
    • Method chaining for clean configuration
  • Renamed Classes: Removed "Plugin" prefix for clarity
    • PluginTypedErrorComponentTypedError (with backward compatibility alias)
    • createPluginTypedError()createComponentTypedError()
    • Old names deprecated but still functional

Improved:

  • Test Coverage: Increased from 87.81% to 91.81% overall
    • string-utils: 0% → 100%
    • typed.ts: 48.68% → 83.17%
    • i18n-builder: 61.53% → 86.66%
    • 714 total tests (all passing)
  • Error Translation: All error classes now properly translate messages
    • TypedError, TypedHandleableError, TranslatableError
    • Multi-language support with template variables
    • Context-aware language selection
  • Type Safety: Enhanced generic types throughout
    • Better inference for component IDs and string keys
    • Stricter validation at compile time
  • Documentation: Comprehensive test examples for all features
    • t() function special cases
    • Context variable integration
    • Error translation patterns
    • Builder pattern usage

Fixed:

  • TranslatableError now requires componentId as first parameter (breaking change)
  • I18nError.stringKeyNotFound() method added
  • CurrencyCode error now uses correct TranslatableError signature
  • Variable substitution in templates now works with all object types
  • Context variables properly override constants

Testing:

  • Added comprehensive test suites:
    • t-function.spec.ts - All t() function capabilities
    • error-translation.spec.ts - Error class translation
    • context-integration.spec.ts - Context variable injection
    • string-utils.spec.ts - String utility functions
    • i18n-builder.spec.ts - Builder pattern
    • typed-helpers.spec.ts - Typed error helpers

Migration Notes:

// Old TranslatableError signature
new TranslatableError(stringKey, variables, language);

// New signature (v2.1.0)
new TranslatableError(componentId, stringKey, variables, language);

// Context variables now automatically available in t()
engine.t('Price: {currency}'); // Uses context currency
engine.t('Price: {currency}', { currency: 'EUR' }); // Override with provided

// CurrencyCode and Timezone objects work seamlessly
const currency = new CurrencyCode('USD');
engine.translate('app', 'price', { currency }); // Extracts 'USD'

Version 2.0.3

  • Export error classes

Version 2.0.2

  • Version bump

Version 2.0.1

  • Minor bugfix

Version 2.0.0

Major Release - Architecture improvements and bug fixes

Fixed:

  • Fixed RegistryError.createWithEngine to use correct parameter order (removed redundant componentId parameter)
  • Fixed PluginTranslatableGenericError.withEngine to accept engine as first parameter instead of instanceKey
  • Fixed LanguageRegistry.getMatchingCode to check and return language codes instead of IDs
  • Fixed createTranslationAdapter to support both full TranslationEngine interface and simplified bound interface
  • Fixed TypedError constructor to use correct componentId parameter
  • Added missing Common_Test to CoreStringKey enum
  • Fixed mock TranslationEngine signatures in tests to include componentId parameter

Improved:

  • Enhanced createTranslationAdapter with dual interface support (4-param and 3-param calling conventions)
  • Improved JSDoc documentation for createTranslationAdapter with usage examples
  • Added French language support to typed-error tests
  • Updated all test files to use v2 LanguageRegistry APIs
  • Added PluginI18nEngine.resetAll() calls in test beforeEach hooks for better isolation

Internal:

  • Refactored core-i18n.ts to use lazy initialization pattern with Proxy for backward compatibility
  • Updated error classes to use getCoreI18nEngine() instead of direct singleton import
  • Fixed duplicate LanguageRegistry exports by commenting out v1 export
  • Added v1 compatibility methods to v2 LanguageRegistry
  • Changed getDefault() to return LanguageDefinition | null instead of throwing

Testing:

  • All 511 tests passing
  • Fixed registry-error.spec.ts mock expectations
  • Fixed language-registry.spec.ts to handle null default language
  • Fixed create-translation-adapter.spec.ts parameter detection
  • Fixed typed-error.spec.ts to import and use PluginI18nEngine

Version 1.3.27

  • Version bump
  • Fix plugin engine to pass constants to templates as legacy engine did

Version 1.3.20

  • Version bump

Version 1.3.17

  • Skip 1.3.16 for homogenization
  • Add component registration aliases for t() func
  • Update readme

Version 1.3.15

  • Improve constructor for default instances
  • Update README

Version 1.3.14

  • Re-export with js again

Version 1.3.13

  • Migrate to es2022/nx monorepo

Version 1.3.12

  • Update typed-handleable to plugin i18n

Version 1.3.11

  • Export i18nconfig

Version 1.3.10

  • Add UnifiedTranslator

Version 1.3.9

  • Add more handleable/typed classes

Version 1.3.8

  • Add TypedHandleable

Version 1.3.7

  • Add handleable at i18n level
  • Add TranslatableGenericHandleable at i18n level

Version 1.3.6

  • Simplify LanguageContextSpace and generics related to it
  • Make plugin engine respect admin context

Version 1.3.5

  • CommonJS

Version 1.3.4

  • Deprecate clearAllInstances

Version 1.3.3

  • Make LanguageRegistry static

Version 1.3.2

  • Add functionality to Language Registry for getMatchingLanguageCode

Version 1.3.1

  • Changed: CoreLanguageCode is now string - Language Registry is single source of truth
    • Use LanguageRegistry.getLanguageIds() for runtime validation
    • Use getCoreLanguageCodes() for static arrays (Mongoose schemas, etc.)
    • Runtime validation via registry, not compile-time types
  • Added: getCoreLanguageCodes() - Get core language codes as runtime array
  • Added: getCoreLanguageDefinitions() - Get core language definitions
  • Philosophy: Registry-based validation over hardcoded types
  • Benefit: Maximum flexibility - add languages without code changes

Version 1.2.5

  • Sat Oct 25 2025 15:01:00 GMT-0700 (Pacific Daylight Time)

Added

  • createTranslationAdapter - Generic utility function to adapt PluginI18nEngine instances to the TranslationEngine interface, enabling seamless integration with error classes and other components expecting the simpler interface
    • Maintains full type safety with generic string key and language types
    • Provides graceful error handling with fallback to key strings
    • Zero overhead - direct delegation to underlying PluginI18nEngine
    • Comprehensive test coverage (19 tests)
    • Supports both full TranslationEngine interface and simplified bound interface

Benefits

  • Eliminates need for custom adapter implementations in consuming packages
  • Standardizes translation engine integration across the monorepo
  • Simplifies error class constructors that require translation engines

Migration

Packages using custom translation adapters can now replace them with:

import { createTranslationAdapter } from '@digitaldefiance/i18n-lib';
const adapter = createTranslationAdapter(pluginEngine, 'component-id');

Version 1.2.4

  • Sat Oct 25 2025 14:29:00 GMT-0700 (Pacific Daylight Time)
    • Remove StringLanguage generic for TLanguage in GlobalActiveLanguage

Version 1.2.3

  • Thu Oct 23 2025 18:50:00 GMT-0700 (Pacific Daylight Time)
    • Minor update to fix safeTranslate being private

Version 1.2.2

  • Thu Oct 23 2025 18:40:00 GMT-0700 (Pacific Daylight Time)

i18n Library - TranslationEngine Interface Refactoring

  • Made TranslationEngine interface generic with TStringKey type parameter for improved type safety
  • Changed translate and safeTranslate methods from optional to required in TranslationEngine interface
  • Exported TranslationEngine from typed-error.ts for consistent usage across packages
  • Updated TypedHandleableError in ecies-lib to use generic TranslationEngine<TStringKey> instead of inline interface types
  • Updated test mocks to implement both required translate and safeTranslate methods

Breaking Changes:

  • Any code implementing TranslationEngine must now provide both translate and safeTranslate methods (previously optional)
  • TranslationEngine now requires explicit type parameter when used (e.g., TranslationEngine<EciesStringKey>)

Version 1.2.1

  • Thu Oct 23 2025 15:10:00 GMT-0700 (Pacific Daylight Time)
    • Update README

Version 1.2.0

  • Thu Oct 23 2025 14:13:00 GMT-0700 (Pacific Daylight Time)

Breaking Changes

  • Removed CoreLanguage enum - Replaced with CoreLanguageCode type and LanguageCodes constants
  • Language identifiers now use BCP 47 codes - Changed from descriptive names (e.g., 'English (US)') to standard codes (e.g., 'en-US')
  • API changes:
    • CoreLanguageCoreLanguageCode (union type)
    • DefaultLanguage enum → DefaultLanguageCode type
    • All language references updated to use LanguageCodes constants

Added

  • LanguageCodes constants object - Provides standard BCP 47 language codes:
    • EN_US, EN_GB, FR, ES, DE, ZH_CN, JA, UK
  • LanguageDisplayNames mapping - Maps language codes to human-readable names
  • CommonLanguageCode type - Type for built-in language codes
  • LanguageCode type - Generic string type for custom language codes
  • Custom language code support - Any string can now be used as a language code

Changed

  • Language code format - All language identifiers now use BCP 47 standard (e.g., 'en-US' instead of 'English (US)')
  • Type system - Languages are now string-based types instead of enums, allowing custom language codes
  • Documentation - Updated README with new API usage examples and language code constants

Migration Guide

// Before (v1.1.x)
import { CoreLanguage } from '@digitaldefiance/i18n-lib';
i18n.setLanguage(CoreLanguage.French);

// After
import { LanguageCodes } from '@digitaldefiance/i18n-lib';
i18n.setLanguage(LanguageCodes.FR);

// Extending with custom language codes
type MyLanguageCodes = CoreLanguageCode | 'pt-BR' | 'it';
const myEngine = PluginI18nEngine.createInstance<MyLanguageCodes>('custom', languages);

Version 1.1.10

  • Fri Oct 17 2025 15:02:00 GMT-0700 (Pacific Daylight Time)
    • Add String

Version 1.1.9

  • Fri Oct 17 2025 14:44:00 GMT-0700 (Pacific Daylight Time)
    • Add String

Version 1.1.8

  • Wed Oct 15 2025 16:43:00 GMT-0700 (Pacific Daylight Time)
    • Fix to translatable prototype inheritance

Version 1.1.7

  • Wed Oct 15 2025 16:13:00 GMT-0700 (Pacific Daylight Time) Fixed:
    • Corrected safeCoreTranslation fallback format to use [CoreStringKey.${stringKey}]
    • Fixed import issues with DefaultInstanceKey Added:
      • New TranslatableGenericError class for generic translatable errors across any component
      • CoreI18nComponentId constant export
      • 130+ new tests for comprehensive coverage
      • Complete usage documentation Changed:
      • Standardized all fallback formats to use square brackets [componentId.stringKey]
      • Refactored to use CoreI18nComponentId constant All tests pass and backward compatibility is maintained.

Version 1.1.6

  • Tue Oct 14 2025 17:04:00 GMT-0700 (Pacific Daylight Time)
    • Added missing T function to i18n plugin engine

Version 1.1.5

  • Tue Oct 14 2025 14:48:00 GMT-0700 (Pacific Daylight Time)
    • [Current] HotFix for GlobalActiveContext
      • Fixed getInstance method to throw RegistryError when instance not found instead of auto-creating instances
    • Improved test reliability and proper error handling for non-existent instances
    • Updated API documentation to reflect error-throwing behavior

Version 1.1.4

  • Tue Oct 14 2025 14:21:00 GMT-0700 (Pacific Daylight Time)
    • Removed duplicate parallel RegistryContext and focused on GlobalActiveContext

Version 1.1.3

  • Tue Oct 14 2025 14:00:00 GMT-0700 (Pacific Daylight Time)
    • Added GlobalActiveContext class instead of plain object

Version 1.1.2

  • Sat Oct 11 2025 19:25:00 GMT-0700 (Pacific Daylight Time)
    • Added cleanup mechanisms for other modules to deregister, etc.

Version 1.1.1

  • Sat Oct 11 2025 17:47:00 GMT-0700 (Pacific Daylight Time)
    • Improved type checking for completeness of component translations during registration
    • Updated README/Migration guide for clarity.

Version 1.1.0

  • Sat Oct 11 2025 16:49:00 GMT-0700 (Pacific Daylight Time)
    • Introduced plugin-based architecture with component registration and compile-time type safety
    • Added PluginI18nEngine with comprehensive validation and fallback system
    • Maintained full support for legacy I18nEngine
    • Added pre-built core and user system components
    • Enhanced template processing and context management features
    • Improved documentation and examples for both architectures

Version 1.0.33

  • Wed Sep 24 2025 15:20:07 GMT-0700 (Pacific Daylight Time)

    • Initial release of the TypeScript internationalization library with enum translation, template processing, context management, and currency formatting. PluginI18nEngine.resetAll(); });

    afterEach(() => { PluginI18nEngine.resetAll(); });

    it('should translate', () => { const engine = PluginI18nEngine.createInstance('test', languages); engine.registerComponent(registration); expect(engine.translate('app', 'hello')).toBe('Hello'); }); });


## TypeScript Support

Full TypeScript support with generic types:

```typescript
// Type-safe language codes
type MyLanguages = 'en-US' | 'fr' | 'es';
const engine = PluginI18nEngine.createInstance<MyLanguages>('app', languages);

// Type-safe string keys
enum MyStringKeys {
  Welcome = 'welcome',
  Goodbye = 'goodbye'
}

// Type-safe component registration
const registration: ComponentRegistration<MyStringKeys, MyLanguages> = {
  component: {
    id: 'app',
    name: 'App',
    stringKeys: Object.values(MyStringKeys)
  },
  strings: {
    'en-US': {
      [MyStringKeys.Welcome]: 'Welcome',
      [MyStringKeys.Goodbye]: 'Goodbye'
    },
    'fr': {
      [MyStringKeys.Welcome]: 'Bienvenue',
      [MyStringKeys.Goodbye]: 'Au revoir'
    }
  }
};

Browser Support

  • Chrome/Edge: Latest 2 versions
  • Firefox: Latest 2 versions
  • Safari: Latest 2 versions
  • Node.js: 18+

Testing

Testing Approach

The i18n-lib package uses a comprehensive testing strategy combining unit tests, integration tests, and property-based testing to ensure correctness across all features.

Test Framework: Jest with TypeScript support
Property-Based Testing: fast-check for testing universal properties
Coverage Target: 90%+ statement coverage, 85%+ branch coverage

Test Structure

tests/
  ├── unit/              # Unit tests for individual components
  ├── integration/       # Integration tests for component interactions
  ├── property/          # Property-based tests using fast-check
  └── fixtures/          # Test data and mock translations

Running Tests

# Run all tests
npm test

# Run with coverage
npm test -- --coverage

# Run specific test file
npm test -- plugin-i18n-engine.spec.ts

# Run in watch mode
npm test -- --watch

Test Patterns

Testing Translation Registration

import { PluginI18nEngine, LanguageCodes } from '@digitaldefiance/i18n-lib';

describe('Component Registration', () => {
  let engine: PluginI18nEngine;

  beforeEach(() => {
    PluginI18nEngine.resetAll();
    engine = PluginI18nEngine.createInstance('test', [
      { id: LanguageCodes.EN_US, name: 'English', code: 'en-US', isDefault: true }
    ]);
  });

  afterEach(() => {
    PluginI18nEngine.resetAll();
  });

  it('should register component with translations', () => {
    engine.registerComponent({
      component: {
        id: 'test',
        name: 'Test',
        stringKeys: ['hello']
      },
      strings: {
        [LanguageCodes.EN_US]: {
          hello: 'Hello, {name}!'
        }
      }
    });

    expect(engine.translate('test', 'hello', { name: 'World' }))
      .toBe('Hello, World!');
  });
});

Testing ICU MessageFormat

import { formatICUMessage } from '@digitaldefiance/i18n-lib';

describe('ICU MessageFormat', () => {
  it('should format plural messages', () => {
    const message = '{count, plural, one {# item} other {# items}}';
    
    expect(formatICUMessage(message, { count: 1 })).toBe('1 item');
    expect(formatICUMessage(message, { count: 5 })).toBe('5 items');
  });

  it('should handle nested select and plural', () => {
    const message = '{gender, select, male {He has} female {She has}} {count, plural, one {# item} other {# items}}';
    
    expect(formatICUMessage(message, { gender: 'female', count: 2 }))
      .toBe('She has 2 items');
  });
});

Testing Error Handling

import { RegistryError, RegistryErrorType } from '@digitaldefiance/i18n-lib';

describe('Error Handling', () => {
  it('should throw RegistryError for missing component', () => {
    expect(() => {
      engine.translate('missing', 'key');
    }).toThrow(RegistryError);
  });

  it('should provide error metadata', () => {
    try {
      engine.translate('missing', 'key');
    } catch (error) {
      expect(error).toBeInstanceOf(RegistryError);
      expect(error.type).toBe(RegistryErrorType.COMPONENT_NOT_FOUND);
      expect(error.metadata).toEqual({ componentId: 'missing' });
    }
  });
});

Property-Based Testing

import * as fc from 'fast-check';
import { createPluralString } from '@digitaldefiance/i18n-lib';

describe('Pluralization Properties', () => {
  it('should always return a string for any count', () => {
    fc.assert(
      fc.property(fc.integer(), (count) => {
        const plural = createPluralString({
          one: '{count} item',
          other: '{count} items'
        });
        
        const result = engine.translate('test', 'items', { count });
        expect(typeof result).toBe('string');
        expect(result.length).toBeGreaterThan(0);
      })
    );
  });
});

Testing Best Practices

  1. Always reset engine state between tests using PluginI18nEngine.resetAll()
  2. Test with multiple languages to ensure translations work correctly
  3. Test edge cases like empty strings, special characters, and missing variables
  4. Use property-based tests for testing universal properties across many inputs
  5. Mock external dependencies when testing error conditions

Cross-Package Testing

When testing packages that depend on i18n-lib:

import { PluginI18nEngine } from '@digitaldefiance/i18n-lib';
import { YourService } from 'your-package';

describe('Service with i18n', () => {
  beforeEach(() => {
    // Set up i18n engine for your service
    PluginI18nEngine.resetAll();
    const engine = PluginI18nEngine.createInstance('test', languages);
    // Register your component translations
  });

  afterEach(() => {
    PluginI18nEngine.resetAll();
  });

  it('should use translated error messages', () => {
    const service = new YourService();
    expect(() => service.doSomething()).toThrow(/translated message/);
  });
});

License

MIT License - See LICENSE file for details

Contributing

Contributions welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass (npm test)
  5. Submit a pull request

Support


Version: 2.0.0 Status: Production Ready
Bundle Size: ~25KB (minified + gzipped)

About

Digital Defiance TypeScript Internationalization Library

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages