Internationalization JavaFX2与国际化

Internationalization JavaFX2与国际化,internationalization,javafx-2,Internationalization,Javafx 2,在学习了基础知识之后,我刚刚开始编写我的第一个JavaFX2应用程序,并希望将其国际化 我注意到在JavaFX1.x中,脚本语言允许非常简单的字符串国际化。JavaFX2中是否有类似的功能 基本上:java FX 2应用程序国际化的最佳实践是什么?java应用程序国际化的基本步骤包括Locale本地化和资源绑定。在JavaFX中,您可以使用FXMLLoader#setResources()来实现此目的。这里有一个SSCCE演示来演示它。代码是自描述性的。 演示包结构: bundledemo

在学习了基础知识之后,我刚刚开始编写我的第一个JavaFX2应用程序,并希望将其国际化

我注意到在JavaFX1.x中,脚本语言允许非常简单的字符串国际化。JavaFX2中是否有类似的功能

基本上:java FX 2应用程序国际化的最佳实践是什么?

java应用程序国际化的基本步骤包括
Locale
本地化和资源绑定。在JavaFX中,您可以使用
FXMLLoader#setResources()
来实现此目的。这里有一个SSCCE演示来演示它。代码是自描述性的。
演示包结构:

bundledemo
    |------ BundleDemo.java
    |------ MyController.java
    |------ MyView.fxml  
bundles
    |------ MyBundle_en.properties
    |------ MyBundle_kg.properties
MyBundle_en.properties

key1=Name Surname
key2=How are you?
key1=Aты Жөнү
key2=Кандайсың?
MyBundle_kg.properties

key1=Name Surname
key2=How are you?
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>
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);
    }
}
package bundledemo;
//导入被忽略。
公共类BundleDemo扩展了应用程序{
私人舞台;
@凌驾
公共无效开始(阶段primaryStage){
阶段=初级阶段;
按钮btnEN=新按钮();
btnEN.setText(“英语”);
setOnAction(新的EventHandler(){
@重写公共无效句柄(ActionEvent事件){
加载视图(新区域设置(“en”、“en”));
}
});
按钮btnKG=新按钮();
btnKG.setText(“吉尔吉斯”);
setOnAction(新的EventHandler(){
@重写公共无效句柄(ActionEvent事件){
loadView(新区域设置(“kg”、“kg”);
}
});
VBox根=新的VBox(20);
root.getChildren().add(HBoxBuilder.create().spating(10).style(“-fx背景色:灰色”).padding(新插图(5)).children(btnEN,btnKG.build());
root.getChildren().add(newstackpane());
原始阶段。设置场景(新场景(根,300250));
primaryStage.show();
}
私有void加载视图(区域设置){
试一试{
FXMLLoader FXMLLoader=新的FXMLLoader();
setResources(ResourceBundle.getBundle(“bundles.MyBundle”,locale));
Pane Pane=(BorderPane)fxmloader.load(this.getClass().getResource(“MyView.fxml”).openStream());
//替换内容
StackPane content=(StackPane)((VBox)stage.getScene().getRoot()).getChildren().get(1);
content.getChildren().clear();
content.getChildren().add(窗格);
}捕获(IOEX异常){
例如printStackTrace();
}
}
公共静态void main(字符串[]args){
发射(args);
}
}
截图:

这对我来说很有用:

└───src
    ├───app
    ├───bundles // <- here the "bundles"
    ├───dicts
    ├───images
    ├───libs
    └───resources
样本内容:

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

非常好的答案,我会接受它,但我应该提到,我正在用代码而不是FXML构建接口。是否有一种快速简便的代码国际化方法,我意识到我可以做ResourceBundle.getBundle+查找,但我希望可以用%键表示法来代替。然后你可以像在任何其他Java应用程序中一样,用普通的方法来做这件事。确定用户/客户机的区域设置,然后相应地更改应用程序的区域设置(从DB vs.获取特定于语言的数据)。通过
ResourceBundle.getBundle(“bundles.MyBundle”,locale)
加载适当的bundle。通过
bundle.getString(“key”)
更改视图/页面中使用的所有文本。如果我通过setResources()方法提供ResourceBundle,这对我不起作用。当我通过load()方法提供ResourceBundle时,它正在工作。@Jurica Krizanic:有相同的问题,并通过相同的方法解决了它:
FXMLLoader.load(getClass().getResource(sceneId),getResources())
其中
sceneId
是字符串和方法
getResources()
返回具有正确区域设置的资源。Hello@UlukBiy我们可以在
中多次添加文本,如“%key2%key1”。因为我已经试过了,但它给了我一个例外…但我不知道它是否可能。。。!关于语言之间的切换,这里有一些信息:[[1]:@Moritz如果你点击了链接,就会看到详细的响应和完整的源文件,我在stackoverflow.com上添加了一个响应链接。因为你,我必须在所有地方插入相同的代码。我希望你喜欢,而不是不喜欢