显然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文件。虽然这会起作用,但从长远来看它可能会成为一个痛苦(除此之外,我认为这不会解决我们所有的问题)。
答案 0 :(得分: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
的函数,并确保该文件在返回之前存在。
答案 1 :(得分: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");
}
两者都找到相同的文件。
老实说,我不喜欢。
答案 2 :(得分:0)
我知道这是一个老问题,但我遇到了完全相同的问题,我找到了一个更优雅的解决方案。您需要的是将语言环境委派给文件映射到标准Java API,就像API解决密钥翻译一样。因此,在您的示例中,如果当前区域设置为fr_FR,您要加载名为“content_fr.html”和“order_fr.html”的文件,对吧?
然后只需拥有一组资源包文件并指定一个变量将当前语言环境转换为最近的现有语言环境:
文件translation.properties:
localeCode =
文件translation_fr.properties:
localeCode = fr
文件translation_en.properties:
localeCode = en
然后你只需要读取“localeCode”的值并将其与“content”和“.html”或“order”和“.html”连接起来。