一、概述
- 软件的国际化:软件开发时,要使它能同时应对世界不同地区和国家的访问,并针对不同地区和国家的访问,提供相应的、符合来访者阅读习惯的页面或数据。
- 国际化开发的(JavaWeb)具体:如 根据不同国家的来访者提供不同的语言
- 国际化又简称为 i18n:internationalization
- 区别翻译软件
1.1、合格的国际化软件
合格的国际化软件必须包含静态数据和动态数据的国际化。
1.2、固定文本元素的国际化
- 软件中固定不变的信息(菜单栏、导航条、错误提示信息等)写在一个properties文件中,根据不同的国家编写不同properties文件。这一组properties文件称之为一个资源包
- JavaAPI提供了一个ResourceBundle 类用于描述一个资源包,该类提供了一个getBundle方法可以根据来访者的国家地区自动获取相应的资源文件予以显示。
1.3、创建资源包与资源文件
- 资源包与资源文件必须由共同的基名
- 每个资源文件的名称中还必须有标识其本地信息的附加部分
- 举例:一个资源包的基名是“properties”,则与中文、英文环境相对应的资源文件名则为: “properites_zh.properties” “properites_en.properties”
- 每个资源包都应有一个默认资源文件,这个文件不带有标识本地信息的附加部分若ResourceBundle对象在资源包中找不到与用户匹配的资源文件,它将选择该资源包中与用户最相近的资源文件,如果再找不到,则使用默认资源文件;举例“properties.proerties”
1.4、资源文件的书写格式
- 资源文件中采用的是properties格式文件,所以文件中的所有字符都必须是ASCII字码。
- 像中文的非ACSII字符,须先进行编码。(java提供了一个native2ascII命令用于编码)
- 资源文件的内容采用“关键字=值”的形式,软件根据关键字检索值显示在页面上
- 资源包中的所有资源文件的关键字必须相同,值则为相应国家的文字
举例:
中文资源文件
username=\u7528\u6237\u540d
password=\u5bc6\u7801
submit=\u63d0\u4ea4
英文资源文件
username=username
password=password
submit=submit
二、实现固定文本的格式化 静态数据
2.1、实现固定文本格式化的步骤
1.ResourceBundle类该提供了一个静态方法getBundle,该方法用于装载资源文件,并创建ResourceBundle实例
Locale currentLocale = Locale.getDefault();
ResourceBundle myResources =
ResourceBundle.getBundle(basename, currentLocale);
basename为资源包基名(且必须为完整路径)。
2.如果与该locale对象匹配的资源包子类找不到。则选用默认资源文件予以显示。
3.加载资源文件后, 程序调用ResourceBundle 实例对象的 getString 方法获取指定的资源信息名称所对应的值。
String value = myResources.getString(“key");
4.在WEB应用中实现固定文本的国际化
2.2、示例
package cn.itcase.locale;
import java.util.Locale;
import java.util.ResourceBundle;
import org.junit.Test;
public class I18n {
// 国际化 静态数据
@Test
public void I18nTest() {
// 中文语言环境
Locale le = Locale.CHINA;
// System.out.println(le.getCountry());
// 创建工具类对象ResourceBundle
ResourceBundle bundle = ResourceBundle
.getBundle("cn.itcase.locale.msg", le);
// 根据key获取配置文件中的值
System.out.println(bundle.getString("hello"));
System.out.println(bundle.getString("username"));
System.out.println(bundle.getString("pwd"));
System.out.println(bundle.getString("title"));
System.out.println(bundle.getString("submit"));
}
}
msg.properties 中文环境
hello=\u4F60\u597D
username=\u7528\u6237\u540D
pwd=\u5BC6\u7801
title=\u767B\u9646\u9875\u9762
submit=\ \u767B\u9646
jsp页面
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<%
ResourceBundle bundle = ResourceBundle.getBundle("cn.itcase.locale.msg",request.getLocale());
%>
<base href="<%=basePath%>">
<title><%=bundle.getString("title") %></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>
<form name="frmLogin" action="${pageContext.request.contextPath }/admin?method=login" method="post">
<table align="center" border="1">
<tr>
<td><%=bundle.getString("username") %></td>
<td>
<input type="text" name="userName">
</td>
</tr>
<tr>
<td><%=bundle.getString("pwd") %></td>
<td>
<input type="password" name="pwd">
</td>
</tr>
<tr>
<td>
<input type="submit" value="<%=bundle.getString("submit") %>">
</td>
</tr>
</table>
</form>
</body>
</html>
三、动态数据国际化 动态数据
3.1、概述
- 程序运行动态产生的数据如:日期,数值,时间,货币等
- 无法进行简单的分离需要特殊处理
- Java提供API处理动态数据,位于 java.util 包和 java.text 包中
3.2、Locale类
3.2.1、概述
- Locale 实例对象代表特定地理位置。
- Locale 对象本身不会验证它代表地理位置信息是否正确,只是向本地敏感的类提供国家地区信息,与国际化相关的格式化和解析任务由本地敏感的类去完成
- 若JDK中的某个类在运行时需要根据 Locale 对象来调整其功能,这个类就称为本地敏感类
3.2.2、示例
package cn.itcase.locale;
import java.util.Locale;
public class LocaleZh {
public static void main(String[] args) {
// 模拟中文语言环境
// Locale le = Locale.CHINA;
Locale le = Locale.getDefault(); // 当前系统默认的语言环境
System.out.println(le.getCountry()); // 国家简称
System.out.println(le.getDisplayCountry()); // 国家名称
System.out.println(le.getLanguage()); // 语言
// 模拟美国国家
Locale us = Locale.US;
System.out.println(us.getCountry());
System.out.println(us.getDisplayCountry());
}
}
3.3、DateFormat 类
3.3.1、概述
- 时间/日期格式化输出 、国际化时间/日期
- 可以将一个时间/日期格式化为一个可以表示某个地区的时间/日期字符串输出
- 它还定义了一些用于描述日期/时间的显示模式的 int 型的常量;包括FULL, LONG, MEDIUM, DEFAULT, SHORT,实例化DateFormat对象时,可以使用这些常量,控制日期/时间的显示长度
3.3.2、示例
package cn.itcase.locale;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.ResourceBundle;
import org.junit.Test;
public class I18n {
// 动态数据 时间格式化
@Test
public void dataformatTest() {
/*
* 日期
* SHORT 19-7-19
* LOGIN 2019年7月19日
* MEDIUM 2019-7-19
* FULL 2019年7月19日 星期五
* 时间
* SHORT 下午10:33
* LOGN 下午10时35分44秒
* MEDIUM 23:07:43
* FULL 下午11时10分18秒 CST
*
*/
// 日期格式
int dateStyle = DateFormat.FULL;
// 时间格式化
int timeStyle = DateFormat.FULL;
// 工具类
DateFormat df = DateFormat.getDateTimeInstance(dateStyle, timeStyle,
Locale.CHINA);
String date = df.format(new Date());
System.out.println(date);
/*实例化DataFormat的九中方式
* 三种带参数的
* 1.getDateInstance(int style, Locale aLocale)
* 指定日期显示模式和本地信息来获得DateFormat实例对象,
* 该实例对象不处理时间值部分
*
* 2.getTimeInstance(int style, Locale aLocale)
* 指定时间显示模式和本地信息来获得DateFormat实例对象,
* 该实例对象不处理日期值部分。
*
* 3.getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale)
* 以单独指定的日期显示模式、时间显示模式和本地信息
* 来获得DateFormat实例对象
*
* dataformat对象
* format: 将date对象格式化为符合某个本地环境习惯的字符串。
* parse:将字符串解析为日期/时间对象
* 注意:parse和format完全相反
*
*
* DateFormat特点:
* DateFormat 对象线程不安全,因此每个线程都应该创建自己的 DateFormat实例对象
*/
}
}
/*将字符串"2019-7-19 下午11时10分18秒 CST "反向解析为一个date对象
结果为 Fri Jul 19 23:10:18 CST 2019*/
@Test
public void DataTest() throws Exception {
try {
// 数据准备 將字符串转化为date对象
String str = "2019-7-19 下午11时10分18秒 CST ";
// 创建DateFormat工具类,国际化日期
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT,
DateFormat.FULL, Locale.getDefault());
Date d = df.parse(str);
System.out.println(d);
} catch (Exception e) {
e.printStackTrace();
}
}
3.4、NumberFormat
3.4.1、概述
将一个数值格式化为符合某个国家地区习惯的数值字符串,也可以将符合某个国家地区习惯的数值字符串解析为对应的数值
3.4.2、示例
// 国际化 动态文本 数值
@Test
public void NumberFormatTest() {
/*
* NumberFormat对象的方法 format 方法:将一个数值格式化为符合某个国家地区习惯的数值字符串
* parse方法:将符合某个国家地区习惯的数值字符串解析为对应的数值。
*
* 实例化NumberFormat类提供的参数 1.NumberFormat类实例化时,locale对象可作参数也可不作。
*
* 2.getNumberInstance(Locale locale)
* 以参数locale对象所标识的本地信息来获得具有多种用途的NumberFormat实例对象。
*
* 3.getIntegerInstance(Locale locale)
* 以参数locale对象所标识的本地信息来获得处理整数的NumberFormat实例对象。
*
* 4.getCurrencyInstance(Locale locale)
* 以参数locale对象所标识的本地信息来获得处理货币的NumberFormat实例对象
*
* 5.getPercentInstance(Locale locale)
* 以参数locale对象所标识的本地信息来获得处理百分比数值的NumberFormat实例对象
*/
// 模拟语言环境
//Locale le = Locale.CHINA;
Locale le = Locale.US;
// 国际化工具类
// 数值
// NumberFormat nt = NumberFormat.getNumberInstance(le);//20,000
// 货币
NumberFormat nt = NumberFormat.getCurrencyInstance(le); //¥20,000.00
// 百分比
// NumberFormat nt = NumberFormat.getPercentInstance(le); //2,000,000%
//整数
//NumberFormat nt = NumberFormat.getIntegerInstance(le); // 20,000
String str = nt.format(20000);
System.out.println(str);
}
3.5、MessageFormat类
3.5.1、概述
- MessageFormat类用以批量处理一个字符串中的多个国际化相关数据的情况
- MessageFormat类允许开发人员用占位符替换掉字符串中的敏感数据(即国际化相关的数据)。
- MessageFormat类在格式化输出包含占位符的文本时,messageFormat类可以接收一个参数数组,以替换文本中的每一个占位符。
模式字符串:
At 12:30 on {0},a hurricance destroyed {1} houses and caused {2} of damage.
占位符
占位符的三种写法
- {argumentIndex}: 0-9 之间的数字,表示要格式化对象数据在参数数组中的索引号
- {argumentIndex,formatType}: 参数的格式化类型
- {argumentIndex,formatType,FormatStyle}: 格式化的样式,它的值必须是与格式化类型相匹配的合法模式、或表示合法模式的字符串。
3.5.2、示例
@Test
public void MessageFormatTest() throws Exception {
// 数据参数准备
String pattern = "on{0},a hurricance destroyed {1} houses and caused "
+ "{2} of damage.";
// 实例化MessageFormat对象,并装载相应的模式字符串
MessageFormat mt = new MessageFormat(pattern, Locale.US);
// 准备数组
String datetime = "Jul 3, 2019 12:30 PM";
Date date = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
DateFormat.SHORT, Locale.US).parse(datetime);
Object msgArgs[] = { date, new Integer(99), new Double(1E7) }; // 1E7表示1*10的7次方
// 执行格式化操作
String result = mt.format(msgArgs);
System.out.println(result);
/*输出结果:on7/3/19 12:30 PM,a hurricance destroyed 99 houses and caused 10,000,000 of damage.*/
}
四、JSTL国际化标签库
4.1、<fmt:setLocale>标签
4.1.1、概述
该标签用于jsp页面中显示的设置用户本地化信息,并将设置的本地信息以Locale对象的形式保存在某个web域中
4.1.2、语法
<fmt:setLocale value=“locale” [variant=“variant”] [scope=“{page|request..}”]/>
属性名 | 是否支持EL | 类型说明 | 属性描述 |
value | true | String或java.util.Locale | 指定用户的本地化信息,一个字符串或java.util.Local实例对象。如果是字符串必须包含小写的语言名而后是大写的国家名:zh_CN |
variant | true | String | 指定创建Locale实例对象时设置的变量部分,它作用于标识开发商或特定浏览器为实现扩展功能而自定义的信息。 |
scope
| false | String | 指定构造出来的Locale实例对象保存在哪个web作用域中。 |
4.1.2、示例
<fmt:setLocale value="<%=request.getLocale() %>"/>
4.2、<fmt:setBundle>标签
4.2.1、概述
该标签用于根据<fmt:setLocale>标签设置的本地化信息创建一个资源包(ResourceBundle)实例对象,并将其绑定到一个web域的属性上。
4.2.2、语法
<fmt: setBundle basename=“basename” [var=“varname”] [scope=“{page|request|session|application}”] />
属性名 | 是否支持EL | 属性类型 | 属性描述 |
basename | true | String | 指定创建ResourceBundle实例对象的基名。 |
var | false | String | 指定将创建出来的ResourceBundle实例对象保存在web域中的属性名。 |
scope | false | String | 指定将创建出来的ResourceBundle实例对象保存在哪个web作用域中。 |
4.2.3、示例
<f:setBundle basename="cn.itcase.login.login" var="message" scope="page"/>
4.3、<fmt:message>标签
4.3.1、概述
该标签用于从一个资源包中读取信息并进行格式化输出
4.3.2、语法
<fmt:message key=“messageKey” [bundle=“resourceBundle”] [var=“varname”] [scope=“page|request|session|application”] />
属性名 | 是否支持EL | 属性类型 | 属性描述 |
key | true | String | 指定要输出的信息的关键字。 |
bundle | true | LocalizationContext | 指定ResourceBundle对象在web域中的属性名称。 |
var | false | String | 用于指定格式化输出结果保存到某个web域中的属性名。 |
scope | false | String | 指定将格式化结果保存到哪个web域中。 |
4.3.3、示例
<fmt:message key="name" bundle="${message}"/>
4.4、日期、数字格式化
- <fmt:formatDate>
- <fmt:parseDate>
- <fmt:formatNumber>
- <fmt:parseNumber>
4.5、示例
<%@ 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>
<!-- 一、设置本地化对象 -->
<fmt:setLocale value="${pageContext.request.locale}"/>
<!-- 二、设置工具类 -->
<fmt:setBundle basename="cn.itcase.locale.msg" var="bundle"/>
<title><fmt:message key="title" bundle="${bundle}"></fmt:message></title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
<body>
<form name="frmLogin" action="${pageContext.request.contextPath }/admin?method=login" method="post">
<table align="center" border="1">
<tr>
<td><fmt:message key="username" bundle="${bundle}"></fmt:message></td>
<td>
<input type="text" name="userName">
</td>
</tr>
<tr>
<td><fmt:message key="pwd" bundle="${bundle}"></fmt:message></td>
<td>
<input type="password" name="pwd">
</td>
</tr>
<tr>
<td>
<input type="submit" value="<fmt:message key="submit" bundle="${bundle}"/>">
</td>
</tr>
</table>
</form>
</body>
</html>