- 浏览: 387116 次
- 性别:
- 来自: 南京
文章分类
最新评论
-
793059909:
scala> def count(x:Double,n: ...
快学Scala习题解答—第二章 控制结构和函数 -
793059909:
scala> def countdown(n:Int){ ...
快学Scala习题解答—第二章 控制结构和函数 -
daquan198163:
可是奇慢无比啊,切换个页签得等一分钟啊!!!!!!!!
误会ZK Studio了!Sorry,Sorry! -
rmn190:
受教了, 今天我第一天遇到这个问题, 以前没想到fmt标签还跟 ...
JSP中的国际化(转) -
suu:
都是栈里的拷贝 这句话让我从一头雾水到豁然开朗 谢谢了.
争论话题:Java传值还是传引用?
地区确定和本地化
设计多语言 web 应用程序时,您必须首先决定如何确定用户的语言和地区首选项,以及如何使这些首选项与该应用程序和基础的 Java 运行环境支持的一套地区设置相匹配。 这部分首先描述了 web 应用程序必须具有的外部环境和要求。 下一步,我们将了解相关的 Java 2 Standard Edition (J2SE) 平台提供的功能,最后我们将了解 JavaServer Pages 标准标记库的标记如何连接到环境和 J2SE 中。
确定用户首选项
web 应用程序有两种方法来确定用户的语言首选项:首先,它可以由浏览器使用 HTTP 请求报头字段 Accept-Language 传输至服务器的语言和地区首选项。 尽管标准规定了许多语言标记,但是一般使用 ISO 639 语言代码(如 ja 为日文)和 ISO 3166 国家代码(如 IT 代表意大利)。 浏览器通常让用户创建一个语言列表作为其首选项的一部分。 然而,这种方法不太可靠;用户不一定会创建该列表,而且该列表不一定会包含该应用程序支持的地区设置。 由于这些不确定性,多语言应用程序通常采用第二种方法:他们让用户直接从支持语言的列表中选择,并把选择的语言作为用户资料的一部分进行保存,或只在进行该会话的时候保存。 一个好的方法是,在对用户一无所知的情况下,首先使用 Accept-Language 信息,在应用程序的开始页面中给予用户直接选择语言的机会。
将 Accept-Language 地区设置主要用于语言和文化首选项是没什么意义的。 例如,它们不应该被解释为表示用户居住的国家。 同样,在很多情况下浏览器提供的地区设置只有一个语言代码,而一些地区敏感的功能(例如,日期格式)则随着国家的不同而相异。 在很多情况下,通过语言假设主要国家的规范是合理的(如果没有指定国家);例如,如果指定了日本语,则可使用日本通用的日期格式。 然而,如果是根据国家而设置的重要功能(例如货币),则必须给用户一个机会来修正该假设。
在许多情况下,web 应用程序是由若干组件组合而来的,这些组件可能已经本地化为不同的语言。 一个特别值得一提的组件是 Java 运行环境,它在一些地区敏感区域可能具备支持超过 40 种语言中的 100 种区域设置的功能(例如日期格式),远远超出了典型的 web 应用程序。 因此,应用程序开发者必须决定是否在整个应用程序中限制所支持语言的本地化功能,或者充分发挥每个组件的功能优势。 第一种方法的优势在于用户可以看到的全部页面都使用同一语言,而第二种方法可能导致页面中存在不同的语言——其中一种语言出现在绝大多数文本中,而另一种则出现在例如日期的格式中。
Java 2 Standard Edition Platform 中的本地化
为了了解 JSTL 如何确定应用程序被哪些地区设置支持,我们来看看在基础的 Java 2 Standard Edition 平台中是如何进行本地化的。 java.util 软件包的核心主要有两种类:Locale 和 ResourceBundle。
Locale 对象只是用来确定地区设置的:它们结合了 ISO 639 语言代码(例如,ja 代表日文)和 ISO 3166 国家代码(例如,IT 代表意大利),还可能包含一个(非标准化的)变量字符串。 注意,HTTP 的地区标识符使用相同的 ISO 标准,所以对比通常比较容易。
ResourceBundle 对象是本地化对象的容器,形成成键/值对。 一个基础资源束定义了一个基础束的名称、一套键以及默认值(通常是英文值,但不是必须的)。 例如,一个简单的 Messages 资源束可能定义 greeting-day 键的默认值为 Hello。 其他的特定语言和国家束可以被定义,其名称由基础名称组成(通过后缀指示其语言、国家和变量)并提供已本地化的值。 例如,德语 Messages_de 资源束可以给出 Guten Tag 值(针对 greeting-day 键),而一个奥地利 Messages_de_AT 束可能用 Servus 值来覆盖该值。 资源束可以作为 Java 类或简单的“属性”文本文件来执行。
JavaServer Pages 应用程序的本地化方法
要对基于 JavaServer Pages 技术的应用程序进行本地化,方法通常有两个。 第一个方法是使用国际化的页面,这些页面常可以通过自定义标记从资源束获得与特定地区设置相关的内容。 如果页面需要保持复杂的结构并与所有地区设置同步,则通常会采取这种方法。 第二种方法使用单独的特定地区设置页面以及分发到适当页面的 servlet(取决于用户的地区选择)。 如果页面包含的主要是文本或者地区设置间的结构截然不同时,则通常会采取这种方法。
地区确定和 JSTL 中的本地化
JSTL 构建于 J2SE 工具之上,它可进行地区确定和本地化。 使用任何一种 JSP 本地化方法(如上所述)均可以进行地区确定,而本地化功能的目的是为国际化的页面提供支持。
JSTL 对上述两种确定用户地区首选项的方法都提供支持。 应用程序可以使用 JSTL 的 <fmt:setLocale> 操作,指定一个固定的地区(通常是用户从支持语言列表中所直接选择的)。 一旦使用了该操作,指定的地区设置将应用于所有的地区敏感操作中。 如果没有使用 <fmt:setLocale> 操作,地区敏感操作将会从地区选择列表中搜索第一种支持的地区设置,这些地区设置通常由 Accept-Language 报头提供。
下面是一些您可以用于 web 应用程序开始页面的代码片断。 这些代码片断可让用户非常轻松地选择他或她的地区设置。 假设这些代码是 locale-choice.jsp 页面中的一部分:
<%-- 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 页面上。 如果定义了 locale 参数,则它将被用于进行会话的地区设置。
第二部分(此部分是生成的 HTML 页面内容的一部分)为用户提供了返回同一页面的链接,但是根据选定的国家提供了 locale 参数设置。 注意,在本地语言中已经给出国家的名称,所以即使页面的其他部分已经本地化为用户不能识别的语言,但是用户仍然可以容易地识别这些名称。 例如,“日本”是“日本”的数字字符引用,即“日本”的日语单词。 新版的浏览器如果装有日本字体,将会正确地转换这些文本;对于旧版的浏览器,使用图片则可能更合适一些。
最后一部分显示如何使用 <c:url> 标记生成 URL,此 URL 包含了一个会话 ID,如果需要对该会话进行追踪的话(如果用户启用了 cookies,则 cookies 将代替 URL 重写)。 这将确保一旦选择了地区设置,该选择将应用于该 web 应用程序中的所有页面。
如果从 web 应用程序本身的用户界面中选择了地区设置,然后使用 <fmt:setLocale> 进行设置,那么就可以假设该应用程序确实支持此地区设置。 另一方面,如果没有使用 <fmt:setLocale> 并且 JSTL 必须从 Accept-Language 报头中的地区设置列表中找到一个支持的地区设置,那么情况会变得更复杂。
要决定哪个地区设置是被支持的,JSTL 将参考该应用程序所使用的资源束。 有两种操作可用于访问资源束:<fmt:bundle> 和 <fmt:setBundle>。 它们的基本功能是相同的:它们查询一个资源束并创建一个“本地化环境”,在这个“本地化环境”中包含了对该资源束和用于请求该资源束的地区设置的引用。
<fmt:bundle> 和 <fmt:setBundle> 操作所使用的资源束查询允许多次请求地区设置(这样它就可以处理由 Accept-Language 报头提供的列表),并使用由 web 应用程序定义的备用(fallback)地区设置。 如果使用 <fmt:setLocale> 操作设置地区,那么 <fmt:bundle> 和 <fmt:setBundle> 操作将请求用于该地区设置的束,或者,如果不成功的话,将请求用于备用地区设置的束。 如果没有使用 <fmt:setLocale>,随后的操作将请求用于由 Accept-Language 报头提供的地区设置和备用地区设置,直到请求成功。 在每种情况下,基本查询(查询束的基本名称和一个请求地区设置)将为请求地区设置本身搜索一个资源束,随后搜索更简单的地区设置(首先从请求地区设置中舍弃变量,然后舍弃国家组件)。 如果全部的请求地区设置以及备用地区设置的查询都失败,那么将使用基础束。
以下是一些例子。 让我们假设某个应用程序拥有用于 en、zh_CN、zh_TW、ja 和 ko 的束。 备用地区设置被设置为 en。 没有使用 <fmt:setLocale> 标记。 下表显示最终本地化环境的束和地区设置(用于一些请求地区设置列表):
被请求的地区设置
结果束
结果地区设置
zh_SG、zh_CN
zh_CN
zh_CN
zh、ja
ja
ja
es_MX
en
en
en_US
en
en_US
ja、zh_CN
ja
ja
ResourceBundle 类的行家会注意到,JSTL 操作所使用的查询策略与 ResourceBundle 所使用的查询策略是不同的。 ResourceBundle 使用的策略只接受一个请求地区设置,这不足以处理由 Accept-Language 报头所提供的地区设置列表,并且它会恢复 Java 运行环境的默认地区设置,此默认地区设置与 web 应用程序和其用户并不相关,使用它将导致不可移植性。
那么,为什么查询资源束时存在两种不同的操作呢? 它们的区别在于它们使用的方法:<fmt:bundle> 标记提供了一个用于嵌套标记的环境,而 <fmt:setBundle> 操作将最终本地化环境存储在一个变量中,此变量可以在相同页面中被后继操作访问,并且可以被其他页面中的操作所访问(这取决于该变量的范围)。
<fmt:message> 操作是一种利用本地化环境的 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 将格式化标记限制到应用程序所支持的语言范围内的方法,这样展现在读者面前的页面语言将完全统一。 嵌套于 <fmt:bundle> 标记中的格式化操作使用该标记的本地化环境来确定它们应该使用的地区设置。 例如,让我们观察下面的页面片断:
<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 Accept-Language 地区设置是 fr 和 en,并且基础的 Java 运行环境对这两种语言的日期格式都支持(但 web 应用程序的 Messages 束只存在于 en),那么第一个日期采用法文格式,而第二个则采用英文格式。 因此,页面设计者可以决定是使用统一的语言还是通过选择适当的标记嵌套来利用所有现有的本地化信息。
最后,为什么本地化环境使用请求地区设置而不使用由资源束找到的地区设置? 答案是,这样可以避免丢失重要的信息,某些格式标记可能需要这些信息。 很多应用程序不能区分相同语言中不同变量之间的区别,而且只提供(例如)英文资源束,期望着这些文本在英国、澳大利亚和新加坡都能被同样理解。 然而对于日期格式,国家是很关键的——对于英国读者来说,“2/6/02”表示“ 2002 年 6 月 2 日”,但对于习惯美国规范的读者来说,则表示“2002 年 2 月 6 日”。 所以,在很多情况下,如果使用了请求地区设置(而不是资源束地区设置),则国家信息将会被保留。
字符编码
当前,我们使用两种截然不同的模块表示存储在计算机中或通过网络传输的文本:旧的字符编码模式专门用于较小的语言集合、国家和/或操作系统(包括如 ISO 8859 系列、 Windows 代码页和 EUC 编码);而新的基于 Unicode 编码的模式能够(至少理论上能够)表示所有的语言并可以在任何地方使用。
旧的模块具有很大的劣势:
每种旧的字符编码方法通常只支持一个小的语言集合。 例如,Shift-JIS 支持日文和英文,但不支持其他的亚洲或欧洲语言。 ISO 8859-1 支持一些西欧语言但不支持东欧语言。
字符转换可能会带来意料之外的信息丢失。 开发者通常选择 ISO 8859-1 作为德语、法语和其它西欧语言的编码方法,然后会很惊讶地发现“€”字符(德国、法国和许多其他欧洲国家通用货币的标志)不被这种编码所支持。 为了防止这种信息丢失,您必须使用 Windows-1252、ISO 8859-15 或其他编码方法,这取决于浏览器的基础操作系统。
当前版本的主要软件系统所包含的创建、分发和解释 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 声明中予以说明。 对于采用标准语法的文件,容器将考虑两种主要的信息来源:首先它们访问应用程序的配置描述符,查询一个 page-encoding 元素,该元素位于 jsp-property-group(其 URL 格式与文件相匹配);然后在此页中查询 pageEncoding 属性。 如果两者都没有,容器也会寻找 contentType 属性中的 charset (参阅下一部分“处理 Web 页面编码”),或使用 ISO 8859-1 作为最终的备用选择。
以下是基于 JSP 2.0 的应用程序的一些简单建议:对于采用 XML 语法的文件,确保没有使用 UTF-8 或 UTF-16 编码的文件能够正确识别它们的字符编码。 对于采用标准语法的文件,如果您对所有源文件使用 UTF-8,则请在配置描述符中只使用一个元素 page-encoding 来阐述它。 如果您使用特定地区设置编码,则根据该地区设置来组织或命名您的文件,并使用 page-encoding 元素来描述它们的关系。 例如,如果全部的韩文文件以 EUC-KR 编码并保存在 /ko/KR web 的应用程序的子目录中,请使用以下语句:
<jsp-property-group>
<url-pattern>/ko/KR/*</url-pattern>
<page-encoding>EUC-KR</page-encoding>
</jsp-property-group>
如果应用程序中的源文件不能以这种方式组织,则为每个源文件添加 pageEncoding 属性。 不过请切记,此属性必须能够在文件的开始处找到并且只能用于标识 ASCII 扩展码的字符编码。 后一个限制考虑到了 UTF-8 和许多旧的字符编码,但没考虑 UTF-16 或基于 EBCDIC 的编码。 不建议根据 contentType 属性中的 charset 值来标识源程序页编码;这个值应只用于标识 web 页面编码(参见下一部分)。
关于源文件字符编码,JSP 1.2 规范没有清楚地区分使用标准语法的文件和使用 XML 语法的文件。 它也没有提供识别配置描述符中的字符编码的方法。 为确保正确检测字符编码,设计用于 JSP 1.2 容器的应用程序应总是识别每个使用 pageEncoding 属性的源文件中的字符编码。
JSTL 定义了一个<c:import> 操作,该操作允许包含由 URL 指定到 JSP 生成的页面的外部数据。 该操作允许字符编码规范,如果外部数据没有指定它本身的编码时会使用此规范。
处理 Web 页面编码
web 应用程序必须选择生成的 web 页中使用的字符编码(该编码被称为“反应字符编码”),它基于目标浏览器的性能、页面内容的编写系统和语言以及可能的浏览器主机的操作系统。 根据 HTTP 规范,字符编码在 Content-Type 实体报头的 charset 参数中被指定。
如果所有目标浏览器都支持 UTF-8,一般来说最好使用这种编码,这样就可以支持多语言文档并避免字符转换带来的信息丢失。
如果不能使用 UTF-8 ,必须小心谨慎地使用应用程序将字符编码与使用的语言相匹配,包括一些特殊字符。 为防止出现错误,可能需要在整个页面里使用同一种语言,如本文开始部分“地区确定和本地化”中所述。 同样,也有必要避免使用“€”字符。
Web 应用程序可以直接指定一个页面的字符编码,也可以让 JSP 技术根据地区设置信息间接决定。
通过页面的 contentType 属性的显式规范最为简便,该属性可让应用程序连同生成页面的内容类型一起来指定字符编码。 如果应用程序在处理请求时需要设置字符编码,则它需要使用一个自定义操作或一些 Java 代码来调用 javax.servlet.ServletResponse.setContentType 方法或新的(在 Servlet 2.4 中)javax.servlet.ServletResponse.setCharacterEncoding 方法。
间接地,每当字符编码创建一个本地化环境时,它们也是由 JSTL 格式化操作(包括 <fmt:message>)以及 <fmt:bundle>、<fmt:setBundle> 和 <fmt:setLocale> 操作无条件地来决定。 通过 ServletResponse.setLocale 方法,它们将本地化环境的地区设置或指定的地区设置映射到一个字符编码并根据页面的内容类型对其进行设置。 Servlet 2.4 规范通过配置描述符中的 locale-encoding-mapping-list 元素为应用程序提供了一个控制映射的方法。 如果应用程序没有提供此元素,或者当您使用基于旧的 Servlet 规范的容器时,那么从地区设置到字符编码的映射取决于该容器;典型的实现依赖于旧的字符编码。
间接决定字符编码是可行的,只要旧的字符编码可以被接受,并且整个页面使用相同的语言而且避免出现常用字符编码所不支持的特殊字符。 然而,若要利用 UTF-8 则要求使用显式规范。 因为 Servlet 2.4 规范使显式规范优先于隐式规范,所以将字符编码设置为 contentType 属性的一部分已足够——随后使用 JSTL 格式化操作不会影响字符的编码。 不过,在早期版本的 Servlet 规范中,并不保证地区设置信息中的显式规范优先于隐式决定。 如果需要与基于旧规范的容器兼容,您必须通过在显式字符编码规范和首次使用自定义操作之间调用 ServletResponse.flushBuffer 来冻结字符编码,这些自定义操作可能间接决定字符编码。
处理请求参数编码
JSP 技术不仅能够生成 web 页面,而且还可以接收和解释与 HTTP 请求一起收到的参数——通常是来自某种表格的输入,这种表格属于前面生成的 web 页面的一部分。 用于这些参数的字符编码并非在任何地方都被指定,但实际标准是浏览器使用的编码要与包含这些表格的网页使用的编码相同。
这意味着 web 应用程序需要跟踪先前生成的网页的编码。 一个常用的机制是把编码的名称存储到表格本身的一个隐藏域中,在下一个请求时解压缩为第一个参数,然后用它来解码出其他的参数。 然而,JSP 页面还可以使用会话管理来跟踪请求之间的信息。
应用程序可以使用 JSTL 自定义操作 <fmt:requestEncoding> 来指定要编码的参数的编码方法。 如果应用程序总是发送 UTF-8 编码的页面,那么可以简单指定这种编码为请求编码。 否则,如果它将直接指定生成页面的编码,它应该将该编码作为会话信息的一部分进行跟踪并直接将其传递给 <fmt:requestEncoding> 操作。 如果它依赖于字符编码的间接决定,则它会简单地使用 <fmt:requestEncoding> 操作而无需指定一种字符编码;间接决定生成页面的编码这一操作还会在会话中储存信息,<fmt:requestEncoding> 可以检索和使用这些信息。
格式化和解析
以本地化的格式表示数据(如数字和日期)是任何类型地应用程序都要完成的常见任务,就如同用户提供的输入解释。 不同语言和文化所使用的格式区别很大,所以如果开发者不依靠现有的库的话,那么这个工作就不会是一项简单的任务。
幸运的是,确实存在这样的库。 Java 2 Standard Edition (J2SE) 平台提供了在 java.text 软件包中用于格式化和解析常用数据类型的类库,并且 Sun 已将这些类库本地化为 100 多种地区设置。
JavaServer Pages 标准标记库提供了自定义操作,可将这些功能直接应用到 JSP 页面中。
用于格式化和解析操作的地区确定
您可以在预定义的本地化环境中对数字和日期使用格式化和解析的操作(例如,如果标记嵌套于一个 <fmt:bundle> 标记中),或者在这种环境以外进行操作。 如果您在预定义的本地化环境中使用操作,则它们将使用此本地化环境的地区设置。 否则,它们将决定 <fmt:bundle> 和 <fmt:setBundle> 操作(如前文所述)的,用于修改的资源束查询策略所使用的地区设置。 主要的区别在于:与查找资源束不同,算法通过使用 java.text.NumberFormat.getAvailableLocales 方法(用于数字格式化和解析操作)或者 java.text.DateFormat.getAvailableLocales 方法(用于日期和时间格式化和分解操作)来决定受支持的地区设置。
数字格式化和解析
JSTL 用于数字格式化和解析的自定义操作 <fmt:formatNumber> 和 <fmt:parseNumber> 基于 J2SE 类 java.text.NumberFormat,用于处理简单的数字以及百分比和货币值。
特别值得一提的是它们对货币格式化的支持。 传统上,许多格式化库假设货币符号可以从地区设置中得出——例如,如果地区设置是中国,那么货币符号就是人民币(RMB)。 在一个跨境交易的环境中,这并没有多大的意义。 如果某个英国公司以英镑来计算价格,而 web 应用程序将价格显示为人民币(RMB)的形式,就会出现两个问题:第一,人民币的汇率比英镑低;其次,人民币换回英镑会比较困难。 由于货币的选择属于商业上的决定,所以货币必须作为值的一部分而不是格式的一部分。
因此,<fmt:formatNumber> 操作可以让应用程序指定一个 ISO 4217 货币代码或货币符号,它将覆盖本地化数字格式使用的默认货币。 假设应用程序使用一个带有值和货币属性的价格 bean,下面的页面语句片断可以对价格进行格式化:
<fmt:formatNumber type="currency" value="${price.value}"
currencyCode="${price.currency}" />
如果 JSP 页面指定了一个货币代码,则底层的 NumberFormat 对象会尝试对指定的货币使用一个货币符号,该指定的货币已本地化为所处本地化环境的地区设置。 例如,如果为美元指定货币代码 USD,则它可能会使用符号“$”(如果地区设置是en_US),在其他可接受该货币符号的地区设置中将使用 US$,或者如果本地化符号未知,则使用备用货币代码 USD。
日期和时间的格式化和解析
用于日期和时间的格式化和解析的 JSTL 自定义操作 <fmt:formatDate> 和 <fmt:parseDate> 基于 J2SE 类 java.text.DateFormat 并用于处理不同的日期和时间表示方法。
令人感兴趣的一点是显示的日期和时间不仅仅取决于一种指定地区设置的格式,还取决于时区信息。 用户通常对服务器时区不感兴趣,但另一方面,要找出用户所在地的时区却并不简单。应用程序可以通过使用一些客户端的 JavaScript 代码来找出用户的当前时区与格林尼治标准时间的偏差,或让用户指定当前时区并将其作为用户信息的一部分。 JSTL 操作并没有解决这个问题,但它们提供了两个自定义操作,可以用来告知有关时区的日期和时间的格式化和解析:<fmt:timeZone> 和 <fmt:setTimeZone>。 与 <fmt:bundle> 和 <fmt:setBundle> 一样,<fmt:timeZone> 标记可为嵌套标记定义时区,而 <fmt:setTimeZone> 将时区储存在一个变量中以供后继操作使用。
信息格式化
<fmt:message> 操作(前面已提及)不但能从一个资源束中获取一个字符串并将其插入至生成的页面中,而且它还可以执行参数替换并根据需要格式化参数。 它基于 java.text.MessageFormat 类,因此该操作获取的字符串实际上是一个 MessageFormat 模式字符串。 <fmt:param> 操作提供了必要的自变量。
例如,如果 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>
并且找到的资源束是德语,而且 为 greeting 键提供了“Willkommen! Heute ist der {0,date,long}.”值,那么生成日期为(假设)2002 年 6 月 21 日的页面内容将会是“Willkommen! Heute ist der 21. Juni 2002.”
设计多语言 web 应用程序时,您必须首先决定如何确定用户的语言和地区首选项,以及如何使这些首选项与该应用程序和基础的 Java 运行环境支持的一套地区设置相匹配。 这部分首先描述了 web 应用程序必须具有的外部环境和要求。 下一步,我们将了解相关的 Java 2 Standard Edition (J2SE) 平台提供的功能,最后我们将了解 JavaServer Pages 标准标记库的标记如何连接到环境和 J2SE 中。
确定用户首选项
web 应用程序有两种方法来确定用户的语言首选项:首先,它可以由浏览器使用 HTTP 请求报头字段 Accept-Language 传输至服务器的语言和地区首选项。 尽管标准规定了许多语言标记,但是一般使用 ISO 639 语言代码(如 ja 为日文)和 ISO 3166 国家代码(如 IT 代表意大利)。 浏览器通常让用户创建一个语言列表作为其首选项的一部分。 然而,这种方法不太可靠;用户不一定会创建该列表,而且该列表不一定会包含该应用程序支持的地区设置。 由于这些不确定性,多语言应用程序通常采用第二种方法:他们让用户直接从支持语言的列表中选择,并把选择的语言作为用户资料的一部分进行保存,或只在进行该会话的时候保存。 一个好的方法是,在对用户一无所知的情况下,首先使用 Accept-Language 信息,在应用程序的开始页面中给予用户直接选择语言的机会。
将 Accept-Language 地区设置主要用于语言和文化首选项是没什么意义的。 例如,它们不应该被解释为表示用户居住的国家。 同样,在很多情况下浏览器提供的地区设置只有一个语言代码,而一些地区敏感的功能(例如,日期格式)则随着国家的不同而相异。 在很多情况下,通过语言假设主要国家的规范是合理的(如果没有指定国家);例如,如果指定了日本语,则可使用日本通用的日期格式。 然而,如果是根据国家而设置的重要功能(例如货币),则必须给用户一个机会来修正该假设。
在许多情况下,web 应用程序是由若干组件组合而来的,这些组件可能已经本地化为不同的语言。 一个特别值得一提的组件是 Java 运行环境,它在一些地区敏感区域可能具备支持超过 40 种语言中的 100 种区域设置的功能(例如日期格式),远远超出了典型的 web 应用程序。 因此,应用程序开发者必须决定是否在整个应用程序中限制所支持语言的本地化功能,或者充分发挥每个组件的功能优势。 第一种方法的优势在于用户可以看到的全部页面都使用同一语言,而第二种方法可能导致页面中存在不同的语言——其中一种语言出现在绝大多数文本中,而另一种则出现在例如日期的格式中。
Java 2 Standard Edition Platform 中的本地化
为了了解 JSTL 如何确定应用程序被哪些地区设置支持,我们来看看在基础的 Java 2 Standard Edition 平台中是如何进行本地化的。 java.util 软件包的核心主要有两种类:Locale 和 ResourceBundle。
Locale 对象只是用来确定地区设置的:它们结合了 ISO 639 语言代码(例如,ja 代表日文)和 ISO 3166 国家代码(例如,IT 代表意大利),还可能包含一个(非标准化的)变量字符串。 注意,HTTP 的地区标识符使用相同的 ISO 标准,所以对比通常比较容易。
ResourceBundle 对象是本地化对象的容器,形成成键/值对。 一个基础资源束定义了一个基础束的名称、一套键以及默认值(通常是英文值,但不是必须的)。 例如,一个简单的 Messages 资源束可能定义 greeting-day 键的默认值为 Hello。 其他的特定语言和国家束可以被定义,其名称由基础名称组成(通过后缀指示其语言、国家和变量)并提供已本地化的值。 例如,德语 Messages_de 资源束可以给出 Guten Tag 值(针对 greeting-day 键),而一个奥地利 Messages_de_AT 束可能用 Servus 值来覆盖该值。 资源束可以作为 Java 类或简单的“属性”文本文件来执行。
JavaServer Pages 应用程序的本地化方法
要对基于 JavaServer Pages 技术的应用程序进行本地化,方法通常有两个。 第一个方法是使用国际化的页面,这些页面常可以通过自定义标记从资源束获得与特定地区设置相关的内容。 如果页面需要保持复杂的结构并与所有地区设置同步,则通常会采取这种方法。 第二种方法使用单独的特定地区设置页面以及分发到适当页面的 servlet(取决于用户的地区选择)。 如果页面包含的主要是文本或者地区设置间的结构截然不同时,则通常会采取这种方法。
地区确定和 JSTL 中的本地化
JSTL 构建于 J2SE 工具之上,它可进行地区确定和本地化。 使用任何一种 JSP 本地化方法(如上所述)均可以进行地区确定,而本地化功能的目的是为国际化的页面提供支持。
JSTL 对上述两种确定用户地区首选项的方法都提供支持。 应用程序可以使用 JSTL 的 <fmt:setLocale> 操作,指定一个固定的地区(通常是用户从支持语言列表中所直接选择的)。 一旦使用了该操作,指定的地区设置将应用于所有的地区敏感操作中。 如果没有使用 <fmt:setLocale> 操作,地区敏感操作将会从地区选择列表中搜索第一种支持的地区设置,这些地区设置通常由 Accept-Language 报头提供。
下面是一些您可以用于 web 应用程序开始页面的代码片断。 这些代码片断可让用户非常轻松地选择他或她的地区设置。 假设这些代码是 locale-choice.jsp 页面中的一部分:
<%-- 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 页面上。 如果定义了 locale 参数,则它将被用于进行会话的地区设置。
第二部分(此部分是生成的 HTML 页面内容的一部分)为用户提供了返回同一页面的链接,但是根据选定的国家提供了 locale 参数设置。 注意,在本地语言中已经给出国家的名称,所以即使页面的其他部分已经本地化为用户不能识别的语言,但是用户仍然可以容易地识别这些名称。 例如,“日本”是“日本”的数字字符引用,即“日本”的日语单词。 新版的浏览器如果装有日本字体,将会正确地转换这些文本;对于旧版的浏览器,使用图片则可能更合适一些。
最后一部分显示如何使用 <c:url> 标记生成 URL,此 URL 包含了一个会话 ID,如果需要对该会话进行追踪的话(如果用户启用了 cookies,则 cookies 将代替 URL 重写)。 这将确保一旦选择了地区设置,该选择将应用于该 web 应用程序中的所有页面。
如果从 web 应用程序本身的用户界面中选择了地区设置,然后使用 <fmt:setLocale> 进行设置,那么就可以假设该应用程序确实支持此地区设置。 另一方面,如果没有使用 <fmt:setLocale> 并且 JSTL 必须从 Accept-Language 报头中的地区设置列表中找到一个支持的地区设置,那么情况会变得更复杂。
要决定哪个地区设置是被支持的,JSTL 将参考该应用程序所使用的资源束。 有两种操作可用于访问资源束:<fmt:bundle> 和 <fmt:setBundle>。 它们的基本功能是相同的:它们查询一个资源束并创建一个“本地化环境”,在这个“本地化环境”中包含了对该资源束和用于请求该资源束的地区设置的引用。
<fmt:bundle> 和 <fmt:setBundle> 操作所使用的资源束查询允许多次请求地区设置(这样它就可以处理由 Accept-Language 报头提供的列表),并使用由 web 应用程序定义的备用(fallback)地区设置。 如果使用 <fmt:setLocale> 操作设置地区,那么 <fmt:bundle> 和 <fmt:setBundle> 操作将请求用于该地区设置的束,或者,如果不成功的话,将请求用于备用地区设置的束。 如果没有使用 <fmt:setLocale>,随后的操作将请求用于由 Accept-Language 报头提供的地区设置和备用地区设置,直到请求成功。 在每种情况下,基本查询(查询束的基本名称和一个请求地区设置)将为请求地区设置本身搜索一个资源束,随后搜索更简单的地区设置(首先从请求地区设置中舍弃变量,然后舍弃国家组件)。 如果全部的请求地区设置以及备用地区设置的查询都失败,那么将使用基础束。
以下是一些例子。 让我们假设某个应用程序拥有用于 en、zh_CN、zh_TW、ja 和 ko 的束。 备用地区设置被设置为 en。 没有使用 <fmt:setLocale> 标记。 下表显示最终本地化环境的束和地区设置(用于一些请求地区设置列表):
被请求的地区设置
结果束
结果地区设置
zh_SG、zh_CN
zh_CN
zh_CN
zh、ja
ja
ja
es_MX
en
en
en_US
en
en_US
ja、zh_CN
ja
ja
ResourceBundle 类的行家会注意到,JSTL 操作所使用的查询策略与 ResourceBundle 所使用的查询策略是不同的。 ResourceBundle 使用的策略只接受一个请求地区设置,这不足以处理由 Accept-Language 报头所提供的地区设置列表,并且它会恢复 Java 运行环境的默认地区设置,此默认地区设置与 web 应用程序和其用户并不相关,使用它将导致不可移植性。
那么,为什么查询资源束时存在两种不同的操作呢? 它们的区别在于它们使用的方法:<fmt:bundle> 标记提供了一个用于嵌套标记的环境,而 <fmt:setBundle> 操作将最终本地化环境存储在一个变量中,此变量可以在相同页面中被后继操作访问,并且可以被其他页面中的操作所访问(这取决于该变量的范围)。
<fmt:message> 操作是一种利用本地化环境的 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 将格式化标记限制到应用程序所支持的语言范围内的方法,这样展现在读者面前的页面语言将完全统一。 嵌套于 <fmt:bundle> 标记中的格式化操作使用该标记的本地化环境来确定它们应该使用的地区设置。 例如,让我们观察下面的页面片断:
<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 Accept-Language 地区设置是 fr 和 en,并且基础的 Java 运行环境对这两种语言的日期格式都支持(但 web 应用程序的 Messages 束只存在于 en),那么第一个日期采用法文格式,而第二个则采用英文格式。 因此,页面设计者可以决定是使用统一的语言还是通过选择适当的标记嵌套来利用所有现有的本地化信息。
最后,为什么本地化环境使用请求地区设置而不使用由资源束找到的地区设置? 答案是,这样可以避免丢失重要的信息,某些格式标记可能需要这些信息。 很多应用程序不能区分相同语言中不同变量之间的区别,而且只提供(例如)英文资源束,期望着这些文本在英国、澳大利亚和新加坡都能被同样理解。 然而对于日期格式,国家是很关键的——对于英国读者来说,“2/6/02”表示“ 2002 年 6 月 2 日”,但对于习惯美国规范的读者来说,则表示“2002 年 2 月 6 日”。 所以,在很多情况下,如果使用了请求地区设置(而不是资源束地区设置),则国家信息将会被保留。
字符编码
当前,我们使用两种截然不同的模块表示存储在计算机中或通过网络传输的文本:旧的字符编码模式专门用于较小的语言集合、国家和/或操作系统(包括如 ISO 8859 系列、 Windows 代码页和 EUC 编码);而新的基于 Unicode 编码的模式能够(至少理论上能够)表示所有的语言并可以在任何地方使用。
旧的模块具有很大的劣势:
每种旧的字符编码方法通常只支持一个小的语言集合。 例如,Shift-JIS 支持日文和英文,但不支持其他的亚洲或欧洲语言。 ISO 8859-1 支持一些西欧语言但不支持东欧语言。
字符转换可能会带来意料之外的信息丢失。 开发者通常选择 ISO 8859-1 作为德语、法语和其它西欧语言的编码方法,然后会很惊讶地发现“€”字符(德国、法国和许多其他欧洲国家通用货币的标志)不被这种编码所支持。 为了防止这种信息丢失,您必须使用 Windows-1252、ISO 8859-15 或其他编码方法,这取决于浏览器的基础操作系统。
当前版本的主要软件系统所包含的创建、分发和解释 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 声明中予以说明。 对于采用标准语法的文件,容器将考虑两种主要的信息来源:首先它们访问应用程序的配置描述符,查询一个 page-encoding 元素,该元素位于 jsp-property-group(其 URL 格式与文件相匹配);然后在此页中查询 pageEncoding 属性。 如果两者都没有,容器也会寻找 contentType 属性中的 charset (参阅下一部分“处理 Web 页面编码”),或使用 ISO 8859-1 作为最终的备用选择。
以下是基于 JSP 2.0 的应用程序的一些简单建议:对于采用 XML 语法的文件,确保没有使用 UTF-8 或 UTF-16 编码的文件能够正确识别它们的字符编码。 对于采用标准语法的文件,如果您对所有源文件使用 UTF-8,则请在配置描述符中只使用一个元素 page-encoding 来阐述它。 如果您使用特定地区设置编码,则根据该地区设置来组织或命名您的文件,并使用 page-encoding 元素来描述它们的关系。 例如,如果全部的韩文文件以 EUC-KR 编码并保存在 /ko/KR web 的应用程序的子目录中,请使用以下语句:
<jsp-property-group>
<url-pattern>/ko/KR/*</url-pattern>
<page-encoding>EUC-KR</page-encoding>
</jsp-property-group>
如果应用程序中的源文件不能以这种方式组织,则为每个源文件添加 pageEncoding 属性。 不过请切记,此属性必须能够在文件的开始处找到并且只能用于标识 ASCII 扩展码的字符编码。 后一个限制考虑到了 UTF-8 和许多旧的字符编码,但没考虑 UTF-16 或基于 EBCDIC 的编码。 不建议根据 contentType 属性中的 charset 值来标识源程序页编码;这个值应只用于标识 web 页面编码(参见下一部分)。
关于源文件字符编码,JSP 1.2 规范没有清楚地区分使用标准语法的文件和使用 XML 语法的文件。 它也没有提供识别配置描述符中的字符编码的方法。 为确保正确检测字符编码,设计用于 JSP 1.2 容器的应用程序应总是识别每个使用 pageEncoding 属性的源文件中的字符编码。
JSTL 定义了一个<c:import> 操作,该操作允许包含由 URL 指定到 JSP 生成的页面的外部数据。 该操作允许字符编码规范,如果外部数据没有指定它本身的编码时会使用此规范。
处理 Web 页面编码
web 应用程序必须选择生成的 web 页中使用的字符编码(该编码被称为“反应字符编码”),它基于目标浏览器的性能、页面内容的编写系统和语言以及可能的浏览器主机的操作系统。 根据 HTTP 规范,字符编码在 Content-Type 实体报头的 charset 参数中被指定。
如果所有目标浏览器都支持 UTF-8,一般来说最好使用这种编码,这样就可以支持多语言文档并避免字符转换带来的信息丢失。
如果不能使用 UTF-8 ,必须小心谨慎地使用应用程序将字符编码与使用的语言相匹配,包括一些特殊字符。 为防止出现错误,可能需要在整个页面里使用同一种语言,如本文开始部分“地区确定和本地化”中所述。 同样,也有必要避免使用“€”字符。
Web 应用程序可以直接指定一个页面的字符编码,也可以让 JSP 技术根据地区设置信息间接决定。
通过页面的 contentType 属性的显式规范最为简便,该属性可让应用程序连同生成页面的内容类型一起来指定字符编码。 如果应用程序在处理请求时需要设置字符编码,则它需要使用一个自定义操作或一些 Java 代码来调用 javax.servlet.ServletResponse.setContentType 方法或新的(在 Servlet 2.4 中)javax.servlet.ServletResponse.setCharacterEncoding 方法。
间接地,每当字符编码创建一个本地化环境时,它们也是由 JSTL 格式化操作(包括 <fmt:message>)以及 <fmt:bundle>、<fmt:setBundle> 和 <fmt:setLocale> 操作无条件地来决定。 通过 ServletResponse.setLocale 方法,它们将本地化环境的地区设置或指定的地区设置映射到一个字符编码并根据页面的内容类型对其进行设置。 Servlet 2.4 规范通过配置描述符中的 locale-encoding-mapping-list 元素为应用程序提供了一个控制映射的方法。 如果应用程序没有提供此元素,或者当您使用基于旧的 Servlet 规范的容器时,那么从地区设置到字符编码的映射取决于该容器;典型的实现依赖于旧的字符编码。
间接决定字符编码是可行的,只要旧的字符编码可以被接受,并且整个页面使用相同的语言而且避免出现常用字符编码所不支持的特殊字符。 然而,若要利用 UTF-8 则要求使用显式规范。 因为 Servlet 2.4 规范使显式规范优先于隐式规范,所以将字符编码设置为 contentType 属性的一部分已足够——随后使用 JSTL 格式化操作不会影响字符的编码。 不过,在早期版本的 Servlet 规范中,并不保证地区设置信息中的显式规范优先于隐式决定。 如果需要与基于旧规范的容器兼容,您必须通过在显式字符编码规范和首次使用自定义操作之间调用 ServletResponse.flushBuffer 来冻结字符编码,这些自定义操作可能间接决定字符编码。
处理请求参数编码
JSP 技术不仅能够生成 web 页面,而且还可以接收和解释与 HTTP 请求一起收到的参数——通常是来自某种表格的输入,这种表格属于前面生成的 web 页面的一部分。 用于这些参数的字符编码并非在任何地方都被指定,但实际标准是浏览器使用的编码要与包含这些表格的网页使用的编码相同。
这意味着 web 应用程序需要跟踪先前生成的网页的编码。 一个常用的机制是把编码的名称存储到表格本身的一个隐藏域中,在下一个请求时解压缩为第一个参数,然后用它来解码出其他的参数。 然而,JSP 页面还可以使用会话管理来跟踪请求之间的信息。
应用程序可以使用 JSTL 自定义操作 <fmt:requestEncoding> 来指定要编码的参数的编码方法。 如果应用程序总是发送 UTF-8 编码的页面,那么可以简单指定这种编码为请求编码。 否则,如果它将直接指定生成页面的编码,它应该将该编码作为会话信息的一部分进行跟踪并直接将其传递给 <fmt:requestEncoding> 操作。 如果它依赖于字符编码的间接决定,则它会简单地使用 <fmt:requestEncoding> 操作而无需指定一种字符编码;间接决定生成页面的编码这一操作还会在会话中储存信息,<fmt:requestEncoding> 可以检索和使用这些信息。
格式化和解析
以本地化的格式表示数据(如数字和日期)是任何类型地应用程序都要完成的常见任务,就如同用户提供的输入解释。 不同语言和文化所使用的格式区别很大,所以如果开发者不依靠现有的库的话,那么这个工作就不会是一项简单的任务。
幸运的是,确实存在这样的库。 Java 2 Standard Edition (J2SE) 平台提供了在 java.text 软件包中用于格式化和解析常用数据类型的类库,并且 Sun 已将这些类库本地化为 100 多种地区设置。
JavaServer Pages 标准标记库提供了自定义操作,可将这些功能直接应用到 JSP 页面中。
用于格式化和解析操作的地区确定
您可以在预定义的本地化环境中对数字和日期使用格式化和解析的操作(例如,如果标记嵌套于一个 <fmt:bundle> 标记中),或者在这种环境以外进行操作。 如果您在预定义的本地化环境中使用操作,则它们将使用此本地化环境的地区设置。 否则,它们将决定 <fmt:bundle> 和 <fmt:setBundle> 操作(如前文所述)的,用于修改的资源束查询策略所使用的地区设置。 主要的区别在于:与查找资源束不同,算法通过使用 java.text.NumberFormat.getAvailableLocales 方法(用于数字格式化和解析操作)或者 java.text.DateFormat.getAvailableLocales 方法(用于日期和时间格式化和分解操作)来决定受支持的地区设置。
数字格式化和解析
JSTL 用于数字格式化和解析的自定义操作 <fmt:formatNumber> 和 <fmt:parseNumber> 基于 J2SE 类 java.text.NumberFormat,用于处理简单的数字以及百分比和货币值。
特别值得一提的是它们对货币格式化的支持。 传统上,许多格式化库假设货币符号可以从地区设置中得出——例如,如果地区设置是中国,那么货币符号就是人民币(RMB)。 在一个跨境交易的环境中,这并没有多大的意义。 如果某个英国公司以英镑来计算价格,而 web 应用程序将价格显示为人民币(RMB)的形式,就会出现两个问题:第一,人民币的汇率比英镑低;其次,人民币换回英镑会比较困难。 由于货币的选择属于商业上的决定,所以货币必须作为值的一部分而不是格式的一部分。
因此,<fmt:formatNumber> 操作可以让应用程序指定一个 ISO 4217 货币代码或货币符号,它将覆盖本地化数字格式使用的默认货币。 假设应用程序使用一个带有值和货币属性的价格 bean,下面的页面语句片断可以对价格进行格式化:
<fmt:formatNumber type="currency" value="${price.value}"
currencyCode="${price.currency}" />
如果 JSP 页面指定了一个货币代码,则底层的 NumberFormat 对象会尝试对指定的货币使用一个货币符号,该指定的货币已本地化为所处本地化环境的地区设置。 例如,如果为美元指定货币代码 USD,则它可能会使用符号“$”(如果地区设置是en_US),在其他可接受该货币符号的地区设置中将使用 US$,或者如果本地化符号未知,则使用备用货币代码 USD。
日期和时间的格式化和解析
用于日期和时间的格式化和解析的 JSTL 自定义操作 <fmt:formatDate> 和 <fmt:parseDate> 基于 J2SE 类 java.text.DateFormat 并用于处理不同的日期和时间表示方法。
令人感兴趣的一点是显示的日期和时间不仅仅取决于一种指定地区设置的格式,还取决于时区信息。 用户通常对服务器时区不感兴趣,但另一方面,要找出用户所在地的时区却并不简单。应用程序可以通过使用一些客户端的 JavaScript 代码来找出用户的当前时区与格林尼治标准时间的偏差,或让用户指定当前时区并将其作为用户信息的一部分。 JSTL 操作并没有解决这个问题,但它们提供了两个自定义操作,可以用来告知有关时区的日期和时间的格式化和解析:<fmt:timeZone> 和 <fmt:setTimeZone>。 与 <fmt:bundle> 和 <fmt:setBundle> 一样,<fmt:timeZone> 标记可为嵌套标记定义时区,而 <fmt:setTimeZone> 将时区储存在一个变量中以供后继操作使用。
信息格式化
<fmt:message> 操作(前面已提及)不但能从一个资源束中获取一个字符串并将其插入至生成的页面中,而且它还可以执行参数替换并根据需要格式化参数。 它基于 java.text.MessageFormat 类,因此该操作获取的字符串实际上是一个 MessageFormat 模式字符串。 <fmt:param> 操作提供了必要的自变量。
例如,如果 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>
并且找到的资源束是德语,而且 为 greeting 键提供了“Willkommen! Heute ist der {0,date,long}.”值,那么生成日期为(假设)2002 年 6 月 21 日的页面内容将会是“Willkommen! Heute ist der 21. Juni 2002.”
发表评论
-
欢迎关注微信公众账号PigCode
2014-03-25 21:02 931开通了微信公众账号,欢迎大家关注: PigCode 不定 ... -
[FAQ]为什么引入lambda表达式
2013-07-02 20:54 1587Lambda表达式(闭包)在很多现代化的编程语言中很常见。在 ... -
[FAQ]什么是lambda表达式
2013-07-01 23:01 1503在一般数学计算中,lambda表达式就 ... -
Java&Scala比较---设计模式(Singleton)
2013-03-31 11:56 1328单例模式在Scala中就是一个默认实现的模式。 对于Java中 ... -
榨干Hello World:J2SE篇
2010-07-26 23:43 0昨天一时兴起想起这个问题(我好像一般都是一时兴起才会写 ... -
使用Ant部署项目细节问题及解决办法
2009-04-23 22:57 4105说原创也谈不上, ... -
重构?测试?TDD?Ant?
2009-04-11 23:56 2884很意外的,今天花 ... -
《重构:改善既有的代码设计》笔记
2009-03-21 15:30 0现在越看自己的代码越感觉恶心,感觉写得太糟糕了,根本见 ... -
5分钟搞定Schema
2008-12-18 21:38 3296事先声明:搞定不是精通,只是能够运用! 其实schema很简单 ... -
JNDI学习
2008-12-02 17:50 0之前接触过一点E ... -
Struts2源码研究1
2008-08-21 17:30 4992看struts2一周,就搞定了一个程序,郁闷。还有源码里的一个 ... -
将Struts2+EJB3程序从eclipse转移到Intellij Idea上
2008-08-20 16:12 2188之前写了个Struts2+EJB3的入门程序,好不容易搞 ... -
坎坷的Struts2+EJB3入门程序
2008-08-15 22:24 5088最近在看Struts2和EJB3,出于好奇,就想试试用部署在t ... -
集成jdk到editplus(转)
2008-04-11 21:11 1645对于像我这样的java新手,写java程序用edit ... -
Intellij idea性能优化
2008-03-24 12:54 9147-Xms256m -Xmx384m -XX:MaxPermSi ... -
Struts meets Swing 1 (翻译)
2008-03-13 13:49 2110原文:http://javaboutique.internet ... -
使用Maven2快速创建项目(转)
2008-01-30 16:33 13044源地址:http://www.intellij.org.cn/ ... -
什么是Spring(转)
2008-01-16 13:00 1726最近研究Spring,她包含 ... -
Intellij IDEA的部署问题。。。
2008-01-03 17:22 5321在网上偶尔都能看到说Intellij IDEA是如何的好 ... -
JasperReports Web Application Sample (翻译)
2007-12-20 14:20 4500Web Application Sample This sam ...
相关推荐
"jsp实现国际化dwi18n"是一个示例项目,旨在演示如何在JSP应用中实现多语言支持,即“国际化”功能。国际化是一个重要的设计原则,它允许软件产品适应不同地区的语言和文化习惯。 1. **什么是国际化(i18n)?** ...
本示例“JSP国际化_demo”提供了中文和英文两种语言的支持,旨在帮助开发者理解如何在JSP中实现国际化功能。** 在JSP中实现国际化,主要依靠以下三个关键组件: 1. **资源文件(Resource Bundle)**:资源文件通常...
3. **JSP 国际化** 在JSP中,我们可以通过 `<fmt:setLocale>` 标签来设置当前请求的 Locale。然后,使用 `<fmt:message>` 标签来获取与当前 Locale 对应的资源包中的字符串。 4. **语言切换实现** - 用户界面:...
在JSP中,实现国际化通常涉及以下几个关键元素: 1. **资源文件**(Resource Bundle):以.properties格式存储不同语言的文本内容,例如`messages_en.properties`(英文)和`messages_zh_CN.properties`(简体中文...
在这个特定的例子中,我们关注的是`JSP`的`国际化(i18n)`应用。`i18n`是`internationalization`的缩写,意指软件或网站的设计和开发考虑到全球不同地区的用户需求,支持多种语言和文化环境。 `JSP`的`国际化`主要...
JSP(JavaServer Pages)提供了一种强大的工具来处理这个问题,通过使用JSTL(JavaServer Pages Standard Tag Library)的`fmt`标签库,我们可以轻松地实现货币和日期的国际化格式化。 1. **货币格式化** 在JSP中...
然后,在 JSP 文件中使用 fmt 标记来实现客户浏览器语言国际化。 解决方案二:基于动态加载的国际化配置 第二种解决方案是基于动态加载的国际化配置。这可以实现基于请求的国际化配置或基于 Session 的国际化配置...
在现代Web开发中,为了让网站或应用能够适应全球不同地区的用户,实现“国际化”(Internationalization,简称i18n)变得越来越重要。本主题主要关注如何通过纯前端技术实现Web页面的多语言切换,让内容能够以用户...
标题 "spring国际化jsp" 暗示我们讨论的是在Spring框架中实现Web应用程序的国际化(i18n)过程,特别是在使用JSP(JavaServer Pages)时。这通常涉及到资源包(properties文件)的使用,以存储不同语言的文本字符串...
在Web应用开发中,特别是使用Struts框架时,中文显示和国际化(Internationalization,简称i18n)问题是开发者常遇的挑战。本文将深入探讨解决Struts中文问题及国际化问题的终极方案,确保不同地区和语言环境下的...
在JSP中,格式化数字是一项常见的任务,特别是在展示数据时,我们往往需要将数字以特定的格式呈现,比如...同时,这些格式化功能也为国际化和本地化提供了便利,可以根据不同地区的习惯自动调整数字和日期的显示格式。
JSP通过资源包(Resource Bundle)实现国际化,根据用户的选择或浏览器设置,加载相应的语言文件。 8. **安全性** 企业办公系统的安全尤为重要。JSP项目通常会包含防止SQL注入、XSS攻击的措施,以及用户身份验证和...
在SpringMVC中实现国际化,可以通过配置`HandlerInterceptor`拦截器或者在控制器中设置`LocaleResolver`来实现,允许用户在请求中切换语言。 5. **SpringMVC的国际化实现**: 在SpringMVC中,我们可以在`web.xml`中...
它们可以从资源包中获取,允许开发者将消息文本与实际代码分离,方便国际化。 4. **Struts标签库**: - Struts1提供了一套丰富的JSP标签库,如`<bean:message>`和`<html:error>`,这些标签可以方便地与资源包中的...
通过这种方式,我们可以实现一个功能强大的自定义JSP标签库,它不仅支持文本国际化,还能处理图片和JavaScript文件的国际化,使得Web应用更加灵活且易于维护。在实际项目中,可以根据具体需求调整标签库的功能和结构...
在jsp应用程序中,我们可能需要使用资源文件来存储国际化信息。在这种情况下,可能出现中文乱码问题。解决方法是使用jdk的native2ascii工具将资源文件转换为ASCII编码,然后使用ResourceBundle Editor插件来编辑资源...
在SSM框架上实现国际化和多语言功能,可以使得应用程序能够适应不同国家和地区用户的语言需求,提升用户体验。以下将详细介绍如何在SSM框架中实现这一功能。 首先,我们需要理解“国际化”(Internationalization)...
1. JSP文件:包含实现表单验证和国际化逻辑的JSP页面。这些页面可能包含了HTML元素、JSP脚本和EL表达式,用于处理用户输入并展示错误信息。 2. JavaBean类:可能包含了用于验证表单数据的业务逻辑,这些Java类通常...
**国际化和本地化** 在JSP中,可以通过资源包(properties文件)支持不同地区的语言,为用户提供本地化的界面。 **安全性** JSP开发需要注意防止SQL注入、跨站脚本攻击(XSS)等问题,通过验证用户输入、使用预编译...
9. **国际化与本地化**:如果案例中涉及,可以学习如何实现多语言支持,使用资源包处理不同地区的语言需求。 10. **性能优化**:分析源码时,还可以关注缓存策略、减少数据库查询、页面静态化等优化手段,提升系统...