Javafx Internationalization with custom language

后端 未结 1 1074
陌清茗
陌清茗 2020-12-19 19:13

I\'m developing a JavaFX application with multiple language support. My app sometimes shows an alert box, for example:

package application;
    
import java.u         


        
相关标签:
1条回答
  • 2020-12-19 20:11

    I am very upset that the JRE inside very few exotic languages. And this is a big problem. I've been looking for a solution, I created an open source project which demonstrates how to add new languages resources in this project.

    Project on GitHub

    I translated the system controls JavaFX into a new language (be-BY, ru-RU):

    Structure of my project:

    java
        |------ com\krasutski\language\Messages.java
        |------ com\krasutski\util\PropertyLoader.java
        |------ com\krasutski\util\ReflectionUtils.java
        |------ com\krasutski\view\MainController.java
        |------ com\krasutski\MainApp.java
    resources
        |------ com\sun\javafx\scene\control\skin\resources\controls_be_BY.properties
        |------ com\sun\javafx\scene\control\skin\resources\controls_ru.properties
        |------ fxml\main.fxml
        |------ icons\app-128x128x32.png
        |------ messages\messages.properties
        |------ messages\messages_be_BY.properties
        |------ messages\messages_ru.properties
        |------ styles\styles.css
    

    the solution to the problem is in 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;
        }
    }
    

    and in 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;
        }
    }
    

    An example slice file controls_be_BY.properties

    # encoding=utf-8
    # ProgressIndicator, the string that's displayed at 100%
    ProgressIndicator.doneString=Гатова
    
    # ListView
    ListView.noContent=Няма змесціва
    
    # TableView
    TableView.noContent=Няма змесціва ў табліцы
    TableView.noColumns=Няма калонак ў табліцы
    

    Here you don't need to use a special character \u you just write to any text editor which supports Unicode.

    You can add your exotic languages folder resources/com/sun/javafx/scene/control/skin/resources of this project. Send me your controls_*.properties and I'll add them to this project.

    Ready assembled example you can download in the releases section

    0 讨论(0)
提交回复
热议问题