如何避免Java ResourceBundle字符串中的重复? [英] How do I avoid repetition in Java ResourceBundle strings?

查看:134
本文介绍了如何避免Java ResourceBundle字符串中的重复?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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

 公共类ExpandingResourceBundleControl扩展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 )
抛出IllegalAccessException,InstantiationException,IOException {

ResourceBundle inner = super.newBundle(baseName,locale,format,loader,reload);
返回内部== null? null:new ExpandingResourceBundle(inner,loader);
}
}

ExpandingResourceBundle 委托真实资源包,但执行{{this.kind.of.thing}}转换以查找资源中的密钥。



每次你想得到其中一个,你必须去:

  ResourceBundle.getBundle(com / acme / app / Bundle ,扩展); 

此工作正常 - 暂时。



最终发生的是一些新代码(在我们的例子中是自动生成的代码,它是由Matisse吐出的)在不指定自定义控件的情况下查找相同的资源包。如果你编写一个简单的单元测试来调用它然后没有,这似乎是不可重现的,但它是在应用程序运行真实时发生的。不知何故, ResourceBundle 中的缓存弹出了良好的值,并用破坏的值替换它。我还没弄清楚为什么和Sun的jar文件是在没有调试信息的情况下编译的,所以调试它是一件苦差事。



我的问题:


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


  2. 是否有其他方式可以优雅地处理这类事情,或许根本没有篡改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 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包以获取更多详细信息。


We had a lot of strings which contained the same sub-string, from sentences about checking the log or how to contact support, to branding-like strings containing the company or product name. The repetition was causing a few issues for ourselves (primarily typos or copy/paste errors) but it also causes issues in that it increases the amount of text our translator has to translate.

The solution I came up with went something like this:

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 delegates to the real resource bundle but performs conversion of {{this.kind.of.thing}} to look up the key in the resources.

Every time you want to get one of these, you have to go:

ResourceBundle.getBundle("com/acme/app/Bundle", EXPANDING);

And this works fine -- for a while.

What eventually happens is that some new code (in our case autogenerated code which was spat out of Matisse) looks up the same resource bundle without specifying the custom control. This appears to be non-reproducible if you write a simple unit test which calls it with and then without, but it occurs when the application is run for real. Somehow the cache inside ResourceBundle ejects the good value and replaces it with the broken one. I am yet to figure out why and Sun's jar files were compiled without debug info so debugging it is a chore.

My questions:

  1. Is there some way of globally setting the default ResourceBundle.Control that I might not be aware of? That would solve everything rather elegantly.

  2. Is there some other way of handling this kind of thing elegantly, perhaps without tampering with the ResourceBundle classes at all?

解决方案

I think this is a fundamental flaw in the way ResourceBundles are designed to function: keys that reference other keys automatically violate the DRY (don't repeat yourself) principle. The way I got around this was similar to your method: create a ReflectiveResourceBundle class that allows you to specify Resource keys in the messages using EL notation.

THE WRONG WAY:

my.name.first=Bob
my.name.last=Smith
my.name.full=Bob Smith

THE RIGHT WAY:

my.name.first=Bob
my.name.last=Smith
my.name.full=${my.name.first} ${my.name.last}

I've uploaded the code to GitHub so you or anyone else can download it. Additionally, I've added some sample code for anyone using the Stripes Framework (http://www.stripesframework.org/) to get you quickly up-and-running.

The trick to getting this to work with standard JSTL fmt taglibs was to set up an interceptor that replaced the HttpServletRequest's resource with our own. The code looks something like this:

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

Take a look at the stripes.interceptor package in the link above for more details.

这篇关于如何避免Java ResourceBundle字符串中的重复?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆