D) Mehrsprachigkeit mit Bundles in Java
Bestimmt kennen Sie das: Sie haben ein großes Programm mit vielen GUI-Beschriftungen. Nun kommt ein User auf die Idee, dass es das Programm ja auch in anderen Sprachen geben könnte. Also suchen Sie alle setText()
-Methoden aus Ihrem Code und erstellen zum Beispiel noch eine englische Version. Sehr aufwendig. Vor allem, weil es einen vorgefertigten Standard in Java für dieses Problem gibt: Bundles. Bundle ist englisch und heißt übersetzt „Bündel“. Und genau das ist es auch – ein Bündel aus Vertextungen, also bspw. für Buttons, Labels, Konsolenausgaben oder Ähnlichem. Dieses Kapitel wird den Einsatz von Bundles ohne IDE, wie auch unter der Verwendung der IDE NetBeans erläutern.
Vorbereitung
Zuerst brauchen wir ein kleines Programm, um die Bundles in Aktion zu sehen. Legen Sie dazu mit Ihrem Texteditor oder Ihrer IDE folgendes Programm an:
public class TestBundle { public static void main(String[] args){ System.out.print("Hallo Welt"); } }
Um Bundles zu testen, brauchen Sie keine aufwendige GUI, denn jeder String
im Programm kann von Bundles dargestellt werden. Damit Sie Bundels kennenlernen, reicht dieses Programm also vollkommen.
Ein Bundle ohne IDE anlegen
Konsolenuser erstellen eine Datei Bundle.properties und speichern diese im Root-Ordner, in welchem sich auch die kompilierten .class-Dateien befinden, ab. In die Datei schreiben Sie lediglich folgende Zeile:
test=Hallo Welt
Wie Sie sehen, handelt es sich hierbei um eine gewöhnliche Properties-Datei (siehe Kapitel 09.09 Standardisiertes Speichern). Auf diese Art können Sie beliebig viele Keys hinzufügen und abspeichern. Im Programm müssen Sie jetzt die Output-Zeile folgendermaßen abändern und java.util.ResourceBundle
importieren:
System.out.print(ResourceBundle.getBundle("Bundle").getString("test"));
Jetzt können Sie das Programm kompilieren und ausführen. Auf dem Bildschirm erscheint der Text Hallo Welt.
Ein Bundle mit NetBeans anlegen
NetBeans-User gehen in ein beliebiges Package und fügen über das Kontextmenü New/Empty File (ggf. Muss Empty File über Other Files im Kontextmenü ausgewählt werden) eine neue Datei ein. Als Name wird Bundle.properties angegeben. Öffnen Sie nun das Kontextmenü der neu erschienenen Datei und wählen Sie Open aus. Eine Tabelle öffnet sich. Drücken Sie auf den Button New Property, geben Sie bei Key den Wert test ein, und bei Value den Wert Hallo Welt. Auf diese Art können Sie beliebig viele Keys hinzufügen. Nun wechseln Sie zu Ihrem Programm und markieren Sie den Inhalt der Klammern beim Aufruf von println()
. Betätigen Sie die Tastenkombination Strg+Shift+J und wählen Sie im Verzeichnisbaum das Bundle aus. Anschließend suchen Sie bei Key den Eintrag test heraus. Im Feld Value erscheint jetzt Hallo Welt
. Wenn Sie jetzt das Programm ausführen, können Sie ebenfalls Hallo Welt
im Ausgabefenster lesen.
Bundles anlegen – Zusammenfassung
In beiden Vorgehensweisen ist test ein Key. Der Name dieses Keys ist etwas unglücklich gewählt, da er nicht den Java-Konventionen entspricht. Normalerweise sollte man anhand von Keys immer erlesen können, wo er (oder die Value) verwendet wird. Zum Beispiel könnte ein Key MainFrame.menu.exitItem.text
heißen. Aus dieser Namensgebung geht hervor, dass der zum Key gehörige Wert die Vertextung eines Beenden-Buttons im Menü beinhaltet. Bitte beachten Sie, dass es nicht zwingend notwendig ist, die Keys nach diesem Muster zu benennen. Es wird Ihnen jedoch die Arbeit mit Bundles sehr vereinfachen. Vor allem, wenn mehrere hundert Keys in einem Bundle stecken, wie es bei einem großem Programm der Fall ist. In unserem Beispielprogramm hätte man den Key statt test bspw. Main.greeting.outputtext nennen können.
Mehrere Bundles verwenden
Sie fragen sich jetzt sicher: Und wozu ist das Ganze gut? Was hilft mir das, wenn ich ein Programm schnell übersetzen will? Es gibt doch dann trotzdem 2 oder mehr Versionen des Programms! Aber wir sind ja auch noch nicht fertig! Wir haben jetzt ein Bundle für die Standardsprache (in unserem Fall Deutsch) erstellt. Um noch mehr Sprachen zu verwenden, muss man noch mehr Bundles schreiben!
Als Konsolenuser legen Sie im selben Verzeichnis, in welchem schon das Standard-Bundle liegt, eine weitere Datei mit dem Namen Bundle_en.properties an. Nun müssen alle Keys aus dem Standard-Bundle abgeschrieben (in der selben Reihenfolge) oder kopiert werden, und natürlich die Values ins Englische übersetzt werden.
test=Hello World
Zum Ausführen in der englischen Sprache müssen Sie jetzt der JVM noch den Parameter -Duser.language=en
übergeben. Schon startet Ihr Programm mit einer englischen Vertextung. Falls Sie zusätzlich noch zwischen verschiedenen Englisch-Dialekten unterscheiden wollen, können Sie sogenannte Language-Codes verwenden. Um in Amerika gesprochenes Englisch von britischem Englisch zu unterscheiden, benennen Sie ihre Bundles Bundle_en_US.properties
bzw. Bundle_en_US.properties
. In diesem Fall müssen Sie dann auch -Duser.language=en_US
verwenden, um das Programm zu starten.
Die Netbeansuser öffnen das Kontextmenü des Standard-Bundle und wählen Add/Locale aus. Anschließend geben Sie beim Ländercode das passende Kürzel (hier en) an und drücken auf OK. Netbeans legt nun eine neue Datei mit dem Namen Bundle_
plus dem jeweiligen Ländercode plus .properties
an, für in Großbritannien gesprochenes Englisch dann Bundle_en_GB.properties
.
Anhand dieser differenzierten Dateien unterscheidet später die JVM, welche Sprache sie laden soll.
Dann öffnen Sie noch einmal das Kontextmenü der Standard-Bundle und wählen Open aus. Es erscheint wieder die Tabelle, allerdings diesmal mit einer neuen Spalte: en. Jetzt können Sie bequem übersetzen.
Damit Netbeans das Programm in anderen Sprachen ausführt, muss es noch konfiguriert werden. Öffnen Sie dazu die Combobox in der RunToolbar und wählen Sie Customize. Es öffnet sich ein Dialog. Dort klicken Sie auf die New-Schaltfläche und geben in das Namens-Feld English ein. Anschließend erweitern Sie die Liste der JVM-Optionen um -Duser.language=en
. Sollten Sie Sprachen nach Regionen unterscheiden, müssen Sie zusätzlich noch den Ländercode angeben: -Duser.language=en_US
, um das amerikanische Englisch zu verwenden. Abschließend schließen Sie den Dialog mit dem OK-Button. Wenn Sie jetzt nochmal die Combobox aufklappen, sehen Sie den Eintrag English. Wählen Sie ihn aus und starten Sie das Programm – auch hier erscheint nun die englische Textausgabe.
Hinweis: NetBeans hat teilweise Probleme, die Bundels mit in den Root-Ordner Ihrer .class-Dateien zu kopieren und verwendet deshalb zur Laufzeit in diesem Fall die alten Bundles mit eventuell fehlenden Keys. Wenn dies bei Ihnen der Fall ist, müssen Sie die Bundles über einen Dateimanager Ihrer Wahl manuell kopieren.
Auf die jeweilige Art können beliebig viele Bundles (alle natürlich im selben Verzeichnis) erstellt werden – Sie müssen nur über den Parameter -Duser.language=xy
das Kürzel der gewünschten Sprache angeben, und es wird automatisch die gewählte Übersetzung verwendet (selbstverständlich nur, sofern dieses Bundle auch existiert). Wenn Sie diesen Parameter weglassen, wird das Standard-Bundle verwendet. Achten Sie auch darauf, dass alle Bundles dieselben Schüssel besitzen, sonst wird eine MissingResourceException
geworfen!
Tipp 1: Wenn Sie mit dem GUI-Editor arbeiten, können Sie beim Text von Lables & Co auf die drei Punkte klicken, und in der Combobox oben „Resource Bundle“ auswählen. Anschließend sehen Sie ungefähr den Dialog, den Sie auch mit Str+Umschalt+J erreichen.
Tipp 2: Bei längeren Texten, die später in einem Label angezeigt werden, ist es sinnvoll, den Text schon im Bundle mit HTML-Tags zu umranden. Dadurch bricht das Label den Text automatisch um, wenn der Text zu lang wird. Statische Umbrüche können mit \n
realisiert werden.
Tipp 3: Sie können die Sprache auch fließend zur Laufzeit ändern. Dazu ändern Sie die System-Locale:
locale = new Locale("fr", "FR"); Locale.setDefault(locale);
Alle Strings, die von nun an aus geladen werden, sind Französisch. Strings, die schon geladen wurden, bleiben unverändert. Das heißt, wenn Sie dem Benutzer anbieten, die Sprache während der Laufzeit zu ändern, sollten Sie danach alle Fenster aktualisieren.
Häufig verwendete Kürzel:
- en – Englisch
- de – Deutsch
- es – Spanisch
- el – Griechisch
- fr – Französisch
- it – Italienisch
Bundles in spezifischen Packages
Bis jetzt haben Sie als Konsolenuser die Bundles der Einfachheit halber noch direkt in den Root-Ordner mit den .class-Dateien gelegt. Wollen Sie aber, dass die Bundles in einem besonderen Package liegen, können Sie den Pfad (ausgehend vom Rootverzeichnis der .class-Dateien) wie folgt angeben: ResourceBundle.getBundle("de/jbb/Bundle").getString("test")
. Achten Sie bitte darauf, dass alle Bundles im selben Verzeichnis liegen!
Sehr schöner Artikel. Danke dafür.
Kleine Korrekturen/Updates, die mir aufgefallen sind.
Mit aktueller Netbeans Version 7 kann man beim Hinzufügen von lokalen Properties Dateien sowohl „Language Code“ als auch „Country Code“ angeben oder eben gleich ein Preset auswählen.
Dann sieht der Dateiname des deutschen Properties File demnach so aus: „Bundle_de_DE.properties“.
(Also: „Bundle__.properties“)
Das muss man beachten, wenn man den Start-Parameter setzt.
Diese müssen dann heißen: „-Duser.language=de_DE“.
Im übrigen klappt es bei mir auch nur MIT dem Minuszeichen vor dem Parameter. 🙂
Interessant wäre jetzt noch zu wissen, dass man natürlich auch zur Laufzeit die Locale Einstellung verändern kann.
Über die Klasse Locale.
z.B.
Locale.setDefault(new Locale(„de_DE“));
Locale.setDefault(Locale.GERMAN);
Dann kann man in seiner Anwendung eine ComboBox einbauen mit der man die Sprache dynamisch ändern kann. Bereits offene Fenster, müssen dann natürlich neu erzeugt werden oder man updated sie alle. 🙂
Edit:
In den Kommentaren sind wohl < und > verboten.
Zeile 6 müsste heißen:
(Also: “Bundle_[CountryCode]_[LanguageCode].properties”)
Hallo Chris,
danke für deine Anregungen. Ich habe sie alle in den Text eingearbeitet, ich hoffe, diesmal hat sich der Fehlerteufel bezüglich der „-„-Zeichen herausgehalten. 🙂
Viele Grüße,
Fabian