首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >本地化JavaFx控件

本地化JavaFx控件
EN

Stack Overflow用户
提问于 2014-09-11 23:26:43
回答 5查看 2.9K关注 0票数 5

我正在尝试为JavaFx控件添加我的语言的ResourceBundle,但失败了。

我尝试在类路径中添加controls_fi_FI.properties。并希望它能起作用,但不是。

然后,我查看了负责本地化控件的JavaFx的ControlResources类,并注意到包的基名是"com\sun\javafx\scene\control\skin\resources\controls".

如何将我的properties-file添加到这个包中?我觉得很奇怪,几乎没有任何关于如何做到这一点的信息?

EN

回答 5

Stack Overflow用户

发布于 2014-09-12 01:51:43

我只能通过一个相当大的黑客才能让它工作,这甚至不是远程便携的。然而,也许它会给你足够的工作来创建一个可行的解决方案。(这可以在Java 8下运行。)

我创建了一个包com.sun.javafx.scene.control.skin.resources,并在其中创建了一个controls_fi_FI.properties文件,只有一行

代码语言:javascript
复制
ProgressIndicator.doneString=Valmis

我创建了一个包含以下内容的测试应用程序:

代码语言:javascript
复制
import java.util.Locale;
import java.util.ResourceBundle;

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.BorderPane;


public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
            System.out.println(ResourceBundle.getBundle("com/sun/javafx/scene/control/skin/resources/controls").getString("ProgressIndicator.doneString"));

            BorderPane root = new BorderPane();
            ProgressIndicator progressIndicator = new ProgressIndicator(1);
            root.setCenter(progressIndicator);
            Scene scene = new Scene(root,400,400);
            primaryStage.setScene(scene);
            primaryStage.show();
    }

    public static void main(String[] args) {
        Locale.setDefault(new Locale("fi", "FI"));
        launch(args);
    }
}

以大多数方式运行此应用程序并不能达到预期效果:虽然System.out.println(...)会生成正确的结果,但进度指示器中显示的文本却是错误的。

但是,如果我将com/sun/javafx/control/skin/resources/controls_fi_FI.properties捆绑到一个jar文件中,并将该jar文件移动到我的jre/lib/ext安装目录的JDK子目录中(即.与jfxrt.jar相同的位置),它按要求运行(至少在我的简单测试中是这样;正如我所说的,我不认为这是一种健壮的解决方案)。

问题似乎是ControlsResources是由扩展类加载器加载的,所以使用相同的类加载器来加载资源包。

有了比我更好的类加载器知识,您也许能够将其转化为一个合理的解决方案……

票数 4
EN

Stack Overflow用户

发布于 2017-08-31 19:19:53

我创建了简单的"Hello,world!“展示使用多语言支持的现成JavaFX项目的示例是为那些需要更多异国语言(be-BY,ru-RU等)的人准备的。

下面是我解决这个问题的方法,它对我很有效

Messages.java

代码语言:javascript
复制
/**
 * 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

代码语言:javascript
复制
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;
    }
}

我在hereGitHub上描述了更多内容

以下是白俄罗斯语的演示:

票数 2
EN

Stack Overflow用户

发布于 2018-02-14 02:30:50

我反向加载了包,并想出了一个糟糕的解决方案,以防将jar放到jre/lib/ext中是不可取的。默认算法要求捆绑包文件采用ISO-8859-1编码,并且不提供任何指定编码的方法。我的解决方案也解决了编码问题。

以下方法使用应用程序类加载器加载资源,并使用扩展类加载器( javafx类在运行时使用扩展类加载器查找包)将生成的包放入包缓存中。

代码语言:javascript
复制
import com.sun.javafx.scene.control.skin.resources.ControlResources;
import java.util.Locale;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
// rest of the imports is ommitted

private void putResourceBundleInCache(String baseName, Charset cs) throws ReflectiveOperationException, IOException {
    Locale currentLocale = Locale.getDefault();
    ResourceBundle.Control control = ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT);
    String resourceName = control.toResourceName(control.toBundleName(baseName, currentLocale), "properties");
    ResourceBundle bundle;
    try (Reader reader = new InputStreamReader(getClass().getClassLoader().getResourceAsStream(resourceName), cs)) {
        bundle = new PropertyResourceBundle(reader);
    }
    Class<?> cacheKeyClass = Class.forName("java.util.ResourceBundle$CacheKey");
    Constructor<?> cacheKeyClassConstructor = cacheKeyClass.getDeclaredConstructor(String.class, Locale.class, ClassLoader.class);
    cacheKeyClassConstructor.setAccessible(true);
    Object cacheKey = cacheKeyClassConstructor.newInstance(baseName, currentLocale, ControlResources.class.getClassLoader());
    Method putBundleInCache = ResourceBundle.class.getDeclaredMethod("putBundleInCache", cacheKeyClass, ResourceBundle.class, ResourceBundle.Control.class);
    putBundleInCache.setAccessible(true);
    putBundleInCache.invoke(null, cacheKey, bundle, control);
}

我从start方法调用它,如下所示:

代码语言:javascript
复制
public void start(Stage primaryStage) throws Exception {
    putResourceBundleInCache("com/sun/javafx/scene/control/skin/resources/controls", StandardCharsets.UTF_8);
    // mian logic here
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25791416

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档