JavaFX:在运行时更改应用程序语言

我正在使用FXML中描述的核心组件制作JavaFX桌面应用程序,我想为用户提供更改语言的选项。 但是,一旦从FXML加载组件,我还没有找到任何直接的方法来更改语言。

问题是如何处理在JavaFX中切换语言的任何标准方法。

你可以做这样的事情。 在您的回答中,您可能希望将其实现为单例,或者使用DI框架在您需要的任何地方注入单个实例:

public class ObservableResourceFactory { private ObjectProperty resources = new SimpleObjectProperty<>(); public ObjectProperty resourcesProperty() { return resources ; } public final ResourceBundle getResources() { return resourcesProperty().get(); } public final void setResources(ResourceBundle resources) { resourcesProperty().set(resources); } public StringBinding getStringBinding(String key) { return new StringBinding() { { bind(resourcesProperty()); } @Override public String computeValue() { return getResources().getString(key); } }; } } 

现在你可以做以下事情:

 ObservableResourceFactory resourceFactory = .... ; resourceBundle.setResources(...); Label greetingLabel = new Label(); greetingLabel.textProperty().bind(resourceFactory.getStringBinding("greeting")); 

每次更新资源时都是如此

 resourceFactory.setResources(...); 

将导致标签更新其文本。

这是一个SSCCE(对于将ResourceBundle强制转换为单个可运行类的极其难看的方式道歉…)

 import java.util.ListResourceBundle; import java.util.Locale; import java.util.ResourceBundle; import javafx.application.Application; import javafx.beans.binding.StringBinding; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.control.ComboBox; import javafx.scene.control.Label; import javafx.scene.control.ListCell; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; public class ResourceBundleBindingExample extends Application { private static final String RESOURCE_NAME = Resources.class.getTypeName() ; private static final ObservableResourceFactory RESOURCE_FACTORY = new ObservableResourceFactory(); static { RESOURCE_FACTORY.setResources(ResourceBundle.getBundle(RESOURCE_NAME)); } @Override public void start(Stage primaryStage) { ComboBox languageSelect = new ComboBox<>(); languageSelect.getItems().addAll(Locale.ENGLISH, Locale.FRENCH); languageSelect.setValue(Locale.ENGLISH); languageSelect.setCellFactory(lv -> new LocaleCell()); languageSelect.setButtonCell(new LocaleCell()); languageSelect.valueProperty().addListener((obs, oldValue, newValue) -> { if (newValue != null) { RESOURCE_FACTORY.setResources(ResourceBundle.getBundle(RESOURCE_NAME, newValue)); } }); Label label = new Label(); label.textProperty().bind(RESOURCE_FACTORY.getStringBinding("greeting")); BorderPane root = new BorderPane(null, languageSelect, null, label, null); root.setPadding(new Insets(10)); Scene scene = new Scene(root, 400, 400); primaryStage.setScene(scene); primaryStage.show(); } public static class LocaleCell extends ListCell { @Override public void updateItem(Locale locale, boolean empty) { super.updateItem(locale, empty); if (empty) { setText(null); } else { setText(locale.getDisplayLanguage(locale)); } } } public static class ObservableResourceFactory { private ObjectProperty resources = new SimpleObjectProperty<>(); public ObjectProperty resourcesProperty() { return resources ; } public final ResourceBundle getResources() { return resourcesProperty().get(); } public final void setResources(ResourceBundle resources) { resourcesProperty().set(resources); } public StringBinding getStringBinding(String key) { return new StringBinding() { { bind(resourcesProperty()); } @Override public String computeValue() { return getResources().getString(key); } }; } } public static class Resources extends ListResourceBundle { @Override protected Object[][] getContents() { return new Object[][] { {"greeting", "Hello"} }; } } public static class Resources_fr extends ListResourceBundle { @Override protected Object[][] getContents() { return new Object[][] { {"greeting", "Bonjour"} }; } } public static void main(String[] args) { launch(args); } } 

我目前正在使用singleton(在后期阶段可能通过DI框架注入)作为语言ResourceBundle的包装器。

我的计划是实现可观察模式并通知所有需要更改的组件(用@FXML语句注入的子组件)。