Mehrsprachige Webseiten mit Lift und OSGi

Für die Internationalisierung von Webseiten bietet Lift bereits einige Mechanismen. Wird das Framework aber in einer OSGi-Umgebung verwendet, benötigt man einen kleinen Workaround, damit die Resource Bundles in Form von Property-Files gefunden werden können.

Internationalisierung mit Lift

Zunächst eine kleine Zusammenfassung der Möglichkeiten zur Internationalisierung mit Lift: Die String-Ressourcen müssen in so genannten "Property-Bundles" abgelegt werden. Das sind ganz normale Java-Properties-Dateien in der folgenden Form:

title=Meine Website
yes=Ja
no=Nein
deletequestion=Möchten Sie alles löschen?

Der Name der Property-Bundles beginnt immer mit lift. Jedoch werden unterschiedliche Suffixe angehängt, die die entsprechende Sprache und optional das Land im ISO-Format angeben. Zum Beispiel enthält die Datei lift_en.properties englische String-Ressourcen während lift_de.properties deutsche und lift_de_CH.properties schweizerdeutsche enthält. Den Präfix lift kann man im Boot-Loader der Webapplikation spezifizieren:

LiftRules.resourceNames = "anotherPrefix" :: Nil

Die Variable resourceNames ist dabei eine Liste von Strings. Das heißt, man kann seine Resource-Bundles auch in mehrere Dateien mit unterschiedlichen Präfixen aufteilen, damit man z.B. in großen Projekten nicht den Überblick verliert.

Hat man die Resource-Bundles erstellt, kann man Strings in HTML-Templates mit <lift:loc locid="..." /> übersetzen. Verwendet man also die Properties-Datei aus obigem Beispiel, dann wird das folgende Template

<html>
<head>
<title><lift:loc locid="title" /></title>
</head>
<body>
<lift:loc locid="deletequestion" />
<button><lift:loc locid="yes" /></button>
<button><lift:loc locid="no" /></button>
</body>
</html>

in folgenden HTML-Code übersetzt:

<html>
<head>
<title>Meine Website</title>
</head>
<body>
Möchten Sie alles Löschen?
<button>Ja</button>
<button>Nein</button>
</body>
</html>

Im Scala-Quellcode kann man stattdessen das Stateful-Objekt net.liftweb.http.S verwenden. Es definiert die Methode ?, die einen String als Parameter annimmt und diesen im Resource-Bundle sucht:

def snippet(xhtml: NodeSeq): NodeSeq =
  <p>{ S ? "deletequestion" }</p>

Ein kleiner Tipp: Möchte man in den HTML-Templates Tag-Attribute übersetzen (z.B. das Attribut value eines input-Elements), dann sollte man den entsprechenden Teil in ein Snippet auslagern, sodass man das S-Objekt verwenden kann:

def inputButton(xhtml: NodeSeq): NodeSeq =
  <input type="button" value={ S ? "yes" } />

Resource-Bundles in der OSGi-Umgebung

Das Problem mit der oben beschriebenen Methode ist, dass die Resource-Bundles von Lift im Classpath mittels getClass.getClassLoader.getResourceAsStream() gesucht werden. In einer OSGi-Umgebung können Sie demnach nicht mehr gefunden werden, da der Classloader des Bundles net.liftweb.lift-webkit verwendet wird.

Wie eingangs erwähnt, kann man dies mit einem Workaround lösen. Dazu muss man im BootLoader eine Resource-Bundle-Factory definieren:

LiftRules.resourceBundleFactories prepend {
  case (basename, locale) => ResourceBundle.getBundle(basename, locale)
}

Dadurch werden die Resource-Bundles über den Classloader des Bundles, das den BootLoader enthält, geladen.

Zusammenfassung

Die Mechanismen zur Internationalisierung mit Lift sind ausreichend für die meisten Webseiten. Wenn man etwas mit dem Lift-Tag nicht übersetzen kann (z.B. Attribute) oder man mehr Kontrolle benötigt, muss man auf Snippets ausweichen. In OSGi-Umgebungen muss man eine Resource-Bundle-Factory erzeugen, die die Properties-Dateien über den korrekten Classloader lädt.

blog comments powered by Disqus