如何避免Java ResourceBundle字符串中的重复?

时间:2010-04-09 06:03:44

标签: java substitution resourcebundle

我们有很多字符串包含相同的子字符串,从关于检查日志或如何联系支持的句子到包含公司或产品名称的类似品牌的字符串。重复导致了我们自己的一些问题(主要是拼写错误或复制/粘贴错误),但它也会导致问题,因为它增加了翻译人员必须翻译的文本数量。

我提出的解决方案是这样的:

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文件是在没有调试信息的情况下编译的,所以调试它是一件苦差事。

我的问题:

  1. 有没有办法全局设置我可能不知道的默认ResourceBundle.Control?这样可以相当优雅地解决所有问题。

  2. 还有其他方法可以优雅地处理这类事情,或许根本没有篡改ResourceBundle类吗?

2 个答案:

答案 0 :(得分:6)

我认为这是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}

uploaded the code to GitHub所以您或其他任何人都可以下载它。此外,我为使用Stripes Framework(http://www.stripesframework.org/)的任何人添加了一些示例代码,以帮助您快速启动并运行。

让它与标准JSTL fmt taglib一起工作的技巧是设置一个拦截器,用我们自己的资源替换HttpServletRequest的资源。代码看起来像这样:

ResourceBundle bundle = MyStaticResourceHoldingTheBundle.getBundle();
Config.set(request, Config.FMT_LOCALIZATION_CONTEXT, new LocalizationContext(bundle, locale));

请查看上面链接中的stripes.interceptor包以获取更多详细信息。

答案 1 :(得分:0)

如果字符串重复是本地化的,你知道某个字符串会被重复但只在同一个项目中,以至于共享资源包不是设计的噩梦,那么你可以考虑将字符串分解为多个键 - 价值部分。将重复的部分与不重复的部分分开,并重复使用重复的部分。例如,假设您需要显示以下两个字符串:

  1. “红顶罗宾是一种原产于澳大利亚的小雀形目鸟。”
  2. “红顶罗宾在大陆大部分地区的干燥地区都有发现。”
  3. 资源包可以如下:

    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).

    但是,您需要注意的一件事是,所有语言中的主语谓词顺序等语法规则可能并不相同。因此,在分割句子时你需要小心一点。