什么是国际化
指软件在开发时就应该具备支持多种语言和地区的功能,当应对不同国家和地区的用户访问,针对不同国家和地区的用户,提供相应的、符合来访者阅读习惯的页面和数据。
由于国际化internationalization这个单词的首字母“i”和尾字母“n”之间有18个字符,因此国际化被简称为i18n。
实现国际化的API
Locale类
几乎所有对国际化的支持都需要依赖这个类
如何创建Locale实例对象
使用Locale类的构造方法
有三个重载的构造方法
public Locale(String language)
public Locale(String language,String country)
public Locale(String language,String country,String variant)
如果Locale对象仅仅用于说明当地的语言信息,则使用第一个构造方法:
Locale enLocale = new Locale("en");
如果要创建一个标识当地语言信息以及国家信息的Locale对象时,使用第二个构造方法即可:
Locale enLocale = new Locale("en","US");
如果要创建一个带有附加变量的Locale对象时,则使用第三个构造方法即可,例如,创建一个标识传统西班牙排序的Local对象,具体示例如下:
Locale enLocale = new Locale("es","ES","Traditional_WIN");
使用Locale类的常量
如Locale.ENGLISH、Locale.GERMAN、Locale.US、Locale.HK等,这些常量分别对应一些提前创建好的表示不同语言和国家的Locale对象。
Locale locale=Locale.CHINESE;
常用方法
String getCountry()
获取Locale实例对象的ISO国家代码
String getLanguage()
获取Locale实例对象的ISO语言代码
String getVariant()
获取Locale实例对象的变量编码
String getDisplayCountry()
获取Locale实例对象适合显示给用户的国家名称
String getDisplayCountry(Locale inLocale)
String getDisplayLanguage()
获取Locale实例对象适合显示给用户的语言名称
String getDisplayLanguage(Locale inLocale)
String getDisplayName()
获取Local实例对象显示的名称
String getDisplayName(Locale inLocale)
ResourceBundle类
在开发一个国际化的Web应用时,通常会存储许多用于保存各个国家语言的资源文件,这些资源文件都需要使用类加载器来加载,这样的加载方式比较麻烦。
为了方便获取这些资源文件,JDK提供了一个ResourceBundle类,该类用于描述一个资源包,对于不同的本地环境,可以有不同的ResourceBundle对象与之关联。
资源包简介
在设计一个国际化的应用时,应该把程序显示的文本内容(例如,菜单和按钮的标题)从源文件中分离出来,放在独立的资源文件(扩展名为.properties的文件)中,并针对不同的本地环境编写不同的资源文件。
一个资源包中每个资源文件都必须拥有共同的基名。除了基名,每个资源文件的名称中还必须有标识其本地信息的附加部分。
例如:一个资源包的基名是myproperties,对应资源文件的名称如下:
默认资源文件名:myproperites.properties
对应的中文资源文件名为:myproperites_zh.properties
对应的英文资源文件名为:myproperites_en.properties
资源文件格式
username=itcast
创建ResourceBundle对象,读取资源文件
ResourceBundle类提供了两个用于创建ResourceBundle对象的静态方法,该方法用于装载资源文件,并创建ResourceBundle实例
getBundle(String baseName)
getBundle(String baseName,Locale locale)
参数baseName用于指定资源文件的名称,参数Locale用于指定使用的Locale对象,如果没有指定Locale参数,则使用本地默认的Locale
Locale locale=Locale.US;
ResourceBundle myResources= ResourceBundle.getBundle("MyResources",locale);
DateFormat类
可以将一个日期/时间对象格式化为表示某个特定地区的日期/时间字符串,也可以将某个地区的日期/时间的字符串解析为相应的Date对象。
DateFormat中的常量
包括SHORT 、DEFAULT、MEDIUM、LONG、FULL,在实例化DateFormat对象时,可以使用这些常量控制日期/时间的显示长度。
SHORT模式完全是数字的,这个日期/时间显示的格式为“13-12-11 下午4:41”;
MEDIUM模式比SHORT模式长些,这个日期/时间显示的格式为“2013-12-11 16:41:20”
LONG模式比MEDIUM模式更长一些,这个日期/时间显示的格式为“2013年12月11日 下午04时41分20秒”
FULL模式指定日期/时间的完整格式,这个日期/时间显示的格式为“2013年12月11日 星期三 下午04时41分20秒 CST”
DEFAULT表示默认的显示模式,它的值为MEDIUM。
获取DateFormat类的实例对象
由于DateFormat是一个抽象类,不能使用构造方法创建实例对象,因此,JDK提供了一些用于获取DateFormat实例对象的静态方法
getDateInstance(int style, Locale aLocale):以指定的日期显示模式和本地信息来获取DateFormat对象,该对象不处理时间值部分。
getTimeInstance(int style, Locale aLocale):以指定的时间显示模式和本地信息来获取DateFormat对象,该对象不处理日期值部分。
getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale):以单独指定的日期显示模式、时间显示模式和本地信息来获得DateFormat实例对象。
日期/时间的格式化和解析
format()方法
将日期/时间对象格式化为符合本地习惯的字符串
String dateTime=DateFormat.getDateTimeInstance().format(new Date());
parse()方法
将某个本地习惯的日期/时间字符串解析为Date对象
DateFormat df = DateFormat.getDateInstance(DateFormat.Long,Locale.US);
Date date = df.parse("September 15,2013");
NumberFormat类
可以将一个数值格式化为本地格式的字符串,也可以将某个本地格式的数值字符串解析为对应的数值
获取NumberFormat类的实例对象
实例化NumberFormat类时,可以使用Locale对象作为参数,也可以不使用,接下来列举使用Locale对象作为参数的方法
getNumberInstance(Locale locale):以参数Locale对象所标识的本地信息来获取具有多种用途的NumberFormat实例对象
getIntegerInstance(Locale locale):以参数Locale对象所标识的本地信息来获取处理整数的NumberFormat实例对象
getCurrencyInstance(Locale locale):以参数Locale对象所标识的本地信息来获取处理货币的NumberFormat实例对象
getPercentInstance(Locale locale):以参数Locale对象所标识的本地信息来获取处理百分比数值的NumberFormat实例对象
数值的格式化和解析
format()方法
将一个数值格式化为符合某个国家或地区习惯的数值字符串
String numberString = NumberFormat.getInstance().format(12345);
parse()方法
将符合某个国家或地区习惯的数值字符串解析为对应的Number对象
NumberFormat nf = NumberFormat.getInstance(Locale.ENGLISH);
Number number=nf.parse("12.345");
MessageFormat类
用参数替换模式字符串中的占位符的方式,它将根据模式字符串中包含的占位符产生一系列的格式化对象,然后调用这些格式化对象对参数进行格式化,并将格式化后的结果字符串插入到模式字符串中的适当位置
模式化字符串与占位符
On {0},there was {1} on planet {2}.
花括号以及花括号内的数字被称为占位符,如{0}、{1},这些占位符都会被MessageFormat格式化的参数所代替
MessageFormat类格式化模式字符串
创建MessageFormat对象
两个构造方法
public MessageFormat(String pattern)
public MessageFormat(String pattern, Locale locale)
调用MessageFormat对象的format()方法
用于执行模式字符串的格式化操作,在调用format()方法时,需要传递一个Object类型的参数数组,数组中的每个元素分别用于替换模式字符串中与其索引对应的占位符。
加强对MessageFormat的学习
占位符总共有三种形式
{ ArgumentIndex }
{ ArgumentIndex , FormatType }
{ ArgumentIndex, FormatType, FormatStyle }
开发国际化的Web应用
获取Web应用中的本地信息
要实现Web应用的国际化,首先需要获取客户端浏览器的本地信息,根据客户端浏览器的本地信息来访问相应的资源文件。
大多数Web浏览器通常会在HTTP请求消息中通过Accept-Language消息头附带本地信息,Web容器则可以根据Accept-Language消息头创建标识客户端本地信息的Locale对象。
HttpServletRequest对象提供了两个方法
getLocale()方法
用于返回代表客户端的首选本地信息的Locale对象
getLocales()方法
用于返回一个Enumeration集合
国际化标签库
为了简化Web应用的国际化开发,JSTL中提供了一个用于实现国际化和格式化功能的标签库,简称为国际化标签库,其前缀名为fmt。
国际化标签库封装了java.util和java.text这两个包中与国际化相关的API类的功能,并提供了绑定资源包和从资源包中的本地资源文件内读取文本内容的标签、对数值和日期等本地敏感的数据按本地化信息进行显示和解析的标签、按本地特定的时区来调整时间的标签。
如果要在JSP页面中使用格式化的标签,需要用taglib指令指明这个标签库的路径为
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
设置全局信息标签
<fmt:setLocale>标签
设定语言地区
用于在JSP页面中显式地设置用户的本地化信息,并将设置的本地化信息以Locale对象的形式保存在某个Web域中。
使用<fmt:setLocale>标签设置本地化信息后,国际化标签库中的其他标签将使用该本地化信息,而忽略客户端浏览器传递过来的本地信息。
用来设定用户的语言地区代码,即设置格式化或解析日期/时间、数值时所使用的语言环境。
<fmt:setLocale value="locale"
[variant="variant"]
[scope="{page|request|session|application}"]/>
variant:特定web浏览器或供应商代码
可以从http://www.w3.org/查询语言代码,在http://unicode.org找到国家和地区代码。例如en表示英文、en_US表示英文(美国)、zh_CN表示中文(中国)。
<fmt:requestEncoding>标签
设定请求的字符编码集合
用于设置统一的请求消息的字符集编码
用于向JSP容器指定请求(request)的字符编码
<fmt:requestEncoding [value="charsetName"]/>
value属性用于指定请求消息的字符集编码,其类型为String,支持动态属性值
设置请求编码:<fmt:requestEncoding value="gb2312"/>
相当于JSP内置对象中的setCharacterEncoding()方法
几点说明:
调用<fmt:requestEncoding>标签能够正确解码请求参数值中的非ISO-8859-1编码的字符,但是必须在获取任何请求参数之前进行调用。
有的浏览器没有完全遵守HTTP规范,在请求消息中没有包含Content-Type请求头,这时需要使用<fmt:requestEncoding>标签来设置请求编码。
如果不设置value属性,首先会采用请求消息的Content-Type头中定义的字符集编码,其次会采用session域中的javax.servlet.jsp.jstl.fmt.request.charest属性的值,再次会采用ISO-8859-1字符集编码。
信息显示标签
获取系统设定的语言资源,从而可以轻易地做到多国化信息
<fmt:message>标签
用于从一个资源包中读取信息并进行格式化输出
语法1:没有标签体的情况
<fmt:message key="messageKey"
[bundle="resourceBundle"]
[var="varName"]
scope="{page|request|session|application}"/>
语法2:在标签体中指定格式化文本串中的占位符参数的情况
<fmt:message key="messageKey"
[bundle="resourceBundle"]
[var="varName"]
scope="{page|request|session|application}">
<fmt:param>subtags
</fmt:message>
语法3:在标签体重指定消息关键字和可选择的占位符参数
<fmt:message key="messageKey"
[bundle="resourceBundle"]
[var="varName"]
scope="{page|request|session|application}">
key
optional <fmt:param>subtags
</fmt:message>
<fmt:Bundle>标签
用于根据<fmt:setLocale>标签设置的本地化信息创建一个资源包实例对象,但它创建的ResourceBundle实例对象只在其标签内有效。
用来根据本地化环境来选择所需的资源包
<fmt:Bundle basename="basename" [prefix="prefix"]>
body content
</fmt:Bundle>
<fmt:setBundle>标签
用于创建一个资源包实例对象,并将其绑定到一个Web域的属性上。用来为本地化环境设置一个缺省的资源包,在<fmt:message>标签的特定作用域内起作用<fmt:setBundle basename="basename" [var="varName"] [scope="{page|request|session|application}"]/>
basename属性:用于指定创建ResourceBundle实例对象的基名。
var属性:用于指定将创建出的ResourceBundle实例对象保存到 Web域中的属性名称。
scope属性:用于指定将创建出的ResourceBundle实例对象保存在哪个Web作用域中。
一些特性:
如果basename属性的值为null、空字符串或找不到basename属性指定的资源,<fmt:setBundle>标签保存到Web域中的属性的值为null。
如果没有指定var属性,<fmt:setBundle>标签将把ResourceBundle实例对象以域属性名javax.servlet.jsp.jstl.fmt.localizationContext保存到Web域中。所有没有嵌套在<fmt:Bundle>标签中且未指定bundle属性的<fmt:formatDate>都将使用该标签创建的资源包。
<fmt:param>标签
用于为格式化文本串中的占位符设置参数值,它只能嵌套在<fmt:message>标签内使用
用来为<fmt:message>标签指定文本消息参数值,动态的设定参数
语法1:用value属性指定参数值
<fmt:param value="messageParameter"/>
语法2:在标签体重指定参数的值的情况:
<fmt:param>
Body content
</fmt:param>
在使用消息标签之前,必须首先创建资源文件,其扩展名为properties,资源文件内容必须按照“key=value”的格式,也就是一个索引对应一个值。资源文件需要放置在应用程序的WEB-INF/classes目录下。
数字及日期格式化标签
<fmt:timeZone>标签
用于设置时区,但它的设置值只对其标签体部分有效
<fmt:timeZone value="timeZone">
Body content
</fmt:timeZone>
value属性支持动态属性值,它的值可以是一个命名时区的字符串,也可以是java.util.TimeZone类的一个实例对象。如果value属性的值为null或空字符串,标签体重的内容就使用GMT的0基准时区。如果value属性的值是表示时区名称的字符串,这个字符串通过java.util.TimeZone.getTimeZone()静态方法被解析为java.util.TimeZone类的实例对象。
<fmt:setTimeZone>标签
用于在JSP页面中显式的设置时区,并将设置的时区信息以TimeZone对象的形式保存在某个Web域中
<fmt:setTimeZone value="timeZone"
[var="varName"]
[scope="{page|request|session|application}"]/>
value属性用于指定表示时区的ID字符串或TimeZone对象。其值的设置与<fmt:timeZone>标签相同。<fmt:setTimeZone>标签将创建出的TimeZone实例对象保存在scope属性指定的Web域中,如果没有指定var属性,其在Web域中的属性名称为javax.servlet.jsp.jstl.fmt.timeZone,所有没有嵌套在其他<fmt:timeZone>标签中且未指定timezone属性的<fmt:formatDate>标签都将使用该属性名关联的时区。
<fmt:formatDate>标签
用于对日期和时间按本地化信息进行格式化,或对日期和时间按JSP页面作者自定义的格式进行格式化。
<fmt:formatDate value="date"
[type="{time|date|both}"]
[dateStyle="{dafault|short|medium|long|full}"]
[timeStyle="{dafault|short|medium|long|full}"]
[pattern="customPattern"]
[timeZone="timeZone"]
[var="varName"]
[scope="{page|request|session|application}"]/>
value
java.util.Date类
指定要进行格式化的日期/时间
type
String
指定要设置格式的Date实例的部分,可为time/date/both
dateStyle
String
设置使用于特定语言环境的日期格式,可为default/short/medium/long/full
timeStyle
String
设置使用于特定语言环境的时间格式,可为default/short/medium/long/full
pattern
String
用户自定义日期/时间格式
timeZone
String或java.util.TimeZone
需格式化的时间所在时区
var
String
用来存储格式化后结果的范围变量名
scope
String
范围变量var的作用域
<fmt:parseDate>标签
与<fmt:formatDate>标签的作用相反,它用于把已经格式化的标准日期格式解析成java.util.Date实例对象
<fmt:parseDate value="dateString"
[type="{time|date|both}"]
[dateStyle="{dafault|short|medium|long|full}"]
[timeStyle="{dafault|short|medium|long|full}"]
[pattern="customPattern"]
[timeZone="timeZone"]
[parseLocale="parseLocale"]
[var="varName"]
[scope="{page|request|session|application}"]>
date value to be parsed
</fmt:parseDate>
value
java.util.Date类
指定要进行解析的日期/时间
type
String
指定需要解析的Date实例的部分,可为time/date/both
dateStyle
String
设置Date实例日期部分解析方式,可为default/short/medium/long/full
timeStyle
String
设置Date实例时间部分解析方式,可为default/short/medium/long/full
pattern
String
用户自定义日期/时间的格式以确定解析方式
timeZone
String或java.util.TimeZone
需解析的时间所在时区
parseLocale
String或为java.util.Locale类
指定一种语言环境,根据这种语言环境来解析日期/时间值
var
String
用来存储解析结果的范围变量名
scope
String
范围变量var的作用域
需要注意的是,value属性的值必须是合法的日期/时间字符串,否则会抛出异常。
<fmt:formatNumber>标签
用于将数值、货币或百分数按本地化信息进行格式化
<fmt:formatNumber [type="{number|currency|percent}"]
[pattern="customPattern"]
[currencyCode="currencyCode"]
[currencySymbol="currencySymbol"]
[groupingUsed="true|false"]
[maxIntegerDigits="maxIntegerDigits"]
[minIntegerDigits="minIntegerDigits"]
[maxFractionDigits="maxFractionDigits"]
[minFractionDigits="minFractionDigits"]
[var="varName"]
[scope="{page|request|session|application}"]>
Number
</fmt:formatNumber>
value
String或为Number
指定需格式化的数值
type
String
指定格式化方式,其取值有number、currency、percent
pattern
String
用户自定义格式化方式
currencyCode
String
设置所显示数值的货币单位
currencySymbol
String
设置所显示数值的货币符号
maxintegerDigits
int
设置格式化后数值的最大整数位数
minintegerDigits
int
设置格式化后数值的最小整数位数
maxFractionDigits
int
设置格式化后数值的最大小数位数
minFractionDigits
int
设置格式化后数值的最小小数位数
groupingUsed
Boolean
指定格式化后是否要对小数点前面的数字分组
var
String
用来存储格式化后数值的范围变量名称
scope
String
范围变量var的作用域
需要注意的是,如果<fmt:formatNumber>标签不能确定格式化的本地环境,就使用Number.toString()作为输出格式。
<fmt:parseNumber>标签
与<fmt:formatNumber>标签的作用相反,它用于将一个按本地化方式被格式化后的数值、货币或百分数解析为数值
<fmt:parseNumber [type="{number|currency|percent}"]
[pattern="customPattern"]
[parseLocale="parseLocale"]
[intergerOnly="true|false"]
[var="varName"]
[scope="{page|request|session|application}"]>
Numberic value to be parsed
</fmt:parseNumber>
parseLocale属性用于指定解析字符串时所用的本地环境。intergerOnly属性用于指定是否只解析数值字符串的整数部分。在使用<fmt:parseNumber>标签解析值时要特别注意,它执行的解析非常严格,要解析的数值字符串必须严格符合特定的本地环境及pattern属性设置的自定义格式。
value
String
需解析的数值字符串
type
String
指定数值字符串,其取值有number、currency、percentage
pattern
String
用户自定义数值字符串的格式以确定解析方式
parseLocale
String或为java.util.Locale类
指定一种语言环境,根据这种语言环境来解析数值字符串
integerOnly
Boolean
设置要解析的部分是否仅为数值字符串的整数部分
var
String
存储数值解析结果的范围变量名
scope
String
范围变量var的作用域