如何避免 Java ResourceBundle 字符串中的重复?
-
25-09-2019 - |
题
我们有很多包含相同子字符串的字符串,从有关检查日志或如何联系支持人员的句子,到包含公司或产品名称的类似品牌的字符串。重复给我们自己带来了一些问题(主要是拼写错误或复制/粘贴错误),但它也导致了问题,因为它增加了翻译人员必须翻译的文本量。
我想出的解决方案是这样的:
public class ExpandingResourceBundleControl extends ResourceBundle.Control {
public static final ResourceBundle.Control EXPANDING =
new ExpandingResourceBundleControl();
private ExpandingResourceBundleControl() { }
@Override
public ResourceBundle newBundle(String baseName, Locale locale, String format,
ClassLoader loader, boolean reload)
throws IllegalAccessException, InstantiationException, IOException {
ResourceBundle inner = super.newBundle(baseName, locale, format, loader, reload);
return inner == null ? null : new ExpandingResourceBundle(inner, loader);
}
}
ExpandingResourceBundle
委托给真实的资源包,但执行 {{this.kind.of.thing}} 的转换以查找资源中的键。
每次你想要获得其中之一时,你都必须去:
ResourceBundle.getBundle("com/acme/app/Bundle", EXPANDING);
这在一段时间内效果很好。
最终发生的情况是,一些新代码(在我们的例子中是从 Matisse 中自动生成的代码)查找相同的资源包,而不指定自定义控件。如果您编写一个简单的单元测试,先调用它,然后调用它,这似乎是不可重现的,但当应用程序真正运行时,就会发生这种情况。不知何故里面的缓存 ResourceBundle
弹出好的值并用损坏的值替换它。我还没有弄清楚为什么 Sun 的 jar 文件是在没有调试信息的情况下编译的,因此调试它是一件苦差事。
我的问题:
有没有某种方法可以全局设置我可能不知道的默认 ResourceBundle.Control?这将相当优雅地解决所有问题。
是否有其他方法可以优雅地处理此类事情,也许根本不篡改 ResourceBundle 类?
解决方案
我认为这是 ResourceBundles 设计功能的一个根本缺陷:引用其他键的键自动违反了 DRY(不要重复自己)原则。我解决这个问题的方法与你的方法类似:创建一个 ReflectiveResourceBundle 类,允许您使用 EL 表示法在消息中指定资源键。
错误的方法:
my.name.first=Bob
my.name.last=Smith
my.name.full=Bob Smith
正确的方式:
my.name.first=Bob
my.name.last=Smith
my.name.full=${my.name.first} ${my.name.last}
我有 代码上传到GitHub 这样您或其他任何人都可以下载它。此外,我还为使用 Stripes 框架的任何人添加了一些示例代码(http://www.stripesframework.org/)让您快速启动并运行。
让它与标准 JSTL fmt 标签库一起工作的技巧是设置一个拦截器,用我们自己的资源替换 HttpServletRequest 的资源。代码看起来像这样:
ResourceBundle bundle = MyStaticResourceHoldingTheBundle.getBundle();
Config.set(request, Config.FMT_LOCALIZATION_CONTEXT, new LocalizationContext(bundle, locale));
查看上面链接中的 stripes.interceptor 包以了解更多详细信息。
其他提示
如果字符串重复是本地化的,即您知道某个字符串将被重复,但仅在同一项目内重复,这样共享资源包就不是设计噩梦,那么您可能会考虑将字符串分解为多个键值部分。将重复的部分与不重复的部分分开,并重复使用重复的部分。例如,假设您需要显示以下两个字符串:
- “红顶知更鸟是一种原产于澳大利亚的小型雀形目鸟类。”
- “红顶知更鸟分布在非洲大陆大部分干旱地区。”
资源包可能如下:
robin.name=The Red-capped Robin
robin.native=is a small passerine bird native to Australia.
robin.region=is found in dryer regions across much of the continent.
然后在需要的地方组合所需的部分 bundle.getString("robin.name")+bundle.getString(robin.native).
不过,您需要注意的一件事是,诸如主语谓语顺序等语法规则。可能并非所有语言都相同。因此,在拆分句子时需要小心一些。