国际化概述
软件的国际化:软件开发时,要使它能同时应对世界不同地区和国家的访问,并针对不同地区和国家的访问,提供相应的、符合来访者阅读习惯的页面或数据。
国际化又简称为 i18n:internationalization(18是指i与n之间省略的18个字母)
软件实现国际化,需要具备的条件
对于程序中固定使用的静态文本数据,例如菜单栏、导航条等中使用的文本元素、或错误提示信息,状态信息等,需要根据来访者的地区和国家,选择不同语言的文本为之服务。
对于程序动态产生的数据,例如(日期,货币等),软件应能根据当前所在的国家或地区的文化习惯进行显示。
注意:一个合格的国际化软件必须包含
静态数据和
动态数据的国际化。
国际化--静态数据
对于软件中的菜单栏、导航条、错误提示信息,状态信息等这些固定不变的文本信息,可以把它们写在一个properties文件中,并根据不同的国家编写不同的properties文件。这
一组properties文件称之为
一个资源包。
在JavaAPI中提供了一个
ResourceBundle 类用于描述一个资源包,并且 ResourceBundle类提供了相应的方法
getBundle(
参数1,参数2
)(参数1:包名+资源文件基名,参数2:Locale 对象表示了特定的地理、政治和文化地区)
,这个方法可以根据来访者的国家地区自动获取与之对应的资源文件予以显示。
创建资源包和资源文件
一个资源包中的每个资源文件都必须拥有共同的
基名。除了基名,每个资源文件的名称中还必须有标识其本地信息的附加部分。
例如:一个资源包的基名是“myproperties”,则与中文、英文环境相对应的资源文件名则为:
“myproperites_zh.properties” “myproperites_en.properties”
每个资源包都应有一个默认资源文件,这个文件不带有标识本地信息的附加部分。若ResourceBundle对象在资源包中找不到与用户匹配的资源文件,它将选择该资源包中与用户最相近的资源文件,如果再找不到,则使用默认资源文件。例如:
myproperites.properties
资源文件的书写格式
资源文件的内容通常采用“关键字=值”的形式,软件根据关键字检索值显示在页面上。一个资源包中的所有资源文件的关键字必须相同,值则为相应国家的文字。
资源文件中采用的是properties格式文件,所以文件中的所有字符都必须是ASCII字码,对于像中文这样的非ACSII字符,须先进行编码,
属性文件是不能保存中文的
。(java提供了一个native2ascII命令用于编码,像MyEclipse登工具,提供可视化的编辑界面,可直接输入中文,会自动转成ASCII字码)。
静态数据国际化案例
资源包com.cn.i18n.i18nProperties_en.properties(包名+基名+语言简称.properties)
hello=Hello
userName=User Name
pwd=Password
资源包com.cn.i18n.i18nProperties_zh.properties(包名+基名+语言简称.properties)
hello=\u60A8\u597D
userName=\u7528\u6237\u540D
pwd=\u5BC6\u7801
测试代码
/**
* 国际化—静态数据
* @throws Exception
*/
@Test
public void testI18n1() throws Exception {
//中文语言环境
// Locale locale = Locale.CHINA;
Locale locale = Locale.getDefault();//获得此 Java 虚拟机实例的当前默认语言环境值。
/**
创建工具类对象ResourceBundle
1.getBundle(参数1,参数2);
参数1:包名+资源包基名(必须为完整路径)
2.一个资源包中的每个资源文件都必须拥有共同的基名。除了基名,每个资源文件的名称中还必须有标识其本地信息的附加部分。例如:一个资源包的基名是“myproperties”,则与中文、英文环境相对应的资源文件名则为:“myproperites_zh.properties” “myproperites_en.properties”
每个资源包都应有一个默认资源文件,这个文件不带有标识本地信息的附加部分。若ResourceBundle对象在资源包中找不到与用户匹配的资源文件,它将选择该资源包中与用户最相近的资源文件,如果再找不到,则使用默认资源文件。例如:myproperites.properties
*/
ResourceBundle bundle = ResourceBundle.getBundle("com.cn.i18n.i18nProperties", locale);//国际化资源文件资源文件全名:i18nProperties_en.properties 或 i18nProperties_cn.properties
//根据key获取配置文件中的值
System.out.println(bundle.getString("hello"));
System.out.println(bundle.getString("userName"));
System.out.println(bundle.getString("pwd"));
}
不同模拟语言的环境下的效果
国际化--动态数据
数值,货币,时间,日期等数据由于可能在程序运行时动态产生,所以无法像文字一样简单地将它们从应用程序中分离出来,而是需要特殊处理。Java 中提供了解决这些问题的 API 类(位于 java.util 包和 java.text 包中)
Locale 类
Locale 实例对象代表一个特定的地理,政治、文化区域。
一个 Locale 对象本身不会验证它代表的语言和国家地区信息是否正确,只是向本地敏感的类提供国家地区信息,与国际化相关的格式化和解析任务由本地敏感的类去完成。(若JDK中的某个类在运行时需要根据 Locale 对象来调整其功能,这个类就称为本地敏感类)
/**
* 1.本地化对象:Locale
* 封装语言、国家信息的对象,有java.util提供
* @throws Exception
*/
@Test
public void testLocale() throws Exception {
//模拟中国语言环境
System.out.println("***************************模拟中国语言环境");
// Locale china = Locale.CHINA;
Locale china = Locale.getDefault(); //获取当前系统默认的语言环境
System.out.println(china.getCountry()); //CN 国家的简称
System.out.println(china.getDisplayCountry()); //中国 国家名称
System.out.println(china.getLanguage());//zh 语言简称
//模拟美国语言环境
System.out.println("***************************模拟美国语言环境");
Locale us = Locale.US;
System.out.println(us.getCountry());
System.out.println(us.getDisplayCountry());
System.out.println(us.getLanguage());
}
DateFormat 类
DateFormat 类可以将一个日期/时间对象格式化为表示某个国家地区的日期/时间字符串。
DateFormat 类除了可按国家地区格式化输出日期外,它还定义了一些用于描述日期/时间的显示模式的 int 型的常量,包括FULL, LONG, MEDIUM, DEFAULT, SHORT,实例化DateFormat对象时,可以使用这些常量,控制日期/时间的显示长度。
显示模型效果:
/**
* 国际化日期
* 日期格式
* FULL 2017年5月4日 星期四
* LONG 2017年5月4日
* MEDIUM 2017-5-4
* DEFAULT 2017-5-4
* SHORT 17-5-4
* 时间格式
* FULL 上午09时01分18秒 CST
* LONG 上午09时01分05秒
* MEDIUM 9:01:33
* DEFAULT 9:01:42
* SHORT 上午9:02
* @throws Exception
*/
@Test
public void testI18n7() throws Exception {
//日期格式
int dateStyle = DateFormat.DEFAULT;//参数常量可为:FULL, LONG,MEDIUM, SHORT
//时间格式
int timeStyle = DateFormat.DEFAULT;
//模拟语言环境
Locale locale = Locale.CHINA;
//工具类
DateFormat df = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
String str = df.format(new Date());将date对象格式化为符合某个本地环境习惯的字符串。
System.out.println(str);
}
/**
* 笔试题目:将时间值:09-11-28 上午10时25分39秒 CST,反向解析成一个date对象
*/
@Test
public void testI18n8() throws Exception {
//日期格式
int dateStyle = DateFormat.SHORT;
//时间格式
int timeStyle = DateFormat.FULL;
//语言环境
Locale locale = Locale.CHINA;
//工具类
DateFormat df = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
//解析
String str = "09-11-28 上午10时25分39秒 CST";
Date date = df.parse(str);//将字符串解析为日期/时间对象
System.out.println(date);
}
/**
* 国际化日期
* 日期格式
* FULL 2017年5月4日 星期四
* LONG 2017年5月4日
* MEDIUM 2017-5-4
* DEFAULT 2017-5-4
* SHORT 17-5-4
* 时间格式
* FULL 上午09时01分18秒 CST
* LONG 上午09时01分05秒
* MEDIUM 9:01:33
* DEFAULT 9:01:42
* SHORT 上午9:02
* @throws Exception
*/
@Test
public void testI18n7() throws Exception {
//日期格式
int dateStyle = DateFormat.DEFAULT;//参数常量可为:FULL, LONG,MEDIUM, SHORT
//时间格式
int timeStyle = DateFormat.DEFAULT;
//模拟语言环境
Locale locale = Locale.CHINA;
//工具类
DateFormat df = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
String str = df.format(new Date());将date对象格式化为符合某个本地环境习惯的字符串。
System.out.println(str);
}
/**
* 笔试题目:将时间值:09-11-28 上午10时25分39秒 CST,反向解析成一个date对象
*/
@Test
public void testI18n8() throws Exception {
//日期格式
int dateStyle = DateFormat.SHORT;
//时间格式
int timeStyle = DateFormat.FULL;
//语言环境
Locale locale = Locale.CHINA;
//工具类
DateFormat df = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
//解析
String str = "09-11-28 上午10时25分39秒 CST";
Date date = df.parse(str);//将字符串解析为日期/时间对象
System.out.println(date);
}
NumberFormat 类
实例化NumberFormat类时,可以使用locale对象作为参数,也可以不使用,下面列出的是使用参数的。
getNumberInstance(Locale locale):以参数locale对象所标识的本地信息来获得具有多种用途的NumberFormat实例对象
getIntegerInstance(Locale locale):以参数locale对象所标识的本地信息来获得处理
整数的NumberFormat实例对象
getCurrencyInstance(Locale locale):以参数locale对象所标识的本地信息来获得处理
货币的NumberFormat实例对象
getPercentInstance(Locale locale):以参数locale对象所标识的本地信息来获得处理
百分比数值的NumberFormat实例对象
/**
* 国际化货币
* @throws Exception
*/
@Test
public void testI18n3() throws Exception {
//模拟语言环境
// Locale locale = Locale.CHINA;
Locale locale = Locale.US;
//数据准备
double number = 100;
//工具类
NumberFormat nf = NumberFormat.getCurrencyInstance(locale);//返回指定语言环境的货币格式。
//国际化货币
String money = nf.format(number);
//测试
System.out.println(money);
}
/**
* 面试题:代码计算 $100*10
* @throws Exception
*/
@Test
public void testI18n4() throws Exception {
//准备数据
String str = "$100";
int number = 10;
//1.分析str值是哪一国家的货币
//模拟语言环境
Locale locale = Locale.US;
//2.工具类
NumberFormat nf = NumberFormat.getCurrencyInstance(locale);//返回指定语言环境的货币格式。
//3.解析str货币
Number n = nf.parse(str);
System.out.println(nf.format(n.doubleValue()*number));//结果为:$1,000.00
}
/**
* 国际化数值
* @throws Exception
*/
@Test
public void testI18n5() throws Exception {
//模拟语言环境
// Locale locale = Locale.US;
Locale locale = Locale.CHINA;
NumberFormat nf = NumberFormat.getNumberInstance(locale);// 返回指定语言环境的通用数字格式。
String str = nf.format(100000000);
System.out.println(str);//结果为:100,000,000
}
/**
* 国际化百分比
*/
@Test
public void testI18n6() throws Exception {
//模拟语言环境
Locale locale = Locale.US;
NumberFormat nf = NumberFormat.getPercentInstance(locale);
String str = nf.format(99.88);
System.out.println(str);//结果为:9,988%
}
国际化--JSP页面
方式1:(由于使用了jsp脚本,所以尽量不用此方法)
资源文件如下:
代码如下:
效果如下:
英文访问:
中文访问:
附加:(设置浏览器语言,以IE浏览器为例)
工具 --> Internet选项 --> ”常规“ --> 外观 --> 语言 --> 添加你需要的语言类型并上移到最上面即选择了浏览器的访问语言。
方式2:(使用jstl标签,推荐)
代码如下:
<%-- 引入jstl国际化与格式化标签库 --%>
<%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
效果如下:
英文环境访问:
中文环境访问:
jstl标签:国际化与格式化标签库
常用的标签:
<fmt:setLocale>标签
<fmt:setLocale>标签用于在JSP页面中显示的设置用户的本地化信息,并将设置的本地信息以Locale对象的形式保存在某个web域中。
语法:<fmt:setLocale value=“locale”
[variant=“variant”]
[scope=“{page|request..}”]/>
例如:<fmt:setLocale value="${pageContext.request.locale }"/>
设置本地化对象
属性名 | 是否支持EL | 类型说明 | 属性描述 |
value | true | String或java.util.Locale | 指定用户的本地化信息,可以是一个字符串或java.util.Local实例对象。如果是字符串必须包含小写的语言名而后是大写的国家名:zh_CN |
variant | true | String | 指定创建Locale实例对象时设置的变量部分,它作用于标识开发商或特定浏览器为实现扩展功能而自定义的信息。 |
scope | false | String | 指定构造出来的Locale实例对象保存在哪个web作用域中。 |
<fmt:setBundle>标签
<fmt:setBundle>标签用于根据<fmt:setLocale>标签设置的本地化信息创建一个资源包(ResourceBundle)实例对象,并将其绑定到一个web域的属性上。
语法:<fmt: setBundle basename=“basename”
[var=“varname”]
[scope=“{page|request|session|application}”] />
例如:<fmt:setBundle basename="com.cn.i18n.i18nProperties" var="bundle"/>
设置工具类
属性名 | 是否支持EL | 属性类型 | 属性描述 |
basename | true | String | 指定创建ResourceBundle实例对象的基名。 |
var | false | String | 指定将创建出来的ResourceBundle实例对象保存在web域中的属性名。 |
scope | false | String | 指定将创建出来的ResourceBundle实例对象保存在哪个web作用域中。 |
<fmt:message>标签
<fmt:message>标签用于从一个资源包中读取信息并进行格式化输出。
语法:<fmt:message key=“messageKey”
[bundle=“resourceBundle”]
[var=“varname”]
[scope=“page|request|session|application”] />
例如:<fmt:message bundle="${bundle }" key="title" />
显示国际化文本
属性名 | 是否支持EL | 属性类型 | 属性描述 |
key | true | String | 指定要输出的信息的关键字。 |
bundle | true | LocalizationContext | 指定ResourceBundle对象在web域中的属性名称。 |
var | false | String | 用于指定格式化输出结果保存到某个web域中的属性名。 |
scope | false | String | 指定将格式化结果保存到哪个web域中。 |
<fmt:formatNumber>标签
格式化数值
pattern:0.00
保留2位小数,会自动补0
pattern:#.##
保留2位小数,不自动补0
<fmt:formatNumber value="999" pattern="0" ></fmt:formatNumber><br/>
<fmt:formatNumber value="999" pattern="0.0" ></fmt:formatNumber><br/>
<fmt:formatNumber value="999.9" pattern="0.00" ></fmt:formatNumber><br/>
<fmt:formatNumber value="999.99" pattern="0.000" ></fmt:formatNumber><br/>
<fmt:formatNumber value="999.9959" pattern="#.##" ></fmt:formatNumber><br/>
<fmt:formatNumber value="999.9929" pattern="#.##" ></fmt:formatNumber><br/>
<fmt:formatDate>标签
格式化日期
<fmt:formatDate value="${requestScope.date }" pattern="yyyy-MM-dd HH:mm:ss"/>
案例:
代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%-- 引入jstl国际化与格式化标签库 --%>
<%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<!--
格式化数字
pattern:0.00 保留2位小数,会自动补0
pattern:#.## 保留2位小数,不自动补0
-->
<fmt:formatNumber value="999" pattern="0" ></fmt:formatNumber><br/>
<fmt:formatNumber value="999" pattern="0.0" ></fmt:formatNumber><br/>
<fmt:formatNumber value="999.9" pattern="0.00" ></fmt:formatNumber><br/>
<fmt:formatNumber value="999.99" pattern="0.000" ></fmt:formatNumber><br/>
<fmt:formatNumber value="999.9959" pattern="#.##" ></fmt:formatNumber><br/>
<fmt:formatNumber value="999.9929" pattern="#.##" ></fmt:formatNumber><br/>
<hr/>
<%
request.setAttribute("date", new Date());
%>
<%-- 格式化日期 --%>
<fmt:formatDate value="${requestScope.date }" pattern="yyyy-MM-dd HH:mm:ss"/>
</body>
</html>