0%

Hadoop-Intellij-Plugin 插件设计和源码分析----国际化多语言支持设计和实现

Hadoop-IntelliJ-Plugin 的国际化多语言支持比较简单,直接使用了Java的本地化实现机制。先简单的介绍一下Java的本地化方法。

本地化介绍

  “国际化信息”也称为“本地化信息”,一般需要两个条件才可以确定一个特定类型的本地化信息,它们分别是“语言类型”和“国家/地区的类型”。如中文本地化信息既有中国大陆地区的中文,又有中国台湾、中国香港地区的中文,还有新加坡地区的中文。
  Java通过java.util.Locale类表示一个本地化对象,它允许通过语言参数和国家/地区参数创建一个确定的本地化对象。语言参数使用ISO标准语言代码表示,这些代码是由ISO-639标准定义的,每一种语言由两个小写字母表示。在许多网站上都可以找到这些代码的完整列表,下面的网址是提供了标准语言代码的信息:http://www.loc.gov/standards/iso639-2/php/English_list.php。
  国家/地区参数也由标准的ISO国家/地区代码表示,这些代码是由ISO-3166标准定义的,每个国家/地区由两个大写字母表示。用户可以从以下网址查看ISO-3166的标准代码:http://www.iso.ch/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html。
  下表给出了一些语言和国家/地区的标准代码:

  Java.util.Locale类是表示语言和国家/地区信息的本地化类,它是创建国际化应用的基础。如下面的例子:

1
//带有语言和国家/地区信息的本地化对象
2
Locale locale1 = new Locale("zh","CN");
3
//只有语言信息的本地化对象
4
Locale locale2 = new Locale("zh");
5
//等同于Locale("zh","CN")
6
Locale locale3 = Locale.CHINA;
7
//等同于Locale("zh")
8
Locale locale4 = Locale.CHINESE;

  如果有些系统需要支持多种语言设置,那就要准备对应的语言资源文件,并以规范的方式进行命名。国际化资源文件的命名规范规定资源名称采用以下的方式进行命名:

<资源名>_<语言代码>_<国家/地区代码>.properties

  其中,语言代码和国家/地区代码都是可选的。<资源名>.properties命名的国际化资源文件是默认的资源文件,即某个本地化类型在系统中找不到对应的资源文件,就采用这个默认的资源文件。<资源名>_<语言代码>.properties命名的国际化资源文件是某一语言默认的资源文件,即某个本地化类型在系统中找不到精确匹配的资源文件,将采用相应语言默认的资源文件。拿我们插件的项目来说明,插件项目目前只支持简体中文和英文两种:

HadoopNavigator_en_US.properties  表示的是英文语言资源文件  
HadoopNavigator_zh_CN.properties 表示的是简体中文语言资源文件  

英文语言信息在资源文件以属性名/值的方式表示:

1
systemText=Hadoop FileSystem
2
settingText=Setting
3
back=Back
4
forward=Forward
5
expandAll=Expand All
6
collapseAll=Collapse All
7
showObjectProperties=Show Object Properties
8
hideObjectProperties=Hide Object Properties
9
connectAction=Connect
10
disconnectAction=DisConnect
11
refreshObjectsStatusAction=Refresh
12
CreateDirectoryAction=Create Directory
13
deleteDirectoryOrFileAction=Delete Directory
14
downDirectoryOrFileAction=Down Directory Or File
15
refreshDirectoryAction=Refresh
16
uploadDirectoryAction=Upload Directory
17
uploadFileAction=Upload File
18
viewFileAction=View
19
objectTypeDirectory=Directory
20
objectTypeFile=File
21
directoryPath=Directory Path
22
directoryOwner=Directory Owner

中文语言信息健/值:

1
systemText=Hadoop\u6587\u4ef6\u7cfb\u7edf
2
settingText=\u8bbe\u7f6e
3
back=\u4e0a\u4e00\u8282\u70b9
4
forward=\u4e0b\u4e00\u8282\u70b9
5
expandAll=\u5168\u90e8\u5c55\u5f00
6
collapseAll=\u5168\u90e8\u6298\u53e0
7
showObjectProperties=\u663e\u793a\u5bf9\u8c61\u5c5e\u6027
8
hideObjectProperties=\u9690\u85cf\u5bf9\u8c61\u5c5e\u6027
9
connectAction=\u8fde\u63a5
10
disconnectAction=\u65ad\u5f00\u8fde\u63a5
11
refreshObjectsStatusAction=\u5237\u65b0
12
CreateDirectoryAction=\u521b\u5efa\u76ee\u5f55
13
deleteDirectoryOrFileAction=\u5220\u9664
14
downDirectoryOrFileAction=\u4e0b\u8f7d
15
refreshDirectoryAction=\u5237\u65b0
16
uploadDirectoryAction=\u4e0a\u4f20\u76ee\u5f55
17
uploadFileAction=\u4e0a\u4f20\u6587\u4ef6
18
viewFileAction=\u67e5\u770b\u6587\u4ef6
19
objectTypeDirectory=\u76ee\u5f55
20
objectTypeFile=\u6587\u4ef6
21
directoryPath=\u76ee\u5f55\u8def\u5f84
22
directoryOwner=\u76ee\u5f55\u6240\u6709\u8005
23
directoryPermission=\u76ee\u5f55\u6743\u9650
24
directoryGroup=\u76ee\u5f55\u6240\u5728\u7684

  本地化不同的同一资源文件,虽然属性值各不相同,但属性名却是相同的,这样应用程序就可以通过Locale对象和属性名精确调用到某个具体的属性值了。

  中文的本地化资源文件内容采用了特殊的编码表示中文字符,这是因为资源文件对文件内容有严格的要求:只能包含ASCII字符。所以必须将非ASCII字符的内容转换为Unicode代码的表示方式。如上面中文的HadoopNavigator_zh_CN.properties资源文件的属性值中文字符串对应的Unicode代码串。

  如果在应用开发时,直接采用Unicode代码编辑资源文件是很不方便的,所以,通常我们直接使用正常的方式编写资源文件,在测试或部署时再采用工具进行转换。JDK在bin目录下为我们提供了一个完成此项功能的native2ascii工具,它可以将中文字符的资源文件转换为Unicode代码格式的文件,命令格式如下:

native2ascii [-reverse] [-encoding 编码] [输入文件 [输出文件]]

  对于语言资源文件的读取解析,Java为我们提供了用于加载本地化资源文件的方便类java.util.ResourceBoundle。ResourceBoundle为加载及访问资源文件提供便捷的操作,下面的语句从相对于类路径的目录中加载一个名为resource的本地化资源文件:

1
/**
2
 * 设置本地化资源
3
 * @param locale
4
 */
5
public void setResourceBundle(Locale locale)
6
{
7
    resourceBundle = ResourceBundle.getBundle("HadoopNavigator", locale);
8
}

  注意资源文件的路径。ResourceBundle在加载资源时,如果指定的本地化资源文件不存在,它按以下顺序尝试加载其他的资源:本地系统默认本地化对象对应的资源→默认的资源。

插件的国际化多语言设计和实现

本地化语言设置管理类 LocalLanguageManager

  定义一个本地化语言设置管理类 LocalLanguageManager ,继承ApplicationComponent,Application级别插件,在IDEA启动时读取操作系统默认的语言类进行相关设置。该类还管理语言设置更改后的事件通知。当用户更改了界面UI的语言设置,会触发LanguageSettingListener ,重新加载语言资源文件,并且通知相关组件,需要调整界面语言。LocalLanguageManager 类代码如下:

1
/**
2
 * 定义本地化语言管理类
3
 * Created by fangyuzhong on 17-7-29.
4
 */
5
public class LocaleLanguageManager  implements ApplicationComponent
6
{
7
    ResourceBundle resourceBundle=null;
8
    /**
9
     * 获取本地化语言管理
10
     * @return
11
     */
12
    public static LocaleLanguageManager getInstance()
13
    {
14
        return  ApplicationManager.getApplication().getComponent(LocaleLanguageManager.class);
15
    }
16
    /**
17
     * 获取本地化资源对象
18
     * @return
19
     */
20
    public ResourceBundle getResourceBundle()
21
    {
22
        return resourceBundle;
23
    }
24
    /**
25
     * 设置本地化资源
26
     * @param locale
27
     */
28
    public void setResourceBundle(Locale locale)
29
    {
30
        resourceBundle = ResourceBundle.getBundle("HadoopNavigator", locale);
31
    }
32
    /**
33
     * 组件初始化 获取系统默认的语言
34
     */
35
    public void initComponent()
36
    {
37
        //获取当前操作系统的语言环境,默认加载
38
        Locale localeDefault = Locale.getDefault();
39
        setResourceBundle(localeDefault);
40
        EventUtil.subscribe(null, ProjectLifecycleListener.TOPIC, this.projectLifecycleListener);
41
    }
42
    public void disposeComponent()
43
    {
44
    }
45
    @NotNull
46
    public String getComponentName()
47
    {
48
        return  "HadoopNavigator.LocaleLanguageManager";
49
    }
50
    /**
51
     * 语言改变监听事件处理
52
     */
53
    private ProjectLifecycleListener projectLifecycleListener = new ProjectLifecycleListener.Adapter()
54
    {
55
        Project project;
56
        public void projectComponentsInitialized(@NotNull Project project)
57
        {
58
            this.project=project;
59
            EventUtil.subscribe(project,null, LanguageSettingsListener.TOPIC, this.languageSettingsListener);
60
        }
61
62
        private LanguageSettingsListener languageSettingsListener = new LanguageSettingsListener()
63
        {
64
            @Override
65
            public void LanguageChanged(Locale locale)
66
            {
67
                resourceBundle = ResourceBundle.getBundle("HadoopNavigator", locale);
68
                final ConnectionBundle connectionBundle = ConnectionManager.getInstance(project).getConnectionBundle();
69
                for(ConnectionHandler connectionHandler :connectionBundle.getConnectionHandlers())
70
                {
71
                    if (connectionHandler != null)
72
                    {
73
                        connectionHandler.getObjectBundle().refreshTreeChildren();
74
                    }
75
                }
76
                //通知相关组件,需要调整界面语言
77
                EventUtil.notify(project, UpdateLanguageListener.TOPIC).UpdateLanguage();
78
            }
79
        };
80
    };
81
}

国际化语言设置UI设计

(1)、RegionSetting类,国际化语言设置类,实现IDEA 配置Configuration接口,可以从配置中读取当前设置的语言,也可以将当前设置的语言写入XML。代码如下:

1
/**
2
 * 定义国际化语言设置类
3
 * Created by fangyuzhong on 17-8-1.
4
 */
5
public class RegionalSettings extends Configuration<RegionalSettingsEditorForm>
6
{
7
    private Locale locale = Locale.getDefault();
8
9
    private Project project=null;
10
11
    public void setProject(Project project)
12
    {
13
        this.project = project;
14
    }
15
    /**
16
     * 获取国际化语言配置实例对象
17
     * @param project
18
     * @return
19
     */
20
    public static RegionalSettings getInstance(Project project)
21
    {
22
        return GeneralProjectSettings.getInstance(project).getRegionalSettings();
23
    }
24
    /**
25
     * 应用
26
     * @throws ConfigurationException
27
     */
28
    @Override
29
    public void apply() throws ConfigurationException
30
    {
31
        super.apply();
32
    }
33
    /**
34
     * 获取当前配置的语言对象
35
     * @return
36
     */
37
    public Locale getLocale()
38
    {
39
        return locale;
40
    }
41
    /**
42
     * 设置当前国际化语言
43
     * @param locale
44
     */
45
    public void setLocale(Locale locale)
46
    {
47
        this.locale = locale;
48
    }
49
    /*********************************************************
50
     *                      Configuration                    *
51
     *********************************************************/
52
    /**
53
     * 实例化国际化设置UI
54
     * @return
55
     */
56
    public RegionalSettingsEditorForm createConfigurationEditor()
57
    {
58
        return new RegionalSettingsEditorForm(this);
59
    }
60
    @Override
61
    public String getConfigElementName()
62
    {
63
        return "regional-settings";
64
    }
65
    /**
66
     * 读取配置,获取当前设置的国际化语言
67
     * @param element
68
     */
69
    public void readConfiguration(Element element)
70
    {
71
        String localeString = SettingsUtil.getString(element, "locale", Locale.getDefault().toString());
72
        boolean useSystemLocale = localeString.equals("SYSTEM_DEFAULT");
73
        if (useSystemLocale)
74
        {
75
            this.locale = Locale.getDefault();
76
        } else
77
        {
78
           this.locale = LocaleOption.getLocalOption(localeString).getLocale();
79
        }
80
        LocaleLanguageManager.getInstance().setResourceBundle(locale);
81
    }
82
    /**
83
     * 将当前的国际化配置写入配置文件
84
     * @param element
85
     */
86
    public void writeConfiguration(Element element)
87
    {
88
        String localLanguage ="SYSTEM_DEFAULT";
89
        if(locale!=null)
90
        {
91
            localLanguage = locale.getLanguage()+"-"+locale.getCountry();
92
        }
93
        SettingsUtil.setString(element, "locale", localLanguage);
94
    }
95
}

(2)、UI对象RegionalSettingsEditorForm,界面上设置语言选择的下拉列表,初始化中文和英文的语言进行填充。代码比较简单,就不贴了。

语言标志类LanguageKeyWord

  定义界面控件语言标示类LanguageKeyWord,将插件界面UI、对话框UI等等需要支持多语言的控件,设置关键字标志,界面控件语言更改可以使用下面的方法:

1
displayName = LocaleLanguageManager.getInstance().getResourceBundle().getString(LanguageKeyWord.DFSLOCATIONS);

  多语言支持的配置界面如下:

----------------------- 本文结束 感谢阅读 -----------------------
坚持原创技术分享,您的支持将鼓励我继续创作!