5

显然ResourceBundle需要在它找到的文件中使用类似语法的属性文件。

我们有一种情况,我们想使用整个文件(在我们的例子中是 HTML 文件)作为“值”。这意味着我们没有这样的密钥。好吧,也许文件名可以作为关键。

这是一个目录树:

src/
    main/
        resources/
            html/
                content.html
                content_de.html
                content_fr.html
                content_es.html
                order.html
                order_de.html
                order_fr.html
                order_es.html

现在我们需要逻辑来根据当前语言环境找到正确的文件。如果当前语言环境是德语并且我正在寻找html/content.html文件,它应该找到html/content_de.html. 它不一定需要立即加载。Java中有一些现有的机制吗?我们需要手动执行此操作吗?

由于一些限制,我们目前计划不使用任何第三方库。因此,如果 Java 6 SE 中有可用的东西,那将是我们最好的选择;但是,如果您知道第三方库,请随意命名。

编辑#1:一个明显的解决方案是使用一个键messages.properties来命名该 HTML 文件。虽然这会起作用,但从长远来看,它可能会成为一件痛苦的事情(除此之外,我认为这不会解决我们所有的问题)。

编辑#2:我忘了说这是一个桌面应用程序。

4

3 回答 3

1

为了表明我没有做任何事情,这里有两次尝试使用“我们自己”的方法:

第一次尝试使用 locale-postfix 构建并直接加载资源:

  public void attempt1(String baseName, String extension) {
    List<String> locales = buildLocaleStrings(Locale.getDefault());
    String resourceFound = null;

    for (String locale : locales) {
      String resourceName = baseName + locale + "." + extension;
      URL resource = getClass().getClassLoader().getResource(resourceName);
      if (resource != null) {
        resourceFound = resourceName;
        break;
      }
    }
    System.out.println("found #1: " + resourceFound);
  }

  private List<String> buildLocaleStrings(Locale localeBase) {
    String locale = "_" + localeBase;
    List<String> locales = new ArrayList<String>();

    while (locale.length() > 0) {
      locales.add(locale);
      locale = locale.replaceFirst("_[^_]*?$", "");
    }
    locales.add("");

    return locales;
  }

第二次尝试“滥用”ResourceBundle及其toString()

  public void attempt2(String baseName, final String extension) {
    ResourceBundle.Control control = new ResourceBundle.Control() {

      private String resourceFound = null;

      @Override
      public List<String> getFormats(String baseName) {
        return Arrays.asList(extension);
      }

      @Override
      public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException {
        String bundleName = toBundleName(baseName, locale);
        String resourceName = toResourceName(bundleName, format);

        if (loader.getResource(resourceName) != null) {
          resourceFound = resourceName;
          return new ResourceBundle() {

            @Override
            public Enumeration<String> getKeys() {
              return null;
            }

            @Override
            protected Object handleGetObject(String key) {
              return null;
            }

          };
        }
        return null;
      }

      @Override
      public String toString() {
        return resourceFound;
      }
    };

    ResourceBundle.getBundle(baseName, control);

    System.out.println("found #2: " + control.toString());
  }

示例调用:

  public void proof() {
    attempt1("html/content", "html");
    attempt2("html/content", "html");
  }

两者都找到相同的文件。

老实说,我都不喜欢。

于 2012-09-02T20:58:55.723 回答
1

为了使这更理想,如果您的文件命名约定保持一致(即对于每个区域设置,您使用语言的两个字母前缀 - 意思是“en”表示英语,“fr”表示法语,“es”表示西班牙语),那么这个过程非常简单。

我们将使用Properties该类来读取属性,然后使用MessageFormat从结果属性中格式化我们想要的适当语言环境。

首先,我们对属性文件进行更改——我们对其进行参数化,以便我们能够传入我们喜欢的任何内容。

content=content_{0}.html
order=order_{0}.html

表示属性的{0}第一个参数。

现在,我们只需要加载属性,并传入适当的参数。

Properties prop = new Properties();
try {
    MessageFormat messageFormat = new MessageFormat("");
    String property;
    // change to suit the locale you wish to serve
    String[] param = {"en"};

    prop.load(new FileReader(new File("/full/path/to/property/file.properties")));
    property = prop.getProperty("content");
    messageFormat.applyPattern(property);
    System.out.println(messageFormat.format(param));
} catch(IOException ioex) {
    System.out.println("no property file here");
}

这打印出来:

content_en.html

在进行此调用之前确保您要访问的 HTML 文件存在,或者将其转换为返回的函数String,并确保文件在返回之前存在。

于 2012-09-02T17:16:18.043 回答
0

我知道这是一个老问题,但我刚刚遇到了完全相同的问题,我找到了一个更优雅的解决方案。您需要将区域设置委托给标准 Java API 的文件映射,就像 API 解决键的翻译一样。因此,在您的示例中,如果当前语言环境是 fr_FR,您希望加载名为“content_fr.html”和“order_fr.html”的文件,对吗?

然后只需拥有一组资源包文件并指定一个变量以将当前语言环境转换为最接近的现有语言环境:

文件翻译.properties:

localeCode = 

文件translation_fr.properties:

localeCode = fr

文件 translation_en.properties:

localeCode = en

然后您只需要读取“localeCode”的值并将其与“content”和“.html”或“order”和“.html”连接起来。

于 2015-06-24T19:33:45.293 回答