Die Unterstützung einer Mehrsprachigkeit in Java Anwendungen wird mit dem ResourceBundle umgesetzt dabei ist unter JavaFX eine kleine Besonderheit zu beachten welche ich hier gerne erläutern möchte.
Am Anfang einer JavaFX Anwendung steht immer eine Stage welche als erstes gestartet wird.
public class Main extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) throws IOException { primaryStage.setTitle(„JTaskEditor by Stefan Draeger ® 2016 http://www.stefan-draeger-software.de“); Pane myPane = (Pane) FXMLLoader.load(getClass().getClassLoader().getResource(„views/main.fxml“)); Scene myScene = new Scene(myPane); primaryStage.setScene(myScene); primaryStage.show(); } }
Für das laden dieser Stage wird der javafx.fxml FXMLLoader benötigt dieser kann im einfachsten Fall ein einzeiliger Aufruf werden. (Wie im Beispiel oben zu sehen.)
Wenn man jedoch ein ResourceBundle für die Mehrsprachigkeit verwenden möchte so muss der javafx.fxml.FXMLLoader wie folgt verwendet werden.
FXMLLoader loader = new FXMLLoader(); ResourceBundle bundle = ResourceBundle.getBundle("bundle.jtaskeditor", getSystemLocale()); loader.setResources(bundle); private Locale getSystemLocale(){ String country = System.getProperty("user.country"); return new Locale(String.format("%s_%s", country.toLowerCase(),country.toUpperCase())); }
Es wird in Zeile 2 das ResourceBundle aus dem Ordner „src/main/resources/bundle“ mit der aktuellen System Sprache (java.util.Locale) geladen. Dazu habe ich eine kleine Methode geschrieben welche die aktuelle java.util.Locale aus den Systempropertys läd.
Die Verwendung dieses ResourceBundle in einer FXML Datei ist relativ einfach wie dieses Beispiel zeigt.
<?xml version="1.0" encoding="UTF-8"?> <?import java.net.*?> <?import javafx.geometry.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <?import javafx.scene.text.*?> <?import javafx.scene.control.MenuItem?> <MenuBar> <menus> <Menu mnemonicParsing="false" text="%file"> <items> <MenuItem text="%new" /> </items> </Menu> </menus> </MenuBar>
Der Key einer Textresource wird mit einem Prozentzeichen eingeleitet, dadurch wird das korrekte Key/Value Paar gefunden und „geladen“. Die Local wird vorher programmatisch eingestellt (auf die Systemsprache), hier könnte man noch über ein Einstellungsfeld in der Anwendung nachdenken jedoch wäre dieses für dieses Tutorial zuviel.
Möchte man nun das ResourceBundle programmatisch im Java Quellcode verwenden so bietet das Objekt java.util.ResourceBundle die Methode bundle.getString(String key) an welche wiederum das korrekte Key / Value Paar findet.
Wenn jedoch der Key nicht existiert, so wird eine MissingResourceException geworfen, bzw in einer FXML Datei eine LoadException: Resource „<<key>>“ not found.
Genau das ist mein Problem.
Was tun wenn der Key nicht gefunden wird, wie kann ich dann einen Standardwert eintragen ohne das die App abstürzt.
Hi,
es gibt immer eine „Default“ Resourcebundle diese lautet einfach nur wie die Anwendung heißt qusi ohne eine Locale im Format de_DE am ende. Die Datei wird im gleichen Ordner abgelegt wo auch die anderen Resourcebundles (*.properties Dateien) liegen.
Gruß,
Stefan Draeger
Das kann man machen, aber sicher wäre eine Lösung in der für jeden nicht gefunden Key ein DefaultValue ausgegeben wird.
Der Fehler im Key muss ja nicht unbedingt in der Rescourcendatei liegen, er kann auch durch eine Tippfehler im fxml sein und dann hilft das Default nicht weiter.
Sorry Josef, aber einen Tippfehler im FXML sollte man in der Produktion finden und beheben. Und wie will man diese besser finden als durch eine Exception die geworfen wird ?
Wenn du für jeden nicht vorhanden Key einen DefaultValue vergibst wird kein Fehler geworfen. Der Qualitätssicherung fällt es dann ggf. nicht auf, und bei Kunden erscheint dann statt „Bitte geben Sie Ihren Namen ein“ der Default Wert „WTF key not found“ … ^^