Transloco

Last updated: July 31, 2025Author: Jakub Pomykała

Installation

Install Transloco using the Angular CLI schematic:

ng add @ngneat/transloco

This command will:

  • Install the necessary packages
  • Set up the basic configuration
  • Create translation files
  • Configure your app module

Alternatively, install manually:

npm install @ngneat/transloco

Module Configuration

If you installed manually, configure Transloco in your app module:

// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { TranslocoModule } from '@ngneat/transloco';

import { AppComponent } from './app.component';
import { translocoConfig } from './transloco-config';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
    TranslocoModule
  ],
  providers: [
    translocoConfig
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

Transloco Configuration

Create the Transloco configuration:

// src/app/transloco-config.ts
import { HttpClient } from '@angular/common/http';
import { Injectable, isDevMode } from '@angular/core';
import {
  Translation,
  TranslocoLoader,
  TranslocoConfig,
  TRANSLOCO_CONFIG,
  TRANSLOCO_LOADER
} from '@ngneat/transloco';

@Injectable({ providedIn: 'root' })
export class TranslocoHttpLoader implements TranslocoLoader {
  constructor(private http: HttpClient) {}

  getTranslation(lang: string) {
    return this.http.get<Translation>(`/assets/i18n/${lang}.json`);
  }
}

export const translocoConfig = [
  {
    provide: TRANSLOCO_CONFIG,
    useValue: {
      availableLangs: ['en', 'pl', 'es', 'fr'],
      defaultLang: 'en',
      fallbackLang: 'en',
      reRenderOnLangChange: true,
      prodMode: !isDevMode(),
    } as TranslocoConfig
  },
  {
    provide: TRANSLOCO_LOADER,
    useClass: TranslocoHttpLoader
  }
];

Translation File Structure

Create translation files in the src/assets/i18n/ directory:

// src/assets/i18n/en.json
{
  "homepage": {
    "title": "Welcome to our website",
    "description": "This is a multilingual Angular application",
    "subtitle": "Built with Transloco"
  },
  "navigation": {
    "home": "Home",
    "about": "About",
    "contact": "Contact",
    "products": "Products"
  },
  "product": {
    "name": "Product Name",
    "price": "Price: {{price}}",
    "available": "Available since: {{date}}",
    "addToCart": "Add to Cart",
    "removeFromCart": "Remove from Cart"
  },
  "cart": {
    "title": "Shopping Cart",
    "empty": "Your cart is empty",
    "itemCount": "{{count}} item",
    "itemCount_other": "{{count}} items",
    "total": "Total: {{amount}}"
  },
  "user": {
    "welcome": "Welcome, {{name}}!",
    "profile": "Profile",
    "logout": "Logout"
  },
  "forms": {
    "email": "Email",
    "password": "Password",
    "submit": "Submit",
    "cancel": "Cancel",
    "save": "Save"
  },
  "messages": {
    "loading": "Loading...",
    "error": "Something went wrong",
    "success": "Operation completed successfully",
    "confirm": "Are you sure?"
  }
}
// src/assets/i18n/pl.json
{
  "homepage": {
    "title": "Witamy na naszej stronie",
    "description": "To jest wielojęzyczna aplikacja Angular",
    "subtitle": "Zbudowana z Transloco"
  },
  "navigation": {
    "home": "Strona główna",
    "about": "O nas",
    "contact": "Kontakt",
    "products": "Produkty"
  },
  "product": {
    "name": "Nazwa produktu",
    "price": "Cena: {{price}}",
    "available": "Dostępne od: {{date}}",
    "addToCart": "Dodaj do koszyka",
    "removeFromCart": "Usuń z koszyka"
  },
  "cart": {
    "title": "Koszyk",
    "empty": "Twój koszyk jest pusty",
    "itemCount": "{{count}} przedmiot",
    "itemCount_other": "{{count}} przedmiotów",
    "total": "Razem: {{amount}}"
  },
  "user": {
    "welcome": "Witaj, {{name}}!",
    "profile": "Profil",
    "logout": "Wyloguj"
  },
  "forms": {
    "email": "Email",
    "password": "Hasło",
    "submit": "Wyślij",
    "cancel": "Anuluj",
    "save": "Zapisz"
  },
  "messages": {
    "loading": "Ładowanie...",
    "error": "Coś poszło nie tak",
    "success": "Operacja zakończona pomyślnie",
    "confirm": "Czy jesteś pewny?"
  }
}
// src/assets/i18n/es.json
{
  "homepage": {
    "title": "Bienvenido a nuestro sitio web",
    "description": "Esta es una aplicación Angular multiidioma",
    "subtitle": "Construida con Transloco"
  },
  "navigation": {
    "home": "Inicio",
    "about": "Acerca de",
    "contact": "Contacto",
    "products": "Productos"
  },
  "product": {
    "name": "Nombre del producto",
    "price": "Precio: {{price}}",
    "available": "Disponible desde: {{date}}",
    "addToCart": "Añadir al carrito",
    "removeFromCart": "Quitar del carrito"
  },
  "cart": {
    "title": "Carrito de compras",
    "empty": "Tu carrito está vacío",
    "itemCount": "{{count}} artículo",
    "itemCount_other": "{{count}} artículos",
    "total": "Total: {{amount}}"
  },
  "user": {
    "welcome": "¡Bienvenido, {{name}}!",
    "profile": "Perfil",
    "logout": "Cerrar sesión"
  },
  "forms": {
    "email": "Correo electrónico",
    "password": "Contraseña",
    "submit": "Enviar",
    "cancel": "Cancelar",
    "save": "Guardar"
  },
  "messages": {
    "loading": "Cargando...",
    "error": "Algo salió mal",
    "success": "Operación completada exitosamente",
    "confirm": "¿Estás seguro?"
  }
}
// src/assets/i18n/fr.json
{
  "homepage": {
    "title": "Bienvenue sur notre site web",
    "description": "Ceci est une application Angular multilingue",
    "subtitle": "Construite avec Transloco"
  },
  "navigation": {
    "home": "Accueil",
    "about": "À propos",
    "contact": "Contact",
    "products": "Produits"
  },
  "product": {
    "name": "Nom du produit",
    "price": "Prix: {{price}}",
    "available": "Disponible depuis: {{date}}",
    "addToCart": "Ajouter au panier",
    "removeFromCart": "Retirer du panier"
  },
  "cart": {
    "title": "Panier",
    "empty": "Votre panier est vide",
    "itemCount": "{{count}} article",
    "itemCount_other": "{{count}} articles",
    "total": "Total: {{amount}}"
  },
  "user": {
    "welcome": "Bienvenue, {{name}} !",
    "profile": "Profil",
    "logout": "Déconnexion"
  },
  "forms": {
    "email": "Email",
    "password": "Mot de passe",
    "submit": "Soumettre",
    "cancel": "Annuler",
    "save": "Sauvegarder"
  },
  "messages": {
    "loading": "Chargement...",
    "error": "Quelque chose s'est mal passé",
    "success": "Opération terminée avec succès",
    "confirm": "Êtes-vous sûr ?"
  }
}

Usage Examples

Basic Component Usage

// app.component.ts
import { Component, OnInit } from '@angular/core';
import { TranslocoService } from '@ngneat/transloco';

@Component({
  selector: 'app-root',
  template: `
    <div class="app-container">
      <app-language-switcher></app-language-switcher>

      <header>
        <h1>{{ 'homepage.title' | transloco }}</h1>
        <p>{{ 'homepage.description' | transloco }}</p>
        <small>{{ 'homepage.subtitle' | transloco }}</small>
      </header>

      <main>
        <app-navigation></app-navigation>
        <app-product-list></app-product-list>
        <app-shopping-cart></app-shopping-cart>
      </main>
    </div>
  `
})
export class AppComponent implements OnInit {

  constructor(private translocoService: TranslocoService) {}

  ngOnInit(): void {
    // Set initial language
    const savedLang = localStorage.getItem('selectedLanguage');
    const browserLang = this.translocoService.getBrowserLang();
    const defaultLang = savedLang || browserLang || 'en';

    this.translocoService.setActiveLang(defaultLang);
  }
}

Language Switcher Component

// language-switcher.component.ts
import { Component } from '@angular/core';
import { TranslocoService } from '@ngneat/transloco';

@Component({
  selector: 'app-language-switcher',
  template: `
    <div class="language-switcher">
      <select
        [value]="translocoService.getActiveLang()"
        (change)="changeLanguage($event)">
        <option *ngFor="let lang of availableLanguages" [value]="lang.code">
          {{ lang.name }}
        </option>
      </select>
    </div>
  `
})
export class LanguageSwitcherComponent {
  availableLanguages = [
    { code: 'en', name: 'English' },
    { code: 'pl', name: 'Polski' },
    { code: 'es', name: 'Español' },
    { code: 'fr', name: 'Français' }
  ];

  constructor(public translocoService: TranslocoService) {}

  changeLanguage(event: Event): void {
    const target = event.target as HTMLSelectElement;
    const language = target.value;

    this.translocoService.setActiveLang(language);
    localStorage.setItem('selectedLanguage', language);
  }
}
// navigation.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-navigation',
  template: `
    <nav class="main-navigation">
      <a routerLink="/" class="nav-link">
        {{ 'navigation.home' | transloco }}
      </a>
      <a routerLink="/about" class="nav-link">
        {{ 'navigation.about' | transloco }}
      </a>
      <a routerLink="/products" class="nav-link">
        {{ 'navigation.products' | transloco }}
      </a>
      <a routerLink="/contact" class="nav-link">
        {{ 'navigation.contact' | transloco }}
      </a>
    </nav>
  `
})
export class NavigationComponent {}

Product Component with Parameters

// product.component.ts
import { Component, Input } from '@angular/core';
import { TranslocoService } from '@ngneat/transloco';

@Component({
  selector: 'app-product',
  template: `
    <div class="product-card">
      <h3>{{ product.name }}</h3>
      <p>{{ 'product.price' | transloco:{ price: product.price | currency } }}</p>
      <p>{{ 'product.available' | transloco:{ date: product.availableDate | date } }}</p>

      <div class="product-actions">
        <button
          class="btn btn-primary"
          (click)="addToCart()"
          [disabled]="isInCart">
          {{ (isInCart ? 'product.removeFromCart' : 'product.addToCart') | transloco }}
        </button>
      </div>
    </div>
  `
})
export class ProductComponent {
  @Input() product: any;
  @Input() isInCart: boolean = false;

  constructor(private translocoService: TranslocoService) {}

  addToCart(): void {
    // Cart logic here
    console.log('Product added to cart');
  }
}

Service with Transloco

// notification.service.ts
import { Injectable } from '@angular/core';
import { TranslocoService } from '@ngneat/transloco';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class NotificationService {

  constructor(private translocoService: TranslocoService) {}

  showWelcomeMessage(userName: string): Observable<string> {
    return this.translocoService.selectTranslate('user.welcome', { name: userName });
  }

  getLoadingMessage(): string {
    return this.translocoService.translate('messages.loading');
  }

  getSuccessMessage(): Observable<string> {
    return this.translocoService.selectTranslate('messages.success');
  }

  getErrorMessage(): Observable<string> {
    return this.translocoService.selectTranslate('messages.error');
  }

  getConfirmationMessage(): Observable<string> {
    return this.translocoService.selectTranslate('messages.confirm');
  }
}

Shopping Cart with Pluralization

// shopping-cart.component.ts
import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-shopping-cart',
  template: `
    <div class="shopping-cart">
      <h2>{{ 'cart.title' | transloco }}</h2>

      <div *ngIf="items.length === 0" class="empty-cart">
        {{ 'cart.empty' | transloco }}
      </div>

      <div *ngIf="items.length > 0" class="cart-content">
        <div class="cart-summary">
          {{ 'cart.itemCount' | transloco:{ count: items.length } }}
        </div>

        <div class="cart-items">
          <div *ngFor="let item of items" class="cart-item">
            <span>{{ item.name }}</span>
            <span>{{ item.price | currency }}</span>
          </div>
        </div>

        <div class="cart-total">
          {{ 'cart.total' | transloco:{ amount: getTotal() | currency } }}
        </div>
      </div>
    </div>
  `
})
export class ShoppingCartComponent {
  @Input() items: any[] = [];

  getTotal(): number {
    return this.items.reduce((total, item) => total + item.price, 0);
  }
}

Structural Directive Usage

// conditional-content.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-conditional-content',
  template: `
    <div>
      <!-- Using structural directive -->
      <div *transloco="let t">
        <h1>{{ t('homepage.title') }}</h1>
        <p>{{ t('homepage.description') }}</p>

        <!-- Nested translations -->
        <div *transloco="let nav; read: 'navigation'">
          <a>{{ nav('home') }}</a>
          <a>{{ nav('about') }}</a>
          <a>{{ nav('contact') }}</a>
        </div>
      </div>
    </div>
  `
})
export class ConditionalContentComponent {}

Advanced Features

Lazy Loading Scoped Translations

// feature.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { TranslocoModule, TRANSLOCO_SCOPE } from '@ngneat/transloco';

@NgModule({
  declarations: [],
  imports: [
    CommonModule,
    TranslocoModule
  ],
  providers: [
    {
      provide: TRANSLOCO_SCOPE,
      useValue: 'feature'
    }
  ]
})
export class FeatureModule {}

Custom Pluralization Rules

// transloco-config.ts (enhanced)
import { TranslocoConfig } from '@ngneat/transloco';

export const translocoConfig: TranslocoConfig = {
  availableLangs: ['en', 'pl', 'es', 'fr'],
  defaultLang: 'en',
  fallbackLang: 'en',
  reRenderOnLangChange: true,
  prodMode: !isDevMode(),
  missingHandler: {
    useFallbackTranslation: true,
    allowEmpty: false
  },
  interpolation: {
    marker: ['{{', '}}']
  }
};

SimpleLocalize Configuration

To manage translations with SimpleLocalize, you need to set up the CLI tool.

# macOS / Linux / Windows (WSL) curl -s https://get.simplelocalize.io/2.9/install | bash # Windows (PowerShell) . { iwr -useb https://get.simplelocalize.io/2.9/install-windows } | iex; # npm npm install @simplelocalize/cli
# macOS / Linux / Windows (WSL)
curl -s https://get.simplelocalize.io/2.9/install | bash

# Windows (PowerShell)
. { iwr -useb https://get.simplelocalize.io/2.9/install-windows } | iex;

# npm
npm install @simplelocalize/cli

Create simplelocalize.yml in your project root:

apiKey: YOUR_PROJECT_API_KEY

uploadFormat: single-language-json
uploadPath: ./src/assets/i18n/{lang}.json
uploadLanguageKey: en
uploadOptions:
  - REPLACE_TRANSLATION_IF_FOUND

downloadPath: ./src/assets/i18n/{lang}.json
downloadLanguageKeys: ['en', 'pl', 'es', 'fr']
downloadFormat: single-language-json

Work with the CLI to manage your translations:

# Upload translations to SimpleLocalize
simplelocalize upload

# Download translations for all languages
simplelocalize download

# Build your Angular application
ng build

Key Features

  • Modern Architecture: Built for modern Angular with RxJS
  • Tree-shakable: Only load the translations you need
  • Type Safety: Full TypeScript support with strict typing
  • Lazy Loading: Load translations on demand with scoped modules
  • Hot Reload: Real-time translation updates in development
  • ICU Message Format: Advanced pluralization and formatting
  • Structural Directive: Powerful template syntax for complex translations
  • SSR Support: Full server-side rendering compatibility

Performance Benefits

  • Small Bundle Size: Optimized for minimal impact on bundle size
  • Lazy Loading: Load translations only when needed
  • Caching: Built-in translation caching
  • Change Detection: Optimized change detection strategy
  • Memory Management: Efficient memory usage with proper cleanup

Resources

Was this helpful?