Angulars i18n-Philosophie
Sie bauen eine Angular-App. Jetzt müssen Sie mehrere Sprachen unterstützen.
Sie haben zwei Möglichkeiten:
-
@angular/localize (offizielle Angular-Lösung)
- Übersetzung zur Kompilierzeit (verschiedener Build pro Sprache)
- Schnellste Laufzeit-Performance
- Mehr Build-Komplexität
-
ngx-translate (Community-Bibliothek)
- Laufzeit-Übersetzung (einzelner Build, dynamisches Umschalten)
- Einfacheres Deployment
- Etwas langsamere Laufzeit
Dieser Leitfaden deckt @angular/localize ab (empfohlen vom Angular-Team). Wenn Sie dynamisches Sprachumschalten in derselben App-Instanz benötigen, verwenden Sie stattdessen ngx-translate.
Was Sie bauen werden
Am Ende dieses Tutorials werden Sie eine Angular-App haben, die:
- ✅ Separate Bundles pro Sprache kompiliert
- ✅ Angulars native i18n-APIs verwendet
- ✅ Pluralisierung korrekt handhabt (Englisch, Spanisch, Polnisch, Arabisch usw.)
- ✅ Daten, Zahlen, Währungen nach Locale formatiert
- ✅ Mit Locale-basiertem Routing deployt (
/en/,/es/,/fr/) - ✅ Sich in CI/CD für automatisierte Übersetzung integriert
Tech-Stack:
- Angular 17+
- @angular/localize
- Angular CLI
- TypeScript
Schritt 1: Installieren Sie @angular/localize
Wenn Sie ein neues Angular-Projekt starten:
Terminalng new my-app cd my-app ng add @angular/localize
Dies fügt @angular/localize zu Ihrem Projekt hinzu und konfiguriert angular.json.
Für bestehende Projekte:
Terminalng add @angular/localize
Was es tut:
- Installiert das
@angular/localizePaket - Fügt Polyfill zu
polyfills.tshinzu - Aktualisiert
angular.jsonmit i18n-Konfiguration
Schritt 2: Strings für die Übersetzung markieren
Einfache Übersetzung (i18n-Attribut)
Verwenden Sie das i18n-Attribut an jedem HTML-Element:
HTML1<!-- Vorher: Hartcodiertes Englisch --> 2<h1>Welcome to our app</h1> 3<button>Sign up</button> 4 5<!-- Nachher: Für Übersetzung markiert --> 6<h1 i18n>Welcome to our app</h1> 7<button i18n>Sign up</button>
Das war's. Angular wird diese Strings während des Builds extrahieren.
Attribute (i18n-*)
Element-Attribute übersetzen:
HTML1<!-- Platzhalter übersetzen --> 2<input 3 type="text" 4 placeholder="Enter your email" 5 i18n-placeholder 6/> 7 8<!-- Titel übersetzen --> 9<img 10 src="logo.png" 11 title="Company logo" 12 i18n-title 13/> 14 15<!-- aria-label für Barrierefreiheit übersetzen --> 16<button 17 aria-label="Close dialog" 18 i18n-aria-label 19> 20 ✕ 21</button>
Komponenten-TypeScript (Template Literals)
Für Strings in TypeScript verwenden Sie $localize:
TypeScript1import { Component } from '@angular/core'; 2 3@Component({ 4 selector: 'app-root', 5 template: ` 6 <h1>{{ title }}</h1> 7 `, 8}) 9export class AppComponent { 10 // String für Übersetzung markieren 11 title = $localize`Welcome to our app`; 12 13 showMessage() { 14 // Kann im Code verwendet werden 15 alert($localize`Settings saved successfully!`); 16 } 17}
Hinweis: $localize ist zur Kompilierzeit, wird also zur Build-Zeit durch den übersetzten String ersetzt.
Kontext hinzufügen (Bedeutung & Beschreibung)
Helfen Sie Übersetzern, den Kontext zu verstehen:
HTML1<!-- Bedeutung und Beschreibung hinzufügen --> 2<h1 i18n="site header|Welcome message for homepage@@homeTitle"> 3 Welcome to our app 4</h1> 5 6<!-- Format: [meaning]|[description]@@[id] -->
- Meaning: Kategorie oder Kontext ("site header")
- Description: Erklärung ("Welcome message for homepage")
- ID: Eindeutiger Identifikator (@@homeTitle). Empfohlen für Tracking
Warum IDs verwenden?
- Verhindert doppelte Extraktionen
- Erlaubt Änderung des Quelltexts, ohne Übersetzungen zu brechen
- Macht Updates klarer
Beispiel mit ID:
HTML1<button i18n="@@signupButton">Sign up</button> 2 3<!-- Später ändern Sie den Text: --> 4<button i18n="@@signupButton">Create account</button>
Übersetzer sehen ein Update zu signupButton, keinen neuen String.
Schritt 3: Übersetzungs-Strings extrahieren
Führen Sie Angulars Extraktions-Tool aus:
Terminalng extract-i18n --output-path src/locale
Dies erstellt:
src/locale/
└── messages.xlf (oder .json, .xmb je nach Format)
Standardformat ist XLIFF (.xlf). Es sieht so aus:
XML1<?xml version="1.0" encoding="UTF-8" ?> 2<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> 3 <file source-language="en" datatype="plaintext"> 4 <body> 5 <trans-unit id="homeTitle" datatype="html"> 6 <source>Welcome to our app</source> 7 <context-group purpose="location"> 8 <context context-type="sourcefile">src/app/app.component.html</context> 9 </context-group> 10 <note priority="1" from="description">Welcome message for homepage</note> 11 <note priority="1" from="meaning">site header</note> 12 </trans-unit> 13 </body> 14 </file> 15</xliff>
Alternative Formate
JSON (einfacher zu lesen):
Terminalng extract-i18n --format json
Output:
JSON1{ 2 "locale": "en", 3 "translations": { 4 "homeTitle": { 5 "translation": "Welcome to our app", 6 "description": "Welcome message for homepage" 7 } 8 } 9}
Wir empfehlen JSON für einfachere menschliche Bearbeitung und TMS-Integration.
Schritt 4: Die extrahierten Dateien übersetzen
Manuelle Übersetzung (Kleine Projekte)
Kopieren Sie die Basisdatei für jede Sprache:
Terminalcp src/locale/messages.xlf src/locale/messages.es.xlf cp src/locale/messages.xlf src/locale/messages.fr.xlf
Bearbeiten Sie messages.es.xlf:
XML1<trans-unit id="homeTitle"> 2 <source>Welcome to our app</source> 3 <target>Bienvenido a nuestra aplicación</target> 4</trans-unit>
Für JSON-Format:
JSON1{ 2 "locale": "es", 3 "translations": { 4 "homeTitle": { 5 "translation": "Bienvenido a nuestra aplicación" 6 } 7 } 8}
Automatisierte Übersetzung (IntlPull)
Für Produktions-Apps nutzen Sie ein TMS:
Terminalnpm install -D @intlpullhq/cli
Konfigurieren (.intlpull.json):
JSON1{ 2 "projectId": "proj_abc123", 3 "sourceLanguage": "en", 4 "targetLanguages": ["es", "fr", "de"], 5 "format": "xlf", 6 "outputDir": "src/locale" 7}
Workflow:
Terminal1# 1. Extrahieren 2ng extract-i18n --output-path src/locale 3 4# 2. Upload zu IntlPull für Übersetzung 5npx @intlpullhq/cli upload 6 7# 3. Übersetzungen herunterladen 8npx @intlpullhq/cli download 9 10# 4. Build mit Übersetzungen 11ng build --localize
Ergebnis: Automatisierte Übersetzungs-Pipeline in CI/CD.
Schritt 5: angular.json für mehrere Locales konfigurieren
Bearbeiten Sie angular.json:
JSON1{ 2 "projects": { 3 "my-app": { 4 "i18n": { 5 "sourceLocale": "en", 6 "locales": { 7 "es": { 8 "translation": "src/locale/messages.es.xlf", 9 "baseHref": "/es/" 10 }, 11 "fr": { 12 "translation": "src/locale/messages.fr.xlf", 13 "baseHref": "/fr/" 14 }, 15 "de": { 16 "translation": "src/locale/messages.de.xlf", 17 "baseHref": "/de/" 18 } 19 } 20 }, 21 "architect": { 22 "build": { 23 "configurations": { 24 "production": { 25 "localize": true 26 }, 27 "es": { 28 "localize": ["es"] 29 }, 30 "fr": { 31 "localize": ["fr"] 32 } 33 } 34 }, 35 "serve": { 36 "configurations": { 37 "es": { 38 "browserTarget": "my-app:build:development,es" 39 }, 40 "fr": { 41 "browserTarget": "my-app:build:development,fr" 42 } 43 } 44 } 45 } 46 } 47 } 48}
Was dies tut:
- Definiert unterstützte Locales
- Setzt baseHref für jede (URLs:
/en/,/es/,/fr/) - Konfiguriert Build, um separate Bundles zu kompilieren
Schritt 6: Build und Serve
Entwicklung (Einzelne Locale)
App in spezifischer Locale ausführen:
Terminalng serve --configuration=es
Öffnet App auf Spanisch unter http://localhost:4200/
Produktion (Alle Locales)
Alle Locales bauen:
Terminalng build --localize
Output:
dist/my-app/
├── en/ (Englischer Build)
│ ├── index.html
│ ├── main.js
│ └── ...
├── es/ (Spanischer Build)
│ ├── index.html
│ ├── main.js
│ └── ...
├── fr/ (Französischer Build)
│ └── ...
Jeder Ordner ist ein kompletter App-Build, übersetzt.
Deploy
Statisches Hosting (Vercel, Netlify, Firebase):
Deployen Sie den dist/my-app/ Ordner. Server-Routen:
/en/*→dist/my-app/en//es/*→dist/my-app/es//fr/*→dist/my-app/fr/
Nginx-Beispiel:
NGINX1server { 2 listen 80; 3 4 location /en/ { 5 alias /var/www/my-app/en/; 6 try_files $uri $uri/ /en/index.html; 7 } 8 9 location /es/ { 10 alias /var/www/my-app/es/; 11 try_files $uri $uri/ /es/index.html; 12 } 13 14 location /fr/ { 15 alias /var/www/my-app/fr/; 16 try_files $uri $uri/ /fr/index.html; 17 } 18 19 # Root auf Standardsprache umleiten 20 location = / { 21 return 302 /en/; 22 } 23}
Schritt 7: Pluralisierung & ICU-Nachrichten
Pluralisierung
Verschiedene Sprachen haben unterschiedliche Pluralregeln:
- Englisch: 1 Element, 2 Elemente (2 Formen)
- Spanisch: gleich (2 Formen)
- Polnisch: 1, 2-4, 5+ (3 Formen)
- Arabisch: 0, 1, 2, 3-10, 11-99, 100+ (6 Formen!)
Angulars ICU-Syntax handhabt dies:
HTML1<span i18n> 2 {count, plural, 3 =0 {No items} 4 =1 {One item} 5 other {{{count}} items} 6 } 7</span>
In Komponente:
TypeScriptexport class CartComponent { count = 5; }
Output:
count = 0: "No items"count = 1: "One item"count = 5: "5 items"
Übersetzung (Spanisch):
XML1<trans-unit id="..."> 2 <source>{count, plural, =0 {No items} =1 {One item} other {{{count}} items}}</source> 3 <target>{count, plural, =0 {Sin artículos} =1 {Un artículo} other {{{count}} artículos}}</target> 4</trans-unit>
Geschlecht (Select)
HTML1<span i18n> 2 {gender, select, 3 male {He liked your post} 4 female {She liked your post} 5 other {They liked your post} 6 } 7</span>
Komponente:
TypeScriptexport class NotificationComponent { gender = 'female'; // oder 'male', 'other' }
Interpolation
Variablen in Übersetzungen übergeben:
HTML<p i18n> Hello {{ userName }}, you have {{ messageCount }} new messages. </p>
Übersetzung:
XML<source>Hello {{ userName }}, you have {{ messageCount }} new messages.</source> <target>Hola {{ userName }}, tienes {{ messageCount }} mensajes nuevos.</target>
Variablen ({{ userName }}) bleiben unverändert. Übersetzer fassen sie nicht an.
Schritt 8: Daten, Zahlen, Währungen formatieren
Angular bietet eingebaute Pipes:
Datumsformatierung
HTML<p>{{ releaseDate | date:'fullDate' }}</p>
Automatische Locale-Anpassung:
- Englisch: "Monday, January 15, 2026"
- Spanisch: "lunes, 15 de enero de 2026"
- Deutsch: "Montag, 15. Januar 2026"
Locale in App bereitstellen:
TypeScript1import { LOCALE_ID } from '@angular/core'; 2import { registerLocaleData } from '@angular/common'; 3import localeEs from '@angular/common/locales/es'; 4import localeFr from '@angular/common/locales/fr'; 5 6registerLocaleData(localeEs); 7registerLocaleData(localeFr); 8 9@NgModule({ 10 providers: [ 11 { provide: LOCALE_ID, useValue: 'es' } // oder dynamisch erkennen 12 ] 13}) 14export class AppModule {}
Zahlenformatierung
HTML<p>{{ price | number:'1.2-2' }}</p>
Output:
- Englisch: "1,234.56"
- Deutsch: "1.234,56"
- Französisch: "1 234,56"
Währungsformatierung
HTML<p>{{ price | currency:'USD' }}</p>
Output:
- Englisch: "$1,234.56"
- Spanisch (Spanien): "1.234,56 US$"
Locale-spezifische Währung verwenden:
HTML<p>{{ price | currency:currencyCode }}</p>
TypeScriptexport class ProductComponent { currencyCode = 'EUR'; // oder 'USD', 'GBP' usw. }
Schritt 9: Laufzeit-Locale-Erkennung
Problem: Angulars @angular/localize ist zur Kompilierzeit, also müssen Sie den richtigen Build ausliefern.
Lösung: Erkennen Sie die Locale des Benutzers und leiten Sie zum korrekten Build um.
Von URL erkennen
Benutzer besucht /es/products → lädt spanischen Build.
Das geschieht automatisch, wenn Sie baseHref in angular.json konfigurieren.
Vom Browser erkennen
Wenn der Benutzer Root / besucht, leiten Sie basierend auf der Browsersprache um:
index.html:
HTML1<script> 2 // Browsersprache erkennen 3 const lang = navigator.language.split('-')[0]; // 'en', 'es', 'fr', etc. 4 const supportedLocales = ['en', 'es', 'fr', 'de']; 5 6 // Umleitung zur korrekten Locale 7 if (supportedLocales.includes(lang)) { 8 window.location.href = `/${lang}/`; 9 } else { 10 window.location.href = '/en/'; // Standard 11 } 12</script>
Server-seitige Erkennung (Empfohlen)
Verwenden Sie den Server zum Umleiten basierend auf dem Accept-Language Header:
Nginx-Beispiel:
NGINX1location = / { 2 # Sprache aus Accept-Language Header erkennen 3 set $lang "en"; 4 if ($http_accept_language ~* "^es") { 5 set $lang "es"; 6 } 7 if ($http_accept_language ~* "^fr") { 8 set $lang "fr"; 9 } 10 11 return 302 /$lang/; 12}
Schritt 10: Sprachumschalter
Erstellen Sie eine Sprachumschalter-Komponente:
TypeScript1import { Component } from '@angular/core'; 2 3@Component({ 4 selector: 'app-language-switcher', 5 template: ` 6 <select (change)="changeLanguage($event)"> 7 <option value="en">English</option> 8 <option value="es">Español</option> 9 <option value="fr">Français</option> 10 <option value="de">Deutsch</option> 11 </select> 12 `, 13}) 14export class LanguageSwitcherComponent { 15 changeLanguage(event: Event) { 16 const select = event.target as HTMLSelectElement; 17 const locale = select.value; 18 19 // Umleitung zur neuen Locale 20 const currentPath = window.location.pathname.split('/').slice(2).join('/'); 21 window.location.href = `/${locale}/${currentPath}`; 22 } 23}
Was es tut:
- Benutzer wählt "Español"
- Leitet von
/en/productszu/es/productsum - Angular serviert spanischen Build
Fortgeschritten: CI/CD-Integration
GitHub Actions Beispiel
.github/workflows/i18n-deploy.yml:
YAML1name: Build & Deploy with i18n 2 3on: 4 push: 5 branches: [main] 6 7jobs: 8 build-deploy: 9 runs-on: ubuntu-latest 10 steps: 11 - uses: actions/checkout@v3 12 13 - name: Setup Node 14 uses: actions/setup-node@v3 15 with: 16 node-version: '18' 17 18 - name: Install dependencies 19 run: npm ci 20 21 - name: Extract i18n strings 22 run: ng extract-i18n --output-path src/locale 23 24 - name: Upload to IntlPull 25 run: npx @intlpullhq/cli upload 26 env: 27 INTLPULL_API_KEY: ${{ secrets.INTLPULL_API_KEY }} 28 29 - name: Download translations 30 run: npx @intlpullhq/cli download 31 32 - name: Build all locales 33 run: ng build --localize --configuration production 34 35 - name: Deploy to Vercel 36 uses: amondnet/vercel-action@v20 37 with: 38 vercel-token: ${{ secrets.VERCEL_TOKEN }} 39 vercel-org-id: ${{ secrets.VERCEL_ORG_ID }} 40 vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }} 41 working-directory: ./dist/my-app
Ergebnis: Jeder Commit löst Übersetzungs-Sync + Deployment aus.
