Adobe Flex i18n

Hier mal zur Abwechslung ein kleiner Text für interessierte Programmierer.

Ich verwende bei der Arbeit momentan Adobe Flex um eine Internetanwendung zu erstellen. Diese Anwendung soll mehrsprachig verfügbar sein und man soll die Sprache der Anwendung on-the-fly umstellen können, ohne sie neu zu starten.

Wir speichern unsere internationalisierten Werte in einem XML File, der normale Weg bei Flex sind wohl RessourceBundles. Aber das spielt für das, auf was ich hinaus will keine Rolle.
Wir hatten bisher einen Recht umständlichen Weg gewählt, alle Labels etc. dynamisch zu ersetzen. Dies hat mich beim Übersetzen der Anwendung so gestört, dass ich ein bisschen recherchiert habe und dabei auf einen sehr einfachen aber auch effektiven Weg gestossen bin, das zu machen.

Eine wirklich fantastische Sache an Flex ist der Einsatz von Databindings, der sich durch alle Bereiche zieht. Man kann zum Beispiel Texte an Variablen oder Funktionen binden.
Dies in Kombination mit einer Funktion, die auf ein Event hört und schon hat man eine sich selbst aktualisierende Anwendung beim Sprachwechsel.

Hier mal ein bisschen Code um das zu verdeutlichen:
View.mxml

<mx:button label="{I18n.getText('module', 'key')}" />

ActionScript Klasse I18n:

public class I18n extends EventDispatcher
{
  // [...]
  private var currentLanguage:String = "de";

  [Bindable(event="languageChanged")]
  public function getText(module:String, key:String):String
  {
    return getTextFromXML(module, text);
  }

  public function changeLanguage(language:String):void
  {
    this.currentLanguage = language;
    this.dispatchEvent(new Event("languageChanged"));
  }
}

In der MXML Datei wird die Funktion I18n::getText an das Label Property der Button Komponente gebunden. Die Funktion selbst ruft eine andere Funktion auf, die abhängig von der gerade gewählten Sprache (currentLang) den durch module und key bezeichneten Wert aus einer XML Datei holt. Dieser Teil ist natürlich Implementierungssache und kann komplett anders aussehen.
Das wichtige an getText ist die Zeile darüber: [Bindable(event=“languageChanged“)]. Dies bedeutet, dass die Funktion auf ein Event „languageChanged“ hört. Wird dieses dispatched, aktualisieren sich alle daran gebundenen Werte.

Die Funktion changeLanguage wird beim Ändern der Sprache aufgerufen. Hier wird die Sprache auf den aktuellen Wert gesetzt und das languageChanged Event dispatched. Um dieses zu tun, muss die I18n klasse von EventDispatcher abgeleitet sein.

Und das war’s auch schon. Keine große Sache, aber mir hat es das Leben deutlich vereinfacht 😉