Bundletexte zurück in den Quelltext

Mit erscheinen der Version 7 der NetBeans Plattform sind auch einige neue Annotations hinzugekommen. Es scheint als würden die NetBeans Entwickler so langsam das Potential dieses Programmierkonstruktes nutzen wollen. Mit allen Konsequenzen. Eine dieser Neuerungen ist die Annotation @Message. Geertjan hat in seinem Blog bereits einen Kommentar darüber abgegeben.

Ziel dieser Annotation ist es (wohl) die Texte einer Benutzeroberfläche wieder zurück in den Quelltext zu packen. Und seien wir ehrlich, die Grundidee dahinter ist nicht schlecht. Es ist um einiges einfacher nur eine einzelne Datei zu bearbeiten statt sich mit “vielen” (Source, Bundle, Layer, …) auseinander setzen zu müssen und auch noch den Überblick dabei zu behalten.

Die Annotation kann an Klassen, Konstruktoren oder Methoden angebracht werden. Aber auch in der package-info lässt sie sich angeben. Der Kompiler erstellt in dem zugehörigen Paket automatisch eine Bundle.properties mit allen definierten Texten sowie eine neue Klasse Bundle in der für jeden Bundlekey eine eigene Methode generiert wird. Diese Methode kann dann verwendet werden um an den gewünschten Text zu gelangen.

Bisher wurden Bundletexte in einer ähnlichen Form wie hier ermittelt:

1
2
3
JButton button = new JButton(
    NbBundle.getMessage(MyPanel.class, "MyPanel.button_title")
    );

Zusätzlich musste man darauf achten, dass eine zugehörige Bundle.properties angelegt wurde und darin auch der Schlüssel MyPanel.button_title vorhanden ist. Danach liegt es einzig und alleine am Programmierer darauf zu achten, dass der Schlüssel auch in der korrekten Bundledatei bleibt. Vor allem beim Refaktoring kann das schon mal aufwändig werden. Werden hier Fehler gemacht, werden diese frühestens zur Laufzeit entdeckt. Bei Texten, die selten benötigt werden kann dieser Fehler aber auch schon mal eine ganze weile unbemerkt in den Tiefen des Programms schlummern bevor er bemerkt wird. Und nach Murphy wird es der Endanwender sein, der diesen (vermeidbaren) Fehler schließlich entdeckt.

Mit der @Message Annotation kann die Bundle.properties (fast) vollständig ignoriert werden. Sowohl Key als auch der Standardtext dafür werden direkt in den Quelltext geschrieben. Allerdings nicht wie bei “hardcodierten” Texten an der Stelle wo sie benötigt werden, sondern an der “nächstbesten passenden Stelle”. Genauer kann ich das nicht sagen. Denn es ist stark Kontextabhängig ob die Annotation an der zugehörigen Methode oder in der Klasse oder gar in der package-info angebracht wird. Es liegt auch daran, wie oft dieser Text verwendet wird. Wird er in mehreren Methoden benötigt, macht die Klasse mehr Sinn als eine dieser Methoden. Bei Texten, die gar in mehreren Klassen angewandt wird ist die Sache schon komplizierter. Eigentlich hebelt man hier die eigentliche Absicht, die Texte wieder näher an den Quelltext zu binden, wieder aus.

Das obige Beispiel würde jetzt so aussehen:

1
2
3
4
5
@NbBundle.Messages("MyPanel.button_title=The Button Title")
public MyPanel()
{
  JButton button = new JButton(Bundle.MyPanel_button_title());
}

Alle Punkte in den Bundlekeys werden bei den Methodennamen automatisch in Unterstriche umgewandelt. Und wie man an diesem kleinen Beispiel bereits sieht, sollte man sich in Zusammenhang mit der Annotation wieder Gedanken machen, wie man die Keys benennt.

Die @Message Annotation kann auch mit Texten umgehen, in denen “Variablen” verwendet werden. Sobald im Text ein {0} bekommt die generierte Methode eine passende Parameterliste über die die Variablenwerte übergeben werden können:

1
2
3
4
5
6
@NbBundle.Messages("MyPanel.button_title=Button Number {0}")
public MyPanel()
{
  JButton button1 = new JButton(Bundle.MyPanel_button_title(1));
  JButton button2 = new JButton(Bundle.MyPanel_button_title(2));
}

Um die ganze Sache noch zu verfeinern kann man den generierten Parametern auch Namen geben:

1
2
3
4
@NbBundle.Messages({
  "# {0} - number",
  "MyPanel.button_title=Button Number {0}"
})

Hier wird number als Name für den ersten Parameter verwendet.

Wie hier zu sehen ist, kann man auch durchaus mehrere Bundleeinträge in einer Annotation unterbringen. Wie z.B. auch bei @SuppressWarning üblich wird ein “String-Array” erwartet und jeder String daraus als Zeile in der Bundle.properties eingetragen und entsprechende Methoden in der Bundle Klasse generiert.

Ein Problem ergibt sich daraus allerdings. Wir verwenden bei uns z.B. den Suite Translator für unsere RCP Anwendungen. Dieser erkennt allerdings nur Bundle-Dateien, die auch im Quellordner der Module liegen. Mit der @Messages Annotation existieren die Bundle.properties Dateien aber erst nach dem Compilevorgang. Um wirklich die vollständige Anwendung übersetzen zu können wird also immer eine Compilierte Version der Anwendung benötigt. Oder es müssen Tools erstellt werden, die auch die @Messages Annotations im Quelltext erkennen.

Sie können eine Kommentar,oderTrackback von Ihrer Webseite hinterlassen.

Leave a Reply


eins + 8 =