Szukaj…


Ładowanie pakietu zasobów

JavaFX zapewnia łatwy sposób na internacjonalizację interfejsów użytkownika. Podczas tworzenia widoku z pliku FXML możesz dostarczyć FXMLLoader z pakietem zasobów:

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

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

Ten dostarczony pakiet jest automatycznie używany do tłumaczenia wszystkich tekstów w pliku FXML, które zaczynają się od % . Powiedzmy, że twój plik właściwości strings_en_UK.properties zawiera następujący wiersz:

ui.button.text=I'm a Button

Jeśli masz definicję przycisku w swoim FXML, tak jak to:

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

Automatycznie otrzyma tłumaczenie dla klucza ui.button.text .

Kontroler

Pakiety zasobów zawierają obiekty specyficzne dla ustawień regionalnych. Możesz przekazać pakiet do FXMLLoader podczas jego tworzenia. Kontroler musi implementować interfejs Initializable i przesłonić metodę initialize(URL location, ResourceBundle resources) . Drugi parametr tej metody to ResourceBundle który jest przekazywany z FXMLLoader do kontrolera i może być wykorzystywany przez kontroler do dalszego tłumaczenia tekstów lub modyfikowania innych informacji zależnych od ustawień regionalnych.

public class MyController implements Initializable {

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

Dynamiczne przełączanie języka podczas działania aplikacji

Ten przykład pokazuje, jak zbudować aplikację JavaFX, w której język można dynamicznie przełączać podczas działania aplikacji.

Są to pliki pakietów wiadomości użyte w przykładzie:

messages_en.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}

Podstawową ideą jest posiadanie klasy użyteczności I18N (alternatywnie może to być implementowane jako singleton).

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;
    }
}

Ta klasa ma statyczne locale które są obiektami locale Locale Java opakowanymi w obiekt JavaFX ObjectProperty , dzięki czemu można utworzyć powiązania dla tej właściwości. Pierwsze metody to standardowe metody uzyskiwania i ustawiania właściwości JavaFX.

get(final String key, final Object... args) to podstawowa metoda używana do rzeczywistego wyodrębnienia wiadomości z zestawu ResourceBundle .

Dwie metody o nazwie createStringBinding tworzą StringBinding który jest powiązany z polem locale StringBinding , więc powiązania będą się zmieniać za każdym razem, gdy zmieni się właściwość locale StringBinding . Pierwszy z nich wykorzystuje To argumenty, aby pobrać i formatowanie wiadomości za pomocą get metoda wspomniano powyżej, drugi jest przekazywany w Callable , które muszą produkować nową wartość ciągu.

Dwie ostatnie metody to metody tworzenia komponentów JavaFX. Pierwsza metoda służy do tworzenia Label i wykorzystuje Callable do wewnętrznego wiązania łańcucha. Drugi tworzy Button i używa wartości klucza do pobrania powiązania String.

Oczywiście można stworzyć wiele innych obiektów, takich jak MenuItem lub ToolTip ale te dwa powinny wystarczyć na przykład.

Ten kod pokazuje, jak ta klasa jest używana w aplikacji:

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);
    }
}

Aplikacja pokazuje trzy różne sposoby korzystania z StringBinding utworzonego przez klasę I18N :

  1. tytuł okna jest związany bezpośrednio za pomocą StringBinding .
  2. przyciski używają metody pomocnika z klawiszami wiadomości
  3. etykieta używa metody pomocniczej z Callable . Ten Callable używa I18N.get() metodę, aby uzyskać przetłumaczone sformatowany ciąg zawierający rzeczywistą liczbę przełączników.

Po kliknięciu przycisku licznik jest zwiększany i ustawiana jest właściwość locale I18N , co z kolei powoduje zmianę powiązań ciągów, a tym samym ustawienie ciągu interfejsu użytkownika na nowe wartości.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow