2012-11-16 55 views
2

我試圖從BuildPath中得到i18n屬性文件。如果您試圖獲得PropertiesFileResourceBundle.getBundle將拋出java.util.MissingResourceException。有沒有一種方法可以從BuildPath之外加載i18n文件,但是仍然能夠檢測到您的語言環境?沒有RessourceBundle的Java i18n

編輯:

這裏是解決方案,我能與Paweł Dyda幫助創建。也許有人會需要它。可能會有一些改進,但它可以工作;)

import java.io.File; 
import java.io.FileNotFoundException; 
import java.io.UnsupportedEncodingException; 
import java.net.URLDecoder; 
import java.util.List; 
import java.util.Locale; 
import java.util.MissingResourceException; 
import java.util.ResourceBundle.Control; 

import org.apache.commons.configuration.ConfigurationException; 
import org.apache.commons.configuration.PropertiesConfiguration; 
import org.apache.commons.io.FilenameUtils; 
import org.apache.log4j.Logger; 

public class GlobalConfigurationProvider { 

    Logger logger = Logger.getLogger(GlobalConfigurationProvider.class); 

    private static GlobalConfigurationProvider instance; 

    PropertiesConfiguration i18n; 


    private GlobalConfigurationProvider() { 
     String path = GlobalConfigurationProvider.class.getProtectionDomain().getCodeSource().getLocation().getPath(); 
     String decodedPath = ""; 
     try { 
      decodedPath = URLDecoder.decode(path, "UTF-8"); 
      // This ugly thing is needed to get the correct 
      // Path 
      File f = new File(decodedPath); 
      f = f.getParentFile().getParentFile(); 
      decodedPath = f.getAbsolutePath(); 
     } catch (UnsupportedEncodingException e) { 
      e.printStackTrace(); 
      this.logger.error("Failed to decode the Jar path", e); 
     } 
     this.logger.debug("The Path of the jar is: " + decodedPath); 

     String configFolder = FilenameUtils.concat(decodedPath, "cfg"); 
     String i18nFolder = FilenameUtils.concat(configFolder, "i18n"); 
     File i18nFile = null; 
     try { 
      i18nFile = this.getFileForLocation(new File(i18nFolder), Locale.getDefault()); 
     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
      this.logger.error("Can't find the LocaleFile", e); 
     } 
     if (!i18nFile.exists()) { 
      // If this can't be found something is wrong 
      i18nFile = new File(i18nFolder, "eng.i18n"); 
      if (!i18nFile.exists()) { 
       this.logger.error("Can't find the i18n File at the Location: " + i18nFile.getAbsolutePath()); 
      } 
     } 

     this.logger.debug("The Path to the i18n File is: " + i18nFile); 

     try { 
      this.i18n = new PropertiesConfiguration(i18nFile); 
     } catch (ConfigurationException e) { 
      this.logger.error("Couldn't Initialize the i18nPropertiesFile", e); 
     } 
    } 

    private File getFileForLocation(File i18nFolder, Locale locale) throws FileNotFoundException { 
     Control control = Control.getControl(Control.FORMAT_DEFAULT); 
     List<Locale> locales = control.getCandidateLocales(this.getBaseName(), locale); 
     File f = null; 
     for (Locale l : locales) { 
      String i18nBundleName = control.toBundleName(this.getBaseName(), l); 
      String i18nFileName = control.toResourceName(i18nBundleName, "properties"); 
      f = new File(i18nFolder, i18nFileName); 
      this.logger.debug("Looking for the i18n File at: " + f); 
      if (f.exists()) { 
       return f; 
      } 
     } 
     // Last try for a File that should exist 
     if (!locale.equals(Locale.US)) { 
      return this.getFileForLocation(i18nFolder, Locale.US); 
     } 
     throw new FileNotFoundException("Can't find any i18n Files in the Folder " + i18nFolder.getAbsolutePath()); 
    } 

    private String getBaseName() { 
     // TODO: Get this from the Settings later 
     return "messages"; 
    } 

    public static GlobalConfigurationProvider getInstance() { 
     if (GlobalConfigurationProvider.instance == null) { 
      GlobalConfigurationProvider.instance = new GlobalConfigurationProvider(); 
     } 
     return GlobalConfigurationProvider.instance; 
    } 

    public String getI18nString(String key) { 
     try { 
      return this.i18n.getString(key); 
     } catch (MissingResourceException e) { 
      return '!' + key + '!'; 
     } 
    } 

} 
+0

你可以使用'PropertyReader',但這樣做你不會實現I18N。 –

+0

是的,我知道我可以像普通的屬性文件一樣使用它。但對我來說,它很重要,它會自動獲取語言環境。 – Robin

回答

2

當然有一些方法可以做到這一點。無論如何,我相信你的問題是你試圖加載的資源的錯誤路徑。

儘管如此,當然您正在尋找使用語言環境回退機制來加載特定資源的方式。可以辦到。您可能想看看ResourceBundle.Control課程。例如你可以回退語言環境列表:

Control control = Control.getControl(Control.FORMAT_DEFAULT); 
List<Locale> locales = control.getCandidateLocales("messages", 
      Locale.forLanguageTag("zh-TW")); 

從那裏,你其實可以創建你正在尋找的資源文件的名稱:

for (Locale locale : locales) { 
     String bundleName = control.toBundleName("messages", locale); 
     String resourceName = control.toResourceName(bundleName, "properties"); 
     // break if resource under given name exist 
} 

然後,你需要加載該資源以某種方式 - 您可能想要使用ClassLoader'sgetResourceAsStream(String)爲您打開InputStream。最後一步可能是實際使用的流作爲輸入到PropertyResourceBundle

ResourceBundle bundle = new PropertyResourceBundle(inputStream); 

您也可以通過一個Reader而不是InputStream,其中至少有一個好處 - 你實際上可能允許屬性文件中UTF進行編碼-8,而不是常規的ISO8859-1。

+0

我認爲這不會工作,如果屬性文件不在構建路徑? – Robin

+1

@Robin:因爲您可以將任意的'InputStream'或'Reader'傳遞給PropertyResourceBundle,所以屬性文件的位置確實無關緊要。您可能無法使用'ClassLoader'加載它,但是您不需要。 BTW。您可以使用[JarFile](http://docs.oracle.com/javase/7/docs/api/java/util/jar/JarFile.html)從任意位置讀取任意Jar文件。 –

+0

好吧,我現在得到你的答案。這可能是一個非常好的主意!不幸的是我現在無法嘗試。但我會完全嘗試它,因爲它似乎比我的實際解決方案更好。 – Robin