Java Internationalization (i18n) 8. April 2003 Java i18n Übersicht • i18n = i plus 18 Buchstaben ’nternationalizatio’ plus n • Internationalisierung • Lokalisierung • Pakete java.util, java.text • http://java.sun.com/docs/books/tutorial/i18n Java i18n Tutorial 1 Motivation • Global eingesetzte Programme müssen Sprache und Kultur (Locale) des Benutzers berücksichtigen. • Manchmal auch individuelle Anpassungen pro Benutzer oder Benutzergruppe erforderlich. • Manchmal ist firmen- oder branchenspezifische Terminologie zu berücksichtigen. • Erfordert Trennung von Programm und Locale-abhängigen Daten. • Erfordert Mechanismus für inkrementelle Anpassung (Vererbung). 2 Internationalisierung Vorbereiten eines Programmes für globalen Einsatz. Programm abstrahiert von lokalisierbaren Daten (durch Indirektion). • Beschriftung von GUI-Elementen, Dokumentation, Meldungen. • Datums- und Zeitformat: Reihenfolge, Trennzeichen, Sprache, Benutzereinstellungen. • Zahlenformat: Tausendertrennunug, Dezimaltrennuung, Währungssymbol. • Sortierung von Zeichenketten in der landesüblichen Reihenfolge (Umlaute, Sonderzeichen). 3 Lokalisierung Anpassen eines Programms an eine bestimmte Sprache oder Region. Meist Erstellen eines oder mehrerer Property-Files. Programm wird nicht verändert oder neu kompiliert. Oft werden Property-Files von Hilfskräften oder Dolmetscher erstellt. Häufig werden nur (wichtige) Teile eines Programms lokalisiert. Lokalisierung für neue Sprache ist ohne Programmänderung auch später möglich. 4 Klasse java.util.Locale Jedes Java-Programm enthält ein default-Locale, das vom OS bereitgestellt wird (Locale.getDefault()). Default-Locale kann auch gesetzt werden (meist bei Programmstart) mit Locale.setDefault(new Locale(lang)); Locale.setDefault(new Locale(lang, country)); Locale.setDefault(new Locale(lang, country, variant)); Sprachcode (2-stellig, klein) gemäß ISO 639, z.B.: de, en. Landcode (2-stellig, groß) gemäß ISO 3166, z.B.: AT, CH, US. 5 Abstrakte Klasse java.util.ResourceBundle Ein ResourceBundle repräsentiert eine Menge von benannten Resourcen, die zusammengehören und für verschiedene Locales vorliegen (können). ResourceBundle erlaubt Abbildung eines Schlüssels (String) auf ein Objekt unter Berücksichtigung des Locales. Beliebige Implementierungen sind möglich. ResourceBundle rb; rb = ResourceBundle.getBundle(baseName); rb = ResourceBundle.getBundle(baseName,locale); Object val = rb.getObject(key); String s = rb.getString(key); 6 Implementierung/Bundle baseName zunächst als Klassenname interpretiert, geladen und instanziiert: baseName.class. Wenn nicht erfolgreich, dann als Property-File: baseName.properties. Wenn nicht erfolgreich dann MissingResourceException. Aus baseName werden gemäß locale sämtliche Spezialisierungen durch Anfügen von Suffix generiert, zB. baseName, baseName_de, baseName_de_AT, baseName_de_AT_42 und als Klasse (.class) bzw. Property-File (.properties) behandelt. Alle zusammen bilden die Ressourcen von baseName für ein bestimmtes Locale. 7 Vererbung Stärker spezialisierte Resourcen erben von weniger spezialisierten. myfile_de_AT_42 erbt von myfile_de_AT. myfile_de_AT erbt von myfile_de. myfile_de erbt von myfile. Fallback bis zu Basisname, daher immer Basisname.properties zuerst erstellen. Basisname legt auch Art der Implementierung fest. Selektives Überschreiben durch Spezialisierung möglich. 8 Klasse java.util.PropertyResourceBundle Ein PropertyResourceBundle verwendet Property-Files als Speicherformat. Nur String-Ressourcen möglich. Die Suchreihenfolge für Property-Files für Locale (de, AT) lautet: myfile_de_AT.properties myfile_de.properties myfile.properties Öffnen und verwenden von PropertyResourceBundle mit ResourceBundle rb = ResourceBundle.getBundle(baseName); String s = rb.getString("mykey"); 9 Caching • ResourceBundles werden in einem Soft-Cache verwaltet. • Änderungen an einem Property-File während des Betriebes oft nicht sofort berücksichtigt. • Vor OutOfMemoryError werden Ressourcen freigegeben, meist auch schon vorher (je nach verfügbarem Speicher). 10 Property-Files Bestehen aus einer Folge von Zeilen. Jede Zeile enthält ein (key, value) Paar der Art: key = value Zum Beispiel: button_ok_label = OK button_ok_tooltip = Send request to server. menuitem_ok_label = OK message_1_text = Number of files deleted: {0}. message_2_text = Number of errors detected: {0}. 11 Parameter und Formate Klasse java.text.MessageFormat Parameter mit {0}, {1} etc. bezeichnet. Formatangaben für Parameter möglich (z.B.: {0,number,currency}). Ein Formatstring (Pattern) wird mit Parametern befüllt und formatiert. String text = rb.getString("message_1_text"); Object[] params = new Object[]{new Integer(10)}; String fmtText = MessageFormat.format(text, params); System.out.println(fmtText); 12 Sprachliche Feinheiten Das Zusammensetzen von natürlichsprachigem Text ist nicht immer trivial. Zum Beispiel liefert folgendes Property bei Parameterwert 1 einen falschen deutschen Text. message_1_text = Es wurden {0} Dateien entfernt. Die einfachste Abhilfe ist die Umformulierung wie vorher. Fallunterscheidung durch spezielles Textformat wäre aber auch möglich. 13 ClassLoader Die Suche nach Ressourcen erfolgt innerhalb des verwendeten CLASSPATH. Klasse ClassLoader berücksichtigt den CLASSPATH und erlaubt das Laden von Klassen und den Zugriff auf sonstige Files (=Ressourcen). In einer JVM können mehrere ClassLoader verwendet werden. Damit kann das Laden von Ressourcen von alternativen Quellen (z.B. per ftp, http, CVS, spezieller CLASSPATH, etc.) durchgeführt werden. Default ClassLoader ist ClassLoader.getSystemClassLoader(). Jede Klasse kennt ihren ClassLoader (myClass.getClassLoader()). ResourceBundle wird wie Klasse durch ClassLoader verwaltet, liefert diesen aber (leider) nicht. 14