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.

OptionTypeDescription
defaultLangstringDefault language code (e.g., 'en')
supportedLangsstring[]All supported language codes
coreNamespacesstring[]Namespaces preloaded via APP_INITIALIZER before the app renders
loaderTranslationLoaderFunction that loads translation files. Use httpLoader() or importLoader()
detectLanguagebooleanEnable browser language detection via navigator.language
storageKeystringlocalStorage key for persisting language preference across sessions
namespaceSeparatorstringSeparator between namespace and key path (default: ':')
fallbackChainRecord<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

AccessResult
String coercion / template interpolationReturns the key path (e.g., 'common.nav.title')
Property accessReturns another recursive proxy
JSON serializationReturns {}
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.

  1. SSR token — Language injected via CURRENT_LANGUAGE on the server (always checked)
  2. localStorage — Previously persisted preference (always checked if storageKey is configured)
  3. Browsernavigator.language with base-language matching (e.g., browser 'pt' matches config 'pt-BR') (only when detectLanguage: true)
  4. 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

PhaseWhat happens
Server renderCURRENT_LANGUAGE is set from the request, core namespaces load, then all loaded translations are serialized into TransferState
Client hydrationTranslations are restored from TransferState synchronously — no HTTP requests, no FOUC, no NG0501
After hydrationTransferState entry is removed to free memory. Subsequent namespace loads use normal HTTP loading

TranslationSSRConfig

OptionTypeDescription
langFromRequest(req: unknown) => stringExtract the language from the incoming HTTP request

Error Behavior

Angular Translation Service is designed to be crash-proof. Here's how errors are handled:

ScenarioBehavior
Namespace fails to loadError logged to console. Template shows empty strings (via recursive proxy)
Missing translation keyReturns the raw key string (e.g., 'common:nav.missing')
setLang() with unsupported languageLogs a warning and returns early — no state change
Accessing nested keys while loadingRecursive proxy returns empty strings, preventing template crashes