在学习了基础知识之后,我才开始编写我的第一个JavaFX 2应用程序,并希望对其进行国际化。
我注意到在JavaFX 1.x中,脚本语言允许非常简单的字符串国际化。JavaFX 2中是否有任何类似的功能?
基本上:国际化JavaFX 2应用程序的最佳实践是什么?
Answers:
国际化Java应用程序的基本步骤(除其他步骤外)是大小调整Locale
和资源捆绑。在JavaFX中,您可以FXMLLoader#setResources()
用于此目的。这里是一个SSCCE演示来演示它。这些代码是自我描述的。
演示包结构:
bundledemo
|------ BundleDemo.java
|------ MyController.java
|------ MyView.fxml
bundles
|------ MyBundle_en.properties
|------ MyBundle_kg.properties
MyBundle_zh.properties
key1=Name Surname
key2=How are you?
MyBundle_kg.properties
key1=Aты Жөнү
key2=Кандайсың?
MyView.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.*?>
<BorderPane fx:controller="bundledemo.MyController" xmlns:fx="http://javafx.com/fxml">
<top>
<!-- This label's text will be set by the controller -->
<Label fx:id="lblTextByController"/>
</top>
<center>
<!-- This label's text will be taken from the bundle automatically -->
<Label text="%key2"/>
</center>
</BorderPane>
MyController.java
package bundledemo;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
public class MyController implements Initializable {
@FXML private Label lblTextByController;
private ResourceBundle bundle;
@Override
public void initialize(URL location, ResourceBundle resources) {
bundle = resources;
lblTextByController.setText(bundle.getString("key1"));
}
}
BundleDemo.java
package bundledemo;
// imports are ignored.
public class BundleDemo extends Application {
private Stage stage;
@Override
public void start(Stage primaryStage) {
stage = primaryStage;
Button btnEN = new Button();
btnEN.setText("English");
btnEN.setOnAction(new EventHandler<ActionEvent>() {
@Override public void handle(ActionEvent event) {
loadView(new Locale("en", "EN"));
}
});
Button btnKG = new Button();
btnKG.setText("Kyrgyz");
btnKG.setOnAction(new EventHandler<ActionEvent>() {
@Override public void handle(ActionEvent event) {
loadView(new Locale("kg", "KG"));
}
});
VBox root = new VBox(20);
root.getChildren().add(HBoxBuilder.create().spacing(10).style("-fx-background-color: gray").padding(new Insets(5)).children(btnEN, btnKG).build());
root.getChildren().add(new StackPane());
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
}
private void loadView(Locale locale) {
try {
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setResources(ResourceBundle.getBundle("bundles.MyBundle", locale));
Pane pane = (BorderPane) fxmlLoader.load(this.getClass().getResource("MyView.fxml").openStream());
// replace the content
StackPane content = (StackPane) ((VBox) stage.getScene().getRoot()).getChildren().get(1);
content.getChildren().clear();
content.getChildren().add(pane);
} catch (IOException ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
屏幕截图:
ResourceBundle.getBundle("bundles.MyBundle", locale)
。更改您在视图/页面中使用的每个文本bundle.getString("key")
。
FXMLLoader.load(getClass().getResource(sceneId), getResources())
在哪里返回具有正确语言环境的资源。sceneId
getResources()
这对我有用:
└───src
├───app
├───bundles // <- here the "bundles"
├───dicts
├───images
├───libs
└───resources
在捆绑包中
LangBundle_en.properties
LangBundle_de.properties
样本内容:
enter_pwd=Enter your password:
要加载它们,我使用以下代码:
@Override
public void initialize(URL location, ResourceBundle resources) {
ResourceBundle lngBndl = ResourceBundle
.getBundle("bundles.LangBundle", new Locale("en", "EN"));
tvSetupPwd.setText(lngBndl.getString("enter_pwd"));
// ...
}
更新:
解决方案在 Messages.java
/**
* The class with all messages of this application.
*/
public abstract class Messages {
private static ResourceBundle BUNDLE;
private static final String FIELD_NAME = "lookup";
private static final String BUNDLE_NAME = "messages/messages";
private static final String CONTROLS_BUNDLE_NAME = "com/sun/javafx/scene/control/skin/resources/controls";
public static final String MAIN_APP_TITLE;
public static final String DIALOG_HEADER;
public static final String MAIN_CONTROLLER_CONTENT_TEXT;
public static final String MAIN_CONTROLLER_HELLO_TEXT;
public static final String MAIN_CONTROLLER_GOODBYE_TEXT;
static {
final Locale locale = Locale.getDefault();
final ClassLoader classLoader = ControlResources.class.getClassLoader();
final ResourceBundle controlBundle = getBundle(CONTROLS_BUNDLE_NAME,
locale, classLoader, PropertyLoader.getInstance());
final ResourceBundle overrideBundle = getBundle(CONTROLS_BUNDLE_NAME,
PropertyLoader.getInstance());
final Map override = getUnsafeFieldValue(overrideBundle, FIELD_NAME);
final Map original = getUnsafeFieldValue(controlBundle, FIELD_NAME);
//noinspection ConstantConditions,ConstantConditions,unchecked
original.putAll(override);
BUNDLE = getBundle(BUNDLE_NAME, PropertyLoader.getInstance());
MAIN_APP_TITLE = BUNDLE.getString("MainApp.title");
DIALOG_HEADER = BUNDLE.getString("Dialog.information.header");
MAIN_CONTROLLER_CONTENT_TEXT = BUNDLE.getString("MainController.contentText");
MAIN_CONTROLLER_HELLO_TEXT = BUNDLE.getString("MainController.helloText");
MAIN_CONTROLLER_GOODBYE_TEXT = BUNDLE.getString("MainController.goodbyeText");
}
public static ResourceBundle GetBundle() {
return BUNDLE;
}
}
和在 PropertyLoader.java
public class PropertyLoader extends ResourceBundle.Control {
private static final String PROPERTIES_RESOURCE_NAME = "properties";
private static final PropertyLoader INSTANCE = new PropertyLoader();
public static PropertyLoader getInstance() {
return INSTANCE;
}
@Override
public ResourceBundle newBundle(final String baseName, final Locale locale, final String format,
final ClassLoader loader, final boolean reload)
throws IllegalAccessException, InstantiationException, IOException {
final String bundleName = toBundleName(baseName, locale);
final String resourceName = toResourceName(bundleName, PROPERTIES_RESOURCE_NAME);
ResourceBundle bundle = null;
InputStream stream = null;
if (reload) {
final URL url = loader.getResource(resourceName);
if (url != null) {
final URLConnection connection = url.openConnection();
if (connection != null) {
connection.setUseCaches(false);
stream = connection.getInputStream();
}
}
} else {
stream = loader.getResourceAsStream(resourceName);
}
if (stream != null) {
try {
bundle = new PropertyResourceBundle(new InputStreamReader(stream, StandardCharsets.UTF_8));
} finally {
stream.close();
}
}
return bundle;
}
}