51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 5822|回复: 1
打印 上一主题 下一主题

国际化 Eclipse 插件(2)

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2007-11-14 17:22:45 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
现在,让我们着手国际化 Eclipse 插件的实际步骤:
我们将详细讨论每一步。
第 1 步:将可翻译字符串移到 *.properties 文件中
幸好,Eclipse 的 Java 开发工具为正确地分隔可翻译字符串提供了很多帮助。包上下文菜单中的 Find Strings to Externalize 选项显示了 Externalize Strings向导。这个向导将引导您完成一系列步骤,以便寻找代码中的硬编码字符串、将它们分成可翻译或不可翻译,然后在适当的情况下修改代码以使用资源束。
在使用该向导之 ,我们通过一个标准的“Hello World”来介绍 Externalize Strings向导:

清单 3. Hello world,翻译之前
  package com.jumpstart.nls.example.helloworld;  public class HelloWorld {     static public void main(String[] args) {       System.out.println("Copyright (c) IBM Corp. 2002.");       System.out.println("Hello.");       System.out.println("How are you?");       System.out.println("Goodbye.");   }}

从包上下文菜单中选择 Find Strings to Externalize 将显示一个选择对话框,其中显示了包中可能包含可翻译文本的所有编译单元。因为我们现在只有一个 Java 文件,因此从 HelloWorld.java 文件中直接选择 Externalize Strings 比较简单。它会显示 Externalize Strings 向导:

图 1. Externalize Strings 向导

通过从表中选择一项,然后选择右边的一个按钮,可以将字符串标记成以下三种情况之一:
  • Translate
    操作:将一项添加到特性文件中;自动生成的键和访问代码就代替代码中原来的字符串。已经用注释标记符(如“ // $NON-NLS-1$ ”)将用于指定键的字符串标记成不可翻译的
  • Never Translate
    操作:用注释标记符将字符串标记成不可翻译的。 Externalize Strings向导在以后的操作中不会把它标志成未翻译的。
  • Skip
    操作:不做修改。 Externalize Strings向导后面的操作会将字符串标志成可能可以翻译。
注: // $NON-NLS-1$ 注释标记符中的尾数表示在一行中有几个字符串的情况下,哪个字符串无需翻译。例如:
x.foo("Date", "TOD", "Time"); // $NON-NLS-2$

这里,中间的参数被标志成无需 NLS。其它两个则被跳过。
回到我们的示例,请注意,在列表的下面汇总了每个类别的字符串总数。外向化字符串的键名称是根据字符串值自动生成的,但可以在表中直接对其重命名。此外,可以指定一个可选的前缀(在下面的示例中是 S_ )。

图 2. Externalize Strings 向导

提示:单击给定行的第一列中的图标将前进到下一个选项:Translate、Never Translate 或 Skip。
既然我们已经标识了哪些字符串是可翻译的,那么继续到下一步,选择如何对其外向化。这里是选择 Next之后显示的页面; Property file name和资源束取值方法 Class name被修改成包含比缺省值更特殊的值:

图 3. Externalize Strings 向导

资源束取值方法类将包含用于装入特性文件的代码,以及从文件中取出字符串的静态方法。向导会生成这个类,或者您可以指定自己现有的备用实现。在后一种情况下,您也许要取消选择 Use default substitution choice,并指定用于检索外向化字符串的备用代码模式。如果取值方法类在包外部(例如,集中式资源束取值方法类),您可以有选择地对底层源代码指定 Add [an] import declaration
Externalize Strings向导使用了 JDT Refactoring 框架,这样下两个页面看起来就很熟悉。首先,会显示一列警告:

图 4. Externalize Strings 向导

最后,一一显示了建议的更改:

图 5. Externalize Strings 向导

选择了 Finish之后,向导会执行源代码修改、创建资源束取值方法类,并生成初始的特性文件。以下是标准资源束取值方法类的代码:

清单 4. 标准资源束取值方法类
  package com.jumpstart.nls.example.helloworld;  import java.util.MissingResourceException;  import java.util.ResourceBundle;  public class HelloWorldMessages {  private static final String BUNDLE_NAME =     "com.jumpstart.nls.example.helloworld.HelloWorld"; //$NON-NLS-1$  private static final ResourceBundle RESOURCE_BUNDLE =     ResourceBundle.getBundle(BUNDLE_NAME);  private HelloWorldMessages() {}  public static String getString(String key) {     try {         return RESOURCE_BUNDLE.getString(key);     } catch (MissingResourceException e) {         return '!' + key + '!';     }   }  }

该生成代码中的唯一变化是分配给 static final BUNDLE_NAME 的值。在继续下一步之前,以下是 JDT 小组的 Erich Gamma 和 Thomas Mäder 贡献的一些值得注意的准则。
管理资源束和特性文件的准则
这些准则的设计意图是:
  • 减少 NLS 错误的数量,换句话说,在运行时找不到的外向化字符串的值
  • 启用代码中引用的键和特性文件中定义的键之间的交叉引用
  • 简化外向化字符串的管理。使用集中式特性文件可能导致频繁的更改冲突。此外,它要求使用前缀以使键成为唯一,并使键的管理变得复杂。
要实现这些目标,我们建议以下准则:
1. 每个包使用一个特性文件,按类名称来限定键
例如,JDT 搜索组件的所有字符串都在 SearchMessages.properties 中,其中键/值对如下:
SearchPage.expression.pattern=(? = any character, * = any string) ShowTypeHierarchyAction.selectionDialog.title=Show in Type Hierarchy

2. 使用专用静态资源束取值方法类
Externalize Strings 向导生成这个类。它应该与特性文件同名。因此在我们的示例中,它就叫作 SearchMessages。当需要创建格式化的字符串时,将便利方法添加到束取值方法类中。例如:

清单 5. 静态资源束取值方法类
     public static String getFormattedString(String key, Object arg) {          String format= null;          try {              format= RESOURCE_BUNDLE.getString(key);          } catch (MissingResourceException e) {              return "!" + key + "!";//$NON-NLS-2$ //$NON-NLS-1$          }          if (arg == null)              arg= ""; //$NON-NLS-1$          return MessageFormat.format(format, new Object[] { arg });      }     public static String getFormattedString (String key, String[] args) {          return MessageFormat.format(RESOURCE_BUNDLE.getString(key), args);      }

3. 不要使用经过计算的键
没有一种简便方法可以使代码中经过计算的键和特性文件中的键关联起来。尤其是要确定某个键是否不再使用时,这几乎不可能。
4. 键名称的约定是 <classname>.<qualifier>
示例:PackageExplorerPart.title

[ 本帖最后由 sapphire01 于 2007-11-14 17:27 编辑 ]
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏
回复

使用道具 举报

该用户从未签到

2#
 楼主| 发表于 2007-11-14 17:25:33 | 只看该作者
第 2 步:分离与显示相关的参数
并非所有的外向化文本都只是要翻译成目标语言的单词或短语。其中有些与您的插件实现密切相关。这些示例包括属性、首选项和缺省对话框设置。
这里有一些特殊示例,它们会用于特性文件中:
  • 大小或布局约束。例如,不可调整大小的表列的适当宽度
  • 取决于语言或操作系统的缺省字体。Latin-1 语言的有效缺省字体对于 DBCS 语言(请参阅 与字体相关的 .properties 文件以获取更多详细信息)是一个无效选项。
对于那些从 AbstractUIPlugin 中分类出来的插件,还可以在其 缺省首选项存储(pref_store.ini)和 对话框设置(dialog_settings.xml)中找到与本地语言相关的参数。Eclipse Workbench 本身并不使用缺省首选项存储,而是选择将缺省值存储到特性文件,然后通过 AbstractUIPlugin 的 initializeDefaultPreferences(IPreferenceStore) 方法初始化它们。
第 3 步:使用正确的语言环境敏感的数据格式、替代 API
请参考 Java Tutorial: Internationalization系列中的详细介绍。
第 4 步:以本国语言进行测试
测试是否可以翻译产品是很重要的,但已超出了本文的范围。但是,以后的文章(“测试国际化的 Eclipse 插件”)将提供验证产品的本地语言敏感问题的策略。
第 5 步:创建初始已翻译插件片段
现在,我们可以只把本国语言特性文件复制到同名且带有特定语言环境后缀的文件中(例如,MyMessages_xx.properties,其中 xx 是语言),然后前进到第 6 步, 准备和发送本国语言材料以供翻译。在这种情况下,产品是与其代码以及它支持的任何语言都作为一个安装交付的。
但是,这种方法有一些缺点。首先,代码及其本地语言资源都混杂在同一个目录/JAR 文件中。如果翻译比代码交付晚,那么必须更新插件 JAR 文件,尽管底层代码并没有更改。其次,除特性文件之外的其它文件(例如,HTML、XML、图像)本质上并不对语言环境敏感,因此必须将它们分离到每种语言的单独目录中。
为了解决这些问题,Eclipse Platform 引入了另一个与插件相对应的可重用组件的概念,叫作 插件片段。插件片段向其目标插件提供了附加功能。在运行时,这些插件组成部分与所有相关的片段合并在一起。这些组成部分可以包括代码组成部分和与插件相关的资源组成部分,如特性文件和 HTML 文件。换句话说,插件通过其类装入器访问片段的内容。
如何以及为什么使用片段来提供可翻译信息
插件片段是分发已翻译 Eclipse 信息(包括 HTML、XML、INI 和位图文件)的理想方式。由于以非入侵方式交付翻译,所以将 Eclipse Platform 翻译封装到片段 JAR 文件中,然后将其添加到现有 Eclipse 安装中不会更改或修改任何原始的运行时元素。这就引出了 语言包(language pack)的概念。
Eclipse Platform 以用片段中的运行时元素增补原始目标插件的方法来合并插件片段。这不会以任何方式移动、除去或修改目标插件。由于类装入器会寻找片段的资源,所以插件开发人员无需知道是从插件的 JAR 文件还是其片段的某个 JAR 文件装入资源。
Eclipse 语言包 JAR
Java 语言带有资源束功能,因此支持语言包的概念。Java 资源束不要求修改应用程序代码来支持另一种语言。*.properties 文件名称空间通过以下命名约定避免冲突: basename_lang_region_variant。在运行时, ResourceBundle 功能会针对当前语言环境寻找适当的特性文件。
在片段中部署文件(如 HTML 和 XML 文件)与在 Java 资源束中部署文件略有不同,因为 Eclipse 片段使用目录结构来区分不同的语言版本。
示例片段内容
插件和插件片段位于可以在 eclipse 子目录下直接找到的单独子目录中。考虑一下我们的示例片段,它部署在德语系统上,我们会看到一个 \nl 文件夹、一个 fragment.xml 和一个 nl1.jar 文件。

图 6. 片段子目录

通常,会根据资源束规则给已翻译的 *.properties 文件添加后缀,并将它们部署到 JAR 文件中。可是,当一个视图需要一种输入文件类型,而文件名称不象资源束一样是语言环境敏感的(如 *.xml),我们就要为文件的每一个语言版本定义一个子目录结构。上面的 de 子目录就是这样一个示例,其中 de = 德语。
片段清单
每个插件文件夹都可以随意地包含一个片段清单文件 fragment.xml。清单文件描述了插件片段,而且与插件清单文件(plugin.xml)几乎相同,只有以下两点除外:
  • 没有 class 属性,因为片段没有插件类。它们只遵循其目标的规范。
  • 没有相关性,因为片段具有与其目标插件一样的相关性。
用于描述本地语言片段的清单通常很简单,只需指定 <fragment><runtime>/<library> 标记。以下是完整的示例片段清单文件:

清单 6. 片段清单文件
<?xml version="1.0" encoding="UTF-8"?><fragment   id="com.jumpstart.nls.example.helloworld.nl1"   name="NLS Example Plugin NL Support"   version="1.0.0"   provider-name="IBM"   plugin-id="com.jumpstart.nls.example"   plugin-version="1.0.0"><runtime>   <library name="nl1.jar"/>   <library name="$nl$/"/></runtime></fragment>

<fragment> 标记属性是:
  • name ― 可向用户显示的扩展名称。
  • id ― 该片段配置的标识。用于唯一标识该片段实例。
  • plugin-id ― 对目标扩展点的引用。插件片段与此目标扩展合并。
  • plugin-version ― 片段插件的版本。
  • version ― major.minor.service 格式的版本规范。
<runtime> 部分包含了组成插件片段运行时的一个或多个库的定义。被引用的库由平台执行机制使用,在此机制中,插件装入、合并和执行它所需的正确代码。每个 <library> 子标记都有一个 name 属性。它指定了库文件或目录导出掩码。要将文件夹及其子文件夹的内容包括在库中,可以使用掩码 $foldername$/ ,其中 foldername 是要添加到库搜索路径的目录。我们以后会了解到如何使用这个掩码来包括 \nl 文件夹的内容及其子文件夹的内容。
构建片段
Eclipse Workbench 附带了一个在插件开发中使用的工具: 插件开发环境(Plug-in Development Environment (PDE))。PDE 包含了对开发插件片段的支持。
现在,让我们研究如何使用 PDE 构建用于本地语言翻译的片段。在给定片段中,对语言的数量没有实际的限制。那么片段就是包含一种或多种语言翻译的“语言包”的基础。但是,在这个示例中,我们将语言包限定为德语翻译。
要构建插件片段,启动 New Project 向导( File> New> Project...),选择 Plug-in Development类别,然后选择 Fragment Project 类型。在 New Fragment 向导的第一页,输入项目名称。请记住,项目名称也将变成片段标识。例如,启动一个向 HelloWorld 示例添加本地语言支持的项目,我们将项目命名成“com.jumpstart.nls.example.helloworld.nl1”。结尾“.nl1”并不是必需的,但确实有助于区分表示“语言包”的片段和添加附加代码和功能的片段。

图 7. 启动片段项目

Next。在第二页上,会看到项目的源文件夹和运行时库的缺省值:

图 8. 定义片段文件夹

这些值看上去还算合理,所以再按 Next,就转到了“Fragment Code Generators”页面。选择第二个单选按钮,表示我们要从模板创建片段清单文件,然后从列表中选择 Default Fragment Generator向导。

图 9. 选择缺省向导

按了 Next 之后,我们会看到“Simple Fragment Content”页面。这个页面上有两项用于指定某个现有插件上的片段。必须提供插件目标标识和版本。可以使用 Browse按钮来选择要展开的插件。

图 10. 为片段指定目标

现在,让我们进入片段清单编辑器,它与插件清单编辑器一样都是多页面编辑器,带有 Overview、Runtime、Extensions、Extension Points 和 Source 页面。

图 11. 片段清单编辑器

请注意与片段 xml 文件的各个节对应的选项卡页面。我们将使用 Runtime 页面将片段类路径指向包含我们的翻译的库。
我们在新建片段向导中指定了 nl1.jar,因此这个片段的类路径已经包含了那个库。此时缺少的东西就是包含在 \nl 文件夹及其子文件夹的内容。要添加新的运行时库,可以从 Overview 页面的 Runtime Libraries 节中选择 More,或者转到 Runtime 页面,选择 New...,然后输入文件夹掩码 $ foldername$/。

图 12. 片段运行时信息

看一看片段清单编辑器的 Source 页面,我们会见到 PDE 生成所有描述插件片段所必需的 XML。

图 13. 片段源码
回复 支持 反对

使用道具 举报

本版积分规则

关闭

站长推荐上一条 /1 下一条

小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

GMT+8, 2024-11-26 21:44 , Processed in 0.071708 second(s), 27 queries .

Powered by Discuz! X3.2

© 2001-2024 Comsenz Inc.

快速回复 返回顶部 返回列表