Skip to content

@breadstone/ziegel-platform-localization ​

MIT LicenseTypeScriptnpm

Comprehensive localization and resource management for the ziegel platform. Provides localization managers, multiple providers, key resolvers, reactive localization, and advanced internationalization capabilities for enterprise applications.

Localization: Enterprise localization with multiple providers, caching, key resolution, and reactive updates for comprehensive internationalization.

πŸš€ Overview ​

@breadstone/ziegel-platform-localization provides:

  • Localization Manager: Centralized localization management and resource loading
  • Multiple Providers: Map, HTTP loader, composite, and empty providers
  • Key Resolvers: Different naming conventions (camelCase, PascalCase, snake_case, kebab-case)
  • Caching System: Efficient localization caching and performance optimization
  • Value Parsers: Format and reference parsing for complex localization strings
  • Builder Pattern: Fluent API for localization manager configuration
  • Reactive Integration: RxJS integration for reactive localization updates

πŸ“¦ Installation ​

bash
npm install @breadstone/ziegel-platform-localization
# or
yarn add @breadstone/ziegel-platform-localization

🧩 Features & Usage Examples ​

Localization Manager ​

typescript
import {
  LocalizationManager,
  ILocalizationManager,
  MapLocalizationProvider
} from '@breadstone/ziegel-platform-localization';

// Create localization resources
const englishResources = new Map([
  ['welcome.title', 'Welcome to our application'],
  ['welcome.message', 'Hello {name}, enjoy your stay!'],
  ['navigation.home', 'Home'],
  ['navigation.about', 'About'],
  ['navigation.contact', 'Contact'],
  ['forms.validation.required', 'This field is required'],
  ['forms.validation.email', 'Please enter a valid email address']
]);

const germanResources = new Map([
  ['welcome.title', 'Willkommen in unserer Anwendung'],
  ['welcome.message', 'Hallo {name}, viel Spaß beim Verweilen!'],
  ['navigation.home', 'Startseite'],
  ['navigation.about', 'Über uns'],
  ['navigation.contact', 'Kontakt'],
  ['forms.validation.required', 'Dieses Feld ist erforderlich'],
  ['forms.validation.email', 'Bitte geben Sie eine gΓΌltige E-Mail-Adresse ein']
]);

// Setup providers
const englishProvider = new MapLocalizationProvider(englishResources);
const germanProvider = new MapLocalizationProvider(germanResources);

// Create localization manager
const localizationManager: ILocalizationManager = new LocalizationManager();
localizationManager.addProvider('en', englishProvider);
localizationManager.addProvider('de', germanProvider);

// Use localization
localizationManager.setCurrentLocale('de');
const welcomeTitle = localizationManager.getString('welcome.title');
const welcomeMessage = localizationManager.getString('welcome.message', { name: 'Hans' });

console.log(welcomeTitle); // "Willkommen in unserer Anwendung"
console.log(welcomeMessage); // "Hallo Hans, viel Spaß beim Verweilen!"

Builder Pattern ​

typescript
import {
  LocalizationManagerBuilder,
  ILocalizationManagerBuilder,
  HttpLocalizationLoader
} from '@breadstone/ziegel-platform-localization';

// Build localization manager with fluent API
const builder: ILocalizationManagerBuilder = new LocalizationManagerBuilder();

const localizationManager = await builder
  .withDefaultLocale('en')
  .withFallbackLocale('en')
  .withHttpProvider('en', '/api/locales/en.json')
  .withHttpProvider('de', '/api/locales/de.json')
  .withHttpProvider('fr', '/api/locales/fr.json')
  .withCaching(true)
  .withMissingHandler((key, locale) => {
    console.warn(`Missing localization: ${key} for locale: ${locale}`);
    return `[${key}]`;
  })
  .build();

// Use the built manager
const localizedString = localizationManager.getString('app.title');

HTTP Localization Loader ​

typescript
import {
  LoaderLocalizationProvider,
  HttpLocalizationLoader,
  ILocalizationLoader
} from '@breadstone/ziegel-platform-localization';

// Create HTTP loader for dynamic resource loading
const httpLoader: ILocalizationLoader = new HttpLocalizationLoader({
  baseUrl: '/api/locales',
  format: 'json',
  cacheTtl: 3600000, // 1 hour cache
  retryAttempts: 3
});

// Create provider with loader
const loaderProvider = new LoaderLocalizationProvider(httpLoader);

// Load resources dynamically
const resources = await loaderProvider.getResources('de');
console.log('Loaded German resources:', resources);

Key Resolvers ​

typescript
import {
  CamelCaseKeyResolver,
  PascalCaseKeyResolver,
  SnakeCaseKeyResolver,
  KebabCaseKeyResolver,
  IKeyResolver
} from '@breadstone/ziegel-platform-localization';

// Different key naming conventions
const camelResolver: IKeyResolver = new CamelCaseKeyResolver();
const pascalResolver: IKeyResolver = new PascalCaseKeyResolver();
const snakeResolver: IKeyResolver = new SnakeCaseKeyResolver();
const kebabResolver: IKeyResolver = new KebabCaseKeyResolver();

// Test key transformations
const originalKey = 'user_profile_settings';

console.log('Camel:', camelResolver.resolveKey(originalKey)); // "userProfileSettings"
console.log('Pascal:', pascalResolver.resolveKey(originalKey)); // "UserProfileSettings"
console.log('Snake:', snakeResolver.resolveKey(originalKey)); // "user_profile_settings"
console.log('Kebab:', kebabResolver.resolveKey(originalKey)); // "user-profile-settings"

// Use with localization manager
localizationManager.setKeyResolver(camelResolver);

Composite Localization Provider ​

typescript
import {
  CompositeLocalizationProvider,
  MapLocalizationProvider,
  LoaderLocalizationProvider
} from '@breadstone/ziegel-platform-localization';

// Create multiple providers
const memoryProvider = new MapLocalizationProvider(new Map([
  ['app.title', 'My Application'],
  ['app.version', '1.0.0']
]));

const httpProvider = new LoaderLocalizationProvider(
  new HttpLocalizationLoader({ baseUrl: '/api/locales' })
);

// Combine providers (memory provider has priority)
const compositeProvider = new CompositeLocalizationProvider([
  memoryProvider,
  httpProvider
]);

// Provider will check memory first, then HTTP
const localizationManager = new LocalizationManager();
localizationManager.addProvider('en', compositeProvider);

Value Parsers ​

typescript
import {
  FormatLocalizationValueParser,
  RefLocalizationValueParser,
  ILocalizationValueParser
} from '@breadstone/ziegel-platform-localization';

// Format parser for interpolation
const formatParser: ILocalizationValueParser = new FormatLocalizationValueParser();

const formatResult = formatParser.parse(
  'Hello {name}, you have {count} messages',
  { name: 'John', count: 5 }
);
console.log(formatResult); // "Hello John, you have 5 messages"

// Reference parser for cross-references
const refParser: ILocalizationValueParser = new RefLocalizationValueParser();

// Setup reference resolver
refParser.setResolver((key: string) => {
  const refs = new Map([
    ['common.company', 'Acme Corp'],
    ['common.year', '2025']
  ]);
  return refs.get(key) || `[${key}]`;
});

const refResult = refParser.parse(
  'Copyright Β© {ref:common.year} {ref:common.company}',
  {}
);
console.log(refResult); // "Copyright Β© 2025 Acme Corp"

Reactive Localization ​

typescript
import { fromLocalizable, loc, localize } from '@breadstone/ziegel-platform-localization';
import { map, distinctUntilChanged } from 'rxjs/operators';

// Create localizable object
class LocalizableComponent implements ILocalizable {
  constructor(private localizationManager: ILocalizationManager) {}

  getLocalizationManager(): ILocalizationManager {
    return this.localizationManager;
  }
}

const component = new LocalizableComponent(localizationManager);

// Create reactive localization streams
const title$ = fromLocalizable(component, 'welcome.title');
const message$ = loc(component, 'welcome.message', { name: 'User' });

// Subscribe to localization changes
title$.pipe(
  distinctUntilChanged()
).subscribe(title => {
  console.log('Title updated:', title);
  document.title = title;
});

message$.pipe(
  map(msg => msg.toUpperCase())
).subscribe(message => {
  console.log('Message updated:', message);
});

// Trigger updates by changing locale
localizationManager.setCurrentLocale('de'); // Triggers reactive updates

Caching System ​

typescript
import {
  LocalizationCache,
  ILocalizationCache,
  LocalizationManager
} from '@breadstone/ziegel-platform-localization';

// Create custom cache implementation
class CustomLocalizationCache implements ILocalizationCache {
  private cache = new Map&lt;string, Map<string, string&gt;>();
  private ttl = 3600000; // 1 hour
  private timestamps = new Map&lt;string, number&gt;();

  get(locale: string): Map&lt;string, string&gt; | null {
    const timestamp = this.timestamps.get(locale);
    if (timestamp && Date.now() - timestamp > this.ttl) {
      this.cache.delete(locale);
      this.timestamps.delete(locale);
      return null;
    }
    return this.cache.get(locale) || null;
  }

  set(locale: string, resources: Map&lt;string, string&gt;): void {
    this.cache.set(locale, new Map(resources));
    this.timestamps.set(locale, Date.now());
  }

  remove(locale: string): void {
    this.cache.delete(locale);
    this.timestamps.delete(locale);
  }

  clear(): void {
    this.cache.clear();
    this.timestamps.clear();
  }

  has(locale: string): boolean {
    return this.cache.has(locale) &&
           this.timestamps.has(locale) &&
           Date.now() - this.timestamps.get(locale)! <= this.ttl;
  }
}

// Use with localization manager
const customCache = new CustomLocalizationCache();
const cachedManager = new LocalizationManager();
cachedManager.setCache(customCache);

Missing Localization Handlers ​

typescript
import {
  defaultMissingLocalizationHandler,
  emptyLocalizationHandler,
  IMissingLocalizationHandlerFunc
} from '@breadstone/ziegel-platform-localization';

// Use built-in handlers
localizationManager.setMissingHandler(defaultMissingLocalizationHandler);
// Or use empty handler
localizationManager.setMissingHandler(emptyLocalizationHandler);

// Create custom missing handler
const customMissingHandler: IMissingLocalizationHandlerFunc = (key: string, locale: string) => {
  // Log to analytics
  console.warn(`Missing localization key: ${key} for locale: ${locale}`);

  // Send to monitoring service
  fetch('/api/missing-translations', {
    method: 'POST',
    body: JSON.stringify({ key, locale, timestamp: new Date() })
  });

  // Return fallback value
  return `⚠️ ${key}`;
};

localizationManager.setMissingHandler(customMissingHandler);

πŸ“š Package Exports ​

typescript
import {
    // Core Interfaces
    ILocalizable,
    ILocalizationCache,
    ILocalizationManager,
    IMissingLocalizationHandlerFunc,

    // Manager & Builder
    LocalizationManager,
    LocalizationManagerLocator,
    ILocalizationManagerBuilder,
    LocalizationManagerBuilder,

    // Caching
    LocalizationCache,

    // Providers
    ILocalizationProvider,
    LocalizationProviderBase,
    MapLocalizationProvider,
    LoaderLocalizationProvider,
    CompositeLocalizationProvider,
    EmptyLocalizationProvider,

    // Loaders
    ILocalizationLoader,
    HttpLocalizationLoader,

    // Key Resolvers
    IKeyResolver,
    KeyResolverBase,
    CamelCaseKeyResolver,
    PascalCaseKeyResolver,
    SnakeCaseKeyResolver,
    KebabCaseKeyResolver,
    EmptyKeyResolver,

    // Value Parsers
    ILocalizationValueParser,
    FormatLocalizationValueParser,
    RefLocalizationValueParser,

    // Missing Handlers
    defaultMissingLocalizationHandler,
    emptyLocalizationHandler,

    // Reactive Extensions
    fromLocalizable,
    loc,
    localize
} from '@breadstone/ziegel-platform-localization';

πŸ”§ Advanced Usage ​

Multi-Tenant Localization ​

typescript
import { LocalizationManager, MapLocalizationProvider } from '@breadstone/ziegel-platform-localization';

class MultiTenantLocalizationService {
  private managers = new Map&lt;string, ILocalizationManager&gt;();

  getManager(tenantId: string): ILocalizationManager {
    if (!this.managers.has(tenantId)) {
      const manager = new LocalizationManager();
      this.setupTenantLocalization(manager, tenantId);
      this.managers.set(tenantId, manager);
    }
    return this.managers.get(tenantId)!;
  }

  private async setupTenantLocalization(manager: ILocalizationManager, tenantId: string): Promise&lt;void&gt; {
    // Load tenant-specific resources
    const resources = await this.loadTenantResources(tenantId);

    for (const [locale, localeResources] of resources) {
      const provider = new MapLocalizationProvider(localeResources);
      manager.addProvider(locale, provider);
    }
  }

  private async loadTenantResources(tenantId: string): Promise&lt;Map&lt;string, Map<string, string&gt;&gt;> {
    // Load from tenant-specific API endpoint
    const response = await fetch(`/api/tenants/${tenantId}/locales`);
    const data = await response.json();

    const resources = new Map&lt;string, Map<string, string&gt;>();
    for (const [locale, translations] of Object.entries(data)) {
      resources.set(locale, new Map(Object.entries(translations as Record&lt;string, string&gt;)));
    }

    return resources;
  }
}

Lazy Loading with Namespaces ​

typescript
class NamespacedLocalizationManager {
  private loadedNamespaces = new Set<string&gt;();

  constructor(private manager: ILocalizationManager) {}

  async getString(key: string, params?: Record&lt;string, any&gt;): Promise&lt;string&gt; {
    const namespace = this.extractNamespace(key);

    if (!this.loadedNamespaces.has(namespace)) {
      await this.loadNamespace(namespace);
      this.loadedNamespaces.add(namespace);
    }

    return this.manager.getString(key, params);
  }

  private extractNamespace(key: string): string {
    return key.split('.')[0];
  }

  private async loadNamespace(namespace: string): Promise&lt;void&gt; {
    const response = await fetch(`/api/locales/${this.manager.getCurrentLocale()}/${namespace}.json`);
    const resources = await response.json();

    const resourceMap = new Map&lt;string, string&gt;();
    for (const [key, value] of Object.entries(resources)) {
      resourceMap.set(`${namespace}.${key}`, value as string);
    }

    const provider = new MapLocalizationProvider(resourceMap);
    this.manager.addProvider(this.manager.getCurrentLocale(), provider);
  }
}

🎯 Integration Examples ​

React Hook Integration ​

typescript
import React, { createContext, useContext, useEffect, useState } from 'react';
import { ILocalizationManager } from '@breadstone/ziegel-platform-localization';

interface LocalizationContextValue {
  manager: ILocalizationManager;
  locale: string;
  t: (key: string, params?: Record&lt;string, any&gt;) => string;
  setLocale: (locale: string) => void;
}

const LocalizationContext = createContext<LocalizationContextValue | null&gt;(null);

export function LocalizationProvider({
  children,
  manager
}: {
  children: React.ReactNode;
  manager: ILocalizationManager;
}) {
  const [locale, setLocale] = useState(manager.getCurrentLocale());

  const t = (key: string, params?: Record&lt;string, any&gt;) => {
    return manager.getString(key, params);
  };

  const handleSetLocale = (newLocale: string) => {
    manager.setCurrentLocale(newLocale);
    setLocale(newLocale);
  };

  return (
    <LocalizationContext.Provider value={{ manager, locale, t, setLocale: handleSetLocale }}>
      {children}
    </LocalizationContext.Provider&gt;
  );
}

export function useLocalization() {
  const context = useContext(LocalizationContext);
  if (!context) {
    throw new Error('useLocalization must be used within LocalizationProvider');
  }
  return context;
}

// Usage in component
function MyComponent() {
  const { t, locale, setLocale } = useLocalization();

  return (
    <div&gt;
      <h1>{t('welcome.title')}</h1>
      <p&gt;{t('welcome.message', { name: 'World' })}</p&gt;
      <select value={locale} onChange={(e) => setLocale(e.target.value)}>
        <option value="en">English</option&gt;
        <option value="de">Deutsch</option&gt;
        <option value="fr">FranΓ§ais</option&gt;
      </select&gt;
    </div&gt;
  );
}

πŸ“š API Documentation ​

For detailed API documentation, visit: API Docs

  • @breadstone/ziegel-intl: Core internationalization utilities
  • @breadstone/ziegel-platform: Core platform services
  • @breadstone/ziegel-rx: Reactive extensions
  • @breadstone/ziegel-core: Foundation utilities

License ​

MIT

Issues ​

Please report bugs and feature requests in the Issue Tracker


Part of the ziegel Enterprise TypeScript Framework } from '@ziegel/platform-localization';

// Configure dynamic loading const loader = new DynamicResourceLoader({ strategy: ResourceLoadingStrategy.OnDemand, preloadLocales: ['en', 'de'], chunkSize: 50, // Load 50 keys at a time retryPolicy: { maxRetries: 3, backoffFactor: 2 } });

// Load specific namespaces await loader.loadNamespace('common', 'de'); await loader.loadNamespace('forms', 'de');

// Preload critical resources await loader.preloadCritical(['navigation', 'errors']);


### Locale Detection

```typescript
import {
  LocaleDetector,
  DetectionStrategy
} from '@ziegel/platform-localization';

// Configure locale detection
const detector = new LocaleDetector({
  strategies: [
    DetectionStrategy.QueryParameter,
    DetectionStrategy.LocalStorage,
    DetectionStrategy.Navigator,
    DetectionStrategy.AcceptLanguage
  ],
  fallback: 'en',
  cache: true
});

// Detect user locale
const detectedLocale = await detector.detect();
console.log('Detected locale:', detectedLocale);

// Manual locale setting with persistence
await detector.setLocale('de-DE', { persist: true });

Advanced Features ​

Interpolation and Formatting ​

typescript
import {
  Translator,
  InterpolationEngine,
  FormatterRegistry
} from '@ziegel/platform-localization';

// Configure custom formatters
const formatters = new FormatterRegistry();
formatters.register('currency', (value, locale, options) => {
  return new Intl.NumberFormat(locale, {
    style: 'currency',
    currency: options.currency || 'EUR'
  }).format(value);
});

formatters.register('relative', (value, locale) => {
  return new Intl.RelativeTimeFormat(locale).format(value.amount, value.unit);
});

// Create translator with advanced interpolation
const translator = new Translator({
  interpolation: new InterpolationEngine({
    formatters,
    escapeHtml: true,
    maxNestingDepth: 3
  })
});

// Use advanced formatting
const message = translator.translate('product.price', {
  price: { value: 29.99, currency: 'EUR' },
  discount: { amount: -2, unit: 'day' }
});
// Result: "Price: €29.99 (offer ends 2 days ago)"

Pluralization ​

typescript
import {
  PluralResolver,
  PluralRule
} from '@ziegel/platform-localization';

// Configure pluralization rules
const pluralResolver = new PluralResolver({
  rules: {
    en: PluralRule.Simple, // one, other
    de: PluralRule.Simple,
    ru: PluralRule.Complex, // zero, one, few, many, other
    ar: PluralRule.Arabic   // zero, one, two, few, many, other
  }
});

// Define pluralized resources
const resources = {
  en: {
    items: {
      zero: 'No items',
      one: '1 item',
      other: '{{count}} items'
    }
  },
  ru: {
    items: {
      zero: 'НСт элСмСнтов',
      one: '{{count}} элСмСнт',
      few: '{{count}} элСмСнта',
      many: '{{count}} элСмСнтов',
      other: '{{count}} элСмСнта'
    }
  }
};

// Use pluralization
const translator = new Translator({ pluralResolver });
console.log(translator.translate('items', { count: 0 })); // "No items"
console.log(translator.translate('items', { count: 1 })); // "1 item"
console.log(translator.translate('items', { count: 5 })); // "5 items"

Context-Aware Translation ​

typescript
import {
  ContextualTranslator,
  TranslationContext
} from '@ziegel/platform-localization';

// Define context-aware translations
const contextualResources = {
  en: {
    save: {
      button: 'Save',
      'button_urgent': 'Save Now!',
      'menu_item': 'Save File',
      'shortcut': 'Ctrl+S'
    }
  }
};

// Create contextual translator
const translator = new ContextualTranslator({
  resources: contextualResources,
  contextResolver: (key, context) => {
    if (context.component === 'button' && context.priority === 'urgent') {
      return `${key}_urgent`;
    }
    if (context.component) {
      return `${key}_${context.component}`;
    }
    return key;
  }
});

// Use with context
const buttonText = translator.translate('save', {
  component: 'button',
  priority: 'urgent'
}); // "Save Now!"

Hooks and React Integration ​

Core Hooks ​

typescript
import {
  useLocalization,
  useTranslation,
  useLocale,
  useResourceLoader
} from '@ziegel/platform-localization';

function MyComponent() {
  // Main localization hook
  const { t, locale, setLocale, isReady } = useLocalization();

  // Translation-only hook
  const translate = useTranslation();

  // Locale management hook
  const {
    currentLocale,
    availableLocales,
    switchLocale,
    isSupported
  } = useLocale();

  // Resource loading hook
  const {
    loadResources,
    isLoading,
    loadedNamespaces
  } = useResourceLoader();

  useEffect(() => {
    loadResources(['forms', 'validation']);
  }, [loadResources]);

  return (
    <div&gt;
      <h1>{t('welcome')}</h1>
      <button onClick={() => switchLocale('de')}>
        Deutsch
      </button&gt;
    </div&gt;
  );
}

Advanced Hooks ​

typescript
import {
  useTranslationWithFallback,
  useInterpolatedTranslation,
  usePluralTranslation
} from '@ziegel/platform-localization';

function AdvancedComponent({ items, user }) {
  // Translation with fallback
  const tWithFallback = useTranslationWithFallback({
    fallbackLocale: 'en',
    fallbackNamespace: 'common'
  });

  // Interpolated translation
  const tInterpolated = useInterpolatedTranslation({
    formatters: ['currency', 'date', 'relative']
  });

  // Plural translation
  const tPlural = usePluralTranslation();

  return (
    <div&gt;
      <h1>{tWithFallback('greeting', { name: user.name })}</h1>
      <p&gt;{tInterpolated('lastSeen', { date: user.lastSeen })}</p&gt;
      <span&gt;{tPlural('itemCount', { count: items.length })}</span&gt;
    </div&gt;
  );
}

Configuration Options ​

typescript
interface LocalizationConfig {
  // Core settings
  defaultLocale: string;
  supportedLocales: string[];
  fallbackLocale?: string;

  // Resource loading
  resourceLoader: {
    type: 'static' | 'dynamic' | 'hybrid';
    basePath?: string;
    format?: 'json' | 'yaml' | 'po';
    loader?: ResourceLoader;
  };

  // Detection
  detection: {
    strategies: DetectionStrategy[];
    caching: boolean;
    cookieName?: string;
    storageKey?: string;
  };

  // Interpolation
  interpolation: {
    prefix: string;
    suffix: string;
    escapeValue: boolean;
    formatters: FormatterRegistry;
  };

  // Pluralization
  pluralization: {
    resolver: PluralResolver;
    keyGenerator: (key: string, count: number) => string;
  };

  // Performance
  performance: {
    lazy: boolean;
    preload: string[];
    caching: CacheConfig;
    debounceMs: number;
  };

  // Development
  development: {
    debug: boolean;
    missingKeyHandler: (locale: string, key: string) => void;
    saveMissing: boolean;
  };
}

Best Practices ​

Resource Organization ​

typescript
// Organize by feature/domain
const resourceStructure = {
  common: {
    navigation: {},
    buttons: {},
    forms: {}
  },
  features: {
    auth: {},
    dashboard: {},
    settings: {}
  },
  errors: {
    validation: {},
    network: {},
    business: {}
  }
};

// Use consistent naming conventions
const namingConventions = {
  keys: 'camelCase',
  namespaces: 'kebab-case',
  files: 'kebab-case.json'
};

Performance Optimization ​

typescript
// Lazy load non-critical resources
const optimizedConfig = createLocalizationConfig({
  performance: {
    lazy: true,
    preload: ['common', 'navigation'],
    caching: {
      strategy: 'lru',
      maxSize: 100,
      ttl: 3600000
    }
  },
  resourceLoader: {
    type: 'dynamic',
    chunkSize: 25,
    compression: true
  }
});

// Implement resource splitting
const splitResources = {
  critical: ['navigation', 'errors'],
  secondary: ['forms', 'tooltips'],
  tertiary: ['help', 'documentation']
};

Testing ​

typescript
import {
  createMockLocalizationProvider,
  MockResourceLoader
} from '@ziegel/platform-localization/testing';

describe('Localization', () => {
  let provider: LocalizationProvider;

  beforeEach(() => {
    const mockLoader = new MockResourceLoader({
      en: { welcome: 'Welcome' },
      de: { welcome: 'Willkommen' }
    });

    provider = createMockLocalizationProvider({
      defaultLocale: 'en',
      resourceLoader: mockLoader
    });
  });

  it('should translate correctly', async () => {
    await provider.setLocale('de');
    const translation = provider.translate('welcome');
    expect(translation).toBe('Willkommen');
  });

  it('should handle missing keys gracefully', () => {
    const translation = provider.translate('missing.key');
    expect(translation).toBe('missing.key');
  });
});

Migration Guide ​

From react-i18next ​

typescript
// Old: react-i18next
import { useTranslation } from 'react-i18next';

function Component() {
  const { t, i18n } = useTranslation();
  return <h1>{t('welcome')}</h1>;
}

// New: ziegel-platform-localization
import { useLocalization } from '@ziegel/platform-localization';

function Component() {
  const { t, setLocale } = useLocalization();
  return <h1>{t('welcome')}</h1>;
}

Configuration Migration ​

typescript
// Old: i18next config
i18next.init({
  lng: 'en',
  fallbackLng: 'en',
  resources: {
    en: { translation: require('./en.json') }
  }
});

// New: ziegel config
const config = createLocalizationConfig({
  defaultLocale: 'en',
  fallbackLocale: 'en',
  resourceLoader: {
    type: 'static',
    resources: {
      en: require('./en.json')
    }
  }
});

API Reference ​

For detailed API documentation, see the auto-generated API reference.