Suche…


Ressourcenpaket laden

JavaFX bietet eine einfache Möglichkeit, Ihre Benutzeroberflächen zu internationalisieren. Beim Erstellen einer Ansicht aus einer FXML-Datei können Sie dem FXMLLoader ein Ressourcenpaket zur Verfügung stellen:

Locale locale = new Locale("en", "UK");
ResourceBundle bundle = ResourceBundle.getBundle("strings", locale);

Parent root = FXMLLoader.load(getClass().getClassLoader()
                                  .getResource("ui/main.fxml"), bundle);

Dieses mitgelieferte Paket wird automatisch verwendet, um alle Texte in Ihrer FXML-Datei zu übersetzen, die mit einem % . Nehmen wir an, Ihre Eigenschaftsdatei strings_en_UK.properties enthält die folgende Zeile:

ui.button.text=I'm a Button

Wenn Sie eine Button-Definition in Ihrer FXML haben:

<Button text="%ui.button.text"/>

Es erhält automatisch die Übersetzung für den Schlüssel ui.button.text .

Regler

Ressourcenpakete enthalten ländereinstellungsspezifische Objekte. Sie können das Bundle während der Erstellung an den FXMLLoader . Der Controller muss die Initializable Schnittstelle implementieren und die initialize(URL location, ResourceBundle resources) überschreiben. Der zweite Parameter dieser Methode ist ResourceBundle , das vom FXMLLoader an den Controller übergeben wird und von dem Controller verwendet werden kann, um Texte weiter zu übersetzen oder andere vom Gebietsschema abhängige Informationen zu ändern.

public class MyController implements Initializable {

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        label.setText(resources.getString("country"));
    }
}

Dynamisches Wechseln der Sprache, wenn die Anwendung ausgeführt wird

Dieses Beispiel zeigt, wie eine JavaFX-Anwendung erstellt wird, bei der die Sprache dynamisch gewechselt werden kann, während die Anwendung ausgeführt wird.

Dies sind die Nachrichtenpaketdateien, die im Beispiel verwendet werden:

messages_de.properties :

window.title=Dynamic language change
button.english=English
button.german=German
label.numSwitches=Number of language switches: {0}

messages_de.properties :

window.title=Dynamischer Sprachwechsel
button.english=Englisch
button.german=Deutsch
label.numSwitches=Anzahl Sprachwechsel: {0}

Die Grundidee ist die Verwendung einer Dienstklasse I18N (alternativ kann dies als Singleton implementiert werden).

import javafx.beans.binding.Bindings;
import javafx.beans.binding.StringBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.control.Button;
import javafx.scene.control.Label;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.concurrent.Callable;

/**
 * I18N utility class..
 */
public final class I18N {

    /** the current selected Locale. */
    private static final ObjectProperty<Locale> locale;

    static {
        locale = new SimpleObjectProperty<>(getDefaultLocale());
        locale.addListener((observable, oldValue, newValue) -> Locale.setDefault(newValue));
    }

    /**
     * get the supported Locales.
     *
     * @return List of Locale objects.
     */
    public static List<Locale> getSupportedLocales() {
        return new ArrayList<>(Arrays.asList(Locale.ENGLISH, Locale.GERMAN));
    }

    /**
     * get the default locale. This is the systems default if contained in the supported locales, english otherwise.
     *
     * @return
     */
    public static Locale getDefaultLocale() {
        Locale sysDefault = Locale.getDefault();
        return getSupportedLocales().contains(sysDefault) ? sysDefault : Locale.ENGLISH;
    }

    public static Locale getLocale() {
        return locale.get();
    }

    public static void setLocale(Locale locale) {
        localeProperty().set(locale);
        Locale.setDefault(locale);
    }

    public static ObjectProperty<Locale> localeProperty() {
        return locale;
    }

    /**
     * gets the string with the given key from the resource bundle for the current locale and uses it as first argument
     * to MessageFormat.format, passing in the optional args and returning the result.
     *
     * @param key
     *         message key
     * @param args
     *         optional arguments for the message
     * @return localized formatted string
     */
    public static String get(final String key, final Object... args) {
        ResourceBundle bundle = ResourceBundle.getBundle("messages", getLocale());
        return MessageFormat.format(bundle.getString(key), args);
    }

    /**
     * creates a String binding to a localized String for the given message bundle key
     *
     * @param key
     *         key
     * @return String binding
     */
    public static StringBinding createStringBinding(final String key, Object... args) {
        return Bindings.createStringBinding(() -> get(key, args), locale);
    }

    /**
     * creates a String Binding to a localized String that is computed by calling the given func
     *
     * @param func
     *         function called on every change
     * @return StringBinding
     */
    public static StringBinding createStringBinding(Callable<String> func) {
        return Bindings.createStringBinding(func, locale);
    }

    /**
     * creates a bound Label whose value is computed on language change.
     *
     * @param func
     *         the function to compute the value
     * @return Label
     */
    public static Label labelForValue(Callable<String> func) {
        Label label = new Label();
        label.textProperty().bind(createStringBinding(func));
        return label;
    }

    /**
     * creates a bound Button for the given resourcebundle key
     *
     * @param key
     *         ResourceBundle key
     * @param args
     *         optional arguments for the message
     * @return Button
     */
    public static Button buttonForKey(final String key, final Object... args) {
        Button button = new Button();
        button.textProperty().bind(createStringBinding(key, args));
        return button;
    }
}

Diese Klasse hat ein statisches Feld locale , das ein Java ist Locale Objekt in einer JavaFX gewickelte ObjectProperty , so dass Bindungen können für dieses Objekt erstellt werden. Die ersten Methoden sind die Standardmethoden zum Abrufen und Festlegen einer JavaFX-Eigenschaft.

Das get(final String key, final Object... args) ist die Kernmethode, die für die eigentliche Extraktion einer Nachricht aus einem ResourceBundle .

Die beiden Methoden createStringBinding erstellen eine StringBinding , die an das locale gebunden ist. StringBinding ändern sich die Bindungen, wenn sich die Eigenschaft " locale ändert. Der erste verwendet seine Argumente, um eine Nachricht mithilfe der oben genannten get Methode abzurufen und zu formatieren. Der zweite wird in einem Callable , das den neuen String-Wert erzeugen muss.

Die letzten beiden Methoden sind Methoden zum Erstellen von JavaFX-Komponenten. Die erste Methode wird zum Erstellen eines Label und verwendet Callable für die interne Zeichenfolgenbindung. Die zweite erstellt einen Button und verwendet einen Schlüsselwert zum Abrufen der String-Bindung.

Natürlich könnten noch viele andere Objekte wie MenuItem oder ToolTip aber diese beiden sollten für ein Beispiel ausreichen.

Dieser Code zeigt, wie diese Klasse in der Anwendung verwendet wird:

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

import java.util.Locale;

/**
 * Sample application showing dynamic language switching,
 */
public class I18nApplication extends Application {

    /** number of language switches. */
    private Integer numSwitches = 0;

    @Override
    public void start(Stage primaryStage) throws Exception {

        primaryStage.titleProperty().bind(I18N.createStringBinding("window.title"));

        // create content
        BorderPane content = new BorderPane();

        // at the top two buttons
        HBox hbox = new HBox();
        hbox.setPadding(new Insets(5, 5, 5, 5));
        hbox.setSpacing(5);

        Button buttonEnglish = I18N.buttonForKey("button.english");
        buttonEnglish.setOnAction((evt) -> switchLanguage(Locale.ENGLISH));
        hbox.getChildren().add(buttonEnglish);

        Button buttonGerman = I18N.buttonForKey("button.german");
        buttonGerman.setOnAction((evt) -> switchLanguage(Locale.GERMAN));
        hbox.getChildren().add(buttonGerman);

        content.setTop(hbox);

        // a label to display the number of changes, recalculating the text on every change
        final Label label = I18N.labelForValue(() -> I18N.get("label.numSwitches", numSwitches));
        content.setBottom(label);

        primaryStage.setScene(new Scene(content, 400, 200));
        primaryStage.show();
    }

    /**
     * sets the given Locale in the I18N class and keeps count of the number of switches.
     *
     * @param locale
     *         the new local to set
     */
    private void switchLanguage(Locale locale) {
        numSwitches++;
        I18N.setLocale(locale);
    }
}

Die Anwendung zeigt drei verschiedene Arten der Verwendung der von der I18N Klasse erstellten StringBinding :

  1. Der Fenstertitel wird direkt mit einer StringBinding gebunden.
  2. Die Schaltflächen verwenden die Hilfsmethode mit den Nachrichtentasten
  3. Das Label verwendet die Callable mit einem Callable . Dieses Callable verwendet die I18N.get() Methode, um eine formatierte übersetzte Zeichenfolge mit der tatsächlichen Anzahl der Schalter I18N.get() .

Wenn Sie auf eine Schaltfläche klicken, wird der Zähler erhöht und die locale-Eigenschaft von I18N wird festgelegt. I18N wird die Änderung der Zeichenfolgenbindungen ausgelöst und die Zeichenfolge der Benutzeroberfläche auf neue Werte gesetzt.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow