RapidMiner Studio之GUI多语言支持

     RapidMiner的GUI界面的按钮、菜单等显示的文字要根据使用者操作系统的语言环境一致,当前5.3版本只支持英语和日语二种语言环境,在了解其多语言支持的框架之后,可以很轻松的添加中文在内的其它语种的支持。

     RapidMiner GUI启动时,先设置所使用的语言,再根据语言加载资源文件,最后展示界面,现根据这个步骤看下RapidMiner是如何实现多语言支持的: 

     在调用RapidMinerGUI的main方法时,会调用RapidMiner的方法,而调用RapidMiner中的方法,则首先需要加载RapidMiner类,RapidMiner类中的static代码块的开始部分,完成了对GUI界面使用语言的设置:

        //设置默认语言是英文
        String[] default_language = new String[1];
        default_language[0] = "eng";

        //支持的语言列表配置在文件/com/rapidminer/resources/i18n/language_definitions.txt中
        Vector<String> languages = new Vector<String>();
        Scanner scanLanguageDefs = new Scanner(
                RapidMiner.class.getResourceAsStream("/com/rapidminer/resources/i18n/language_definitions.txt"));
        try {
            while (scanLanguageDefs.hasNextLine()) {
                String nextLine = scanLanguageDefs.nextLine();
                if (!nextLine.contains("#")) {
                    languages.add(nextLine);
                }
            }
        } finally {
            scanLanguageDefs.close();
        }

        //配置中没有配置支持的语言,则使用默认的支持语言
        if (languages.size() < 1) {
            ParameterService.registerParameter(new ParameterTypeCategory(PROPERTY_RAPIDMINER_GENERAL_LOCALE_LANGUAGE,
                    "The displayed language", default_language, 0), "general");
        } else {
             
            // 原先的代码是取配置文件中的第一个语言作为GUI的显示语言
            // int idx = 0;
            // String[] languageArray = new String[languages.size()];
            // for (String lang : languages) {
            // languageArray[idx] = lang;
            // ++idx;
            // }

            /*
             * 修改上述规则,默认的显示语言是/com/rapidminer/resources/i18n/
             * language_definitions.txt文件中的第一个语言
             * 现增加判断用户本地语言是否在支持列表中,如是,则使用用户的默认语言作为界面显示语言
             */
            int idx = 1;

            String[] languageArray = new String[languages.size() + 1];
            String localLang = Locale.getDefault().getLanguage();
            for (String lang : languages) {

                /* 本地语言在支持的语言列表中 */
                if (lang.equals(localLang)) {
                    languageArray[0] = localLang;
                }
                languageArray[idx] = lang;
                ++idx;
            }
            if (languageArray[0] == null) {
                languageArray[0] = languageArray[1];
            }
 
            /* 设置GUI的显示语言,取得是集合languageArray的第一个元素 */
            ParameterService.registerParameter(new ParameterTypeCategory(PROPERTY_RAPIDMINER_GENERAL_LOCALE_LANGUAGE,
                    "The displayed language", languageArray, 0), "general");

     由此可见,要添加中文语言支持,只需在配置文件中添加中文语言选项到第一行(默认),然后增加相应资源文件即可。

     在确定使用哪个语言展现GUI后,下面一步的工作就是要实现对该语言的支持,这个工作是由com.rapidminer.tools.I18N来完成的。RapidMinerGUI的run方法会调用RapidMiner.init()方法,RapidMiner.init()的方法的第一步就是调用I18N.getErrorBundle()来完成多语言支持的初始化工作(是在I18N的static代码块中完成的),这部分代码,用到了如下这些类:com.rapidminer.tools.ParameterService,com.rapidminer.tools.ExtensibleResourceBundle,java.util.ResourceBundle,下面一一分析这些类。

    com.rapidminer.tools.I18N static代码块

static {
ParameterService.init();
//获取在RapidMiner中设置的默认语言 String localeLanguage
= ParameterService.getParameterValue(RapidMiner.PROPERTY_RAPIDMINER_GENERAL_LOCALE_LANGUAGE);

//没有设置默认,则取本地语言环境 Locale locale
= Locale.getDefault(); if (localeLanguage != null) { locale = new Locale(localeLanguage); Locale.setDefault(locale); LogService.getRoot().log(Level.INFO, "com.rapidminer.tools.I18N.set_locale_to", locale); } else { LogService.getRoot().log(Level.INFO, "com.rapidminer.tools.I18N.using_default_locale", locale); } JComponent.setDefaultLocale(locale); USER_ERROR_BUNDLE = new ExtensibleResourceBundle(ResourceBundle.getBundle("com.rapidminer.resources.i18n.UserErrorMessages", locale, I18N.class.getClassLoader())); ERROR_BUNDLE = new ExtensibleResourceBundle(ResourceBundle.getBundle("com.rapidminer.resources.i18n.Errors", locale, I18N.class.getClassLoader())); GUI_BUNDLE = new ExtensibleResourceBundle(ResourceBundle.getBundle("com.rapidminer.resources.i18n.GUI", locale, I18N.class.getClassLoader())); ResourceBundle plotterBundle = ResourceBundle.getBundle("com.rapidminer.resources.i18n.PlotterMessages", locale, I18N.class.getClassLoader()); GUI_BUNDLE.addResourceBundle(plotterBundle); }

     上述代码定义了三个资源文件绑定:USER_ERROR_BUNDLE、ERROR_BUNDLE、GUI_BUNDLE,分别用来设置用户错误,系统错误,界面提示语言。

      ResourceBundle这个类提供软件国际化的捷径,这个类的作用就是读取资源属性文件(properties),然后根据.properties文件的名称信息(本地化信息),匹配当前系统的国别语言信息(也可以程序指定),然后获取相应的properties文件的内容。使用这个类,要注意的一点是,这个properties文件的名字是有规范的:一般的命名规范是: 自定义名_语言代码_国别代码.properties,如果是默认的,直接写为:自定义名.properties比如:

      resource_en_US.properties
      resource_zh_CN.properties
      resource.properties
      当在中文操作系统下,如果myres_zh_CN.properties、myres.properties两个文件都存在,则优先会使用myres_zh_CN.properties,当myres_zh_CN.properties不存在时候,会使用默认的myres.properties。没有提供语言和地区的资源文件是系统默认的资源文件,资源文件都必须是ISO-8859-1编码,因此,对于所有非西方语系的处理,都必须先将之转换为Java Unicode Escape格式。转换方法是通过JDK自带的工具native2ascii.
      ResourceBundle本身是一个抽象类,它提供了工厂方法getBundle来获取具体的ResourceBundle实现类,getBundle的第一个参数是带全限定符的资源文件路径(不包括语言环境),第二个参数是语言设置,第三个参数是类加载器(注意getBundle有多个重载的方法)。
      ExtensibleResourceBundle这个类在ResourceBundle基础上增加了多资源文件绑定的功能,其绑定的资源文件通过addResourceBundle方法添加到一个LinkedList中。这样通过key查找value时,会在绑定的多个资源文件中查找。另外I18N类中也提供了静态方法register***Bundle(最终调用的是ExtensibleResourceBundle的addResource
Bundle方法),用于向USER_ERROR_BUNDLE、ERROR_BUNDLE、GUI_BUNDLE添加新的资源文件。
       I18N类中提供了二个实用方法:get***Bundle(获取一个绑定),getMessage(获取key对应的value)。
       get***Bundle方法很简单,其返回的是相应的bundle,下面来看下getMessage方法:
   //bundle是ExtensibleResourceBundle类型的变量,arguments是要替换的参数,按位替换(第一个数值元素替换value中的{0},第二个元素替换{1},以此类推)
public static String getMessage(ResourceBundle bundle, String key, Object... arguments) { try { if (arguments == null || arguments.length == 0) { return bundle.getString(key); } else { String message = bundle.getString(key); if (message != null) { return MessageFormat.format(message, arguments); } else { return key; } } } catch (MissingResourceException e) { LogService.getRoot().log(Level.FINE, "com.rapidminer.tools.I18N.missing_key", key); return key; } }

       bundle变量的实际类型是ExtensibleResourceBundle,利用Java语言的多态,调用getString方法时,其最终调用的是ExtensibleResourceBundle中

handleGetObject方法(ExtensibleResourceBundle重写了父类ResourceBundle的handleGetObject方法):

    @Override
    protected Object handleGetObject(String key) {
        for (ResourceBundle bundle: bundles) {
            if (bundle.containsKey(key))
                return bundle.getObject(key);
        }
        return null;
    }

      这个方法中,通过for语法遍历所有绑定的资源文件,调用ResourceBundle的getObject方法(这时的getObject最终调用的是ResourceBundle具体实现类中的handleGetObject方法)来获取key对应的value值,需要注意的是,一旦通过key获取到了value,方法会立刻返回,而不会检查后面的资源文件中是否包含这个key(多个资源文件包含相同的key时,只会获取最先的资源文件中key对应的value)。

      I18N和ExtensibleResourceBundle还有其它一些方法,这些方法都很简单,就不再作分析了。

      至此,已经看到rapidminer如何支持多语言和多资源文件绑定了,接下来要做的工作就是添加zh的资源文件,使这个工具支持中文。。。

posted @ 2015-07-14 15:21  haizhun  阅读(2273)  评论(0编辑  收藏  举报