Chapter 12.3☕ 15 min read

Internationalization (i18n)

Make your app work in multiple languages. Angular has a built-in i18n pipeline for extraction and translation, or you can build a simpler runtime service with signals.

01What is i18n

i18n (internationalization) is the process of making your app work in multiple languages and locales. The name comes from "i" + 18 letters + "n" in the word "internationalization."

"i18n = multi-language support — Hyderabadi, English, Hindi, Telugu."

Two approaches:

  • Angular i18n — built-in, extract-and-build pipeline, separate builds per language
  • Simple runtime service — custom translation service with signals, single build, runtime switching

Angular's i18n is powerful but requires separate builds per language (5 languages = 5 builds). The simple service approach swaps translations at runtime with signals — great for small-to-medium apps.

02Angular i18n Approach — Extraction

Angular's i18n uses a 4-step pipeline:

Step 1: Mark text in templates

<h1 i18n>Welcome to Biryani Hub</h1>
<p i18n>Order the best biryani in Hyderabad!</p>

Step 2: Extract translatable text

# Terminal:
ng extract-i18n --output-path src/locale
# Generates: src/locale/messages.xlf

Step 3: Translate

<!-- messages.hi.xlf (Hindi) -->
<trans-unit id="123">
  <source>Welcome to Biryani Hub</source>
  <target>बिरयानी हब में आपका स्वागत है</target>
</trans-unit>

Step 4: Build for each language

# Terminal:
ng build --localize
# Builds separate output for each language
# dist/en/, dist/hi/, dist/te/

"Mark → Extract → Translate → Build — 4 step process."

Configure languages in angular.json:

"i18n": {
  "sourceLocale": "en",
  "locales": {
    "hi": "src/locale/messages.hi.xlf",
    "te": "src/locale/messages.te.xlf"
  }
}
03i18n in Templates

Angular provides several i18n directives for templates:

Simple text:

<h1 i18n>Welcome to Biryani Shop</h1>

With meaning and description (for translators):

<h1 i18n="main.title|Main page heading@@mainTitle">Welcome</h1>
<!-- @@mainTitle = unique ID -->
<!-- main.title = meaning -->
<!-- |Main page heading = description for translators -->

Pluralization:

<span i18n>{count, plural,
  =0 {no biryanis available}
  =1 {one biryani available}
  other {{{count}} biryanis available}
}</span>

Gender/selection:

<span i18n>{gender, select,
  male {He ordered biryani}
  female {She ordered biryani}
  other {They ordered biryani}
}</span>

"i18n attribute = translatable mark — Angular isko extract karega." Meaning aur description translators ko context dete hain. Pluralization alag languages mein alag plural rules handle karta hai.

04i18n for Attributes

Not just text — element attributes can also be translated:

<!-- Attribute i18n -->
<input i18n-placeholder placeholder="Enter your name" />
<img i18n-alt alt="A plate of Hyderabadi Biryani" />
<button i18n-title title="Click to place your order">Order</button>
<a i18n-aria-label aria-label="Back to home page" href="/">Back</a>

<!-- Dynamic attributes -->
<input [placeholder] i18n-placeholder placeholder="Search biryanis..." />

"Attributes bhi translate karo — placeholder, alt, title, aria-label sab."

Important: The attribute-name follows the pattern i18n-{attributeName}. For dynamic values, use [placeholder] i18n-placeholder together — the i18n- prefix marks it for extraction, while [placeholder] binds the value.

05Alternative — Simple Translation Service

For small-to-medium apps (10-50 strings), Angular's full i18n pipeline with separate builds may be overkill. Here's a simple translation service with signals:

import { Injectable, signal, computed } from '@angular/core';

type Lang = 'en' | 'hi' | 'te' | 'ur';

const TRANSLATIONS: Record<Lang, Record<string, string>> = {
  en: {
    welcome: 'Welcome to Biryani Hub',
    order: 'Order Now',
    biryaniCount: (count: number) => `${count} biryani(s)`
  },
  hi: {
    welcome: 'बिरयानी हब में आपका स्वागत है',
    order: 'अभी ऑर्डर करें',
    biryaniCount: (count: number) => `${count} बिरयानी`
  },
  te: {
    welcome: 'బిర్యానీ హబ్‌కు స్వాగతం',
    order: 'ఇప్పుడే ఆర్డర్ చేయండి',
    biryaniCount: (count: number) => `${count} బిర్యానీ`
  }
};

@Injectable({ providedIn: 'root' })
export class TranslateService {
  private currentLang = signal<Lang>('en');
  readonly lang = this.currentLang.asReadonly();

  setLang(lang: Lang) { this.currentLang.set(lang); }

  t(key: string, params?: Record<string, any>): string {
    const translation = TRANSLATIONS[this.currentLang()][key];
    if (!translation) return key;
    if (typeof translation === 'function') return translation(params);
    return translation;
  }
}

// In component:
// <h1>{{ translate.t('welcome') }}</h1>
// <button (click)="translate.setLang('hi')">हिन्दी</button>

"Simple approach = apna chhota translator — bada system ki zaroorat nahi for 10-20 strings."

When to use which: Angular i18n for large apps with professional translation teams. Simple service for small apps, MVPs, or when you need runtime language switching.

Key Takeaways

  • ✅ i18n = internationalization — making your app work in multiple languages
  • ✅ Angular i18n: mark with i18n attribute, extract, translate, build --localize
  • ✅ Support: text, plurals, gender/select, attributes (placeholder, alt, title)
  • ✅ Angular i18n creates separate builds per language
  • ✅ Simple alternative: TranslateService with signals for runtime switching
  • ✅ For small apps: use simple service. For large apps: use Angular i18n
Course Search
Search across all chapters & stages
📖

Search the course

Type any topic — branching, stash, rebase, hooks — and jump straight to that chapter.

merge branchesgit stashundo commitrebase