因爲遇到了國際化的需求,研究了一下特此記錄!java
靜態國際化(頁面中比較固定元素如,導航,按鈕,label等)
web
基於Struts2能夠實現國際化數據庫
將須要國際化的元素保存成applicationResource_en_US.properties和applicationResource_zh_CN.properties,有幾國語言就保持幾份。app
在Struts.xml中添加 webapp
<constant name="struts.custom.i18n.resources" value="applicationResource"> </constant><constant name="struts.i18n.encoding" value="UTF-8" />
在jsp頁面中獲取國際化字符串的方法:<s:text name="webapp.footer" />jsp
在action中獲取國際化字符串的方法:getText函數數據庫設計
在普通java文件中獲取國際化字符串方法:因爲普通java文件沒有getText函數,只能寫個工具類根據當前語言環境獲取不一樣資源文件中的值
函數
public class ApplicationResourceProperties { private ApplicationResourceProperties() { } private static ResourceBundle rb; public static synchronized void reload(){ //rb = ResourceBundle.getBundle("applicationResource");// 這句話就是綁定了名爲application的資源文件,後綴都不用寫的 } public static String getValue(String key) { Locale l=(Locale) ServletActionContext.getRequest().getSession().getAttribute("WW_TRANS_I18N_LOCALE"); if(l==null) { l=ServletActionContext.getRequest().getLocale(); } ResourceBundle rb=ResourceBundle.getBundle("applicationResource", l); String temp = rb.getString(key); return temp; } static{ reload(); } }
若是須要國際化的資源保持在數據中,可採用以下方式實現國際化(適合元素相對固定,不會常常改變)工具
<s:property value="%{getText(us_classname)}"/> <!-- 先獲取數據庫中us_classname對應的值,好比:InstructionForProduct,再去資源文件中找"InstructionForProduct"對應的值 -->
動態國際化(元素保持在數據庫中,且會常常變化)spa
(1)採用冗餘數據的方式存儲國際化數據。在數據庫表中引入 標識語種的 LocaI 字段,每一條原始數據記錄在國際化的數據表中 都對應有多條各類語言的記錄。這種方案能夠解決國際化數據的存 儲和訪問的問題,可是,數據表中和國際化無關的字段會有冗餘數 據,數據更新也須要涉及全部語種的記錄以維護數據的一致性,從 而增長了系統運行時的開銷。
(2) 採用單表存儲國際化數據。在數據庫中用專門的數據表維 護國際化數據,記爲 LocaITabIe ,其餘數據表的國際化字段存儲 LocaITable 表中記錄的主鍵值,經過主鍵值與 LocaITable 表關聯。 這種方案將國際化數據和非國際化數據分離開來,減小了冗餘數據, 提升了數據一致性,不過,用單表存儲會形成單表數據過多,從而 增長對該表的訪問時間。因爲國際化的J2EE 系統對國際化數據的插 入、修改、刪除等訪問操做會比較頻繁,在系統數據量超過→定規 模的狀況下,這種方案將大爲下降系統的執行效率。
針對以上兩種設計方案各自的優點和缺點,將這兩種方 案結合,並在此基礎上引入分表的概念,提出了一種混合的 數據庫設計方案。這種方案既能夠減小冗餘數據,維護數據 的一致性,又能夠保證系統的訪問效率。
經過分析數據能夠發現,系統存儲在數據庫中的數據可 以分爲兩種類型。第 種類型的數據通常在系統啓動的時候 加載,在系統運行時被訪問,但基本不進行修改和刪除操做。 這種數據通常是系統的固有信息的描述,好比國家列表、省 市列表等。第 種類型的數據在系統運行時產生,並且在運 行時會有比較多的添加、修改和刪除操做。這種類型的數據 在國際化數據中佔大多數。針對這兩種不一樣類型的數據,採 用了不一樣的國際化方法。
對於第1 種類型的數據,因爲訪問操做比較少,並且一 般能夠在系統運行時能夠直接載入內存,所以採用單表存儲 的方式,能夠在不影響系統執行效率的前提下,避免相關冗 餘數據的出現。對於第 2種類型的數據,因爲訪問操做會比 較頻繁,在系統運行時的數據積累常常會超過必定規模,不 適宜用單表操做,所以採用在數據表中添加標識語種的 Local 字段的方式來存儲。爲了解決上文提到的這種方式所存在的 數據冗餘和一致性的問題,提出了分表的方法。
冗餘數據是因爲非國際化字段的存在而產生的,也正是 因爲冗餘數據的存在,才引起了數據一致性的問題。若是將 國際化和非國際化字段分開,將原始表拆分紅兩個表,就可 以免冗餘數據的產生。咱們提出的分表的方法正是基於這 一思想。分表的具體方法以下: 對於原始表 A(問葉 川兒 ,其中 key 是表 的主鍵字段, (i=1 ,… n) 是表 的非主鍵字段,將 拆分紅兩個表 A' (key ,fml ,fm2 ,...,f Aúx:al(時劇,flq ,fk2 門兒) ,其中 1m; (i =1 ,..., p) 是表 的非國際化字段, hj (j=I ,2 ,... q) 的國際化字段,表 的主鍵字段是 key ALocal key local 爲複合主鍵。 這種分表的方式既避免了冗餘數據的出現,也保證了數 據的一致性。《 不過,這種方法也有不利之處。原始表的拆分使得對原 始數據表的訪問一般須要轉變成對兩個拆分後的表的同時訪問
(3).在數據庫中,對於須要國際化的元素,數據庫中對應多列,列名包含語言信息。例如航空公司默認名稱對應列AirelineName,英文名稱對應AirelineName_en,簡體中文名稱對應AirelineName_zh.對應的java對象屬性名稱保持這種命名風格。利用java反射機制,經過統一的接口獲取語言相關的航空公司名稱,代碼以下:
public static String localize(String localeString,Object obj,String method){ Class cla = obj.getClass();//取得Class對象 Method m = cla.getMethod(method+localeString,null);//取得語言信息相關的方法 String str = String.valueOf(m.invoke(obj,null)); //執行方法,結果爲String if(str == null) str= ""; return str; }
接口中,localeString爲標識語言信息的字符串,如「_en」。obj爲JAVA對象,method爲獲取默認屬性的方法名。