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_zh_CN.properties
//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的资源文件,使这个工具支持中文。。。