In Java steht das Konzept der Internationalisierung zur Verfügung, um Anwendungen entwickeln zu können, deren Benutzeroberflächen Bezeichnungen in landesspezifischer Sprache enthalten. Manchmal wird der Begriff Internationalisierung auch mit i18n abgekürzt, da im Englischen 18 Buchstaben zwischen dem ersten i und dem letzten n des Worts Internationalization stehen. Ein internationalisiertes Programm weist die folgenden Kennzeichen auf: Durch das Hinzufügen von Daten mit lokalem Bezug ist eine Anwendung in der Lage, Texte weltweit in der jeweiligen Landessprache anzuzeigen. Textelemente, wie bspw. Fehlermeldungen und Komponentenbezeichner einer Benutzeroberfläche, werden nicht fest in einem Programm verdrahtet, sondern außerhalb des Quellcodes verankert und dynamisch hinzugebunden. Die Unterstützung weiterer Sprachen erfordert keine erneute Übersetzung der Anwendung. Weitere kulturabhängige Daten, wie bspw. das Datum oder Währungen, erscheinen in Formaten, die mit der Region und Sprache des Endbenutzers konform sind. Unter der Lokalisierung versteht man den Prozess, Software an eine spezielle Region oder Sprache anzupassen, indem spezifische Komponenten hinzugefügt werden und Text übersetzt wird. Der Begriff Lokalisierung wird meist als l10n abgekürzt, da im Englischen 10 Buchstaben zwischen dem l und dem n des Worts Localization stehen. Der Kontext, in dem derartige sprachspezifische Bezeichnungen gespeichert werden, wird in Java auch als Locale bezeichnet. Den größte Zeitbedarf der Lokalisierungsphase nimmt die Übersetzung von Text in Anspruch. Andere Datentypen, wie bspw. Klangdateien oder Bilder, müssen oft nur dann angepasst werden, wenn sie kulturabhängig sind. Java garantiert in diesem Zusammenhang, dass die Formatierung von Datumsangaben, Zahlen und Währungen an lokale Erfordernisse automatisch durchgeführt wird. Das folgende Beispiel illustriert die grundsätzliche Verwendung dieses Konzepts. Die zum detaillierten Verständnis notwendigen Bestandteile werden im Anschluss genauer erläutert. Das folgende Programm begrüßt in zwei Zeilen einen Benutzer: System.out.println("Hallo."); System.out.println("Willkommen in Java!"); Offensichtlich ist das Programm für Anwender im englischsprachigen Raum ungeeignet. Da die Anwendung nicht multilingual arbeitet, muss der Entwickler die Texte ins Englische übersetzen. Meist sind allerdings Übersetzer nicht gleichzeitig Programmierer, so dass die Texte aus dem Quellcode in Textdateien gespeichert werden müssen, bevor sie von einem Übersetzer bearbeitet werden können. Das Programm muss weiterhin derart flexibel sein, dass es Texte auch in anderen Sprachen anzeigen kann. Problematisch hierbei ist, dass meist a priori unbekannt ist, welche Sprachen dies sein werden. Der Endbenutzer muss daher in der Lage sein, die jeweilige Sprache zur Laufzeit angeben zu können. Dieses Problem ist ein typischer Anwendungsbereich der Internationalisierung. Der internationalisierte Code, der keinerlei hart verdrahtete Texte mehr beinhaltet, lautet hierzu folgendermaßen: import java.util.*; public class I18NBeispiel { static public void main(String[] args) { String sprache; String land; if (args.length != 2) { sprache = new String("en"); land = new String("US"); } else { sprache = new String(args[0]); land = new String(args[1]); } Locale currentLocale; ResourceBundle nachrichten; currentLocale = new Locale(sprache, land); nachrichten = ResourceBundle.getBundle("MessagesBundle",curren tLocale; System.out.println(nachrichten.getString("einlei tung")); System.out.println(nachrichten.getString("javaTe xt")); } } Das internationalisierte Programm ist flexibel, da es dem Endbenutzer die Möglichkeit einräumt, seine Sprache und sein Land in der Kommandozeile anzugeben. In den folgenden Beispielen werden die Texte erst auf französisch (der Sprach-Code für französisch ist fr, der Landes-Code ist FR für France) und dann in englischer Sprache (der Sprach-Code für englisch ist en, der Landes-Code ist US für United States) angezeigt. Aufruf: java I18NBeispiel fr FR Ausgabe: Allo. Bienvenue en Java. Aufruf: java I18NBeispiel en US Ausgabe: Hello. Welcome in Java. Betrachtet man den internationalisierten Code näher, so bemerkt man, dass die vorher fest verdrahteten deutschen Texte verschwunden sind. Das Programm ist nun aus den folgenden zwei Gründen weltweit ausführbar: Erstens sind keine Texte fest im Code integriert und zweitens wird der Sprach-Code zur Laufzeit angegeben. Eine erneute Übersetzung ist zur Lokalisierung nicht erforderlich; das Programm ist bereits international einsetzbar. Eine wichtige Frage ist nun, wohin die Texte, die fest in das Programm integriert waren, verschoben worden sind. Die hierzu notwendigen Schritte werden im Folgenden beschrieben: Erzeugung einer Eigenschaftendatei (sog. Properties File) Ein Properties File, das in einem reinen Textformat mit einem beliebigen Texteditor erzeugt wird, speichert Informationen über Charakteristika eines Programms oder einer Umgebung. Im Beispiel speichern die Properties Files die Übersetzungen der Texte, die angezeigt werden sollen. Standardmäßig benennt man das Properties File mit MessagesBundle.properties und fügt die folgenden Zeilen ein: einleitung = Hallo javaText = Willkommen in Java! Nachdem die Texte in einem Properties File angelegt sind, kann dieses in verschiedene Sprachen übersetzt werden. Änderungen des Quellcodes sind hierzu nicht erforderlich. Ein Französisch-Übersetzer würde bspw. ein Properties File MessagesBundle_fr_FR.properties erzeugen, das folgende Zeilen enthält: einleitung = Allo javaText = Bienvenue en Java! Hierbei sollte beachtet werden, dass die Texte rechts der Gleichheitszeichen übersetzt wurden, nicht aber die Bezeichner auf der linken Seite. Diese Schlüssel dürfen nicht verändert werden, da sie vom Programm referenziert werden, wenn der übersetzte Text geladen wird. Wichtig ist weiterhin der Name des Properties Files. Der Name der Datei MessagesBundle_fr_FR.properties beinhaltet den Sprach-Code fr und den Landes-Code FR. Diese Codes werden verwendet, wenn ein Locale-Objekt angelegt wird. Definition der Locale Ein Locale-Objekt identifiziert eine bestimmte Sprache und ein Land. Die folgende Anweisung definiert eine Locale mit der Sprache Französisch und dem Land Frankreich: aLocale = new Locale("fr","FR"); Das vorgeschlagene Programm arbeitet flexibel, da es anstelle fest integrierter Sprach- und Landes-Codes Eingaben aus der Kommandozeile zur Laufzeit akzeptiert: String sprache = new String(args[0]); String land = new String(args[1]); currentLocale = new Locale(sprache, land); Locale-Objekte haben lediglich identifizierende Wirkung. Nach der Definition einer Locale wird diese an andere Objekte übergeben, die Aufgaben wahrnehmen, wie bspw. die Formatierung von Datumsangaben oder Währungen. Diese Objekte werden dann auch als Locale-sensitiv bezeichnet, da ihr Verhalten in Abhängigkeit von der Locale variiert. Das im Folgenden beschriebene ResourceBundle ist ein Beispiel eines Locale-sensitiven Objekts. Erzeugung eines ResourceBundles ResourceBundle-Objekte beinhalten Locale-spezifische Objekte und werden vor allem dazu verwendet, Locale-sensitive Daten, wie bspw. zu übersetzender Text, zu isolieren. Im Beispiel greift das ResourceBundle-Objekt auf die Properties Files zu, die die anzuzeigenden Texte enthalten. Ein ResourceBundle-Objekt wird folgendermaßen erzeugt: nachricht = ResourceBundle.getBundle("MessagesBundle",currentLocale) ; Die Argumente, die an die getBundle-Methode übergeben werden, identifizieren die Properties Files, auf die anschließend zugegriffen wird. Das erste Argument, in diesem Fall MessagesBundle, bezeichnet hierbei die Familie der Properties Files. Die Locale, das zweite Argument der getBundle-Methode, spezifiziert, welche der MessagesBundle-Dateien ausgewählt werden soll. In dem Moment, in dem die Locale erzeugt wird, wird sowohl der Sprach- als auch der Landes-Code an deren Konstruktor übergeben. Hierbei ist zu beachten, dass im Namen des Properties Files der Sprach- und Landes-Code dem MessagesBundle-Objekt folgen. Einladen des Textes aus dem ResourceBundle Properties Files beinhalten Paare aus Schlüssel und dazugehörigem Wert. Die Werte bestehen hierbei aus dem übersetzten Text, den das Programm anzeigen soll. Die Schlüssel werden dann angegeben, wenn die übersetzten Texte aus dem ResourceBundle-Objekt mittels der getString-Methode geladen werden. Um bspw. den Text zu laden, der durch den Schlüssel einleitung identifiziert wird, muss die getString-Methode folgendermaßen aufgerufen werden: String text1 = nachrichten.getString("einleitung"); Das Beispiel verwendet hierbei den Schlüssel einleitung, da dieser den Inhalt des Textes wiedergibt. An dieser Stelle kann aber auch ein beliebiger anderer Text verwendet werden. Der Schlüssel muss allerdings im Programm fest verdrahtet und auch in den Properties Files enthalten sein. Anderenfalls kann die Methode getString die Texte nicht auffinden. Vor der detaillierten Erklärung der weiterführenden Internationalisierungskonzepte sei kurz auf Aspekte hingewiesen, die im Kontext der Internationalisierung nicht zu vernachlässigen sind. Viele Programme sind anfangs nicht internationalisiert (wenn sie zum ersten Mal geschrieben werden). Zur Umwandlung in eine internationalisierte Version sind die folgenden Gesichtspunkte zu beachten: Identifikation kulturabhängiger Daten Nachrichten in Textform sind die offensichtlichste Form von Daten, die von Kultur zu Kultur variieren. Es existieren aber noch weitere Daten, die von einer Region oder Sprache abhängig sind. Die folgende Liste zeigt einige wichtige Beispiele: Texte in Komponenten von Benutzeroberflächen Online-Hilfen Audiodateien Grafiken Icons Datum und Zeit Zahlen und Währungen Maßeinheiten Isolierung von übersetzbarem Text in ResourceBundles Übersetzungen sind stets kostenintensiv. Derartige Kosten können aber reduziert werden, wenn zu übersetzender Text in ResourceBundle-Objekten separiert wird. Derartige Texte sind bspw. Statusnachrichten, Fehlermeldungen oder auch Einträge in Benutzeroberflächen. Es ist zu bedenken, dass alle Vorkommen fest integrierter Texte, die dem Endbenutzer gezeigt werden, gefunden und ausgelagert werden müssen. Verarbeitung von Verbundnachrichten Verbundnachrichten sind durch variable Daten gekennzeichnet. Im Beispiel „Ich esse 4 Scheiben Brot" ist eine Übersetzung dann schwierig, wenn die Zahl der Brotscheiben variabel ist, da die Position der Zahl nicht in allen Sprachen die gleiche ist. Verbundnachrichten sind daher weitestgehend zu vermeiden. Techniken, die angewendet werden sollten, wenn eine derartige Nachricht unvermeidbar ist, sind im Folgenden angegeben. Formatierung von Zahlen und Währungen Wenn eine Anwendung Zahlen und Währungen anzeigt, müssen diese in einer Art und Weise formatiert werden, die unabhängig von einer Localen ist. Formatierung von Datumsangaben und Zeiten Auch Datumsangaben und Zeiten variieren mit der Region und Sprache. Hierzu gilt das bereits vorher angeführte. Geeignete Vergleiche von Zeichenketten Wenn Text sortiert oder durchsucht wird, müssen oft Zeichenketten verglichen werden. Es sollte darauf geachtet werden, dass anzuzeigender Text nicht mit den Methoden der String-Klasse verglichen wird. Die Methoden String.equals und String.compareTo führen bspw. binäre Vergleiche durch, die in einigen Sprachen wirkungslos sind. Anstelle dessen sollte bspw. die Collator-Klasse verwendet werden. Konvertierung von Text, der nicht als Unicode vorliegt Zeichen werden in Java in Unicode kodiert. Eine Anwendung, die Text verwendet, der nicht als Unicode vorliegt, sollte daher in Unicode übersetzt werden. Im Folgenden werden die Eigenschaften der Internationalisierung im Detail erläutert.