|
Norbert Lindenberg English: Developing Multilingual Web Applications Using JavaServer Pages Technology JavaServer Pages (JSP) 技术现已成为深受 Web 应用程序开发者欢迎的工具。 使用 JSP 技术,开发者不需要其他的编程知识就可以设计出动态的 web 网页。 同时,Web 开发者可以使用一种可扩展的标记机制来管理基础软件组件的功能。 通过 Java 标准制定组织(Java Community Process)开发的一个扩展功能可为多语言应用程序的开发提供更有力的支持。 JavaServer Pages 标准标记库除了其他一些功能,还定义了一套可实现本地化和地区敏感(locale-sensitive)格式化的标记。 行文方面,本文首先对 JavaServer Pages 技术进行了简要介绍,以使您能够更好地理解如何使用它们解决国际化的问题。 然后,我会针对多语言 web 应用程序的开发讨论几个核心问题,并介绍如何使用 JavaServer Pages 技术解决它们:这些问题包括地区确定和本地化、字符编码、格式化以及解析。 JavaServer Pages 技术JavaServer Pages(和几种相关技术)构成了 web 应用程序的表示层。 使用 JSP 技术,开发者可以创建动态的 web 页面,这些页面可以与商业逻辑(business logic)、数据库以及其他可从网络上获取的服务形成互动关系。 JavaServer Pages使用 JSP 技术开发的网页结合了 HTML、XML 或其他含有类似 XML 标记(这些标记与基础软件库连接)的静态内容,通常这些软件库使用 Java 编程语言编写。 在这种环境中,非常重要的 Java 技术有 JavaBeans 组件架构(作为 JSP 和 Java 类之间的常规用途接口)、用于访问 SQL 数据库的 Java 数据库连接(JDBC)API 以及各种用于 XML 处理的库。 JSP 页面本身按照 servlet 格式被编译为 Java 代码,以便执行。 Servlet 是 web 服务器的扩展,它被编译并关联至服务器,从而可以获得比脚本语言更快的执行速度。 Servlet 直接以 Java 编程语言编写,并经常与 JSP 网页一起使用,其中 servlet 作为控制部分而 JSP 页面作为应用程序的视图部分。 JavaServer Pages 和底层的 servlet 技术为处理 HTTP 请求和回应信息,以及使用 Cookies 或 URL 重写进行会话维护都提供了广泛的支持。 使用 JSP 技术的一个很重要的原因在于它可以将网页作者和应用程序开发者的工作进行分离。 尽管可以将 Java 语句直接嵌入 JSP 网页,但是,开发者们已经认识到最好避免如此,而现在更倾向于使用自定义标记。 JavaServer Pages 标准标记库JavaServer Pages 标准标记库(JSTL)包含了一系列涵盖数个功能领域的自定义操作,这些功能在 JSP 网页中经常被使用。 该库建立在许多参与者开发自己的库时所获得的经验基础之上,它提供了一种应用程序可以依靠的标准接口,并且可以独立于他们运行的服务器之外。 除了自定义标记,JSTL 还引入了一种表达语言,这种语言运进一步地减少了在 JSP 网页中使用脚本语言的需求,同时还引进了标记库验证程序以限制在 JSP 网页上对脚本和标记库的使用。 这种改进版本的表达语言,以及限制脚本的功能已在随后被集成到 JSP 2.0 规范之中,所以只有使用 JSP 1.2 时才要求 JSTL。 自定义操作包括的主要内容是:
地区确定和本地化设计多语言 web 应用程序时,您必须首先决定如何确定用户的语言和地区首选项,以及如何使这些首选项与该应用程序和基础的 Java 运行环境支持的一套地区设置相匹配。 这部分首先描述了 web 应用程序必须具有的外部环境和要求。 下一步,我们将了解相关的 Java 2 Standard Edition (J2SE) 平台提供的功能,最后我们将了解 JavaServer Pages 标准标记库的标记如何连接到环境和 J2SE 中。 确定用户首选项web 应用程序有两种方法来确定用户的语言首选项:首先,它可以由浏览器使用 HTTP 请求报头字段 将 在许多情况下,web 应用程序是由若干组件组合而来的,这些组件可能已经本地化为不同的语言。 一个特别值得一提的组件是 Java 运行环境,它在一些地区敏感区域可能具备支持超过 40 种语言中的 100 种区域设置的功能(例如日期格式),远远超出了典型的 web 应用程序。 因此,应用程序开发者必须决定是否在整个应用程序中限制所支持语言的本地化功能,或者充分发挥每个组件的功能优势。 第一种方法的优势在于用户可以看到的全部页面都使用同一语言,而第二种方法可能导致页面中存在不同的语言——其中一种语言出现在绝大多数文本中,而另一种则出现在例如日期的格式中。 Java 2 Standard Edition Platform 中的本地化为了了解 JSTL 如何确定应用程序被哪些地区设置支持,我们来看看在基础的 Java 2 Standard Edition 平台中是如何进行本地化的。
JavaServer Pages 应用程序的本地化方法要对基于 JavaServer Pages 技术的应用程序进行本地化,方法通常有两个。 第一个方法是使用国际化的页面,这些页面常可以通过自定义标记从资源束获得与特定地区设置相关的内容。 如果页面需要保持复杂的结构并与所有地区设置同步,则通常会采取这种方法。 第二种方法使用单独的特定地区设置页面以及分发到适当页面的 servlet(取决于用户的地区选择)。 如果页面包含的主要是文本或者地区设置间的结构截然不同时,则通常会采取这种方法。 地区确定和 JSTL 中的本地化JSTL 构建于 J2SE 工具之上,它可进行地区确定和本地化。 使用任何一种 JSP 本地化方法(如上所述)均可以进行地区确定,而本地化功能的目的是为国际化的页面提供支持。 JSTL 对上述两种确定用户地区首选项的方法都提供支持。 应用程序可以使用 JSTL 的 下面是一些您可以用于 web 应用程序开始页面的代码片断。 这些代码片断可让用户非常轻松地选择他或她的地区设置。 假设这些代码是 <%-- Interpret user's locale choice --%> <c:if test="${param['locale'] != null}"> <fmt:setLocale value="${param['locale']}" scope="session" /> </c:if> <%-- Offer locale choice to user --%> <a href="locale-choice.jsp?locale=en-US">USA</a> - <a href="locale-choice.jsp?locale=de-DE">Deutschland</a> - <a href="locale-choice.jsp?locale=ja-JP">日本</a> <%-- Use URL rewriting to ensure proper session tracking --%> <form method="get" action="<c:url value='/locale-choice.jsp' />"> <input type=submit value="Stay in session"> </form> 第一部份(此部分必须在生成的 HTML 页面任何内容之前)表示用户的地区选择,该选择作为一个请求参数显示在 JSP 页面上。 如果定义了 第二部分(此部分是生成的 HTML 页面内容的一部分)为用户提供了返回同一页面的链接,但是根据选定的国家提供了 最后一部分显示如何使用 如果从 web 应用程序本身的用户界面中选择了地区设置,然后使用 要决定哪个地区设置是被支持的,JSTL 将参考该应用程序所使用的资源束。 有两种操作可用于访问资源束:
以下是一些例子。 让我们假设某个应用程序拥有用于
那么,为什么查询资源束时存在两种不同的操作呢? 它们的区别在于它们使用的方法:
<fmt:setBundle basename="Errors" var="errorBundle" /> <fmt:bundle basename="Messages"> <%-- Localization context established by <fmt:bundle> tag --%> <fmt:message key="greeting" /> <p> <%-- Localization context established by <fmt:setBundle> tag --%> <fmt:message key="emptyField" bundle="${errorBundle}" /> </fmt:bundle> 其次,为什么有一个请求地区设置与本地化环境相关联? 这个地区设置是 JSTL 将格式化标记限制到应用程序所支持的语言范围内的方法,这样展现在读者面前的页面语言将完全统一。 嵌套于 <jsp:useBean id="now" class="java.util.Date" /> <fmt:formatDate value="${now}" timeStyle="long" dateStyle="long" /> <p> <fmt:bundle basename="Messages"> <fmt:formatDate value="${now}" timeStyle="long" dateStyle="long" /> </fmt:bundle> 如果 HTTP 最后,为什么本地化环境使用请求地区设置而不使用由资源束找到的地区设置? 答案是,这样可以避免丢失重要的信息,某些格式标记可能需要这些信息。 很多应用程序不能区分相同语言中不同变量之间的区别,而且只提供(例如)英文资源束,期望着这些文本在英国、澳大利亚和新加坡都能被同样理解。 然而对于日期格式,国家是很关键的——对于英国读者来说,“2/6/02”表示“ 2002 年 6 月 2 日”,但对于习惯美国规范的读者来说,则表示“2002 年 2 月 6 日”。 所以,在很多情况下,如果使用了请求地区设置(而不是资源束地区设置),则国家信息将会被保留。 字符编码当前,我们使用两种截然不同的模块表示存储在计算机中或通过网络传输的文本:旧的字符编码模式专门用于较小的语言集合、国家和/或操作系统(包括如 ISO 8859 系列、 Windows 代码页和 EUC 编码);而新的基于 Unicode 编码的模式能够(至少理论上能够)表示所有的语言并可以在任何地方使用。 旧的模块具有很大的劣势:
当前版本的主要软件系统所包含的创建、分发和解释 web 内容都支持新的模块;它们通常将 Unicode 用于内部处理,或者至少知道怎么使用(用于 web、基于 Unicode 编码的)UTF-8。 基于 Unicode 的编码有着以下显著的优势:它们支持多语言页面并清晰区分地区设置(从字符编码处理)问题。 同样,因为编码转换而带来的信息丢失的风险也很小,同时基于 Unicode 的编码与现在的服务器和客户端系统比较吻合。 尽管如此,很多 web 开发者仍然不太愿意使用 UTF-8。其中的原因可能包括对旧版本的浏览器支持不充分,或者缺少支持它的工具。 JavaServer Pages 技术对新旧两种模块都支持。 现在我们来看看字符编码问题所涉及的各种不同领域,并了解 JSP 技术和 JSTL 如何处理它们。 处理源程序页编码JSP 源文件的编码通常由可用的编辑工具决定,所以可能使用特定国家和操作系统的编码。 字符编码与 JSP 运行环境(“容器”)之间的通讯方法有许多种,随着时间推移其中的机制和规则已不断改进。 同时 JSP 源文件相应存在着两种语法:标准语法和基于 XML 的新语法。 在检测字符编码时,JSP 2.0 规范将在这两种语法中进行辨别。 对于采用 XML 语法的文件,编码将被检测为采用 XML 规范;这意味着 UTF-8 或 UTF-16 为默认的编码,而其他的编码必须在文件开始处的 XML 声明中予以说明。 对于采用标准语法的文件,容器将考虑两种主要的信息来源:首先它们访问应用程序的配置描述符,查询一个 以下是基于 JSP 2.0 的应用程序的一些简单建议:对于采用 XML 语法的文件,确保没有使用 UTF-8 或 UTF-16 编码的文件能够正确识别它们的字符编码。 对于采用标准语法的文件,如果您对所有源文件使用 UTF-8,则请在配置描述符中只使用一个元素 <jsp-property-group> <url-pattern>/ko/KR/*</url-pattern> <page-encoding>EUC-KR</page-encoding> </jsp-property-group> 如果应用程序中的源文件不能以这种方式组织,则为每个源文件添加 关于源文件字符编码,JSP 1.2 规范没有清楚地区分使用标准语法的文件和使用 XML 语法的文件。 它也没有提供识别配置描述符中的字符编码的方法。 为确保正确检测字符编码,设计用于 JSP 1.2 容器的应用程序应总是识别每个使用 JSTL 定义了一个 处理 Web 页面编码web 应用程序必须选择生成的 web 页中使用的字符编码(该编码被称为“反应字符编码”),它基于目标浏览器的性能、页面内容的编写系统和语言以及可能的浏览器主机的操作系统。 根据 HTTP 规范,字符编码在 如果所有目标浏览器都支持 UTF-8,一般来说最好使用这种编码,这样就可以支持多语言文档并避免字符转换带来的信息丢失。 如果不能使用 UTF-8 ,必须小心谨慎地使用应用程序将字符编码与使用的语言相匹配,包括一些特殊字符。 为防止出现错误,可能需要在整个页面里使用同一种语言,如本文开始部分“地区确定和本地化”中所述。 同样,也有必要避免使用“€”字符。 Web 应用程序可以直接指定一个页面的字符编码,也可以让 JSP 技术根据地区设置信息间接决定。
间接决定字符编码是可行的,只要旧的字符编码可以被接受,并且整个页面使用相同的语言而且避免出现常用字符编码所不支持的特殊字符。 然而,若要利用 UTF-8 则要求使用显式规范。 因为 Servlet 2.4 规范使显式规范优先于隐式规范,所以将字符编码设置为 处理请求参数编码JSP 技术不仅能够生成 web 页面,而且还可以接收和解释与 HTTP 请求一起收到的参数——通常是来自某种表格的输入,这种表格属于前面生成的 web 页面的一部分。 用于这些参数的字符编码并非在任何地方都被指定,但实际标准是浏览器使用的编码要与包含这些表格的网页使用的编码相同。 这意味着 web 应用程序需要跟踪先前生成的网页的编码。 一个常用的机制是把编码的名称存储到表格本身的一个隐藏域中,在下一个请求时解压缩为第一个参数,然后用它来解码出其他的参数。 然而,JSP 页面还可以使用会话管理来跟踪请求之间的信息。 应用程序可以使用 JSTL 自定义操作 格式化和解析以本地化的格式表示数据(如数字和日期)是任何类型地应用程序都要完成的常见任务,就如同用户提供的输入解释。 不同语言和文化所使用的格式区别很大,所以如果开发者不依靠现有的库的话,那么这个工作就不会是一项简单的任务。 幸运的是,确实存在这样的库。 Java 2 Standard Edition (J2SE) 平台提供了在 JavaServer Pages 标准标记库提供了自定义操作,可将这些功能直接应用到 JSP 页面中。 用于格式化和解析操作的地区确定您可以在预定义的本地化环境中对数字和日期使用格式化和解析的操作(例如,如果标记嵌套于一个 数字格式化和解析JSTL 用于数字格式化和解析的自定义操作 特别值得一提的是它们对货币格式化的支持。 传统上,许多格式化库假设货币符号可以从地区设置中得出——例如,如果地区设置是中国,那么货币符号就是人民币(RMB)。 在一个跨境交易的环境中,这并没有多大的意义。 如果某个英国公司以英镑来计算价格,而 web 应用程序将价格显示为人民币(RMB)的形式,就会出现两个问题:第一,人民币的汇率比英镑低;其次,人民币换回英镑会比较困难。 由于货币的选择属于商业上的决定,所以货币必须作为值的一部分而不是格式的一部分。 因此, <fmt:formatNumber type="currency" value="${price.value}" currencyCode="${price.currency}" /> 如果 JSP 页面指定了一个货币代码,则底层的 日期和时间的格式化和解析用于日期和时间的格式化和解析的 JSTL 自定义操作 令人感兴趣的一点是显示的日期和时间不仅仅取决于一种指定地区设置的格式,还取决于时区信息。 用户通常对服务器时区不感兴趣,但另一方面,要找出用户所在地的时区却并不简单。应用程序可以通过使用一些客户端的 JavaScript 代码来找出用户的当前时区与格林尼治标准时间的偏差,或让用户指定当前时区并将其作为用户信息的一部分。 JSTL 操作并没有解决这个问题,但它们提供了两个自定义操作,可以用来告知有关时区的日期和时间的格式化和解析: 信息格式化
例如,如果 JSP 页面包含了以下语句: <jsp:useBean id="now" class="java.util.Date" /> <fmt:bundle basename="Messages"> <fmt:message key="greeting"> <fmt:param value="${now}" /> </fmt:message> </fmt:bundle> 并且找到的资源束是德语,而且 为 结论如本文所述,JavaServer Pages 技术(特别是 JavaServer Pages 标准标记库)为您提供了一个开发多语言应用程序的坚实基础。 您需要仔细考虑以下几个设计选择:如何确定用户的语言和地区设置首选项,如何构造您用于本地化的 JSP 页面,是否采用单一语言的页面或充分利用现有的地区设置支持,以及使用哪一种字符编码模块。 JSP 技术使您能够选择其中任意一种,这样您就可以将页面以最佳的方式展示给全世界的读者,而且最重要的是,以他们自己的语言来展示。 参考书目R. Fielding et al.: Hypertext Transfer Protocol -- HTTP/1.1. RFC 2616. The Internet Society, 1999. Dave Raggett et al. (ed.): HTML 4.01 Specification. World Wide Web Consortium, 1999. Tim Bray et al. (ed.): Extensible Markup Language (XML) 1.0 (Second Edition). World Wide Web Consortium, 2000. Java 2 Platform, Standard Edition, v 1.4.2 API Specification.Sun Microsystems, 2002. Danny Coward (ed.): Java Servlet Specification. Version 2.3.Sun Microsystems, 2001. Danny Coward, Yutaka Yoshida (ed.): Java Servlet Specification. Version 2.4.Sun Microsystems, 2003. Eduardo Pelegrlopart (ed.): JavaServer Pages Specification. Version 1.2.Sun Microsystems, 2001. Mark Roth, Eduardo Pelegr lopart (ed.): JavaServer Pages Specification. Version 2.0.Sun Microsystems, 2003. Pierre Delisle (ed.): JavaServer Pages Standard Tag Library. Version 1.0.Sun Microsystems, 2002. Pierre Delisle (ed.): JavaServer Pages Standard Tag Library. Version 1.1.Sun Microsystems, 2003. 关于作者Norbert Lindenberg 是 Sun Microsystems 的 Java Web Services 团队内 Java Internationalization 技术主管。在加盟 Sun 之前,曾经供职于 General Magic 和 Apple Computer,参与过多个国际化项目。他毕业于德国的卡尔斯鲁厄大学,拥有计算机科学理科硕士学位。 | |||||||||||||||||||||||
|
| ||||||||||||