Zoeken…


Bronnenbundel laden

JavaFX biedt een eenvoudige manier om uw gebruikersinterfaces te internationaliseren. Tijdens het maken van een weergave van een FXML-bestand kunt u de FXMLLoader voorzien van een FXMLLoader :

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

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

Deze meegeleverde bundel wordt automatisch gebruikt om alle teksten in uw FXML-bestand te vertalen die beginnen met een % . Laten we zeggen dat uw eigenschappenbestand strings_en_UK.properties de volgende regel bevat:

ui.button.text=I'm a Button

Als u een knopdefinitie in uw FXML als volgt heeft:

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

Het ontvangt automatisch de vertaling voor de sleutel ui.button.text .

controleur

A Bronbundels bevatten locale-specifieke objecten. U kunt de bundel doorgeven aan de FXMLLoader tijdens het maken. De controller moet de Initializable interface implementeren en de methode initialize(URL location, ResourceBundle resources) overschrijven. De tweede parameter voor deze methode is ResourceBundle die wordt doorgegeven van de FXMLLoader naar de controller en door de controller kan worden gebruikt om teksten verder te vertalen of andere locale-afhankelijke informatie te wijzigen.

public class MyController implements Initializable {

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

Schakel dynamisch van taal wanneer de toepassing wordt uitgevoerd

Dit voorbeeld laat zien hoe een JavaFX-toepassing wordt gebouwd, waarbij de taal dynamisch kan worden gewijzigd terwijl de toepassing wordt uitgevoerd.

Dit zijn de berichtenbundelbestanden die in het voorbeeld zijn gebruikt:

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

Het basisidee is om een gebruiksklasse I18N te hebben (als alternatief kan dit een singleton zijn).

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

Deze klasse heeft een statisch veld locale dat is een Java Locale voorwerp gewikkeld in een JavaFX ObjectProperty , zodat bindingen kunnen worden gemaakt voor deze eigenschap. De eerste methoden zijn de standaardmethoden om een JavaFX-eigenschap op te halen en in te stellen.

De get(final String key, final Object... args) is de kernmethode die wordt gebruikt voor de echte extractie van een bericht uit een ResourceBundle .

De twee methoden met de naam createStringBinding maken een StringBinding die gebonden is aan het locale veld en dus veranderen de bindingen wanneer de eigenschap locale verandert. De eerste maakt gebruik van deze argumenten op te halen en opmaken van een bericht met behulp van de get methode hierboven genoemde, de tweede wordt doorgegeven in een Callable , waarin de nieuwe reeks waarde moet produceren.

De laatste twee methoden zijn methoden om JavaFX-componenten te maken. De eerste methode wordt gebruikt om een Label te maken en gebruikt Callable voor de interne stringbinding. De tweede maakt een Button en gebruikt een sleutelwaarde voor het ophalen van de stringbinding.

Natuurlijk kunnen er veel meer verschillende objecten worden gemaakt, zoals MenuItem of ToolTip maar deze twee zouden genoeg moeten zijn voor een voorbeeld.

Deze code laat zien hoe deze klasse wordt gebruikt in de toepassing:

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

De applicatie toont drie verschillende manieren om StringBinding gecreëerd door de I18N klasse:

  1. de venstertitel wordt gebonden door rechtstreeks een StringBinding .
  2. de knoppen gebruiken de helper-methode met de berichttoetsen
  3. het label gebruikt de helper-methode met een Callable . Deze Callable gebruikt de methode I18N.get() om een opgemaakte vertaalde tekenreeks te krijgen die het werkelijke aantal schakelaars bevat.

Als u op een knop klikt, wordt de teller verhoogd en wordt de I18N de I18N ingesteld, waardoor de I18N gewijzigd en de string van de gebruikersinterface dus op nieuwe waarden wordt ingesteld.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow