Symfony Translation & i18n mit ICU Message Format
AI generated
SF
{ }
Symfony · Translation · ICU · i18n · Lokalisierung
Symfony Translation & i18n
mit ICU Message Format professionell umsetzen

Einfache String-Ersetzungen reichen für echte Mehrsprachigkeit nicht aus. Plural­formen, Geschlechts­anpassungen, Datums- und Zahlen­formate nach Locale und kontextabhängige Meldungen brauchen das ICU Message Format — das die Symfony-Translation-Komponente seit Version 5 vollständig unterstützt.

17 Min. Lesezeit ICU · XLIFF · Translator · Pluralisierung · Extraktion Symfony 7.x · PHP 8.3+ · intl-Extension

1. Warum einfache Übersetzungen nicht ausreichen

Viele Symfony-Projekte starten mit simplem String-Replacement: Ein Schlüssel wird einem Satz zugeordnet, Variablen werden mit %count% eingebettet. Das funktioniert für Englisch gut — Englisch hat nur zwei Pluralformen, kennt kaum Kasus und kommt mit wenig grammatikalischer Flexion aus. Sobald Deutsch, Russisch, Arabisch oder Polnisch ins Spiel kommen, stößt dieses System an harte Grenzen. Polnisch hat vier Plural­formen, Arabisch sechs, und viele Sprachen passen Artikel und Adjektive ans Geschlecht des Subjekts an. Mit klassischem Symfony Translation und %count%-Variablen sind diese Anforderungen nicht elegant lösbar.

Das ICU Message Format ist der internationale Standard für diese Probleme. Es wurde von der Unicode-Organisation spezifiziert, ist in Android, iOS, Java und allen modernen Frontend-Frameworks verbreitet und steht in PHP über die intl-Extension zur Verfügung. Symfony Translation integriert das ICU Message Format als nativen Formatter — Übersetzungs­kataloge können beide Formate mischen, ältere Meldungen müssen nicht sofort migriert werden. Der entscheidende Vorteil: Übersetzerinnen und Übersetzer beschreiben die sprachliche Logik direkt in der Übersetzung, nicht in PHP-Code.

2. Symfony Translation einrichten und konfigurieren

Die Symfony-Translation-Komponente ist im Standard-Symfony-Skeleton über das Flex-Recipe bereits enthalten. Für ICU Message Format braucht man zusätzlich die PHP intl-Extension, die in den meisten PHP-Installationen aktiv ist. In config/packages/translation.yaml legt man die Standard-Locale, den Fallback und den Pfad zu den Katalogdateien fest. Der Formatter-Typ wird pro Dateiname durch die Dateiendung gesteuert: Dateien mit der Endung +intl-icu.xlf oder +intl-icu.yaml verwenden automatisch den ICU-Formatter, alle anderen Dateien nutzen den klassischen Symfony-Formatter.

Die empfohlene Verzeichnisstruktur legt Übersetzungen in translations/ im Projekt­root ab, unterteilt nach Domain und Locale: messages+intl-icu.de.xlf für die Standard-Domain auf Deutsch, validators+intl-icu.de.xlf für Validierungs­meldungen. Der Befehl bin/console translation:extract de --format=xlf20 --output-format=xliff2 --force durchsucht automatisch alle Twig-Templates und PHP-Klassen nach verwendeten Translations-Schlüsseln und legt fehlende Einträge in den Katalogen an. Das spart erhebliche manuelle Arbeit beim Pflegen großer Übersetzungs­dateien.


<?php
// config/packages/translation.yaml
// framework:
//   default_locale: de
//   translator:
//     default_path: '%kernel.project_dir%/translations'
//     fallbacks: [en]
//     providers: []

// Directory structure for ICU-enabled translations:
// translations/
//   messages+intl-icu.de.xlf   ← ICU formatter activated by filename suffix
//   messages+intl-icu.en.xlf
//   validators+intl-icu.de.xlf
//   emails+intl-icu.de.xlf

// Extract all translation keys from Twig + PHP automatically:
// bin/console translation:extract de --format=xlf20 --force
// bin/console translation:extract en --format=xlf20 --force

// Check for missing translations:
// bin/console debug:translation de
// bin/console debug:translation de --only-missing

// Verify intl extension is available (required for ICU):
// php -m | grep intl

3. ICU Message Format: Syntax und Grundlagen

Das ICU Message Format erweitert einfache Variablen­ersetzungen um eine vollständige Ausdrucks­sprache für sprachliche Varianten. Variablen werden in geschweifte Klammern geschrieben: {name} ersetzt die Variable direkt. Für komplexere Ausdrücke folgt dem Variablen­namen ein Komma und der Ausdrucks­typ: {count, plural, one {# Artikel} other {# Artikel} }. Das Rautezeichen # steht dabei für den formatierten Wert der aktuellen Variablen. Diese Syntax ist für Übersetzerinnen und Übersetzer lesbar genug, um sie ohne PHP-Kenntnisse zu bearbeiten — ein wichtiger Faktor für professionelle Übersetzungs-Workflows mit externen Agenturen.

Der Symfony-Translator übergibt Parameter als assoziatives Array an die trans()-Methode. Im klassischen Format werden Platzhalter wie %name% ersetzt. Im ICU Message Format übergibt man die Werte direkt ohne Prozentzeichen: $translator->trans('greeting', ['name' => 'Maria'], domain: 'messages'). Die ICU-Engine kümmert sich selbst um Typprüfung, Formatierung und die Auswahl der richtigen Sprachvariante. Das Mischen beider Formate in einem Projekt ist möglich — alte Dateien mit der klassischen Endung nutzen den alten Formatter, neue ICU-Dateien mit dem +intl-icu-Suffix den ICU-Formatter.

4. Pluralisierung korrekt umsetzen

Plural­formen sind das häufigste Problem in der Symfony-Translation. Das klassische Format nutzt eine eigene Pipe-Syntax (One article|{count} articles), die für komplexe Plural­regeln schnell unübersichtlich wird. Das ICU Message Format löst Plural­formen mit dem plural-Ausdruck, der von der intl-Extension die sprachspezifischen Plural­regeln der aktuellen Locale lädt. Für Deutsch gibt es die Schlüssel one (Singular) und other (Plural). Für Russisch kommen few und many dazu. Das ICU Message Format kennt die Regeln für alle Sprachen — das Team muss nur die Texte liefern, nicht die Logik programmieren.

Besonders mächtig ist die Kombination von Pluralisierung mit Variablen in derselben Meldung. Eine typische E-Commerce-Meldung: „Sie haben 3 Artikel im Warenkorb. Der Gesamtpreis beträgt 89,90 €." müsste bei einem Artikel den Singular verwenden und den Preis locale-korrekt formatieren. Im ICU Message Format ist das eine einzige Übersetzungs­einheit, die alle Fälle deklarativ abdeckt — ohne if-else-Konstrukte im PHP-Code.


<?php

declare(strict_types=1);

namespace App\Service;

use Symfony\Contracts\Translation\TranslatorInterface;

/**
 * Demonstrates ICU Message Format usage in a Symfony service.
 */
final readonly class OrderSummaryService
{
    public function __construct(
        private TranslatorInterface $translator,
    ) {}

    /**
     * Build a human-readable order summary using ICU pluralization.
     */
    public function getSummaryMessage(int $itemCount, float $total, string $locale): string
    {
        // ICU plural — the translator selects the correct plural rule for the locale
        return $this->translator->trans(
            id: 'order.summary',
            parameters: [
                'count' => $itemCount,
                'total' => $total,
            ],
            locale: $locale,
        );
    }
}

// translations/messages+intl-icu.de.xlf entry (simplified):
// <trans-unit id="order.summary">
//   <source>order.summary</source>
//   <target>{count, plural,
//     one   {Sie haben # Artikel im Warenkorb. Gesamt: {total, number, ::currency/EUR}.}
//     other {Sie haben # Artikel im Warenkorb. Gesamt: {total, number, ::currency/EUR}.}
//   }</target>
// </trans-unit>

// English variant in messages+intl-icu.en.xlf:
// {count, plural,
//   one   {You have # item in your cart. Total: {total, number, ::currency/EUR}.}
//   other {You have # items in your cart. Total: {total, number, ::currency/EUR}.}
// }

5. Select-Ausdrücke für Geschlecht und Varianten

Der select-Ausdruck im ICU Message Format wählt basierend auf einem String-Wert zwischen vordefinierten Varianten. Das klassische Anwendungs­szenario ist die Anpassung von Anrede und Possessiv­pronomen nach Geschlecht: {gender, select, female {Ihre Bestellung} male {Seine Bestellung} other {Ihre Bestellung} }. Der other-Zweig ist Pflicht und dient als Fallback für alle nicht explizit genannten Werte. Das ermöglicht auch den Fall „divers" oder unbekanntes Geschlecht ohne separate Übersetzungs­einheit.

Verschachtelte select- und plural-Ausdrücke sind im ICU Message Format erlaubt und decken komplexe sprachliche Fälle ab. Ein Beispiel: Auf Russisch muss ein Substantiv nach Numerale nicht nur nach Plural­form, sondern auch nach Geschlecht flektiert werden. Diese Logik liegt vollständig in der Übersetzungs­datei — der PHP-Code bleibt unverändert. Für Teams, die mit externen Übersetzungs­agenturen arbeiten, ist das ein wichtiger Vorteil: Die Agenturen arbeiten in ihrer Fachdomäne, ohne dass ein Entwickler­eingriff nötig ist.

6. Datum, Uhrzeit und Zahlen lokalisieren

Das ICU Message Format bringt eigene Formatter für Datum, Uhrzeit und Zahlen mit, die aus dem intl-Standard stammen. Ein Datum formatiert man mit {date, date, medium} für ein mittellanges Format (z. B. „9. Mai 2026" auf Deutsch, „May 9, 2026" auf Englisch). short, long und full sind weitere Stufen. Für Zahlen steht {amount, number, ::currency/EUR} bereit, das die Zahl locale-korrekt mit Währungs­symbol formatiert: „89,90 €" auf Deutsch, „€89.90" auf Englisch. Diese Formatter verwenden automatisch die aktive Locale des Symfony-Translators.

Für Uhrzeiten gilt {time, time, short} für „14:30" (Deutsch) bzw. „2:30 PM" (Englisch-US). Relative Zeitangaben wie „vor 5 Minuten" oder „in 2 Tagen" kann man kombinieren: Eine Übersetzungs­einheit enthält einen plural-Ausdruck für die Zahl und einen select-Ausdruck für Vergangenheit/Zukunft. Das ist ausdrucksstärker als das klassische Symfony-Choiceformat und benötigt kein zusätzliches Twig-Filter. Die Symfony-Translation-Komponente übergibt alle Parameter als native PHP-Werte — \DateTimeInterface-Objekte werden automatisch vom ICU-Formatter korrekt umgewandelt.

7. XLIFF-Kataloge verwalten und extrahieren

XLIFF 2.0 ist das empfohlene Dateiformat für Symfony Translation in produktiven Projekten. Es ist der ISO-Standard für den Austausch von Übersetzungs­daten, wird von professionellen CAT-Tools (Computer-Aided Translation) wie SDL Trados, MemoQ und Memsource unterstützt und enthält Metadaten über den Übersetzungs­status einzelner Einheiten. Das bedeutet: Wenn das Team mit einer externen Übersetzungs­agentur arbeitet, können XLIFF-Dateien direkt übergeben werden, ohne ein proprietäres Format zu benötigen.

Der Extractions-Befehl bin/console translation:extract durchsucht Twig-Templates nach trans-Tags und PHP-Dateien nach $translator->trans()-Aufrufen. Neu gefundene Schlüssel werden in die bestehenden XLIFF-Dateien eingefügt, ohne vorhandene Übersetzungen zu überschreiben. Das --sort-Flag sortiert die Einheiten alphabetisch, was Diff-Lesbarkeit im Git-Repository verbessert. Mit --clean entfernt der Befehl Einträge, die im Code nicht mehr vorkommen — ideal für die regelmäßige Bereinigung alter Übersetzungs­schlüssel in aktiv entwickelten Projekten.


<?xml version="1.0" encoding="utf-8"?>
<!--
  translations/messages+intl-icu.de.xlf
  XLIFF 2.0 with ICU Message Format content
  The +intl-icu suffix in the filename activates the ICU formatter automatically.
-->
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0"
       srcLang="en" trgLang="de">
  <file id="messages+intl-icu.de">

    <!-- Simple variable substitution -->
    <unit id="greeting.user">
      <segment state="translated">
        <source>Hello, {name}!</source>
        <target>Hallo, {name}!</target>
      </segment>
    </unit>

    <!-- ICU plural with currency formatting -->
    <unit id="cart.summary">
      <segment state="translated">
        <source>{count, plural, one {# item} other {# items} } — Total: {total, number, ::currency/EUR}</source>
        <target>{count, plural, one {# Artikel} other {# Artikel} } — Gesamt: {total, number, ::currency/EUR}</target>
      </segment>
    </unit>

    <!-- ICU select for gender-aware salutation -->
    <unit id="order.salutation">
      <segment state="translated">
        <source>Dear {gender, select, female {Ms.} male {Mr.} other {} } {name},</source>
        <target>{gender, select, female {Sehr geehrte Frau} male {Sehr geehrter Herr} other {Sehr geehrte/r} } {name},</target>
      </segment>
    </unit>

    <!-- Date and time formatting via ICU -->
    <unit id="invoice.date">
      <segment state="translated">
        <source>Invoice date: {date, date, long}</source>
        <target>Rechnungsdatum: {date, date, long}</target>
      </segment>
    </unit>

  </file>
</xliff>

8. Translation in Twig-Templates einsetzen

In Twig-Templates nutzt man den trans-Filter und das {% trans %}-Tag für Symfony-Übersetzungen. Mit dem ICU Message Format übergibt man Parameter als Hash: { { 'cart.summary'|trans({count: items|length, total: cartTotal}) } }. Der Filter erkennt automatisch die aktive Locale und leitet den Aufruf an den ICU-Formatter weiter, wenn der Schlüssel in einer +intl-icu-Datei liegt. Die Angabe einer Domain erfolgt als zweiter Parameter: { { 'form.submit'|trans({}, 'forms') } }.

Für längere Übersetzungs­blöcke mit eingebettetem HTML empfiehlt sich das {% trans %}-Tag. Es unterstützt ICU-Variablen und gibt den gesamten Block als Übersetzungs­einheit zurück. Wichtig: HTML in Übersetzungs­strings sollte auf ein Minimum beschränkt werden, weil es die Arbeit für Übersetzerinnen und Übersetzer erschwert. Besser ist es, den HTML-Rahmen im Template zu halten und nur den Text zu übersetzen. Der translation:extract-Befehl erkennt beide Schreib­weisen und fügt beide korrekt in den XLIFF-Katalog ein — ohne manuellen Eingriff.

9. ICU vs. klassisches Symfony-Format im Vergleich

Der Vergleich zeigt, wo das ICU Message Format gegenüber dem klassischen Symfony-Translation-Format gewinnt und wo der Unterschied gering ist.

Anforderung Klassisches Symfony-Format ICU Message Format Empfehlung
Einfache Variable %name% {name} ICU: sauberer, standardkonform
Pluralisierung Pipe-Syntax, begrenzt auf 2–3 Formen Alle Plural­klassen der Locale ICU: unverzichtbar für Slawisch/Arabisch
Geschlecht / Select Nicht nativ unterstützt {gender, select, …} ICU: einzige saubere Lösung
Zahlen/Währung Twig-Filter nötig {amount, number, ::currency/EUR} ICU: in Übersetzung integriert
Kompatibilität mit CAT-Tools XLIFF ist kompatibel XLIFF + ICU: Industriestandard ICU: von Agenturen bevorzugt

Für einfache Projekte mit wenigen Sprachen und ohne komplexe Grammatik­anforderungen funktioniert das klassische Symfony-Translation-Format weiterhin gut. Sobald Russisch, Arabisch, Polnisch oder asiatische Sprachen hinzukommen, ist das ICU Message Format die einzige Lösung, die ohne Hacks in PHP-Code auskommt. Der Migrationspfad ist graduell: Neue Kataloge bekommen die +intl-icu-Endung, alte Kataloge laufen parallel weiter.

Mironsoft

Symfony-Entwicklung, i18n-Architektur und Mehrsprachigkeits-Strategie

Symfony-Applikation professionell mehrsprachig machen?

Wir implementieren vollständige i18n-Lösungen mit Symfony Translation und ICU Message Format — von der XLIFF-Katalog-Struktur über Plural­formen und Geschlechts­varianten bis zur automatischen Extraktion und CAT-Tool-kompatiblen Workflows.

i18n-Architektur

XLIFF-Katalog-Struktur, ICU-Integration und Extractions-Workflow für Symfony-Projekte jeder Größe

Migration

Bestehende Symfony-Translation-Projekte graduell auf ICU Message Format migrieren ohne Breaking Changes

Übersetzungs-Workflow

CAT-Tool-Integration, XLIFF-Export und automatische Synchronisierung mit Übersetzungs­agenturen

10. Zusammenfassung

Das ICU Message Format in der Symfony-Translation-Komponente löst die wichtigsten Schwächen klassischer String-Ersetzungs­systeme: Plural­formen für alle Sprachen, Geschlechts­anpassungen über select, locale-korrekte Datums-, Uhrzeit- und Zahlen­formatierung direkt in der Übersetzungs­einheit — ohne PHP-Code-Änderungen. Die Aktivierung erfolgt über das Dateinamen­suffix +intl-icu, die Migration von bestehenden Projekten ist graduell möglich. XLIFF 2.0 als Dateiformat stellt Kompatibilität mit professionellen CAT-Tools sicher und ermöglicht reibungslose Zusammenarbeit mit Übersetzungs­agenturen.

Der größte Hebel liegt in der Verlagerung von sprachlicher Logik aus dem PHP-Code in die Übersetzungs­datei. Ein Entwickler muss nicht wissen, wie viele Plural­formen Russisch hat — die Übersetzerin weiß es und trägt es direkt in den XLIFF-Katalog ein. Das Symfony-Translation-System verarbeitet diese Information korrekt, ohne dass ein Deployment-Zyklus für sprachliche Änderungen nötig ist. In Projekten mit aktiven Übersetzungs­teams ist das ein fundamentaler Effizienz­gewinn.

Symfony Translation mit ICU — Das Wichtigste auf einen Blick

ICU aktivieren

Dateiendung +intl-icu.xlf oder +intl-icu.yaml — der ICU-Formatter wird automatisch aktiviert. PHP intl-Extension ist Voraussetzung.

Plural & Select

{count, plural, one {# Artikel} other {# Artikel} } und {gender, select, female {…} male {…} other {…} } decken alle sprachlichen Fälle ab.

Zahlen & Datum

{amount, number, ::currency/EUR} und {date, date, long} formatieren locale-korrekt ohne Twig-Filter oder PHP-Formatter.

Extraktion

bin/console translation:extract de --format=xlf20 --force findet alle Schlüssel automatisch und pflegt XLIFF-Kataloge ohne manuellen Aufwand.

11. FAQ: Symfony Translation & i18n mit ICU Message Format

1Was ist das ICU Message Format in Symfony?
Internationaler Standard für Übersetzungen mit Pluralisierung, Geschlecht und Datums-/Zahlenformatierung. Aktivierung per Dateinamen-Suffix +intl-icu. PHP intl-Extension erforderlich.
2Wie aktiviere ich ICU in Symfony?
Katalogdatei als messages+intl-icu.de.xlf benennen. Symfony erkennt das Suffix automatisch und schaltet den ICU-Formatter ein — keine weitere Konfiguration nötig.
3Plural-Formen im ICU Message Format?
zero, one, two, few, many, other — locale-abhängig. Deutsch: one + other. Russisch: one, few, many. Arabisch: alle sechs. Die Regeln kommen aus der intl-Extension automatisch.
4ICU und klassisches Format mischen?
Ja. Klassische Dateien ohne Suffix laufen parallel zu ICU-Dateien mit +intl-icu-Suffix. Migration ist graduell möglich — alte Kataloge müssen nicht sofort umgestellt werden.
5Schlüssel automatisch extrahieren?
bin/console translation:extract de --format=xlf20 --force — findet alle Schlüssel in Twig und PHP, fügt fehlende Einträge in XLIFF ein, lässt bestehende Übersetzungen unberührt.
6Währungsformatierung mit ICU?
{amount, number, ::currency/EUR} in der Übersetzungseinheit. Locale-korrekt: auf Deutsch „89,90 €", auf Englisch „€89.90". Kein Twig-Filter oder PHP-Formatter nötig.
7DateTimeInterface direkt übergeben?
Ja. Symfony konvertiert DateTimeInterface-Objekte automatisch. {date, date, long} in der ICU-Einheit formatiert locale-korrekt ohne manuelles date() oder Twig-Filter.
8XLIFF kompatibel mit Übersetzungstools?
Ja. XLIFF 2.0 ist ISO-Standard, unterstützt von SDL Trados, MemoQ und Memsource. ICU Message Format in XLIFF ist Industriestandard für professionelle i18n-Workflows mit Agenturen.
9Select-Ausdruck für Geschlecht?
{gender, select, female {Sehr geehrte Frau} male {Sehr geehrter Herr} other {Sehr geehrte/r} }. Der other-Zweig ist Pflicht und fängt alle unbekannten Werte ab.
10Welche PHP-Extension brauche ich?
PHP intl-Extension. Prüfung: php -m | grep intl. In Docker: apt-get install php-intl. In den meisten PHP-Installationen standardmäßig aktiv.