筆記:國際化

来源:http://www.cnblogs.com/li3807/archive/2017/05/28/6917052.html
-Advertisement-
Play Games

國際化英文單詞為:Internationalization,又稱I18N,I為因為單詞的第一個字母,18為這個單詞的長度,而N代表這個單詞的最後一個字母。國際化又稱本地化(Localization,L10N)。 Java國際化主要通過如下3個類完成 java.util.ResourceBundle:... ...


國際化英文單詞為:Internationalization,又稱I18N,I為因為單詞的第一個字母,18為這個單詞的長度,而N代表這個單詞的最後一個字母。國際化又稱本地化(Localization,L10N)。

Java國際化主要通過如下3個類完成

  • java.util.ResourceBundle:用於載入一個資源包
  • java.util.Locale:對應一個特定的國家/區域、語言環境。
  • java.text.MessageFormat:用於將消息格式化

為實現程式的國際化,必須提供程式所需要的資源文件。資源文件的內容由key-value對組成,資源文件的命名可以有3種格式:

  • basename_language_country.properties
  • basename_language.properties
  • basename_properties

若資源文件包含非西方字元,則需要用JDK自帶的工具來處理:native2ascii,這個工具的語法格式如下:

native2ascii 資源文件名 目標資源文件名

如:

native2ascii mess_zh_XXX.proerties mess_zh_CN.proerties

Locale類可獲取各國區域環境(如:Locale.ENGLISH、Locale.CHINESE,這些常量返回一個Locale實例),也可以獲取當前系統所使用的區域語言環境,也可以使用語言和區域來創建Locale對象,Java的本地語言使用的時國際化標準組織(ISO)所定義的編碼,本地語言由小寫的兩個字母的代碼表示,遵循ISO-639-1;國家代碼由大寫的兩個字母的代碼組成,遵循ISO-3166-1,下表為常用的代碼:

語言

代碼

國家

代碼

Chinese

zh

China

CN

English

en

United States

US

Japanese

ja

Japan

JP

可以使用Locale的靜態方法 getAvailableLocales 來獲取所支持的語言和國家,該方法返回一個Locale數組,該數組裡包含了java所支持的語言和國家,代碼如下:

Locale[] availableLocales = Locale.getAvailableLocales();

        for (Locale l : availableLocales) {

              System.out.println("Locale DisplayName=" + l.getDisplayName() + " Country=" + l.getCountry() + " Language="

+ l.getLanguage());

}

  1. 數字格式

    數字和貨幣的格式時高度依賴與Locale的,Java類庫提供了一個格式器(formatter)對象的集合,可以對java.text包中的數字值進行格式化和解析,可以通過下麵的步驟來對特定的Locale的數字進行格式化:

  • 獲取Locale對象
  • 使用工廠方法獲取格式器對象,工廠方法時 NumberFormat 類的靜態方法,接受一個Locale 類型的參數,有三個工廠方法:getNumberInstance(數字)、getCurrencyInstance(貨幣) getPercentInstance(百分比)
  • 使用這個格式器對象來完成格式化和解析工作

格式化示例代碼:

Locale deLocale = new Locale("de", "DE");

NumberFormat currFmt = NumberFormat.getCurrencyInstance(deLocale);

double amt = 123878.34;

String formatResult = currFmt.format(amt);

System.out.println("amt=" + amt + " Format=" + formatResult);

如果想要讀取一個按照某個Locale的慣用法而輸入或存儲的數字,那邊就需要使用 parse 方法。

解析示例代碼:

Localede Locale=newLocale("de","DE");

NumberFormat currFmt=NumberFormat.getCurrencyInstance(deLocale);

Number input=currFmt.parse(formatResult);

double parseAmt=input.doubleValue();

System.out.println("FormatAmt="+formatResult+"ParseAmt="+parseAmt);

  1. 日期和時間

    當格式化日期和時間時,需要考慮4個與Locale相關的問題,例如:月份和星期應該用本地語言來表示;年月日的順序要符合本地習慣;西曆可能不是本地首選的日期表示方法;必須要考慮本地時區。Java 使用 DateFormat 類來處理這些問題,和 NumberFormat 類很類似,調用 DateFormat 類的靜態方法,並傳入 Locale 來實例化,還需要設置日期或時間的格式化值,DateFormat 有如下三個工廠方法:

    DateFormat.getDateInstance(dateStyle,loc);

    DateFormat.getTimeInstance(timeStyle,loc);

    DateFormat.getDateTimeInstance(dateStyle,timeStyle,loc);

    其日期和時間的風格使用 DateFormat 的靜態常量來表示,常用的靜態常量如下:

    DateFormat.DEFAULT

    DateFormat.FULL

    DateFormat.LONG

    DateFormat.MEDIUM

    DateFormat.SHORT

    示例代碼如下:

    String fmt = "";

    Date nowDate = new Date();

    DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, zhLocale);

    fmt = dateFormat.format(nowDate);

    System.out.println("Short style date string " + fmt);

       

    dateFormat = DateFormat.getTimeInstance(DateFormat.MEDIUM, zhLocale);

    fmt = dateFormat.format(nowDate);

    System.out.println("MEDIUM style time string " + fmt);

       

    dateFormat = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, zhLocale);

    fmt = dateFormat.format(nowDate);

    System.out.println("FULL style date FULL style time string " + fmt);

    如果要解析一個用戶輸入的日期,可以使用 DateFormat 類的 parse 方法,但其輸入的格式必須和創建 DateFormat 對象設置的風格一致,如果不一致則會拋出 IllegalArgumentException 異常,預設支持寬鬆的轉換,比如日期 2017年2月30日,會被解析為 2017年3月2日,如果希望關閉寬鬆的轉換,需要設置 lenient 標識,示例代碼如下:

    dateFormat.setLenient(false);

    Date convertDate = dateFormat.parse(fmt);

    System.out.println("parse string " + fmt + " convertDate " + convertDate);

  2. 字元串排序

    Java 中的排序時用Unicode字元來決定順序的,比如小寫字母的Unicode值比大寫的大,有重音符的字母的值甚至更大,這樣將使結果失去意義,如果需要定義排序的強度,可以使用Locale對象來創建 Collator 類,該類繼承了 Comparator介面,因此可以將該對象傳遞給 Collections.soft 方法來進行排序,示例代碼如下:

    List<String> list = new LinkedList<>();

    list.add("America");

    list.add("Zulu");

    list.add("able");

    list.add("zebra");

       

    Collator collator = Collator.getInstance(zhLocale);

    // 設置排序強度

    collator.setStrength(Collator.PRIMARY);

    Collections.sort(list, collator);

    可以設置排序強度來選擇不同的排序行為,字元間的差別可以被分為首要的(primary)、其次的(secndary)和再次的(tertiary)。比如,在英語中,A 和 Z 之間的差異被歸類為首要的;A 和 Å (重音符)之間的差異是其次的;A 和 a 之間是再次的,可以使用方法 setStrength 來設置排序強度,Collator.PRIMARY 表示首要的、Collator.SECONDARY 表示其次的、 Collator.TERTIARY 表示再次的,而Collator.IDENTICAL 則表示不允許有任何差異。

    偶爾我們會碰到一個字元或字元序列在描述成Unicode時,可以有多種方式,例如,字母序列"ffi"可以用代碼U+FB03描述成單個字元"拉丁小連字ffi",Unicode 標準對字元串定義了四種範式形式:D、KD、C和KC,其中 D 和 KD 時用於排序的,在範化形式 D 重,重音字元被分解為基字元和組合重音符;範化形式 KD 更進一步將相容性字元也進行了分解,例如 ffi 連字元或商標符號TM,我們可以選擇排序器所使用的範化程度:Collator.NO_DECOMPOSITION表示不對字元串做任何範化;Collator.CANONICAL_DECOMPOSITION 使用範化形式 D;Collator.FULL_DECOMPOSITION 使用範化形式 KD。可以使用方法 setDecomposition 來設置分解模式

  3. 消息格式化

    Java 類庫中有一個 MessageFormat 類,用來格式化帶變數的文本,就像這樣:"今天 {0} 是個好日子,{1} 公司給我發了工資 {2} 元",括弧中的數字是一個占位符,可以用實際的名字和值來替換他,使用靜態的 MessageFormat.format 方法,該方法使用當前系統的 Locale 對值進行格式化,如果需要用指定的 Locale 來進行格式化,需要使用 MessageFormat 實例的 format 方法,示例代碼如下:

    String mfString = "今天 {0} 是個好日子,{1} 公司給我發了工資 {2} 元";

    String formatString = MessageFormat.format(mfString, new Date(), "匯元1", 50000);

    System.out.println(formatString);

       

    MessageFormat mf = new MessageFormat(mfString, zhLocale);

    formatString = mf.format(new Object[]{new Date(), "匯元2", 50000});

    System.out.println(formatString);

    如果還想在指定占位符的同時設置類型和樣式,可以按照如下格式:

    String mfString = "今天 {0,date,long} 是個好日子,{1} 公司給我發了工資 {2,number,currency} 元";

    mf = new MessageFormat(mfString, zhLocale);

    formatString = mf.format(new Object[]{new Date(), "匯元3", 50000});

    System.out.println(formatString);

    輸出內容

    今天 2017年5月26日 是個好日子,匯元3 公司給我發了工資 ¥50,000.00 元

    占位符索引後面可以跟一個類型和樣式,之間用逗號隔開,類型可以是number、time、date、choice,如果類型是 number 則樣式有 integer、currency、percent;如果類型是 time 或 date,那麼樣式有 short、medium、long、full 或者是一個日期模式(yyyy-MM-dd);choice 表示希望消息跟隨占位符的值而變化,選項格式是由一個序列對構成的,每個序列對包含一個下限和一個格式化字元串,下限和字元串使用#號分隔,對於對之間用 | 分隔,示例如下:

    mfString = "今天 {0,date,yyyy-MM-dd} 是個好日子,{1,choice,0#匯元|1#匯元1|2#匯元2} 公司給我發了工資 {2,number,currency} 元";

    mf.applyPattern(mfString);

    formatString = mf.format(new Object[]{new Date(), 1, 50000});

    System.out.println(formatString);

    可以使用 < 符號或 符號 來替換 # ,則表示值小於或者小於等於下限值,示例代碼如下:

    // choice說明: 這個表示 小於 1000 並且 1001-5000 的使用"可憐" ,5001-50000 的使用"不夠",50001 以上為"正好"

    mfString = "今天 {0,date,yyyy-MM-dd} 是個好日子,{1} 公司給我發了工資 {2,number,currency} 元,{2,choice,1000<可憐|5000<不夠|50000<正好}";

    mf.applyPattern(mfString);

    formatString = mf.format(new Object[]{new Date(), "匯元4", 60000});

    System.out.println(formatString

    輸入內容

    今天 2017-05-26 是個好日子,匯元4 公司給我發了工資 ¥60,000.00 元,正好

  4. 資源包

    當本地化一個應用時,可能會有大量的消息字元串、按鈕標簽和其他的東西需要被翻譯,為了能靈活的完成這項任務,你會希望外部定義消息字元串,通常稱之為資源(resource),翻譯人員不需要接觸程式源代碼就可以很容易的編輯資源文件,在Java 中使用屬性文件來設定字元串資源,並未其他類型的資源實現相應的類。

    當本地化一個應用時,會製造出很多資源包(resource bundle),每一個包都是一個屬性文件或者一個描述了玉locale相關的項的類,對於每一個包,都要為所有你想要支持的locale提供相應的版本,並需要對這些包使用一種統一的命名規則,例如,為中國定義的資源放在一個名為"包名_zh_CN"的文件中,而為所有使用中文簡體的國家所共用的資源則放在名為"包名_zh"的文件中,一般來說,使用

    包名_語言_國家

    來命名所有和國家相關的資源,使用

    包名_語言

    來命名所有和語言相關的資源,最後,作為後備,可以把預設資源放到一個沒有尾碼的文件中,可以使用下麵的代碼載入一個包:

    ResourceBundle resourceBundle = ResourceBundle.getBundle(bundleName, locale);

    getBundle 方法載入包的順序如下:

    1. 包名_當前locale的語言_當前locale的國家_當前locale的變數
    2. 包名_當前locale的語言_當前locale的國家
    3. 包名_當前locale的語言
    4. 包名_預設locale的語言_預設locale的國家_預設locale的變數
    5. 包名_預設locale的語言_預設locale的國家
    6. 包名_預設locale的語言
    7. 包名
    8. 拋出 MissingResourceException 異常

    一旦getBundle 方法定位了一個包,比如,"包名_zh_CN" ,他還會繼續查找"包名_zh""包名"這二個包,如果這些包也存在,他們在資源層次中就稱為了"包名_zh_CN"的父包,以後查找資源的時候,如果在當前包中沒有找到,就會去查找其父包。

    1. 屬性文件

      屬性文件是為了提供字元串資源常用的文件,每行存放一個鍵-值對的文本文件,比如,MyProgramStrings.properties 就是一個屬性文件,存儲屬性文件都是ASCII文件,然後可以使用 native2ascii 工具來產生MyProgramStrings_語言_國家.properties 文件,示例如下:

      native2ascii MyProgramStrings.properties MyProgramStrings_zh_CN.properties

      要查找一個具體的字元串,可以調用:

      String resourceText= resourceBundle.getString("show.text");

      示例資源文件內容:

      show.text=\u8fd9\u4e2a\u662f\u8d44\u6e90\u6587\u4ef6\u7684\u5185\u5bb9

    2. 包類

      為了提供字元串以外的資源,需要定義類,必須繼承 ResourceBundle 類(簡單的方法是繼承 ListResourceBundle類),應該使用標準的命名規則來命名類,比如:

      MyProgramResource.java

      MyProgramResource_zh.java

      MyProgramResource_zh_CN.java

      可以使用與載入屬性文件相同的 getBundle 方法來載入這個類,其 bundleName 資源包類的完整命名(包名和類名):

      ResourceBundle resourceBundle1Class =

                                      ResourceBundle.getBundle("locale.MyProgramResource", Locale.SIMPLIFIED_CHINESE);

      要查找一個字元串或其他類型資源可以調用:

      resourceText = resourceBundle1Class.getString("resourceClass.show.text");

      Object resourceObj = resourceBundle1Class.getObject("resourceClass.show.obj");

      如果一個Key同時存在屬性文件和包類,則包類的優先。

         


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • C# 7.0已經出來一段時間了,大家都知道新特性裡面有個對元組的優化:ValueTuple。這裡利用詳盡的例子詳解Tuple VS ValueTuple(元組類VS值元組),10分鐘讓你更瞭解ValueTuple的好處和用法。 如果您對Tuple足夠瞭解,可以直接跳過章節”回顧Tuple”,直達章節 ...
  • 最近需要做一個列印的功能,於是在網上找到了這麼一個方法。 以上就是全部代碼了,調用就很簡單了,方法如下: ...
  • 在基於“less rope to hang yourself with”思想下,.NET 框架沒有給開發提供很多太多的配置選項。但在大多數情況下,GC會跟你的硬體配置,及可用資源以及程式自己的行為做調整。當然也提供一些高級的配置使用,但這取決於你程式的類型。 ...
  • OS模塊 提供對操作系統進行調用的介面 (1)os.getcwd() 獲取當前工作目錄,即當前python腳本工作的目錄路徑 >>> os.getcwd() 獲取Python當前腳本工作的目錄路徑 '/home/zhuzhu' (2)os.chdir("dirname") 改變當前腳本工作目錄;相當 ...
  • random 我們經常看到網站的隨機驗證碼,這些都是由隨機數生成的,因此我們需要瞭解一下隨機數的模塊。如何生成隨機數。 random 生成隨機數 random.random() 生成0-1之間的小數 >>> import random >>> random.random() 0.7386445925 ...
  • time模塊 time模塊提供各種操作時間的函數 #1、時間戳 1970年1月1日之後的秒 #2、元組 包含了:年、日、星期等... time.struct_time #3、格式化的字元串 2014-11-11 11:11 (1)asctime(p_tuple=None) def asctime(p ...
  • eclipse啟動時彈出Failed to create the Java Virtual Machine 一、現象 今天裝eclipse的時候出現Failed to create the Java Virtual Machine 的錯誤。 錯誤圖片如下: 二、出錯原因 把錯誤提示翻譯一下,就是“無 ...
  • Ctrl+1 快捷修複 Ctrl+D 快捷刪除 shift+enter 跳過本行開始下一行 Ctrl+F11 快速運行 Alt+↑/↓ 快速移動行 Ctrl+Alt+↑/↓ 快速複製行 Ctrl+M 視窗最大化 Alt+/ 自動補全 代碼區域右鍵 選中preferences →Java →edito ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...