API Reference
Complete API documentation for @angular-translation-service/core.
TranslationService
The core service providing reactive i18n for Angular applications. Inject via Angular DI.
select<K extends string>(scope: K): Signal<Record<string, unknown> | undefined>
Returns a scope signal for template access. Automatically triggers lazy loading for the namespace. Data is undefined until the namespace loads, then returns a proxy-wrapped dictionary for safe deep property access.
protected readonly common = this.i18n.select('common'); // template: @let t = common(); @if (t) { {{ t.nav.title }} }
translate(key: string, params?: Record<string, string | number>): Signal<string>
Returns a cached signal for a single translation key. Automatically triggers namespace loading. Key format: namespace:dotted.path.
protected readonly title = this.i18n.translate('common:nav.title'); protected readonly greeting = this.i18n.translate('common:greeting', { name: 'Igor' });
instant(key: string, params?: Record<string, string | number>): string
Returns the translation synchronously. Non-reactive and does not trigger lazy loading — use only for imperative code (toasts, logs) when the namespace is already loaded.
setLang(lang: string): Promise<void>
Switches the active language. Reloads all previously requested namespaces for the new language and persists the preference to localStorage (if storageKey is configured). Logs a warning and returns early if the language is not in supportedLangs.
ensureNamespaces(ns: string[]): Promise<void>
Pre-loads additional namespaces. Deduplicates concurrent loads automatically. Useful for route guards or resolvers.
lang: WritableSignal<string>
The current language signal. Read in templates to show the active language.
supportedLangs: readonly string[]
Read-only array of all supported language codes from the configuration. Useful for building language switchers.
// Build a language switcher protected readonly languages = this.i18n.supportedLangs; // template: @for (lang of languages; track lang) { ... }
ready: Signal<boolean>
True when all coreNamespaces have been loaded for the current language.
TranslatePipe
Template sugar for TranslationService.translate(). The pipe caches its signal internally to avoid recreation on every change detection cycle.
Setup
Import TranslatePipe in your component's imports array:
import { TranslatePipe } from '@angular-translation-service/core'; @Component({ imports: [TranslatePipe], template: `...`, })
Usage
<!-- Basic --> <h1>{{ 'common:nav.title' | translate }}</h1> <!-- With params --> <p>{{ 'common:greeting' | translate:{ name: 'Igor' } }}</p>
provideTranslation()
Configures the translation service at the application level. Uses APP_INITIALIZER to preload core namespaces before the app renders.
| Option | Type | Description |
|---|---|---|
defaultLang | string | Default language code (e.g., 'en') |
supportedLangs | string[] | All supported language codes |
coreNamespaces | string[] | Namespaces preloaded via APP_INITIALIZER before the app renders |
loader | TranslationLoader | Function that loads translation files. Use httpLoader() or importLoader() |
detectLanguage | boolean | Enable browser language detection via navigator.language |
storageKey | string | localStorage key for persisting language preference across sessions |
namespaceSeparator | string | Separator between namespace and key path (default: ':') |
fallbackChain | Record<string, string[]> | Fallback language chains for regional locales |
Loaders
httpLoader(basePath: string): TranslationLoader
Creates a fetch-based loader. Loads JSON from: basePath/lang/namespace.json. Place your JSON files in the Angular project's public/ directory (files in public/ are served at the root URL).
// Files at: public/i18n/en/common.json → served at /i18n/en/common.json loader: httpLoader('/i18n')
importLoader(factory: (lang, ns) => Promise<{ default: Record }>): TranslationLoader
Creates a loader using dynamic imports. The factory callback must return a module with a default export containing the translation dictionary. The bundler can statically analyze import paths for tree-shaking and code splitting.
loader: importLoader((lang, ns) => import(`./i18n/${lang}/${ns}.json`) )
Injection Tokens
TRANSLATION_CONFIG: InjectionToken<TranslationConfig>
Injection token for the translation configuration. Automatically provided by provideTranslation(). Useful for custom providers that need access to the configuration.
CURRENT_LANGUAGE: InjectionToken<string>
Injection token for server-side language detection. Provided by provideTranslationSSR() on the server to inject the language from the HTTP request. On the client, language is resolved from TransferState or local detection.
createRecursiveProxy()
Creates a crash-proof proxy object that safely intercepts all property access. Used internally by select() to prevent template errors when namespaces are still loading. The proxy returns nested proxies for any property access, ensuring expressions like t().nav.title never throw — they render as empty strings instead.
Behavior
| Access | Result |
|---|---|
| String coercion / template interpolation | Returns the key path (e.g., 'common.nav.title') |
| Property access | Returns another recursive proxy |
| JSON serialization | Returns {} |
Promise detection (then/catch) | Returns undefined (prevents async unwrapping) |
Iteration (@for loops) | Yields nothing (empty iterator) |
Fallback Chains
Define fallback languages for regional locales. When loading translations, all languages in the chain are fetched in parallel and deep-merged — the most specific locale's keys overwrite fallback keys.
provideTranslation({ defaultLang: 'en', supportedLangs: ['en', 'es', 'es-AR'], fallbackChain: { 'es-AR': ['es', 'en'], // es-AR → es → en 'es': ['en'], // es → en }, // ... })
Language Detection
The initial language is resolved using the following priority chain (first match wins). Steps 1–2 always run; step 3 requires detectLanguage: true.
- SSR token — Language injected via
CURRENT_LANGUAGEon the server (always checked) - localStorage — Previously persisted preference (always checked if
storageKeyis configured) - Browser —
navigator.languagewith base-language matching (e.g., browser'pt'matches config'pt-BR') (only whendetectLanguage: true) - Default — Falls back to
defaultLang
SSR & Hydration
The @angular-translation-service/core/ssr secondary entry point provides seamless server-side rendering with zero flash-of-untranslated-content (FOUC) and no hydration mismatch.
provideTranslationSSR(config: TranslationSSRConfig): EnvironmentProviders
Add to your server application config. On the server, it provides CURRENT_LANGUAGE from the HTTP request and snapshots all loaded translations into TransferState. On the client, it hydrates translations synchronously — no HTTP requests needed for the initial render.
// app.config.server.ts import { provideTranslationSSR } from '@angular-translation-service/core/ssr'; export const serverConfig = { providers: [ provideTranslationSSR({ langFromRequest: (req) => { const accept = (req as Request).headers.get('accept-language') ?? 'en'; return accept.split(',')[0].split('-')[0]; }, }), ], };
How it works
| Phase | What happens |
|---|---|
| Server render | CURRENT_LANGUAGE is set from the request, core namespaces load, then all loaded translations are serialized into TransferState |
| Client hydration | Translations are restored from TransferState synchronously — no HTTP requests, no FOUC, no NG0501 |
| After hydration | TransferState entry is removed to free memory. Subsequent namespace loads use normal HTTP loading |
TranslationSSRConfig
| Option | Type | Description |
|---|---|---|
langFromRequest | (req: unknown) => string | Extract the language from the incoming HTTP request |
Error Behavior
Angular Translation Service is designed to be crash-proof. Here's how errors are handled:
| Scenario | Behavior |
|---|---|
| Namespace fails to load | Error logged to console. Template shows empty strings (via recursive proxy) |
| Missing translation key | Returns the raw key string (e.g., 'common:nav.missing') |
setLang() with unsupported language | Logs a warning and returns early — no state change |
| Accessing nested keys while loading | Recursive proxy returns empty strings, preventing template crashes |