以文本方式查看主题

-  中文XML论坛 - 专业的XML技术讨论区  (http://bbs.xml.org.cn/index.asp)
--  『 DTD/XML Schema 』  (http://bbs.xml.org.cn/list.asp?boardid=23)
----  使 XML 文档支持全球化  (http://bbs.xml.org.cn/dispbbs.asp?boardid=23&rootid=&id=12023)


--  作者:anchen0617
--  发布时间:11/13/2004 2:23:00 PM

--  使 XML 文档支持全球化
通过组织 XML 文档中的可翻译资源来推动使应用程序全球化的过程。您可以使用这项技术,将文档的内容具体化成语言特定的子文档,以及使用用户指定的 XML 元素和属性来构造 XML 文档,以自然地处理已翻译的文档。XML 和 Java 样本示例演示了这些技术如何一起处理全球化。
感谢因特网,它使地球上最远那一端的人们也可以访问您的应用程序。位于最远那一端的用户说什么语言呢?这很难说。幸好,设计应用程序以及构造 XML 文档以允许支持不同语言,并且不会对文档或者,更糟,对应用程序造成问题,这并不困难。本文演示了通过执行三个简单的任务而使文档全球化的一种方法:

将 XML 文档分割成一个带翻译标记的主文档和几个语言特定的子文档
设置应用程序以识别已翻译的元素以及翻成的语言
分别处理已翻译的文档

全球化问题
已翻译的资源是模型定义的固有部分,这一事实使全球化很困难,尤其对于 XML 文档。例如,文档可以定义从对象数据到显示面板等任何事物。这个定义很可能包含持久不变的对象结构,因而不受全球化影响。但它通常还包含了可显示文本或其它根据语言需要而变化的数据的定义。这些定义的存在意味着必须使该文档全球化。

传统的 XML 源翻译
为了说明带有对象结构的可翻译资源的这种混合怎么会导致问题,考虑以下示例 XML 文档。它定义了一个包含必须翻译的元素的虚构面板。

清单 1:传统的 XML 源文档

<traditional>

  <!-- ********************************************************** -->
  <!-- Specify data using in line character coding.               -->
  <!-- ********************************************************** -->  
  <panel>
    <widgetLabel>Label Text</widgetLabel>
    <widget type="text" width="20"/>
  </panel>

</traditional>

在标准方法中,全球化意味着以特定语言(通常是英语)编写文档,然后将文档交给翻译小组处理。接着翻译人员通过复制原始元素并用适当的翻译来替换每个可翻译元素来重新生成文档。但这一过程引起了一些问题。例如,翻译人员如何知道哪个元素需要翻译?一种解决方案是大量地注释源码来特别指出需要翻译的行。但这种方法当然不可靠,常常会导致错误。而且,甚至在辛苦工作之下达到完美的翻译之后,文档已经被复制,并出现维护问题。

要演示我刚才描述的过程,我已将上述文件复制到一个单独的目录,并翻译它:

清单 2:传统的已翻译 XML 源文档

<traditional>

  <!-- ********************************************************** -->
  <!-- Specify data using in line character coding.               -->
  <!-- ********************************************************** -->  
  <panel>
    <widgetLabel>Texte etiquitte</widgetLabel>
    <widget type="text" width="20"/>
  </panel>

</traditional>

记住,翻译人员必须在不打乱周围结构的情况下,精确地确定哪些元素需要翻译并且只更改那些元素。更棘手的是,一旦创建了翻译的文件,如果面板布局发生变化,那么这个变化必须应用到整个文件。例如,假定您决定将 widget 的长度从 20 个字符变到 30 个字符。这个简单的变化引起的冲突会影响每个已翻译文件。

分割 XML 源文档
现在考虑以下替代结构,我们除去了可翻译资源。这里是不带已翻译资源的主 XML 文档:

清单 3:主 XML 源文档

<separated>

  <!-- ********************************************************** -->
  <!-- Specify the translation languages that are supported.      -->
  <!-- ********************************************************** -->  
  <translationLanguages>
    <language default="true">english</language>
    <language>french</language>
  </translationLanguages>

  <!-- ********************************************************** -->
  <!-- Specify data using translation keys.                       -->
  <!-- ********************************************************** -->  
  <panel>
    <widgetLabel translationKey="myWidgetLabel"/>
    <widget type="text" width="20"/>
  </panel>

</separated>

以下是包含特定已翻译信息的单独的 XML 文档:

清单 4:已翻译的 XML 子文档

<separated_english>

  <!-- ********************************************************** -->
  <!-- Specify the translated values for each element.  Note that -->
  <!-- element tags match translation keys in the main document.  -->
  <!-- ********************************************************** -->  
  <myWidgetLabel>Label text</myWidgetLabel>

</separated_english>

<separated_french>

  <!-- ********************************************************** -->
  <!-- Specify the translated values for each element.  Note that -->
  <!-- element tags match translation keys in the main document.  -->
  <!-- ********************************************************** -->  
  <myWidgetLabel>Texte etiquitte</myWidgetLabel>

</separated_french>

通过重新组织该文档,可以清晰地从对象结构描绘出可翻译资源,因为可翻译资源已移入单独的文件或子文档。从实际观点来看,子文档确实是上述所描述的要处理的内容 — 它是用英语写的,然后将它转交给翻译小组,生成已翻译的副本。但重要的差别是,对应该翻译哪些元素这个问题,不再感到迷惑。 所有元素都要被翻译。这种技术不仅创建了一个清晰的文档,而且它使翻译小组兴奋!

主文档中另一个明显变化是添加了一些与翻译相关的元素和属性。特别地,某些元素声明一组支持的翻译语言,而其它元素包含声明翻译键的属性。如果把这些变化集中在一起,会得到下列组织:

主文档声明一组支持的翻译语言。
对于每种声明语言,都有一个包含已翻译元素的独立文档。
主文档中每个已翻译元素包含特殊的 translatedKey 属性。
translatedKey 属性的值是特定元素到已翻译子文档的链接。

这些特殊的翻译标记不仅向 XML 结构提供了逻辑组织,而且允许围绕 XML 语法分析器构建应用程序,以理解如何处理全球化数据。要了解这是如何工作的,先让我们看一些 Java 代码片段。

设置应用程序以处理单独的全球化文档。
下列示例假设您已经使用了 SAX 语法分析器,并且十分熟悉 SAX 应用程序的基本机制。如果您还没有这一知识,则假设应用程序已经创建了 SAX 语法分析器的实例以及能够实现 org.xml.sax.ContentHandler 接口的类的实例。再假设它已经在语法分析器的实例上注册了该类。一旦注册完毕,当语法分析器处理文档时,语法分析器就会通知所有分析事件的内容处理程序。并通过内容处理程序的回调进行通知。您也可以使用这些内容处理程序的回调以利用翻译元素和全球化文档中引入的属性。

在该示例中的设计方法是使用内容处理程序的事件处理方法来识别那些在 XML 文档中某些熟悉的翻译标记并对这些元素进行特殊处理,如清单 5 所示。

该片段演示了如何将应用程序翻译处理与基本语法分析器功能相挂钩。首要问题是将翻译标记处理成大家都知道的属性的形式,以表示该元素已经翻译过了。XML 文档中的每一个元素都会导致语法分析器将一个开始元素事件回调信号发给内容处理程序。在内容处理程序中的 startElement 方法接收控制并传递该元素的一些指定属性。在这一点上,您的应用程序可以检查属性,以核实翻译标记。在该示例中,我们选择属性名称 translatedKey 作为标记。当然,这可以定制成您选择的任意值。如果发现翻译属性,该元素会在表中作为键值对注册。该表对所有声明可翻译的元素进行跟踪并在主文档完全进行语法分析后使用。

内容处理程序应该针对的另一问题就是有翻译的语言集合。在示例 XML 中,我们选择 translationLanguage 元素来声明支持的语言。在代码片段中,通过 processEvent 方法传递所有的元素。为了启动处理元素的特定方法,处理事件的方法使用元素到方法名的映射。处理 translationLanguage 的特定方法简单地注册供以后使用的语言。使用清单 6 中所示代码片段为例:

现在该暂停并回顾一下。迄今为止,我们已经完成了哪些?到目前为止,我已经演示了手头三个任务中的两个:

将 XML 文档分割成一个带翻译标记的主文档和几个语言特定的子文档
设置应用程序以识别被翻译的元素以及语言

剩下的是获取在主文档的语法分析阶段期间,存储的信息,并使用它驱动一个单独的阶段以处理每个语言特定的子文档。

处理语言特定的子文档
最后一项任务是将使用存储在应用程序中的信息来查找和处理所有可应用的子文档。当然,应用程序实际所处理的翻译数据是特定于其自己目的。在该示例中,应用程序从子文档检索已翻译值并将其写成 Java 属性文件。但是该示例的焦点在于存储信息的使用以用我们的好朋友 SAX 语法分析器来访问子文档。

这里的设置与主文档的语法分析十分相似。得到了语法分析器的实例,并且在其上注册 ContentHandler 的实例。差别在于这个处理是由循环包围的,该循环迭代跨越已声明语言所保存的向量。该语言是附加在主 XML 文档名上以获取已翻译的子文档名。该文件名交给语法分析器进行处理。最后一个样本代码片段,请参阅清单 7 。

ContentHandler 的实现只是从子文档中获取已翻译的数据并将其存储在基于键的表中。在 startElement 方法中,通过快速查看翻译键表(在主语法分析过程中建立)来识别声明已翻译的元素。如果在键表中包含该元素,则布尔值设置成获取 characters 方法中的元素数据。一旦字符事件触发了 characters 方法,则获取实际已翻译的数据并添加至已翻译的字符串表中。应用程序可以以任何喜欢的方式使用该表,同样, writePropertiesFileFromTable 的实现并不是我们真正感兴趣之处。然而,将数据写入一组属性文件以创建 Java 资源束,这种方式是 Java 应用程序中使对象全球化的自然方式。

结束语
全球化的艺术是一种微妙的艺术。单一的方法不可能满足每个开发人员或应用程序。这里演示的方法是编程技术和一般常识的混合(当然, 可以组合它们),不偶然性地,即以类似于 Java 资源束那样构造文档。您的应用程序是否用 Java 编写这一点并不重要。我想您会同意,将用户数据与对象结构分离开来是可以极大地改善 XML 库和应用程序的益处。


W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
6,382.813ms