加载本地化资源
Load localized resources
在我正在进行的项目中,我想根据当前语言环境加载不同的资源。使用字符串,这非常简单:只需通过添加一些文件创建资源包,例如 Localization.properties
和 Localization_de.properties
,然后通过 ResourceBundle.getBundle("domain.project.Localization")
.
加载它
但是如何加载不是简单字符串的本地化资源?
具体来说,我想根据区域设置加载图像和 HTML 文件。为该资源获取正确的 URL 就足够了。例如,我想要一个 Welcome.html
和 Welcome_de.html
文件,并在当前语言环境为德语时加载后者。
简单地使用 getClass().getResource("Welcome.html")
是行不通的,它总是准确地返回那个文件并且不进行语言环境处理。除了根据当前语言环境手动修改文件名之外,我还没有找到解决这个问题的便捷方法。
我想出的一个解决方案是向我的 Localization.properties
文件添加一个密钥,其中包含正确的本地化 HTML 文件的名称。但这感觉很老套而且是错误的。
请注意,这不是 Android 应用程序,只是一个标准的 Java 8 桌面应用程序。
拥有保存本地化文件名称的资源确实是一个有效的解决方案,但正如您所提到的那样很麻烦。如果您需要在您的应用程序中显示 HTML 页面,为什么不嵌入小型 Web 服务器并让它服务器 JSP 页面?这样,整个 HTML 将保持不变,页面本身将被本地化。
另一种选择是使用本地模板引擎(例如 FreeMarker)并在提供服务之前动态生成 HTMLs。
定义您的捆绑包:
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");
你做这件事的方式对我来说有点奇怪。我开发了一些国际应用程序,但从未使用过这种方法。您的方法的维护成本非常高。想象一下,您想要更改 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)中,我看到了与上述相同的方法。
(这是对我的评论的补充,以便有更详细的解释)
您可以根据语言将资源放在不同的文件夹中。
文件树可能如下所示:
路径资源
DE
- 图片
- Image1.png
- Image2.png
- 本地化
- MainPage // 更多网站信息....
- 印象
EN
- ...
并像 "file-localization-path-builder-class" 一样使用(声称有史以来最好的名字)
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();
}
无论您需要在何处加载资源,只需使用
调用您的加载程序
getLocalizedPath(PathToFile)
其中 PathToFile 类似于 /Images/Image1.png 或其他内容。
这也应该很容易用于客户端应用程序。
希望这对您有所帮助:)
实际上很容易获得与 ResourceBundle.getBundle
相同的行为。我 looked at the code and found that the most important part for handling of the locales and filenames is ResourceBundle.Control.
所以这里有一个简单的方法 returns 将 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
迭代中找到,然后再测试后备区域设置。
在我正在进行的项目中,我想根据当前语言环境加载不同的资源。使用字符串,这非常简单:只需通过添加一些文件创建资源包,例如 Localization.properties
和 Localization_de.properties
,然后通过 ResourceBundle.getBundle("domain.project.Localization")
.
但是如何加载不是简单字符串的本地化资源?
具体来说,我想根据区域设置加载图像和 HTML 文件。为该资源获取正确的 URL 就足够了。例如,我想要一个 Welcome.html
和 Welcome_de.html
文件,并在当前语言环境为德语时加载后者。
简单地使用 getClass().getResource("Welcome.html")
是行不通的,它总是准确地返回那个文件并且不进行语言环境处理。除了根据当前语言环境手动修改文件名之外,我还没有找到解决这个问题的便捷方法。
我想出的一个解决方案是向我的 Localization.properties
文件添加一个密钥,其中包含正确的本地化 HTML 文件的名称。但这感觉很老套而且是错误的。
请注意,这不是 Android 应用程序,只是一个标准的 Java 8 桌面应用程序。
拥有保存本地化文件名称的资源确实是一个有效的解决方案,但正如您所提到的那样很麻烦。如果您需要在您的应用程序中显示 HTML 页面,为什么不嵌入小型 Web 服务器并让它服务器 JSP 页面?这样,整个 HTML 将保持不变,页面本身将被本地化。
另一种选择是使用本地模板引擎(例如 FreeMarker)并在提供服务之前动态生成 HTMLs。
定义您的捆绑包:
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");
你做这件事的方式对我来说有点奇怪。我开发了一些国际应用程序,但从未使用过这种方法。您的方法的维护成本非常高。想象一下,您想要更改 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)中,我看到了与上述相同的方法。
(这是对我的评论的补充,以便有更详细的解释)
您可以根据语言将资源放在不同的文件夹中。
文件树可能如下所示:
路径资源
DE
- 图片
- Image1.png
- Image2.png
- 本地化
- MainPage // 更多网站信息....
- 印象
- 图片
EN
- ...
并像 "file-localization-path-builder-class" 一样使用(声称有史以来最好的名字)
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();
}
无论您需要在何处加载资源,只需使用
调用您的加载程序getLocalizedPath(PathToFile)
其中 PathToFile 类似于 /Images/Image1.png 或其他内容。
这也应该很容易用于客户端应用程序。
希望这对您有所帮助:)
实际上很容易获得与 ResourceBundle.getBundle
相同的行为。我 looked at the code and found that the most important part for handling of the locales and filenames is ResourceBundle.Control.
所以这里有一个简单的方法 returns 将 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
迭代中找到,然后再测试后备区域设置。