亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

您的位置:首頁技術文章
文章詳情頁

Java中的國際化,第二部分

瀏覽:2日期:2024-06-16 09:55:21
內容: 編者按:使你的Java程序能在本地小鎮甚至飄洋過海都運行良好,這面臨諸多的挑戰.我們已經在第三版中關于國際化探討的第一部分講述了Java國際化的前兩個步驟:使用Unicode字符集編碼,遵循當地使用習慣.接下來的時間,我們我們將繼續探討國際化的第三個步驟:本地化用戶可視信息.版權聲明:任何獲得Matrix授權的網站,轉載時請務必保留以下作者信息和鏈接作者:leniz原文:http://www.onjava.com/pub/a/onjava/excerpt/javaexIAN3_chap8/index1.html譯文:http://www.matrix.org.cn/resource/article/44/44207_Java+Internationalization.html關鍵字:Java;Internationalization本地化用戶可視信息國際化的第三個任務涉及到確保程序中用戶可視信息沒有被硬編碼(hardcode);相反的是,應該依據當地的俗成.在例8-3,字符Portfolio value,Symbol,Shares,和另外一些在程序中都是用英語進行硬編碼的,即使程序可能運行在遙遠的法蘭西國度.唯一避免這種尷尬處境的方法就是:你的程序必須支持在運行之時才實時地提取用戶可視的信息,并且這些信息需被實時地翻譯成各種語言.Java通過java.util包中的ResourceBundle 類來幫助我們完成這個任務.這個類包含了眾多可以通過名稱來查詢的資源.將你所希望等到本地化的地區的當地資源都定義到一個資源包中,運行之時Java將準確的加載本地化資源.通過加載正確的bundle,程序就可以實時的查找到對本地化支持所需要的資源(字符是比較有代表).使用Resource Bundles來處理資源為了定義一系列本地化的資源,你需要繼承ResourceBundle類生成一個類,并提供對handleGetObject()和getKeys()等方法的定義. 將資源的名稱傳給handleGetObject()方法,它將返回一個本地版本的資源.getKeys()返回的是一個Enumeration類型的類,它包含了ResourceBundle中已定義的所有的本地化資源的名稱.然而比直接繼承ResourceBundle類更為簡單的是繼承ListResourceBundle類.你可以簡潔地提供一個特性文件(參閱java.util.Properties),ResourceBundle.getBundle()方法將通過此文件生成一個PropertyResourceBundle實例.在一個程序中,為了能通過ResourceBundle類獲取本地化資源,你必須首先調用,一個靜態的getBundle()方法,這個方法將動態加載并實例化一個ResourceBundle,正如我們即將要涉及的一樣.返回的這個ResourceBundle包含了你所定義的資源名稱,并且是針對某一特定區域的(如果沒有區域被顯式的聲明,那么將加載默認的區域).一旦通過getBundle()方法獲取了你所要的ResourceBundle,你就可以通過getObject()方法以提供資源名稱的方式來獲取已本地化的資源.隨便提一下,你可以通過getString()方法更為便捷的把想要獲得的Object資源自動轉型為String類型.當調用getBundle()方法之時,指定你所希望的ResourceBundle的base name和你所期望的地點(如果你不希望使用默認的地點的話).獲取一個Locale用的是一個雙字的語言代碼,一個可選的雙字國家代碼,以及一個可選的字符變量.getBundle()方法通過把地區信息加上base name的方式,來獲取正確的本地ResourceBundle.查找一個合適的類的方法用的正是下面的算法:1.查詢一個具有下列名字的類 basename_language_country_variant 如果沒有發現這個類,或者沒有特別指定locale的字符變量,那么將進行下一步查詢2.查詢一個具有下列名字的類 basename_language_country 如果沒有發現這個類,或者沒有特別指定locale的國家編碼,那么將進行往下下一步的查詢3.查詢一個具有下列名字的類 basename_language 如果還是沒有發現這個類的話,那么將進行最后一步4.查詢一個與basename同名的類,換句話說,就是找一個與下列名字同名的類. basenam這里包含的是默認的本地資源包,針對的是所有沒有明確提供本地化的區域.在以上處理過程的每一步中,getBundle()都首先用給定的名字檢測一個類文件.如果沒有找到這個類文件,那么它將借助ClassLoader的getResourceAsStream()方法,通過給定的名字和.Properties后綴名去查找一個具有上述組合名稱的Properties文件.如果找到這樣的Properties文件的話,那么將通過這個文件提供的內容,實例化一個Properties Object,并通過getBundle()初始化,返回一個PropertyResourceBundle類,這個類借助ResourceBundle API導入Properties文件中的所有特性.如果上述的四種查詢的任何一個查詢,針對某特定區域的類或Properties文件都沒有被找到,那么它將重復上述的查詢,但查找的是針對默認區域的類或Properties文件. 默認區域的查詢仍然無法獲取合適的ResourceBundle,getBundle()方法將拋出一個MissingResourceException異常.任何一個ResourceBundle Object 都可以有一個特別針對自己的parent ResourceBundle. 當你在ResourceBundle中查找某個資源時,getObejct()首先在一個特定的bundle中查找,如果這個資源沒有在這個bundle中被定義,那么查找將回溯到父bundle中.因此,每一個ResourceBundle都是繼承了父類的資源,可能 覆寫了某些資源,有時甚至覆蓋了全部的(需要注意的是這里提到的術語繼承(inherit)和覆寫(override)區別與通常我們在討論class時所提到的針對父類的繼承和覆寫).上述的意思就是說,我們定義的ResourceBundle不一定非要定義你的應用程序所需要的每一個資源.比如你可能定義了一個專門針對法語用戶的信息ResourceBundle.而此時你希望有個專門針對加拿大的使用法語的用戶的ResourceBundle,你要做的就是覆寫一些信息來定義一個更為小型的而且更具有針對性的信息ResourceBundle.你的程序不需要去查找和建立它所使用的ResourceBundle的父對象.事實上getBundle()方法可以為了你自動的做這些工作.當getBundle()方法查找到一個符合上述要求的類或properties文件時,它卻不是立即返回它已查找到的ResourceBundle.相反的是,它會按照原先的步驟繼續尋找更為普遍性的類或Properties文件,而ResourceBundle可以通過這些來繼承資源.一旦getBundle()方法找到這個更具普遍性的資源bundle,它就會把這些資源組裝成最后的bundle的祖先.一旦確定了返回的最初的ResourceBundle的所有可能,它將創建之.為了繼續不久之前開始的那個例子,那個例子實際運行在魁北克,getBundle()可能首先查找一個不那么特殊的ResourceBundle類,這個類只包含了有限的特別針對魁北克的資源.接著,它查找更具一般的ResourceBundle類,這個類可能包含的是法國的信息.那么它把這個bundle作為剛剛提及的魁北克的最初的bundle的parent bundle. getBundle()最后查找的(可能發現的)是這樣一個類,它定義了一套默認的資源,有可能用的是英語(假設英語是開始的那些編程者的母語).這些bundle作為法語bundle的parent bundle(同時也就是魁北克bundle的爺字輩的bundle).當運用程序查找一個命名的資源之時,魁北克的bundle首先被查找到.如果這個命名資源沒有在此被定義,那么將查找法語的bundle,如果還是沒能找到所需要的資源,那么最后的可能就落在默認的bundle上了.ResourceBundle 舉例調試一些代碼有助于我們把上面討論的東西,理解的更加清晰,透徹.例8-4是一個生成Swing菜單的常規程序.面對給定一系列菜單的細目,它在資源bundle中查找針對這些細目的標簽和快捷鍵的資源,并創建一個本地化的菜單.下面的例子最后附有簡單的測試.圖8-3,是一個分別運行在美國,英格蘭和法國時創建的菜單欄程序.如果沒有那些提供菜單標簽本地化的resource bundle的存在,我們是不可能實現這個程序的. 圖 8-3 本地化菜單panes例8-4 SimpleMenu.javapackage je3.i18n;import javax.swing.*;import java.awt.*;import java.awt.event.*;import java.util.Locale;import java.util.ResourceBundle;import java.util.MissingResourceException;/** A convenience class to automatically create localized menu panes */public class SimpleMenu { /** The convenience method that creates menu panes */ public static JMenu create(ResourceBundle bundle, String menuname, String[] itemnames, ActionListener listener) { // Get the menu title from the bundle. Use name as default label. String menulabel; try { menulabel = bundle.getString(menuname + '.label'); } catch(MissingResourceException e) { menulabel = menuname; } // Create the menu pane. JMenu menu = new JMenu(menulabel); // For each named item in the menu. for(int i = 0; i < itemnames.length; i++) { // Look up the label for the item, using name as default. String itemlabel; try { itemlabel = bundle.getString(menuname+'.'+itemnames[i]+'.label'); } catch (MissingResourceException e) { itemlabel = itemnames[i]} JMenuItem item = new JMenuItem(itemlabel); // Look up an accelerator for the menu item try { String acceleratorText = bundle.getString(menuname+'.'+itemnames[i]+'.accelerator); //綠色為新加bundle.getString(menuname+'.'+itemnames[i]+'.accelerator');//這一行好像有問題. //應該是刪除此行,將上一行補充完整. item.setAccelerator(KeyStroke.getKeyStroke(acceleratorText)); } catch (MissingResourceException e) {} // Register an action listener and command for the item. if (listener != null) { item.addActionListener(listener); item.setActionCommand(itemnames[i]); } // Add the item to the menu. menu.add(item); } // Return the automatically created localized menu. return menu; } /** A simple test program for the above code */ public static void main(String[] args) { // Get the locale: default, or specified on command-line Locale locale; if (args.length == 2) locale = new Locale(args[0], args[1]); else locale = Locale.getDefault( ); // Get the resource bundle for that Locale. This will throw an // (unchecked) MissingResourceException if no bundle is found. ResourceBundle bundle = ResourceBundle.getBundle('com.davidflanagan.examples.i18n.Menus', locale); //注一 // Create a simple GUI window to display the menu with final JFrame f = new JFrame('SimpleMenu: ' + // Window title locale.getDisplayName(Locale.getDefault( ))); JMenuBar menubar = new JMenuBar( ); // Create a menubar. f.setJMenuBar(menubar); // Add menubar to window // Define an action listener that our menu will use. ActionListener listener = new ActionListener( ) { public void actionPerformed(ActionEvent e) { String s = e.getActionCommand( ); Component c = f.getContentPane( ); if (s.equals('red')) c.setBackground(Color.red); else if (s.equals('green')) c.setBackground(Color.green); else if (s.equals('blue')) c.setBackground(Color.blue); } }; // Now create a menu using our convenience routine with the resource // bundle and action listener we've created JMenu menu = SimpleMenu.create(bundle, 'colors', new String[] {'red', 'green', 'blue'}, listener); // Finally add the menu to the GUI, and pop it up menubar.add(menu); // Add the menu to the menubar f.setSize(300, 150); // Set the window size. f.setVisible(true); // Pop the window up. }}這個程序不是獨立的.它依賴資源bundle來做本地化菜單的工作.接下來,羅列了三份properties文件,這些文件是為例子中的資源bundle提供的.注意下面的這個列表包含了三個獨立的文件主體.(注二)# The file Menus.properties is the default 'Menus' resource bundle.# As an American programmer, I made my own locale the default.colors.label=Colorscolors.red.label=Redcolors.red.accelerator=alt Rcolors.green.label=Greencolors.green.accelerator=alt Gcolors.blue.label=Bluecolors.blue.accelerator=alt B# This is the file Menus_en_GB.properties. It is the resource bundle for# British English. Note that it overrides only a single resource definition# and simply inherits the rest from the default (American) bundle.colors.label=Colours# This is the file Menus_fr.properties. It is the resource bundle for all# French-speaking locales. It overrides most, but not all, of the resources# in the default bundle.colors.label=Couleurscolors.red.label=Rougecolors.green.label=Vertcolors.green.accelerator=control shift Vcolors.blue.label=Bleu格式化信息我們已經看到,為了實現程序的國際化,必須把所有用戶可見的信息都放到資源bundle中.當這些文本的本地化只是包含一些象按鍵和菜單欄文本的簡單標簽,那么一切都顯得很直觀.然而,面對的是一部分靜態內容和一部分動態內容的組合體,情況就變得微妙了.比如編譯器可能要顯示一條這樣的信息,Error at line 5 of file “Hello.java,在這種情況下,行數和文件名是動態的,而且是區域獨立的,其余的信息都是靜態的即需要被簡單地本地化操作的.java.text 包中的MessageFormat類,可以幫助我們有效的解決這個難題.為了使用它們,我們只把那些靜態的文字部分儲存在ResourceBundle中,對于那些動態的信息部分中出現的特殊字符也必須被安置好.比如,某個資源bundle包含下面的一條信息Error at line{0} of file {1}.另一個資源bundle可能包含的是一個已被翻譯的Erreur:{1}:{0}的信息.為了使用對付這樣的本地化信息問題,我們從靜態信息中創建一個MessageFormat,然后調用它的format()方法.對隊列中的值進行替換.在這種情況下,這個隊列中包含一個用于行數的Integer 對象和一個用于文件名的String對象MessageFormat對象可以和java.text包中的其它Format類進行通信.它創建和使用NumberFormat對象來格式化數字并使用DateFormat對象格式化日期和時間.另外,可以設計信息,用這些信息創建一個ChoiceFormat對象,以此實現從數字形式到字符形式的轉變.當操作計數值類型時,這些顯得尤其有用,例如對應月份名稱的數字,或當你需要根據數字值的多少來決定某個詞的單數或復數.例8-5 演示了這種MessageFormat的使用.這是一個很方便的類,有一個單獨的靜態方法用于本地化顯示異常信息或錯誤信息.但調用的時候,代碼試圖加載一個名為Errors的ResourceBundle.當找到了這個類,那么它將查詢使用了傳遞過來的異常對象名字的信息資源.如果這個信息資源也被找到,它將顯示這個信息.擁有五個值的隊列被傳遞給format()方法.本地化了的錯誤提示信息可以包括任何一個或是全部這些參數.例子中定義的LocalizedError.display()方法,曾經在本章開始的例8-2中使用過.與此例配合使用的默認Errors.Properties資源bundle, 在代碼后面也有相應提供.應用程序的錯誤信息提示在這里得到了很好的國際化.將一個應用程序的錯誤信息提示應用到一個新的區域中,所要做的無法只是轉化(本地化)Errors.Properties文件.Example 8-5. LocalizedError.javapackage je3.i18n;import java.text.*;import java.io.*;import java.util.*;/** * A convenience class that can display a localized exception message * depending on the class of the exception. It uses a MessageFormat, * and passes five arguments that the localized message may include: * {0}: the message included in the exception or error. * {1}: the full class name of the exception or error. * {2}: the file the exception occurred in * {3}: a line number in that file. * {4}: the current date and time. * Messages are looked up in a ResourceBundle with the basename * 'Errors', using a the full class name of the exception object as * the resource name. If no resource is found for a given exception * class, the superclasses are checked. **/public class LocalizedError { public static void display(Throwable error) { ResourceBundle bundle; // Try to get the resource bundle. // If none, print the error in a nonlocalized way. try { String bundleName = 'com.davidflanagan.examples.i18n.Errors'; bundle = ResourceBundle.getBundle(bundleName); } catch (MissingResourceException e) { error.printStackTrace(System.err); return; } // Look up a localized message resource in that bundle, using the // classname of the error (or its superclasses) as the resource name. // If no resource was found, display the error without localization. String message = null; Class c = error.getClass( ); while((message == null) && (c != Object.class)) { try { message = bundle.getString(c.getName( )); } catch (MissingResourceException e) { c = c.getSuperclass( ); } } if (message == null) { error.printStackTrace(System.err); return; } // Get the filename and linenumber for the exception // In Java 1.4, this is easy, but in prior releases, we had to try // parsing the output Throwable.printStackTrace( ); StackTraceElement frame = error.getStackTrace( )[0]// Java 1.4 String filename = frame.getFileName( ); int linenum = frame.getLineNumber( ); // Set up an array of arguments to use with the message String errmsg = error.getMessage( ); Object[ ] args = { ((errmsg!= null)?errmsg:''), error.getClass( ).getName( ), filename, new Integer(linenum), new Date( ) }; // Finally, display the localized error message, using // MessageFormat.format( ) to substitute the arguments into the message. System.err.println(MessageFormat.format(message, args)); } /** * This is a simple test program that demonstrates the display( ) method. * You can use it to generate and display a FileNotFoundException or an * ArrayIndexOutOfBoundsException **/ public static void main(String[ ] args) { try { FileReader in = new FileReader(args[0]); } catch(Exception e) { LocalizedError.display(e); } }}下面羅列的是資源bundle需要的properties文件,這些文件用于本地化由例8-2的ConvertEncoding所產生的錯誤信息.## This is the file Errors.properties# One property for each class of exceptions that our program might# report. Note the use of backslashes to continue long lines onto the# next. Also note the use of n and t for newlines and tabs#java.io.FileNotFoundException: Error: File '{0}' not foundntError occurred at line {3} of file '{2}'ntat {4}java.io.UnsupportedEncodingException: Error: Specified encoding not supportedntError occurred at line {3} of file '{2}'ntat {4,time} on {4,date}java.io.CharConversionException:Error: Character conversion failure. Input data is not in specified format.# A generic resource. Display a message for any error or exception that# is not handled by a more specific resource.java.lang.Throwable:Error: {1}: {0}ntError occurred at line {3} of file '{2}'nt{4,time,long} {4,date,long}當我們擁有這樣一個resource bundle后, ConvertEncoding 將會產生類似下面的 error messages:Error: File 'myfile (No such file or directory)' not found Error occurred at line 64 of file 'FileInputStream.java' at 7/9/00 9:28 PM或者,如果是在法國的話:Error: File 'myfile (Aucun fichier ou repertoire de ce type)' not found Error occurred at line 64 of file 'FileInputStream.java' at 09/07/00 21:28練習 8-1一些用于國際化的類,例如NumberFormat,DateFormat等,都有一個靜態的方法getAvailableLocales(),這個方法返回一系列他們所支持的本地化對象.你可以在一個給定的本地化對象中,通過getDisplayCountry()方法來獲取這個給定區域的國家名稱.這個方法有兩種方式.一種是不帶參數的,返回顯示的是默認地的國家名稱.另一種是需要提供一個Locale作為參數,返回的是特定區域語言下的國家名稱.寫一個程序,這個程序通過NumberFormat.getAvaileLocales()方法可以顯示所有區域的國家名稱.使用Locale定義的靜態locale常量,用英語,法語,德語,意大利語分別顯示每一個國家的名稱. 附錄:注一:這里的com.davidflanagan.examples.i18n是放置了幾個properties文件的package名,如果你將附帶的properties放到其它的package中,請做相應的變動.Menus是默認的名稱注二:分別保存到三個獨立的文本文件中,用注釋中的名字進行命名,以此為針對中國用戶的菜單可以是:文件四: Menus_zh.propertiescolors.label=顏色設置colors.red.label=紅色colors.red.accelerator=alt Rcolors.green.label=綠色colors.green.accelerator=alt Gcolors.blue.label=藍色colors.blue.accelerator=alt B如果出現中文字符亂碼問題,請將加入下列方法,對菜單字符進行轉換,所以這里也要多考慮一下字符集的問題/*** @todo傳入一個以UTF-8編碼的字符,輸出UTF-16編碼的中文* @ param inputStr String 需要轉換的字串*/public static String getChineseOut(String inputStr){ try{ String temp_s = inputStr; byte[] temp_b = null; temp_b = temp_s.getBytes('ISO8859-1'); String result = new String(temp_b); return result; } catch(Exception e){ e.printStackTrace(); return inputStr; } } Java, java, J2SE, j2se, J2EE, j2ee, J2ME, j2me, ejb, ejb3, JBOSS, jboss, spring, hibernate, jdo, struts, webwork, ajax, AJAX, mysql, MySQL, Oracle, Weblogic, Websphere, scjp, scjd 編者按:使你的Java程序能在本地小鎮甚至飄洋過海都運行良好,這面臨諸多的挑戰.我們已經在第三版中關于國際化探討的第一部分講述了Java國際化的前兩個步驟:使用Unicode字符集編碼,遵?
標簽: Java
相關文章:
主站蜘蛛池模板: 婷婷综合五月 | 国产成人精品一区二三区2022 | 欧美亚洲综合网 | 久久夜色精品国产亚洲 | 亚洲操片 | 在线免费观看日韩视频 | 成人夜色视频在线观看网站 | 91麻豆麻豆 | 黄色三区 | 国产97公开成人免费视频 | 国产欧美视频一区二区三区 | 国产精品视频区 | 亚洲国产午夜 | 久久香蕉国产线看观看8青草 | 婷婷丁香色综合狠狠色 | 亚洲精品国产成人一区二区 | wwww欧美| 欧美一级片在线看 | 亚洲加勒比久久88色综合一区 | 国产麻豆高清视频在线第一页 | 日韩在线观 | 国产精品精品视频 | 欧美成人精品第一区二区三区 | 黄色三级毛片网站 | 成人做爰毛片免费视频 | 免费看色片| 大胆国模一区二区三区伊人 | 国产主播在线播放 | 欧美日韩在线第一页 | 国产黄色在线视频 | 久久r这里只有精品 | 亚洲欧洲国产视频 | 橘子视频在线观看 | 久久久久久国产精品mv | 黄色视频一级毛片 | 久久青青草原精品国产麻豆 | 国产成人成人一区二区 | 色女影院| 精品福利一区二区免费视频 | 久久精品区 | 91久久精品国产免费一区 |