Angular i18n with Transloco: Setup & Translation Guide

From installation to production: configure Transloco, handle plurals with ICU syntax, add smart locale fallbacks, and automate translations with AI.

1

Install Transloco

Transloco is the most popular third-party i18n library for Angular. It provides runtime translation loading, ICU message format support, lazy-loaded scopes, and a clean template API with both structural directives and pipes.

Why Transloco over Angular's built-in i18n? Angular's built-in solution requires a separate build per language and does not support runtime language switching. Transloco loads translations at runtime, so you ship one build and switch languages on the fly.
Terminal
npm install @jsverse/transloco
2

Configure Transloco

Register Transloco in your application config. You need to provide the available languages, set a default language, and configure the translation loader. Transloco supports both standalone components (Angular 14+) and NgModule patterns.

Standalone Components (Recommended)

app.config.ts
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient } from '@angular/common/http';
import {
  provideTransloco,
  TranslocoHttpLoader,
} from '@jsverse/transloco';

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(),
    provideTransloco({
      config: {
        availableLangs: ['en', 'de', 'ja', 'es', 'fr'],
        defaultLang: 'en',
        fallbackLang: 'en',
        reRenderOnLangChange: true,
        prodMode: true,
      },
      loader: TranslocoHttpLoader,
    }),
  ],
};

NgModule Pattern

app.module.ts
// app.module.ts
import { NgModule } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import {
  TranslocoModule,
  TRANSLOCO_LOADER,
  TranslocoHttpLoader,
  provideTransloco,
} from '@jsverse/transloco';

@NgModule({
  imports: [TranslocoModule],
  providers: [
    provideTransloco({
      config: {
        availableLangs: ['en', 'de', 'ja', 'es', 'fr'],
        defaultLang: 'en',
        fallbackLang: 'en',
        reRenderOnLangChange: true,
        prodMode: true,
      },
      loader: TranslocoHttpLoader,
    }),
  ],
})
export class AppModule {}
If translations appear as raw keys like "nav.home" instead of "Home", the most common cause is that TranslocoHttpLoader cannot find your JSON files. Verify your translation files are in src/assets/i18n/ and that your angular.json assets array includes that path.

Create Translation Files

Create one JSON file per language in src/assets/i18n/. Use nested keys to organize strings by feature. Transloco uses the ICU message format for plurals and variables.

assets/i18n/*.json
// assets/i18n/en.json
{
  "nav": {
    "home": "Home",
    "about": "About",
    "settings": "Settings"
  },
  "greeting": "Hello, {{ name }}!",
  "cart": {
    "itemCount": "{count, plural, one {# item} other {# items}}"
  }
}

// assets/i18n/de.json
{
  "nav": {
    "home": "Startseite",
    "about": "Uber uns",
    "settings": "Einstellungen"
  },
  "greeting": "Hallo, {{ name }}!",
  "cart": {
    "itemCount": "{count, plural, one {# Artikel} other {# Artikel}}"
  }
}
3

Use Translations in Templates and Services

Transloco provides three ways to translate in templates: the structural directive (*transloco), the pipe (| transloco), and the service (TranslocoService) for TypeScript code. The structural directive is recommended for most use cases because it creates a single subscription and provides the translate function to the entire template block.

Template Translation

component.html
<!-- Using the transloco directive (recommended) -->
<ng-container *transloco="let t">
  <h1>{{ t('greeting', { name: userName }) }}</h1>
  <nav>
    <a routerLink="/">{{ t('nav.home') }}</a>
    <a routerLink="/about">{{ t('nav.about') }}</a>
  </nav>
</ng-container>

<!-- Using the transloco pipe -->
<h1>{{ 'greeting' | transloco:{ name: userName } }}</h1>

<!-- Using the structural directive with read -->
<ng-container *transloco="let t; read: 'nav'">
  <a routerLink="/">{{ t('home') }}</a>
  <a routerLink="/about">{{ t('about') }}</a>
</ng-container>
Use the read parameter on the structural directive to scope translations to a nested key. This avoids repeating the prefix in every t() call and makes templates cleaner.

Service Translation (TypeScript)

notification.component.ts
import { Component, inject } from '@angular/core';
import { TranslocoService } from '@jsverse/transloco';

@Component({
  selector: 'app-notification',
  template: '<span>{{ message }}</span>',
})
export class NotificationComponent {
  private translocoService = inject(TranslocoService);
  message = '';

  showSuccess() {
    // Translate in TypeScript
    this.message = this.translocoService.translate('notifications.saved');
  }

  switchLanguage(lang: string) {
    this.translocoService.setActiveLang(lang);
  }
}
The transloco pipe creates a new subscription for every usage. In templates with many translated strings, prefer the *transloco structural directive which creates a single subscription for the entire block.
4

Handle Plurals with ICU Message Format

Transloco uses the ICU message format for plurals and select expressions. ICU handles complex plural rules automatically — Arabic (6 forms), Russian (3 forms), Japanese (1 form) — all from a single message string. Define your plural rules in the translation files and Transloco selects the correct form at runtime.

ICU plural syntax
// assets/i18n/en.json
{
  "cart": {
    "itemCount": "{count, plural, one {# item} other {# items}}",
    "emptyMessage": "Your cart is empty"
  },
  "notifications": {
    "unread": "{count, plural, =0 {No new notifications} one {# new notification} other {# new notifications}}"
  }
}

// assets/i18n/ar.json — Arabic has 6 plural forms
{
  "cart": {
    "itemCount": "{count, plural, zero {لا عناصر} one {عنصر واحد} two {عنصران} few {# عناصر} many {# عنصرًا} other {# عنصر}}"
  }
}

// Template usage:
// <span>{{ t('cart.itemCount', { count: cartItems.length }) }}</span>
Never implement custom plural logic in your components. Languages have wildly different plural rules that the ICU specification already handles. Let Transloco and ICU do the work — your job is to define the correct plural forms in your translation files.

Smart Locale Fallbacks with angular-locale-chain

By default, Transloco falls back to your default locale when a translation key is missing. A pt-BR user sees English instead of perfectly good pt-PT translations. angular-locale-chain fixes this by deep-merging translations from a configurable fallback chain before handing them to Transloco. Every key is filled in — no gaps, no missing translations.

Terminal
npm install angular-locale-chain
app.config.ts (with locale chain)
// app.config.ts — with angular-locale-chain
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient } from '@angular/common/http';
import {
  provideTransloco,
  TranslocoHttpLoader,
  TRANSLOCO_LOADER,
  TRANSLOCO_FALLBACK_STRATEGY,
} from '@jsverse/transloco';
import {
  LocaleChainLoader,
  LocaleChainFallbackStrategy,
} from 'angular-locale-chain';

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(),
    provideTransloco({
      config: {
        availableLangs: ['en', 'fr', 'fr-CA', 'pt', 'pt-BR', 'de', 'de-AT'],
        defaultLang: 'en',
        fallbackLang: 'en',
        reRenderOnLangChange: true,
        prodMode: true,
      },
    }),
    {
      provide: TRANSLOCO_LOADER,
      useFactory: () => {
        const inner = new TranslocoHttpLoader();
        return new LocaleChainLoader(inner, {
          defaultLocale: 'en',
        });
      },
    },
    {
      provide: TRANSLOCO_FALLBACK_STRATEGY,
      useFactory: () => new LocaleChainFallbackStrategy(),
    },
  ],
};
angular-locale-chain is an open-source library that solves Transloco bug #574 — missing per-key fallback when a translation file is partially complete.

Recommended File Structure

Project Structure
my-angular-app/
├── src/
│   ├── assets/
│   │   └── i18n/
│   │       ├── en.json           # Source language
│   │       ├── de.json           # German
│   │       ├── ja.json           # Japanese
│   │       ├── es.json           # Spanish
│   │       └── fr.json           # French
│   ├── app/
│   │   ├── app.config.ts         # Transloco provider config
│   │   ├── app.component.ts
│   │   └── components/
│   │       └── lang-switcher/
│   │           └── lang-switcher.component.ts
│   └── main.ts
├── angular.json
└── package.json

Automate Translations

With your Transloco setup complete, translate your locale files using AI. In your IDE, ask your AI assistant to translate your source JSON file, or use the i18n Agent CLI in your CI/CD pipeline for fully automated localization.

Terminal
# In your IDE, ask your AI assistant:
> Translate src/assets/i18n/en.json to German, Japanese, and Spanish

✓ de.json created (1.2s)
✓ ja.json created (1.5s)
✓ es.json created (1.1s)

# Or use the CLI in CI/CD:
npx i18n-agent translate src/assets/i18n/en.json --lang de,ja,es
Translate incrementally — when you add new keys to your source file, translate just the diff rather than regenerating all files. This preserves any human-reviewed translations and avoids unnecessary churn.

Automate Translation Quality

Catch missing keys and broken placeholders before they ship with i18n-validate. Test your UI with pseudo-translations using i18n-pseudo before real translations arrive.

Common Pitfalls

Translations Show Raw Keys

The TranslocoHttpLoader cannot find your JSON files. Check that files are in src/assets/i18n/, the assets array in angular.json includes that path, and the file names match your availableLangs configuration exactly (case-sensitive).

Scoped Keys Not Resolving

When using Transloco scopes, translation files must be at assets/i18n/[scope]/[lang].json, not in the root i18n folder. Also ensure the scope is registered in the component's providers array using TRANSLOCO_SCOPE.

Console Warnings in Production

Set prodMode: true in your Transloco config for production builds. Without it, Transloco logs missing key warnings to the console. It also disables development-time checks that add overhead.

Translations Flash on Route Navigation

Lazy-loaded routes fetch translations after the component renders, causing a brief flash of untranslated keys. Use Transloco's built-in TRANSLOCO_LOADING_TEMPLATE to show a loading state, or pre-load translations in a route guard.

Regional Users See English Instead of Parent Locale

Transloco's built-in fallback only triggers when an entire locale file is missing, not for individual missing keys. Use angular-locale-chain to deep-merge translations from related locales (e.g., pt-BR falls back to pt-PT, then pt, then English).

Try i18n Agent Now

Drop your translation file here

JSON, YAML, PO, XML, CSV, Markdown, Properties

or click to browse

Target languages

No signup requiredInstant estimate

Angular i18n FAQ