javafx
Internationalisering i JavaFX
Sök…
Laddar resursbunt
JavaFX är ett enkelt sätt att internationalisera dina användargränssnitt. När du skapar en vy från en FXML-fil kan du förse FXMLLoader
med en resurspaket:
Locale locale = new Locale("en", "UK");
ResourceBundle bundle = ResourceBundle.getBundle("strings", locale);
Parent root = FXMLLoader.load(getClass().getClassLoader()
.getResource("ui/main.fxml"), bundle);
Detta medföljande paket används automatiskt för att översätta alla texter i din FXML-fil som börjar med en %
. Låt strings_en_UK.properties
säga att din egenskapsfil strings_en_UK.properties
innehåller följande rad:
ui.button.text=I'm a Button
Om du har en knappdefinition i din FXML så här:
<Button text="%ui.button.text"/>
Den får automatiskt översättningen för nyckeln ui.button.text
.
Kontrollant
En resursbunt innehåller platsspecifika objekt. Du kan skicka paketet till FXMLLoader
under skapandet. Styrenheten måste implementera Initializable
gränssnitt och åsidosätta metod för initialize(URL location, ResourceBundle resources)
. Den andra parametern till denna metod är ResourceBundle
som överförs från FXMLLoader till regulatorn och kan användas av kontrollenheten för att ytterligare översätta texter eller modifiera annan platsberoende information.
public class MyController implements Initializable {
@Override
public void initialize(URL location, ResourceBundle resources) {
label.setText(resources.getString("country"));
}
}
Växla språk dynamiskt när applikationen körs
Detta exempel visar hur man bygger en JavaFX-applikation, där språket kan växlas dynamiskt medan applikationen körs.
Dessa är meddelandepaketfilerna som används i exemplet:
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}
Den grundläggande idén är att ha en bruksklass I18N (som alternativ kan detta implementeras en 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;
}
}
Denna klass har en statisk locale
som är ett Java Locale
objekt som är inslaget i ett JavaFX ObjectProperty
, så att bindningar kan skapas för den här egenskapen. De första metoderna är standardmetoderna för att få och ställa in en JavaFX-egenskap.
get(final String key, final Object... args)
är get(final String key, final Object... args)
som används för verklig extraktion av ett meddelande från en ResourceBundle
.
De två metoderna som heter createStringBinding
skapar en StringBinding
som är bunden till locale
och så kommer bindningarna att ändras när locale
ändras. Den första använder sina argument för att hämta och formatera ett meddelande med hjälp av get
metoden som nämns ovan, den andra skickas i en Callable
, som måste producera det nya strängvärdet.
De två sista metoderna är metoder för att skapa JavaFX-komponenter. Den första metoden används för att skapa en Label
och använder en Callable
för sin interna strängbindning. Den andra skapar en Button
och använder ett nyckelvärde för att hämta strängbindningen.
Naturligtvis kan många fler olika objekt skapas som MenuItem
eller ToolTip
men dessa två borde vara tillräckligt för ett exempel.
Den här koden visar hur denna klass används i applikationen:
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);
}
}
Applikationen visar tre olika sätt att använda StringBinding
skapat av klassen I18N
:
- fönstertiteln är bunden av direkt med hjälp av en
StringBinding
. - knapparna använder hjälpmetoden med meddelandetangenterna
- etiketten använder hjälpmetoden med en
Callable
. DennaCallable
använderI18N.get()
för att få en formaterad översatt sträng som innehåller det faktiska antalet switchar.
När du klickar på en knapp ökas räknaren och I18N
s I18N
ställs in, vilket i sin tur utlöser strängbindningarna som ändras och så ställer användargränssnittets sträng till nya värden.