资源包技巧和最佳实践
基本
java.util.ResourceBundle定義了用于訪問Java中翻譯的標(biāo)準(zhǔn)化方法。 它們包含特定于語言環(huán)境的資源。 資源束屬于其成員具有相同基本名稱的族,但是其名稱還具有標(biāo)識
他們的語言環(huán)境。 族中的每個資源束都包含相同的項目,但是這些項目已針對該資源束所代表的語言環(huán)境進行了翻譯。 這些是鍵/值對。 這些鍵唯一地標(biāo)識捆綁軟件中特定于語言環(huán)境的對象。
最基本的示例使用以下知識:
Messages.properties
Messages_de.properties Messages_en.properties
如果您需要在應(yīng)用程序中查詢包,則只需調(diào)用
ResourceBundle bundle = ResourceBundle.getBundle("Messages");方法并查詢返回的包:
bundle.getString("welcome.message");如果您想在此處使用哪種語言環(huán)境,那是對的。 String構(gòu)造函數(shù)隱式使用Locale.getDefault()解析語言。 那可能不是您想要的。 所以你應(yīng)該ResourceBundle bundle =
ResourceBundle.getBundle("Messages", locale);檢索捆綁軟件后,您將無法設(shè)置語言環(huán)境。 每個ResourceBundle都有一個定義的語言環(huán)境。
命名的東西
?
關(guān)于命名的一些想法。 用其內(nèi)容命名捆綁屬性。 您可以通過簡單地將它們命名為“消息”和“錯誤”等來采用更通用的方式。但是,每個子系統(tǒng)或組件也可以具有捆綁軟件。 無論您需要什么。 要維護內(nèi)容,要輸入大量條目并不容易。 因此,任何類型的上下文拆分都會使開發(fā)人員感到高興。 捆綁軟件屬性文件等效于類。 相應(yīng)地命名。 進一步,您應(yīng)該找到一個用于命名密鑰的通用系統(tǒng)。 根據(jù)為屬性文件選擇的拆分,還可能在密鑰中引入某種子系統(tǒng)或組件名稱空間。 頁面前綴也是可能的。 明智地考慮一下,并加以解決。 您的目標(biāo)是盡量減少密鑰重復(fù)。
封裝
?
如您所見,您經(jīng)常使用包的字符串表示形式。 這些實際上是文件名(或更好的類名),您可以通過一個簡單的枚舉來更好地封裝所有內(nèi)容:
有了這個你就可以寫
ResourceBundle bundle = ResourceBundle.getBundle(MESSAGES.getBundleName()); Java Server Faces和ResourceBundle
?
要在基于jsf的應(yīng)用程序中使用資源包,您只需在faces-config.xml中定義它們,并使用xhtml文件中的快捷方式。
JSF負責(zé)其余的工作。 那么參數(shù)替換呢? 考慮如下的鍵值對:
welcome.name=Hi {0}! How are you?您可以通過f:param標(biāo)簽傳遞參數(shù):
<h:outputFormat value="#{msgs['welcome.name']}"><f:param value="Markus" /></h:outputFormat>要更改語言,您必須為當(dāng)前的FacesContext實例設(shè)置特定的語言環(huán)境。 最好通過值更改偵聽器執(zhí)行此操作:
public void countryLocaleCodeChanged(ValueChangeEvent e) {String newLocaleValue = e.getNewValue().toString();//loop country map to compare the locale codefor (Map.Entry<String, Object> entry : countries.entrySet()) {if (entry.getValue().toString().equals(newLocaleValue)) {FacesContext.getCurrentInstance().getViewRoot().setLocale((Locale) entry.getValue());}}} EJB中的資源包
?
JSF顯然很容易集成。 在EJB中使用這些捆綁包怎么辦? 基本上是一樣的。 您可以使用相同的機制來使用和使用捆綁包。 您應(yīng)該記住一件事。 您可能不想始終使用默認語言環(huán)境。 因此,您必須找到一種從UI向下傳遞語言環(huán)境的方法。 如果您想通過@Produces批注@Injecting MessageBundle,則必須考慮多次。 尤其是在使用@Stateless EJB時。 這些實例將合并,您必須將語言環(huán)境傳遞給需要了解當(dāng)前語言環(huán)境的任何業(yè)務(wù)方法。 通常,您可以使用參數(shù)對象或某種用戶會話配置文件來執(zhí)行此操作。 不要將語言環(huán)境全部添加為方法簽名。
來自數(shù)據(jù)庫的資源包
?
在大多數(shù)情況下,我看到您需要從數(shù)據(jù)庫中提取密鑰。 鑒于ResourceBundle的內(nèi)部工作原理(每個語言環(huán)境一個“類”),您最終不得不在自己的ResourceBundle實現(xiàn)中實現(xiàn)邏輯。 您在網(wǎng)絡(luò)上找到的大多數(shù)示例都是通過重寫handleGetObject(String key)方法來實現(xiàn)的。 我不喜歡這種方法,尤其是因為我們有一個更好的方法來使用ResourceBundle.Control機制。 現(xiàn)在,您可以覆蓋newBundle()方法并返回自己的ResourceBundle實現(xiàn)。 您所要做的就是將自己的Control設(shè)置為DatabaseResourceBundle的父級:
DBControl返回MyResourceBundle,它是一個ListResourceBundle:
protected class DBControl extends Control {@Overridepublic ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload)throws IllegalAccessException, InstantiationException, IOException {return new MyResources(locale);}/*** A simple ListResourceBundle*/protected class MyResources extends ListResourceBundle {private Locale locale;/*** ResourceBundle constructor with locale** @param locale*/public MyResources(Locale locale) {this.locale = locale;}@Overrideprotected Object[][] getContents() {TypedQuery<ResourceEntity> query = _entityManager.createNamedQuery("ResourceEntity.findForLocale", ResourceEntity.class);query.setParameter("locale", locale);List<ResourceEntity> resources = query.getResultList();Object[][] all = new Object[resources.size()][2];int i = 0;for (Iterator<ResourceEntity> it = resources.iterator(); it.hasNext();) {ResourceEntity resource = it.next();all[i] = new Object[]{resource.getKey(), resource.getValue()};values.put(resource.getKey(), resource.getValue());i++;}return all;}}}如您所見,這由一個entitymanager和一個簡單的ResourceEntity作為后盾,該ResourceEntity具有構(gòu)建不同捆綁軟件所需的所有字段和NamedQueries。
@Id@GeneratedValue(strategy = GenerationType.AUTO)private Long id;@Column(name = "i18n_key")private String key;@Column(name = "i18n_value")private String value;@Column(name = "i18n_locale")private Locale locale;通過將捆綁包放入私有Map <String,String>值= new HashMap <String,String>(); 在首次構(gòu)建捆綁包之后,您還可以使用一種很好的方法來緩存結(jié)果。
這仍然不是最好的解決方案,因為ResourceBundles具有緩存的方式。 但我稍后可能會更詳細地探討這一點。 到現(xiàn)在為止,此捆綁包將被永久緩存(或至少直到下一次重新部署為止)。
改寫為語言切換
?
最后要提到的是,您還可以在此處添加一些精美的插件。 如果您已經(jīng)有了JSF語言切換魔術(shù),則可以輕松地將ocpsoft的重寫添加到您的應(yīng)用程序中。 這是一種將網(wǎng)址中的語言編碼的簡單方法,例如http://yourhost.com/Bundle-Provider-Tricks/en/index.html 您要做的就是通過添加兩個簡單的依賴關(guān)系來向游戲添加重寫:
重寫需要您添加自己的ConfigurationProvider,這是保存重寫規(guī)則的中心位置。 執(zhí)行以下操作:
public class BundleTricksProvider extends HttpConfigurationProvider {@Overridepublic Configuration getConfiguration(ServletContext context) {return ConfigurationBuilder.begin()// Locale Switch.addRule(Join.path("/{locale}/{page}.html").to("/{page}.xhtml").where("page").matches(".*").where("locale").bindsTo(PhaseBinding.to(El.property("#{languageSwitch.localeCode}")).after(PhaseId.RESTORE_VIEW)));}@Overridepublic int priority() {return 10;} }接下來是將一個名為“ org.ocpsoft.rewrite.config.ConfigurationProvider”的文件添加到您的META-INF / services文件夾,并在其中放置您的ConfigurationProvider實現(xiàn)的標(biāo)準(zhǔn)名稱。 最后要調(diào)整的是LanguageSwitch bean中的邏輯。 重寫不能觸發(fā)ValueChangeEvent(據(jù)我所知:)),因此您必須在調(diào)用setter時添加一些魔術(shù)來更改Locale。 就是這樣..非常簡單!
參考:來自JCG合作伙伴 Markus Eisele的Resource Bundle技巧和最佳實踐 ,位于Enterprise Software Development with Java博客上。
翻譯自: https://www.javacodegeeks.com/2012/09/resource-bundle-tricks-and-best.html
總結(jié)
以上是生活随笔為你收集整理的资源包技巧和最佳实践的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 修复Sonar中常见的Java安全代码冲
- 下一篇: Jenkins:部署JEE工件