代码之家  ›  专栏  ›  技术社区  ›  Hakanai

我怎样避免Java字符串中的重复呢?

  •  14
  • Hakanai  · 技术社区  · 14 年前

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

    我想出的解决办法是这样的:

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

    这很好——有一段时间。

    最终会发生的情况是,一些新代码(在我们的例子中是从马蒂斯发出的自动生成代码)在不指定自定义控件的情况下查找相同的资源包。如果您编写一个简单的单元测试来调用它,然后不调用它,那么这看起来是不可复制的,但是当应用程序真正运行时会发生这种情况。不知怎么的,里面的缓存 ResourceBundle 弹出好的值并用坏的值替换它。我还没有弄清楚为什么sun的jar文件在编译时没有调试信息,所以调试是一件麻烦的事。

    我的问题:

    1. 是否有某种全局设置默认resourcebundle.control的方法,我可能不知道?这会很优雅地解决所有问题。

    2. 有没有其他方法可以优雅地处理这类事情,也许根本不需要修改resourcebundle类?

    2 回复  |  直到 9 年前
        1
  •  6
  •   Matt Brock    9 年前

    我认为这是resourcebundles设计的一个基本缺陷:引用其他键的键会自动违反dry(不要重复自己)原则。我解决这个问题的方法与您的方法类似:创建一个reflecturesourcebundle类,该类允许您使用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框架的任何人添加了一些示例代码( http://www.stripesframework.org/ )让你快点起来跑。

    让它与标准jstl fmt标记库一起工作的诀窍是设置一个拦截器,用我们自己的资源替换httpservletrequest的资源。代码如下所示:

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

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

        2
  •  0
  •   Prachi    14 年前

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

    1. “红帽知更鸟是一种原产于澳大利亚的雀形目小鸟。”
    2. “红冠知更鸟分布在大陆大部分干燥地区。”

    资源包可以如下:

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

    不过,有一点需要注意,像主谓顺序等语法规则在所有语言中可能并不相同。所以你在分句的时候要小心一点。