深入分析JavaWeb Item22 -- 國際化(i18n)
一、國際化開發概述
軟體的國際化:軟體開發時,要使它能同時應對世界不同地區和國家的訪問,並針對不同地區和國家的訪問,提供相應的、符合來訪者閱讀習慣的頁面或資料。
國際化(internationalization)又稱為 i18n(讀法為i 18 n,據說是因為internationalization(國際化)這個單詞從i到n之間有18個英文字母,i18n的名字由此而來)
二、合格的國際化軟體
軟體實現國際化,需具備以下兩個特徵:
1、對於程式中固定使用的文本元素,例如功能表列、導航條等中使用的文本元素、或錯誤提示資訊,狀態資訊等,需要根據來訪者的地區和國家,選擇不同語言的文本為之服務。
2、對於程式動態產生的資料,例如(日期,貨幣等),軟體應能根據當前所在的國家或地區的文化習慣進行顯示。
三、固定文本元素的國際化
對於軟體中的功能表列、導航條、錯誤提示資訊,狀態資訊等這些固定不變的文本資訊,可以把它們寫在一個properties檔案中,並根據不同的國家編寫不同的properties檔案。這一組properties檔案稱之為一個資源套件。
在JavaAPI中提供了一個ResourceBundle 類用於描述一個資源套件,並且 ResourceBundle類提供了相應的方法getBundle,這個方法可以根據來訪者的國家地區自動擷取與之對應的資源檔予以顯示。
3.1、建立資源套件和資源檔
一個資源套件中的每個資源檔都必須擁有共同的基名。除了基名,每個資源檔的名稱中還必須有標識其本地資訊的附加部分。例如:一個資源套件的基名是“myproperties”,則與中文、英文環境相對應的資源檔名則為: “myproperties_zh.properties” “myproperties_en.properties”
每個資源套件都應有一個預設資源檔,這個檔案不帶有標識本地資訊的附加部分。若ResourceBundle對象在資源套件中找不到與使用者匹配的資源檔,它將選擇該資源套件中與使用者最相近的資源檔,如果再找不到,則使用預設資源檔。例如:myproperties.properties
3.2、資源檔的書寫格式
資源檔的內容通常採用“關鍵字=值”的形式,軟體根據關鍵字檢索值顯示在頁面上。一個資源套件中的所有資源檔的關鍵字必須相同,值則為相應國家的文字。
並且資源檔中採用的是properties格式檔案,所以檔案中的所有字元都必須是ASCII字碼,屬性(properties)檔案是不能儲存中文的,對於像中文這樣的非ACSII字元,須先進行編碼。
例如:
國際化的中文環境的properties檔案
國際化的英文環境的properties檔案
java提供了一個native2ascII工具用於將中文字元進行編碼處理,native2ascII的用法如下所示:
3.3、編程實現固定文本的國際化
在JavaAPI中提供了一個ResourceBundle 類用於描述一個資源套件,並且 ResourceBundle類提供了相應的方法getBundle,這個方法可以根據來訪者的國家地區自動擷取與之對應的資源檔予以顯示。
ResourceBundle類提供了一個靜態方法getBundle,該方法用於裝載資源檔,並建立ResourceBundle執行個體:
Locale currentLocale = Locale.getDefault(); ResourceBundle myResources =ResourceBundle.getBundle(basename, currentLocale);
basename為資源套件基名(且必須為完整路徑)。
如果與該locale對象匹配的資源套件子類找不到。一般情況下,則選用預設資源檔予以顯示。
載入資源檔後, 程式就可以調用ResourceBundle 執行個體對象的 getString 方法擷取指定的資源資訊名稱所對應的值。
String value = myResources.getString(“key");
範例:根據國家地區自動擷取與之對應的資源檔
package me.gacl.i18n;import java.util.Locale;import java.util.ResourceBundle;/*** @ClassName: I18NTest* @Description: 編程實現固定文本的國際化* @author: 孤傲蒼狼* @date: 2014-8-29 下午9:34:05**/ public class I18NTest { public static void main(String[] args) { //資源套件基名(包名+myproperties) String basename = "me.gacl.i18n.resource.myproperties"; //設定語言環境 Locale cn = Locale.CHINA;//中文 Locale us = Locale.US;//英文 //根據基名和語言環境載入對應的語言資源檔 ResourceBundle myResourcesCN = ResourceBundle.getBundle(basename,cn);//載入myproperties_zh.properties ResourceBundle myResourcesUS = ResourceBundle.getBundle(basename,us);//載入myproperties_en.properties //載入資源檔後, 程式就可以調用ResourceBundle執行個體對象的 getString方法擷取指定的資源資訊名稱所對應的值。 //String value = myResources.getString(“key"); String usernameCN = myResourcesCN.getString("username"); String passwordCN = myResourcesCN.getString("password"); String usernameUS = myResourcesUS.getString("username"); String passwordUS = myResourcesUS.getString("password"); System.out.println(usernameCN+"--"+passwordCN); System.out.println(usernameUS+"--"+passwordUS); }}
運行結果:
3.4、在WEB應用中實現固定文本的國際化
如下所示:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<% //載入i18n資源檔,request.getLocale()擷取訪問使用者所在的國家地區 ResourceBundle myResourcesBundle = ResourceBundle.getBundle("me.gacl.i18n.resource.myproperties",request.getLocale()); %>
運行結果:
瀏覽器語言是中文環境下的顯示效果:
瀏覽器語言是英文環境下的顯示效果:
同樣一個頁面,在不同語言環境的瀏覽器下顯示出了不同的語言文字效果,這樣就實現了固定文本的國際化。
IE瀏覽器切換使用語言:工具→Internet選項
四、動態資料的國際化
數值,貨幣,時間,日期等資料由於可能在程式運行時動態產生,所以無法像文字一樣簡單地將它們從應用程式中分離出來,而是需要特殊處理。Java 中提供瞭解決這些問題的 API 類(位於 java.util 包和 java.text 包中)
4.1、Locale 類
Locale 執行個體對象代表一個特定的地理,政治、文化地區。
一個 Locale 對象本身不會驗證它代表的語言和國家地區資訊是否正確,只是向本地敏感的類提供國家地區資訊,與國際化相關的格式化和解析任務由本地敏感的類去完成。(若JDK中的某個類在運行時需要根據 Locale 對象來調整其功能,這個類就稱為本地敏感類)
4.2、DateFormat類(日期格式化)
DateFormat 類可以將一個日期/時間對象格式化為表示某個國家地區的日期/時間字串。
DateFormat 類除了可按國家地區格式化輸出日期外,它還定義了一些用於描述日期/時間的顯示模式的 int 型的常量,包括FULL, LONG, MEDIUM, DEFAULT, SHORT,執行個體化DateFormat對象時,可以使用這些常量,控制日期/時間的顯示長度。
4.2.1、執行個體化DateFormat類
執行個體化DateFormat類有九種方式,以下三種為帶參形式,下面列出的三種方式也可以分別不帶參,或只帶顯示樣式的參數。
getDateInstance(int style, Locale aLocale):以指定的日期顯示模式和本地資訊來獲得DateFormat執行個體對象,該執行個體對象不處理時間值部分。
getTimeInstance(int style, Locale aLocale):以指定的時間顯示模式和本地資訊來獲得DateFormat執行個體對象,該執行個體對象不處理日期值部分。
getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale):以單獨指定的日期顯示模式、時間顯示模式和本地資訊來獲得DateFormat執行個體對象。
4.2.2、DateFormat 對象的方法
format:將date對象格式化為符合某個本地環境習慣的字串。
parse:將字串解析為日期/時間對象
注意:parse和format完全相反,一個是把date時間轉化為相應地區和國家的顯示樣式,一個是把相應地區的時間日期轉化成date對象,該方法在使用時,解析的時間或日期要符合指定的國家、地區格式,否則會拋異常。
DateFormat 對象通常不是安全執行緒的,每個線程都應該建立自己的 DateFormat 執行個體對象
4.2.3、DateFormat使用範例
package me.gacl.i18n;import java.text.DateFormat;import java.text.ParseException;import java.util.Date;import java.util.Locale;/*** @ClassName: DateFormatTest* @Description: DateFormat類測試* DateFormat類可以將一個日期/時間對象格式化為表示某個國家地區的日期/時間字串* @author: 孤傲蒼狼* @date: 2014-8-29 下午10:03:26**/ public class DateFormatTest { public static void main(String[] args) throws ParseException { Date date = new Date(); // 當前這一刻的時間(日期、時間) // 輸出日期部分 DateFormat df = DateFormat.getDateInstance(DateFormat.FULL,Locale.GERMAN); String result = df.format(date); System.out.println(result); // 輸出時間部分 df = DateFormat.getTimeInstance(DateFormat.FULL, Locale.CHINA); result = df.format(date); System.out.println(result); // 輸出日期和時間 df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG,Locale.CHINA); result = df.format(date); System.out.println(result); // 把字串反向解析成一個date對象 String s = "10-9-26 下午02時49分53秒"; df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG,Locale.CHINA); Date d = df.parse(s); System.out.println(d); }}
4.3、NumberFormat類(數字格式化)
NumberFormat類可以將一個數值格式化為符合某個國家地區習慣的數值字串,也可以將符合某個國家地區習慣的數值字串解析為對應的數值
NumberFormat類的方法:
format 方法:將一個數值格式化為符合某個國家地區習慣的數值字串
parse 方法:將符合某個國家地區習慣的數值字串解析為對應的數值。
執行個體化NumberFormat類時,可以使用locale對象作為參數,也可以不使用,下面列出的是使用參數的。
getNumberInstance(Locale locale):以參數locale對象所標識的本地資訊來獲得具有多種用途的NumberFormat執行個體對象
getIntegerInstance(Locale locale):以參數locale對象所標識的本地資訊來獲得處理整數的NumberFormat執行個體對象
getCurrencyInstance(Locale locale):以參數locale對象所標識的本地資訊來獲得處理貨幣的NumberFormat執行個體對象
getPercentInstance(Locale locale):以參數locale對象所標識的本地資訊來獲得處理百分比數值的NumberFormat執行個體對象
範例:
package me.gacl.i18n;import java.text.NumberFormat;import java.text.ParseException;import java.util.Locale;/*** @ClassName: NumberFormatTest* @Description: NumberFormat類測試* @author: 孤傲蒼狼* @date: 2014-8-29 下午10:25:29**/ public class NumberFormatTest { public static void main(String[] args) throws ParseException { int price = 89; NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.CHINA); String result = nf.format(price); System.out.println(result); String s = "¥89.00"; nf = NumberFormat.getCurrencyInstance(Locale.CHINA); Number n = nf.parse(s); System.out.println(n.doubleValue() + 1); double num = 0.5; nf = NumberFormat.getPercentInstance(); System.out.println(nf.format(num)); }}
運行結果:
4.4、MessageFormat(文字格式設定化)
如果一個字串中包含了多個與國際化相關的資料,可以使用MessageFormat類對這些資料進行批量處理。
例如:At 12:30 pm on jul 3,1998, a hurricance destroyed 99 houses and caused $1000000 of damage
以上字串中包含了時間、數字、貨幣等多個與國際化相關的資料,對於這種字串,可以使用MessageFormat類對其國際化相關的資料進行批量處理。
MessageFormat 類如何進行批量處理呢?
1.MessageFormat類允許開發人員用預留位置替換掉字串中的敏感性資料(即國際化相關的資料)。
2.MessageFormat類在格式化輸出包含預留位置的文本時,messageFormat類可以接收一個參數數組,以替換文本中的每一個預留位置。
4.4.1、模式字串與預留位置
模式字串:
At {0} on {1},a destroyed {2} houses and caused {3} of damage
字串中的{0}、{1}、{2}、{3}就是預留位置
4.4.2、格式化模式字串
1、執行個體化MessageFormat對象,並裝載相應的模式字串。
2、使用format(object obj[])格式化輸出模式字串,參數數組中指定預留位置相應的替換對象。
範例:
package me.gacl.i18n;import java.text.MessageFormat;import java.util.Date;import java.util.Locale;/*** @ClassName: MessageFormatTest* @Description: MessageFormat類測試* @author: 孤傲蒼狼* @date: 2014-8-29 下午10:29:19**/ public class MessageFormatTest { public static void main(String[] args) { //模式字串 String pattern = "On {0}, a hurricance destroyed {1} houses and caused {2} of damage."; //執行個體化MessageFormat對象,並裝載相應的模式字串 MessageFormat format = new MessageFormat(pattern, Locale.CHINA); Object arr[] = {new Date(), 99, 100000000}; //格式化模式字串,參數數組中指定預留位置相應的替換對象 String result = format.format(arr); System.out.println(result); }}
運行結果:
4.4.3、預留位置的三種書寫方式
{argumentIndex}: 0-9 之間的數字,表示要格式化對象資料在參數數組中的索引號
{argumentIndex,formatType}: 參數的格式化類型
{argumentIndex,formatType,FormatStyle}: 格式化的樣式,它的值必須是與格式化類型相匹配的合法模式、或表示合法模式的字串。
範例:
package me.gacl.i18n;import java.text.MessageFormat;import java.util.Date;import java.util.Locale;/*** @ClassName: MessageFormatTest* @Description: MessageFormat類測試* @author: 孤傲蒼狼* @date: 2014-8-29 下午10:29:19**/ public class MessageFormatTest { public static void main(String[] args) { //模式字串 String pattern = "At {0, time, short} on {0, date}, a destroyed {1} houses and caused {2, number, currency} of damage."; //執行個體化MessageFormat對象,並裝載相應的模式字串 MessageFormat format = new MessageFormat(pattern, Locale.US); Object arr[] = {new Date(), 99, 100000000}; //格式化模式字串,參數數組中指定預留位置相應的替換對象 String result = format.format(arr); System.out.println(result); }}
運行結果:
五、在WEB應用中使用國際化標籤庫實現固定文本的國際化
5.1、國際化標籤
設定一個全域的地區代碼
設定統一的請求編碼
執行個體:
<%@ page language="java" contentType="text/html; charset=gb2312" import="java.util.*"%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
中文-大陸:
英文:
頁面輸出:
中文-大陸: 2015-12-16 英文: Dec 16, 2015
5.2、資訊顯示標籤
設定臨時要讀取的資源檔
通過key取得value
設定一個要讀取的全域的資源檔
執行個體:
<%@ page language="java" contentType="text/html; charset=gb2312" import="java.util.*"%><%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
資料庫驅動程式名:
連接字串:
使用者名稱:
密碼:
名字:
動態提示資訊:
動態提示資訊: 張三
其對應的讀取檔案為dbconn.properties(當然是放在web-inf/classes下了),內容為:
#SQL ServerdriverName=com.microsoft.jdbc.sqlserver.SQLServerDriverconnString=jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=testDatabaseuserName=sa password=123456 name=小平果messageTemp=myname is {0},today is {1,date}
其頁面輸出為:
資料庫驅動程式名:com.microsoft.jdbc.sqlserver.SQLServerDriver 連接字串:jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=testDatabase 使用者名稱:sa 密碼: 123456 名字: Wallace 動態提示資訊:myname is {0},today is {1,date} 動態提示資訊: myname is小平果,today is 2015-12-16
解釋一下其中的幾個標籤:
標籤用於綁定資料來源.properties檔案;
語句,代碼等
標籤用於從指定的資源檔中把指定的索引值取出來;
如果用到var的話就不會在頁面直接輸出,而需要用到標籤來進行頁面的輸出,如上例;
標籤可以配合標籤來進行設定標籤指向鍵的動態值,如上例;
標籤用於設定預設的資料來源;
標籤用來設定預設的資料來源;
5.3、數字及日期格式化標籤
日期的格式化、把普通的日期顯示格式化為標準的日期格式
日期的反格式化、把已經格式化過後的標準日期格式轉化為普通類型、例如字串
數位格式化、把普通的數字格式化為標準的數字格式
數位反格式化、把已經格式化過後的數字反過來轉換成普通的數字
設定一個全域的時區
設定一個臨時的時區
執行個體:
<%@ page contentType="text/html" pageEncoding="GBK"%><%@ page import="java.util.*"%><%@ taglib prefix="fmt" uri=“http://java.sun.com/jsp/jstl/fmt” %>
<% pageContext.setAttribute("dateref" , new Date()) ; %> default顯示日期時間:${date}自訂格式顯示日期時間:${date}
—type:指定要格式化的形式、比如說是只格式化日期、或者只格式化時間、或者是兩者一起、預設為date;一般為both
—datestyle:指定日期的顯示樣式,預設為default
—timestyle:指定時間的顯示樣式,預設為default
—pattern:在自訂日期顯示格式的時候、需要指定的格式、例如:yyyy年MM月dd日 HH時mm分ss秒SSS毫秒(要區分大小寫、目的是為了不與同字母混淆)
格式化數字:${num}科學計數法:${num}
—-maxIntegerDigits:可以顯示的最大整數位
—-maxFractionDigits:可以顯示的最大小數位
—-groupingUsed:是否在數字中加“,”
最後再舉個栗子:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%--匯入國際化標籤庫 --%><%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%-- //載入i18n資源檔,request.getLocale()擷取訪問使用者所在的國家地區 ResourceBundle myResourcesBundle = ResourceBundle.getBundle("me.gacl.i18n.resource.myproperties",request.getLocale()); --%>
<%--
以上就是JavaWeb開發中國際化的總結內容。