l10n - mache deine Anwendung zum Global Player

l10n - mache deine Anwendung zum Global Player

Früher war alles besser™. Wenn man früher eine Anwendung baute, hatte diese in aller Regel nur genau einen Zielmarkt, der idealerweise im selben Land zu finden war wie die Firma, die das Produkt entwickelte. Das Entwicklerteam musste sich also nicht mit LTR/RTL-Sprachen oder mehreren Languagefiles, sowie davon abhängige Interfaceanpassungen rumschlagen.

Zugegeben, "früher war alles besser" ist eine Floskel, die einfach nie stimmt. Pauschalisierung ist immer quatsch. Früher war es für den Entwickler vielleicht einfacher, da er sich nur um eine Sprache kümmern musste. Oder für den Designer, der bei dem Interface die RTL (Right-to-left) Sprachen nicht beachten musste. Früher war es aber für den Anwender ganz sicher nicht besser, der sein bevorzugtes "Programm" nicht in seiner Muttersprache benutzen konnte.

Moderne Anwendungen werden fast immer in dutzende Sprachen übersetzt - internationalisiert. Zur Internationalisierung gehört unter Anderem auch das Anpassen des Datumsformats, das inhaltliche Ändern von Texten und Beachten von lokalen No Go's. In diesem Artikel möchte ich mich primär mit dem Übersetzen und Anpassen der Texte (Localization - l10n, das führende L gefolgt von 10 Buchstaben und dem abschließenden n) widmen.

Im ersten Schritt solltest du dir das Flutter Intl Plugin für VSCode installieren, dass dir die Arbeit mit unterschiedlichen Sprachen deutlich erleichtern wird. Ist das Plugin erstmal installiert, starten wir mit dem Standardtemplate von Flutter. Du kannst in der pubspec.yaml bei deinen Dependencies das intl-Package, wahlweise mit fester Versionsnummer, hinzufügen. Außerdem benötigen wir den flutter_localizations Eintrag, der grundlegende Lokalisierungsmöglichkeiten aktiviert.

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  cupertino_icons: ^0.1.3
  intl:

Anschließend wählst du über die Command-Palette (⌘ + ⇧ + P) den Befehl Flutter: Intl initialize um das grundlegende Setup für die Lokalisierung deiner Flutter Anwendung zu tätigen. Dabei werden die Ordner lib/generated sowie lib/l10n generiert.

Tipp:
Der Ordner generated sollte niemals manuell bearbeitet werden, da die dort enthaltenen Dateien mit jeder Änderung an der .arb-Datei automatisch neu generiert werden. Dadurch wird jede deiner manuellen Anpassungen überschrieben.

Im nächsten Schritt geht es an die Bearbeitung der intl_en.arb. Dort trägst du einen String ein, den du anzeigen möchtest. Lass dich nicht von der .arb-Endung täuschen, unter der Haube ist das ein aufgebohrtes JSON, du kannst dich also an bisherige JSON Syntax halten.

{
  "main_button_pushed_description": "You have pushed the button this many times:"
}

Wenn du nach dem Bearbeiten der .arb-Datei schnell zur messages_en.dart oder l10n.dart wechselst, kannst du sehen, wie der Code auf magische Weise generiert wird.

/// `You have pushed the button this many times:`
  String get main_button_pushed_description {
    return Intl.message(
      'You have pushed the button this many times:',
      name: 'main_button_pushed_description',
      desc: '',
      args: [],
    );
  }

Somit steht dir der vergebene Key überall in der Anwendung zur Verfügung. Um auf den Key zugreifen zu können, musst du in der Anwendung lediglich noch den entsprechenden Import machen. Wie du in der l10n.dart sehen kannst, hat die standardmäßig generierte Klasse den Namen S.

Wer einen deutschen iOS Simulator oder Android Emulator nutzt, wird sich vielleicht fragen "was passiert mit meinen String, wo ich doch nur "en"-Files habe?".
Das ist kein Problem, denn Flutters Fallback, die default language, ist momentan en, so wird jeder Text der nicht in einer anderen Sprache verfügbar ist, aus der englischen Sprachdatei genommen.

Apropos andere Sprachen: neue Sprachen lassen sich ganz bequem über die Command-Palette (⌘ + ⇧ + P) hinzufügen. Einfach den Befehl Flutter Intl: Add locale auswählen, den Language Identifier (z. B. de oder de_DE) eingeben und bestätigen, die Generierung des notwendigen Codes übernimmt das Plugin wieder für dich.

Anschließend kannst du deine Texte einmal in der intl_en.arb und einmal in der intl_de.arb sprachspezifisch bearbeiten.

Tipp:
Du kannst eine intl_de_DE.arb zusammen mit einer intl_de.arb verwenden. Die spezifischere Datei, also de_DE, hat dabei immer vor der unspezifischeren Vorrang. Bedeutet konkret wenn du für Deutschland eigene Texte hast, kannst du diese in der de_DE hinterlegen, wohingegen alle anderen Benutzer aus deutschsprachigen Ländern, zum Beispiel Österreich mit dem Kürzel de_AT, auf die intl_de.arb  zurück greifen.

In der main.dart gibt es noch ein weiteres Text Widget das eine Besonderheit aufweißt: es wird dynamisch über eine variable, counter, gesetzt. Selbstverständlich kannst du auch solche Texte lokalisieren. Dazu legst du ein weiteres Key-Value Paar in der .arb-Datei an:

{
  "main_button_pushed_description": "You have pushed the button this many times:",
  "main_button_count": "Count: {count}"
}

Der Inhalt der geschweiften Klammern wird durch einen Parameter ersetzt, den wir von außen reingeben können. Im Vergleich zum vorher angelegten Getter einer Computed Property wird hier eine Methode in der l10n.dart angelegt:

 /// `Count: {count}`
  String main_button_count(Object count) {
    return Intl.message(
      'Count: $count',
      name: 'main_button_count',
      desc: '',
      args: [count],
    );
  }
}

Die Methode kannst du so benutzen, wie du auch vorher den Getter benutzt hast:

Um in der Anwendung die Verwendung mehrerer Sprachen zu aktivieren, müssen noch zwei Einträge in der main.dart erledigt werden. Die Property localizationsDelegates zeigt an, welche Delegates nun als "Übersetzer" fungieren sollen. Der Eintrag supportedLocales definiert, welche Sprachen tatsächlich unterstützt werden. Dabei wird der erste Eintrag als Fallback benutzt, falls eine vom Benutzer gewählte Sprache nicht unterstützt wird.

Das Team hinter dem flutter_intl Package hat selbstverständlich auch an Anwendungen gedacht, die die englische Sprache nicht unterstützen wollen. So kann neben dem Standardklassennamen S auch die Standardsprache konfiguriert werden. Dazu musst du die pubspec.yaml um folgende Einträge ergänzen:

flutter_intl:
  enabled: true
  class_name: S # Optional. Sets the name for the generated localization class. Default: S
  main_locale: en # Optional. Sets the main locale used for generating localization files. Provided value should comply with ISO-639-1 and ISO-3166-1 (e.g. "en", "en_GB"). Default: en

Das Thema Internationalisierung einer App ist unglaublich komplex. Ich hoffe, ich konnte dir die ersten Schritte näher bringen und dir den Start erleichtern. In einem späteren Blogeintrag können wir sicher etwas mehr in die Tiefe gehen oder Dinge wie das Datumsformat oder RTL-Sprachen näher beleuchten.

Wenn du Lust hast in dem fertigen Projekt zu spielen, dann findest du hier den kompletten Quellcode dazu frei verfügbar. Solltest du Fragen haben, sprich mich einfach an, ich bin jederzeit an einem Austausch interessiert.

Tags :

Pascal Friedrich

Softwareentwickler mit dem Schwerpunkt mobile Apps und Internet of Things. Begeistert von den Möglichkeiten eines Arduinos, Fan von Flutter.