加载本地化资源

时间:2015-01-11 11:25:06

标签: java localization

在我正在开发的项目中,我想根据当前的语言环境加载不同的资源。使用字符串,这非常简单:只需通过添加一些文件来创建资源包,例如Localization.propertiesLocalization_de.properties,然后通过ResourceBundle.getBundle("domain.project.Localization")加载它。

但是如何加载不是简单字符串的本地化资源?

具体来说,我想根据语言环境加载图像和HTML文件。只需获取该资源的正确URL即可。例如,我想要一个Welcome.htmlWelcome_de.html文件,并在当前区域设置为德语时加载更晚的文件。

简单地使用getClass().getResource("Welcome.html")不起作用,它总是返回该文件并且不进行语言环境处理。除了根据当前语言环境手动搞乱文件名之外,我还没有找到解决这个问题的便捷方法。

我提出的一个解决方案是在我的Localization.properties文件中添加一个包含正确本地化HTML文件名称的密钥。但这感觉很糟糕而且错了。

请注意,这不是Android应用程序,只是标准的Java 8桌面应用程序。

5 个答案:

答案 0 :(得分:2)

事实证明,与ResourceBundle.getBundle相同的行为非常容易。我looked at the code发现处理语言环境和文件名最重要的部分是ResourceBundle.Control

所以这是一个简单的方法,它将URL返回到本地化资源(遵循与资源包相同的文件名方案),而不需要缓存并仅支持当前的语言环境:

/** Load localized resource for current locale.
 * 
 * @param baseName Basename of the resource. May include a path.
 * @param suffix File extension of the resource.
 * @return URL for the localized resource or null if none was found.
 */
public static URL getLocalizedResource(String baseName, String suffix) {
    Locale locale = Locale.getDefault();
    ResourceBundle.Control control = ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT);
    List<Locale> candidateLocales = control.getCandidateLocales(baseName, locale);

    for (Locale specificLocale : candidateLocales) {
        String bundleName = control.toBundleName(baseName, specificLocale);
        String resourceName = control.toResourceName(bundleName, suffix);

        // Replace "Utils" with the name of your class!
        URL url = Utils.class.getResource(resourceName);
        if (url != null) {
            return url;
        }
    }

    return null;
}

如果有人想扩展它以支持通用语言环境作为参数:ResourceBundle.getBundleImpl实现中的重要部分是:

for (Locale targetLocale = locale;
     targetLocale != null;
     targetLocale = control.getFallbackLocale(baseName, targetLocale)) {
         List<Locale> candidateLocales = control.getCandidateLocales(baseName, targetLocale);
         ...
}

getCandidateLocales的最后一个条目是空的区域设置(Locale.ROOT)。在测试回退区域设置之前,在第一次for迭代中找到自默认资源以来的区域设置时,应该忽略它。

答案 1 :(得分:1)

(这是我的评论的补充,以便有更详细的解释)

您可以根据他们的语言将资源放在不同的文件夹中。

文件树可能如下所示:

  • pathToRessources

    • DE

      • 图片
        • Image1.png
        • Image2.png
      • 本地化
        • MainPage //这里有更多网站....
        • Impressum
    • EN

      • ...

使用像“文件本地化路径 - 建设者类”(声称有史以来最好的名字)

public static Locale currentLocale = Locale.GERMAN;

public static String baseRessourcePath = "Path to your basic folder for ressources";

public static String getLocalizedPathToFile(String ressourcePath)
{
    return Paths.get(currentLocale.getLanguage(), ressourcePath).toString();
}

无论您何时需要加载ressource,只需使用

调用您的加载程序
getLocalizedPath(PathToFile)

其中 PathToFile 类似于 /Images/Image1.png 或其他内容。

这也应该很容易用于客户端应用程序。

希望这会有所帮助:)

答案 2 :(得分:0)

拥有保存本地化文件名称的资源确实是一种有效的解决方案,但正如您所提到的那样繁琐。如果您需要在应用程序中显示HTML页面,为什么不嵌入小型Web服务器,并拥有服务器JSP页面?这样,整个HTML将保持不变,并且页面本身将被本地化。

另一种选择是使用本地模板引擎(如FreeMarker)并在提供HTML之前动态生成HTML。

答案 3 :(得分:0)

ListResourceBundle怎么办?

定义捆绑包:

public class MyBundle_fr_FR extends ListResourceBundle
{
    public Object[][] getContents()
    {
        return new Object[][] 
        {
            { "welcome_file", getClass().getResource("Welcome_fr.html") },
            { "another_file", getClass().getResource("foo_fr.html") }
        };
    }
}

public class MyBundle_de_DE extends ListResourceBundle
{
    public Object[][] getContents()
    {
        return new Object[][] 
        {
            { "welcome_file", getClass().getResource("Welcome_de.html") },
            { "another_file", getClass().getResource("foo_de.html") }
        };
    }
}

然后像这样使用它:

ResourceBundle bundle = ResourceBundle.getBundle("MyBundle", Locale.GERMANY);
URL url = (URL) bundle.getObject("welcome_file");

答案 4 :(得分:0)

你这样做的方式对我来说有点奇怪。我开发了一些国际应用程序,从未使用过这种方法您的方法的维护成本非常高。想象一下,您想要更改welcome.html文件的一部分,您需要更改所有其他欢迎文件,这是一项巨大的努力。 java中这个问题的常见解决方案是使用JSTL fmt taglib来获取包含键值对的一些属性文件的帮助,键值是固定的,值会根据你所在的语言环境而改变。例如,你在Localization.properties文件您有以下键值:

page.welcome.welcome=welcome

并且您有另一个名称为Localization_de.properties且具有相同键且值不同的文件

page.welcome.welcome=willkommen

现在,在您的welcome.jsp中,您可以使用类似<fmt:message key="page.welcome.welcome"/>之类的内容,以便在您的网页中呈现正确的值。对于图像,您可以采用相同的方法。只需将图像名称作为键导入每个属性文件,并将其正确命名为其值,并使用jsp中的键。 对于i18n,使用eclipse插件(如Resource Bundel Editor)可以让您的生活更轻松。

在我使用的其他语言框架中,像django我看到了与上面相同的方法。