Hawlitzek GmbH/ Veröffentlichungen/ InternationalAge/
 

Hawlitzek IT-Consulting GmbH ©Foto Kirsten Literski-Hawlitzek

InternationalAge

Dieser Artikel ist im JavaMagazin 3/00 erschienen. Vielen Dank an den Software & Support Verlag für die Genehmigung zur Veröffentlichung auf dieser Webseite!

Internationale Anwendungen mit IBM VisualAge for Java

International Age

Die Entwicklung von Anwendungen für den internationalen Markt ist oft mit großem Aufwand verbunden. Häufig werden Programme erst später in andere Sprachen umgesetzt; dann ist es schwierig, alle Strings im Quellcode wieder zu finden und auch unterschiedliche Datums- und Zahlenformate sind zu berücksichtigen sowie die Oberfläche anzupassen. Was bietet die Sprache Java und VisualAge an, um internationale Anwendungen zu schreiben?

Lokalisierung

Praktisch jedes Betriebssystem bietet die Möglichkeit, eine so genannte Locale, das heißt Ländereinstellungen oder ein Gebietsschema, zu definieren. Diese ist nicht zu verwechseln mit dem Tastaturlayout, sondern bezieht sich auf die Formatierung von Zahlen-, Währungs-, Datums- und Zeitangaben.

Im Prinzip bestehen die Ländereinstellungen aus zwei Teilen, der Angabe des Landes und der Sprache. Beide haben Einfluss auf die Darstellung und können getrennt voneinander variieren. So gibt es zum Beispiel in der Schweiz mindestens drei verschiedene Sprachen, aber einen einheitlichen Kulturkreis mit gleicher Zahlendarstellung, Währung etc. Umgekehrt gibt es Länder mit (nahezu) derselben Sprache, aber verschiedenen Formaten, zum Beispiel Großbritannien, Australien und die USA.

Daher beschreibt man Locale-Angaben häufig mit zwei Kürzeln, zum Beispiel en_GB, en_AU, en_US, fr_CH, de_CH oder de_DE, wobei das erste Kürzel für die Sprache steht (nach ISO-639) und das zweite für das Land (nach ISO-3166). Falls das Land nicht relevant ist, kann man die zweite Hälfte auch weglassen.

Daneben muss man bei Zeitangaben auch noch berücksichtigen, dass manche Länder mehrere Zeitzonen umfassen, zum Beispiel Rußland oder die USA.

Java bietet auf Basis der Klassen Locale und TimeZone im Package java.util eine Unterstützung für den Entwickler an. Darauf aufbauend gibt es Formatierungsklassen für Zahlen, Zeit- und Datumswerten. Strings können anhand der Locale dynamisch aus so genannten ResourceBundles geladen werden.

Eine Unterstützung von Codepages ist nicht notwendig, da Java auf Unicode aufsetzt, das alle Zeichensätze umfasst. Es kann jedoch passieren, dass auf vielen Rechnern Zeichensätze installiert sind, die nicht alle Unicode-Zeichen enthalten. Folglich können daraufhin bestimmte Zeichenfamilien (z.B. kyrillisch) zwar benutzt, aber nicht auf dem Bildschirm dargestellt werden.

Formatierung von Zahlen und Zeiten

Die Klasse java.util.Date beinhaltet Datum- und Uhrzeitfunktionen. Sie hat allerdings seit Java 1.1 viel von ihrer Funktionalität eingebüßt, da sie nicht für internationale Darstellungsunterschiede optimiert und für die Verwaltung von Jahren ab 2000 ungeeignet war; zum Beispiel musste das Jahr 2000 als 101 kodiert werden. Deshalb wurden die meisten Methoden als veraltet (deprecated) erklärt und in die Klasse Calendar übertragen. In der Klasse Date selbst blieb eine Datums- und Zeitfunktionalität, die auf einem Zeitmodell in Millisekunden seit dem 1. 1. 1970 basiert.

toString() gibt das Datum in einem Langformat aus, zum Beispiel

Mon Apr 26 13:12:22 GMT+02:00 1999

Dies ist natürlich in der Regel nicht das gewünschte Format. Mit toLocaleString() kann man eine Ausgabe anhand der aktuellen Locale erreichen:

26.04.1999 13:12:22

Eine saubere Lösung (ohne deprecated-Methoden) lässt sich mit der Klasse DateFormat erreichen:

java.text.DateFormat df = java.text.DateFormat.getInstance();
String timestamp = df.format( new java.util.Date(aFile.lastModified()));

Das Ergebnis ist bis auf die fehlenden Sekunden identisch:

26.04.99 13:12.

Neben dieser Klasse, gibt es noch eine Reihe anderer Formatierungsklassen im Package java.text (siehe Abbildung 1).


Abbildung 1: Formatierungsklassen im JDK

Diese Klassen enthalten format-Methoden, mit deren Hilfe man gegebene Datums- Zeit oder Zahlwerte ins eingestellte oder ein angegebenes Gebietsschema umwandeln kann. Umgekehrt kann man mittels parse() eingelesene Werte ins sprachneutrale Format umwandeln.

Die verschiedenen Formate und weitere Informationen zu den verschiedenen Locales finden sich in den LocaleElements- und DateFormateZoneData-Klassen im Package java.text.resources. Darin sind die landesspezifischen Bezeichnungen für Trennzeichen, Monate, Wochentage, Landessprachen, Länder sowie verschiedene Muster für Zahlenformate definiert. Zum Beispiel für Deutschland:

{ "NumberPatterns",
 new String[] {
  "#,##0.###;-#,##0.###", // decimal pattern
  "#,##0.00 DM;-#,##0.00 DM", // currency pattern
  "#,##0%" // percent pattern
 }
}

{ "DateTimePatterns",
 new String[] {
  "H.mm' Uhr 'z", // full time pattern
  "HH:mm:ss z", // long time pattern
  "HH:mm:ss", // medium time pattern
  "HH:mm", // short time pattern
  "EEEE, d. MMMM yyyy", // full date pattern
  "d. MMMM yyyy", // long date pattern
  "dd.MM.yyyy", // medium date pattern
  "dd.MM.yy", // short date pattern
  "{1} {0}" // date-time pattern
 }
}

Dynamisches Laden von Strings

Das Modell der ResourceBundles erlaubt es, internationale Anwendungen zu schreiben, deren String dynamisch anhand der aktuellen Ländereinstellungen geladen und angezeigt werden (siehe Abbildung 2).


Abbildung 2: Laden von Strings aus ResourceBundles

Die Anwendung ist sehr einfach. Statt direkt eine String-Konstante im Code anzulegen, lädt man jeden String mit der Methode getString(schlüssel) aus einem ResourceBundle [1]. Das Bundle kann dabei entweder eine Datei oder eine Klasse sein. Jetzt muss man nur noch beim Start der Anwendung oder in der Initialisierung des Applets die Quelle angeben:

ResourceBundle b = ResourceBundle.getBundle(bundlename); 
                // bundlename ohne Landesendung
String cancelButtonLabel = getString("Cancel");

Die Anwendung sucht nach folgendem Schema ein passendes Bundle:

bundlename_<aktuelles Sprachkürzel>_<aktuelles Landeskürzel>.class,
  z.B. xy_de_DE.class

bundlename_<aktuelles Sprachkürzel>.class, z.B. xy_de.class

bundlename_.class, z.B. xy.class

Falls keine der Klassen gefunden werden kann, erhält man eine MissingResourceException.
Unter Verwendung von ResourceBundles ist die Anwendung völlig unabhängig von der Sprache und muss auch nicht geändert werden, wenn eine neue Sprache hinzukommt. In diesem Fall muss nur eine neue ResourceBundle-Klasse hinzugefügt werden, eine Neukompilation ist nicht notwendig.

Eine solche Bundle-Bundle-Klasse hat folgenden Aufbau:

public class xy_de_DE extends java.util.ListResourceBundle
{
  static final Object[][] contents =
  {
   // Paare aus Schlüssel und lokalisiertem String
   {"Cancel", "Abbrechen"},
   {"Help", "Hilfe"}
  }

  protected Object[][] getContents() { return contents; }
}

Einfachere Beneutzung in VisualAge for Java

Wer konsequent seine Anwendung mit ResourceBundles geschrieben hat, kann sie damit leicht in andere Sprachen umsetzen. Die Auslieferung verschiedener Sprachversionen eines Programms ist nicht notwendig. Schwierig wird es aber, wenn man zunächst nur für eine Sprache mit fest eingebauten Strings programmiert hat und die Übersetzung nachträglich hinzufügen will.

Hierfür bietet die Entwicklungsumgebung VisualAge for Java von IBM eine gute Unterstützung. Alle Klassen können ohne Berücksichtigung einer späteren Internationalisierung entwickelt werden. Danach wählt man die Funktion “Externalize Strings...” aus dem Kontextmenü der Klasse. Darauf hin werden alle Strings in der Klasse herausgesucht und in einem Wizard dargestellt (siehe Abbildung 3). In dieser Dialogbox kann man angeben, in welches ResourceBundle generiert wird (bzw. ein neues anlegen) und welche Strings ausgelagert werden sollen.


Abbildung 3: Auswahl der auszulagernden Strings

Der Code wird danach so umgestaltet, dass diese Zeichenketten aus dem ResourceBundle geladen werden. Dazu wird im Deklarationsteil eine Zeile zur Definition eingefügt:

private static java.util.ResourceBundle resBundle =
 java.util.ResourceBundle.getBundle(
  "de.hawlitzek.vaj.swingexport.SwingExportListBundle"); 

Jeder ausgelagerte String wird aus diesem Bundle geladen. Also wird zum Beispiel

 gvLabel = new Label("Gewinn/Verlust");

durch

 gvLabel = new Label(resBundle.getString("GV_text"));

ersetzt.
Sie können nun weitere Sprachen unterstützen, indem Sie neben dem generieren Standard-Bundle SwingExportListBundle andere Bundles anlegen, zum Beispiel SwingExportListBundle_de_DE. Dies kann durch einfaches Kopieren der Klasse und anschließendes Übersetzen der Strings geschehen.

Strings in grafischen Oberflächen

Bei grafischen Oberflächen müssen Sie darauf achten, dass die Zeichenketten in unterschiedlichen Sprachen verschieden lang sind. Deshalb müssen Sie bei pixelgenauer Positionierung die Größen der Kontrollelemente so gewählt werden, dass für die breiteste Variante genügend Platz bereitsteht.

Besser ist es jedoch, LayoutManager zu verwenden. Diese berechnen den Platzbedarf anhand der tatsächlichen Größe erst zur Laufzeit des Programms.

Wenn Sie den Visual Composition Editor von VisualAge für die Erstellung Ihrer Oberflächen verwenden, können Sie Strings in den Eigenschaften der Beans internationalisiert eingeben. Klicken Sie dazu auf den Knopf für den Property-Editor (die Schaltfäche mit den drei Punkten neben dem String). In der Dialogbox (Abbildung 4) können Sie nun ebenfalls die gewünschte ResourceBundle auswählen und einen Schlüssel für die Zeichenkette und den zugehörigen Standardwert definieren. Alternativ können Sie natürlich auch einen schon vorhandenen Schlüssel auswählen.


Abbildung 4: Auslagern von Strings im grafischen Editor

Fazit

Es gibt wohl kaum eine andere Programmiersprache, bei der die Entwicklung internationaler Anwendungen so einfach ist wie in Java. VisualAge for Java macht die Programmierung dabei noch wesentlich komfortabler. Natürlich kann keine noch so intelligente Sprache und Entwicklungsumgebung alle Aufgaben automatisch lösen, deshalb muss sich der Entwickler immer um einige Aspekte Gedanke machen. Hierzu zählen zum Beispiel die Silbentrennung, die Sortierung von Wörtern und die Umsetzung in Nicht-Unicode-Zeichensätze. Besonders schwierig ist das Zusammenfügen von Zeichenketten, da die Bildung von Sätzen grammatikalischen Regeln unterliegt, die von Sprache zu Sprache variieren.

 

Literatur

 

[1] Beschreibung der Klassen Date und ResourceBundle aus “Java-Programmierung mit IBM VisualAge”, Addison-Wesley, 1999. Abdruck mit freundlicher Genehmigung des Verlags.

 

© 2006 Hawlitzek IT-Consulting GmbH,
Marketing&Design Kirsten Literski-Hawlitzek

Seitenanfang

Hawlitzek GmbH
Die Gründer
Dienstleistungen
Java Downloads
Vorträge
Veröffentlichungen
Kontakt
International
Sitemap