【问题标题】:GWT: Accessing i18n messages in server codeGWT:在服务器代码中访问 i18n 消息
【发布时间】:2011-10-14 15:10:02
【问题描述】:

我有一个扩展com.google.gwt.i18n.client.Messages 类的接口,我用它在我的GWT 应用程序中检索i18n 消息。它看起来像这样:

public interface MyMessages extends com.google.gwt.i18n.client.Messages {
  @DefaultMessage("Hello world")
  @Key("message1")
  String message1();

  @DefaultMessage("Hello again")
  @Key("message2")
  String message2();

  //...
}

通常,我使用GWT.create() 创建它的一个实例,如下所示:

private MyMessages messages = GWT.create(MyMessages.class);

但是,这不适用于服务器端代码,只能用于客户端代码(它会抛出一个错误,指出 GWT.create() 只能在客户端代码中使用)。

similar question 的答案指向一个可以下载的单独库,它可以让您访问服务器上的 i18n 消息,但我不想下载任何额外的库(这似乎是一个简单的问题,必须有一个简单的解决方案)。

总结:如何在服务器端代码中访问我的 i18n 消息?谢谢。

【问题讨论】:

    标签: java gwt


    【解决方案1】:

    在服务器端,您可以使用标准的 Java 本地化工具,例如 ResourceBundle。 看here的使用教程。

    // Create a ResourceBundle out of your property files
    ResourceBundle labels =
      ResourceBundle.getBundle("LabelsBundle", currentLocale);
    
    // Get localized value
    String value = labels.getString(key);
    

    不能在服务器端 Java 上使用从属性文件创建接口并通过延迟绑定提供实现的 GWT 特定方式。

    如果您无所畏惧并愿意花时间,您可以实现代码生成步骤来读取您的属性文件并为您的消息接口生成实现类。这正是 Google GWT 编译器在幕后所做的事情。

    【讨论】:

    • 我在我的 GWT 项目中使用 Maven,其中一件好事是它会查看您的 Messages.properties 文件并自动为您生成一个 Messages 接口。使用 ResourceBundle 是可行的,但我仍然讨厌必须为服务器端代码做一些单独的事情。也许 Google 是在说,“一个设计良好的应用程序不应该需要在服务器端访问 i18n 消息。”
    • 实际上,现在我想起来了,我认为只有客户端可以访问消息是有意义的。服务器总是有相同的语言环境,所以无论客户端在什么语言环境中,它总是返回相同的消息。例如,如果服务器位于加利福尼亚,它总是会检索英文消息,因为默认语言环境是服务器使用英语。当编译成 Javascript 时,GWT 可能会做一些魔术来确定 Web 用户的语言环境并使用适当的 .properties 文件。
    • @Michael 这就是为什么你拒绝的库(我理解你的动机!)让客户端在服务器端设置语言环境......使用 Renato 的消息代码系统是一种方法,虽然它使难以自定义消息(“无法打开文件 'foo'”等)。
    【解决方案2】:

    我同意 Michael 的观点。我在尝试“本地化”服务器上生成的消息时遇到了这个问题……但我决定改为在服务器上抛出一个异常(因为它是一条错误消息,应该仅在例外情况下发生),其中包含消息代码,然后客户端代码可以查找该消息代码并向用户显示正确的本地化消息。

    【讨论】:

    • 是的,我认为这是一个很好的解决方案。这就是我打算做的,但我很懒,决定只访问服务器上的 Messages.properties 文件,因为我的应用程序将永远只使用一种语言。 :)
    • 好主意。有时我们必须传递额外的信息,但它可以作为特定异常的参数包含在内。
    【解决方案3】:

    有一个很棒的 GWT 国际化库gwt-dmesg。它允许您在客户端和服务器之间“共享”.properties 文件。但是,项目似乎被作者放弃了,您必须手动重新编译它以用于 GWT 版本 >= 2.1.0。

    【讨论】:

      【解决方案4】:

      GWT.create() 只能在客户端代码中使用。

      这样做的好处是您提供自己的 I18NProvider 类/接口,然后您可以从中扩展到服务器端 I18N 工厂和客户端 I18N 工厂读取相同的资源包。

      之后,您可以简单地在整个系统中使用它,统一您的代码。 希望对您有所帮助。

      【讨论】:

      • 感谢您的回复。您是说我可以创建一个可用于在客户端和服务器上检索消息的类吗?那太好了。现在,我为每个类使用单独的类。
      • 抱歉回复晚了。是的,这就是重点,单独的类就足够了,问题是您可以创建一个外观来在运行时访问两个不同的类可能会更好,这将为您节省大量时间,并为您提供更整洁的代码。
      【解决方案5】:

      按照 vanje 的回答,并考虑用于属性文件的编码(这可能很麻烦,因为 ResourceBundle 默认使用“ISO-8859-1”,这是我想出的解决方案:

      import java.io.UnsupportedEncodingException;
      import java.util.Locale;
      import java.util.ResourceBundle;
      
      public class MyResourceBundle {
      
          // feature variables
          private ResourceBundle bundle;
          private String fileEncoding;
      
          public MyResourceBundle(Locale locale, String fileEncoding){
              this.bundle = ResourceBundle.getBundle("com.app.Bundle", locale);
              this.fileEncoding = fileEncoding;
          }
      
          public MyResourceBundle(Locale locale){
              this(locale, "UTF-8");
          }
      
          public String getString(String key){
              String value = bundle.getString(key); 
              try {
                  return new String(value.getBytes("ISO-8859-1"), fileEncoding);
              } catch (UnsupportedEncodingException e) {
                  return value;
              }
          }
      }
      

      使用它的方式与常规的 ResourceBundle 用法非常相似:

      private MyResourceBundle labels = new MyResourceBundle("es", "UTF-8");
      String label = labels.getString(key)
      

      或者您可以使用默认使用 UTF-8 的替代构造函数:

      private MyResourceBundle labels = new MyResourceBundle("es");
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-06-15
        • 2011-03-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-16
        相关资源
        最近更新 更多