25

我的主 jar 中打包了一些资源包

widget_en.properties
widget_de.properties

我根据我的默认语言环境检索资源包,如下所示

ResourceBundle.getBundle("widget", Locale.getDefault());

但我想向用户展示支持的可用语言列表,以便可以选择可能与其计算机默认设置不同的语言

但是我在 ResourceBundle 中找不到列出可用语言环境的方法,我不想对列表进行硬编码,因为在添加另一个资源包时我可能会忘记更新它。

编辑

因为我只有不同语言的资源包(我没有国家细化),所以我通过遍历所有已知的语言代码生成了一个列表,并将每个语言代码检查为资源。

String[]langs = Locale.getISOLanguages();
for(String lang:langs)
{
      URL rb = ClassLoader.getSystemResource("widget_"+lang+".properties");
      if(rb!=null)
      {
            System.out.println("Found:"+rb.toString());
      }
}
4

4 回答 4

6

如果您真的将资源文件打包到JAR中,那么我会这样做:

public static void main(String[] args) {
  Set<ResourceBundle> resourceBundles = getResourceBundles(A.class.getName());
  if (resourceBundles.isEmpty())
    // ...
}

public static Set<ResourceBundle> getResourceBundles(String baseName) {
  Set<ResourceBundle> resourceBundles = new HashSet<>();

  for (Locale locale : Locale.getAvailableLocales()) {
    try {
      resourceBundles.add(ResourceBundle.getBundle(baseName, locale));
    } catch (MissingResourceException ex) {
      // ...
    }
  }

  return Collections.unmodifiableSet(resourceBundles);
}

如果您关心您的 JAR,那么您至少会获得一组包含给定baseName.

如果您只有具有类似名称的资源,则baseName_<country>此方法可以完美运行,因为只有那些ResourceBundles将添加到 JAR 中存在的集合中。即使您决定需要单独的baseName_en_USbaseName_en_UK资源,它也会起作用,这并非闻所未闻。

无耻的自插:我写了一个ResourceBundle.Control以 aCharset为参数的,如果你想加载 UTF-8 编码的资源文件,你可能会对它感兴趣。它在 GitHub 上可用。

于 2012-08-22T13:04:56.250 回答
5

我不认为有一个 API,因为可以动态创建新的有效语言环境对象:

Locale locale = new Locale("abcd");

无需在某处注册。widget_abcd.properties然后您可以不受限制地使用资源包 :

ResourceBundle resource= ResourceBundle.getBundle("widget", new Locale("abcd"));

java.util.LocaleAPI 文档:

因为 Locale 对象只是区域的标识符,所以在构造 Locale 时不会执行有效性检查。如果您想查看特定资源是否可用于您构建的 Locale,则必须查询这些资源。

为了解决这个问题,您仍然可以遍历资源目录中所有名为“widget_”的文件并发现新添加的资源包。

请注意,由于上述原因,这Locale.getAvailableLocales() 不是 100% 确定的:您可能有一天会定义一个非标准的语言环境。但是,如果您只添加几个标准语言环境,则可以使用此静态方法迭代系统语言环境并获取相应的包。

于 2012-08-22T12:14:16.643 回答
2

如果你能做出两个基本假设:

1) 你有一个没有语言环境的默认资源包,或者至少有一个你知道的语言环境。

2)您所有的资源都在同一个位置(即单个 jar 文件中的相同路径)

然后您可以获取单个资源的 URL:

URL url = SomeClass.class.getClassLoader().getResource("widget.properties");

一旦你有了它,你应该能够解析 URL。

如果您使用 commons-vfs,您应该能够将 URL 转换为 FileObject:

FileSystemManager manager = VFS.getManager();
FileObject resource = manager.resolveFile(url.toExternalForm());
FileObject parent = resource.getParent();
FileObject children[] = parent.getChildren();
// figure out which ones are bundles, and parse the names into a list of locales.

这将为您省去处理 jar:style url 等复杂性的麻烦,因为 vfs 会为您处理这些。

于 2012-08-22T12:48:56.683 回答
2

A 通过列出文件来解决它。

public class JavaApplication1 {

    public static final ArrayList<String> LOCALES = new ArrayList<>();

    static {
        try {
            File f = new File(JavaApplication1.class.getResource("/l10n").toURI());
            final String bundle = "widget_";// Bundle name prefix.
            for (String s : f.list(new FilenameFilter() {
                @Override
                public boolean accept(File dir, String name) {
                    return name.startsWith(bundle);
                }
            })) {
                LOCALES.add(s.substring(bundle.length(), s.indexOf('.')));
            }
        } catch (URISyntaxException x) {
            throw new RuntimeException(x);
        }
        LOCALES.trimToSize();
    }

    ...

}
于 2015-12-31T20:21:09.737 回答