【问题标题】:How to implement multilanguage in Java/Swing applications?如何在 Java/Swing 应用程序中实现多语言?
【发布时间】:2009-05-23 17:46:57
【问题描述】:

在 Swing 应用程序中实现多语言支持的不同方法是什么?

您是否将 ResourceBundle 与属性文件一起使用并在每一帧中实现它?它对你有好处吗?如果您使用某种 GUI 编辑器会怎样?有没有其他办法?

在工作中,我们使用的是 Matisse4MyEclipse,每次保存屏幕时都会重新生成代码,所以在这里简单地使用 Externalize Strings 是行不通的。一种方法是将其定义为每个组件的自定义属性,这很烦人。另一种方法是在 matisse 生成代码后再次检查多语言组件及其属性,这也很痛苦。

【问题讨论】:

    标签: java swing internationalization multilingual


    【解决方案1】:

    好吧,你必须使用ResourceBundles。但是,如果您要设置组件文本属性,则使用 RB.getString() 的文本而不是人类可读的文本。然后,如果 Matisse 从捆绑密钥中重新生成,则将保留并且本地化将起作用。示例:

    我将使用 Matisse 页面中的这张图片:

    (来源:myeclipseide.com

    在那里你可以看到属性text。有“我的新标签”的价值。您可以使用rb.getString("myNewLabel.my.message") 代替这个,其中rbResourceBundle。唯一的问题应该是过于智能的属性编辑器对你不利。我从不使用任何所见即所得的编辑器(个人喜好,我总是手工设计 UI)。

    【讨论】:

      【解决方案2】:

      这就是我实现国际化的方式:

      • 为每个具有国际化文本的组件命名
      • 在运行时,获取容器(框架、对话框、小程序),迭代所有组件并使用其名称和所有父名称为每个组件构建一个 i18n 键。
      • 为每个组件类型(JTextField、JLable 等)为每个国际化字段(文本、标签、提示等)定义一些键。
      • 获取此 i18n 键并查询您的 ResourceBundle,获取结果并填充组件字段。

      它适用于生成的代码或手动创建的代码。

      编辑:这里是:

      public void buildIds() {
          buildId(true);
          int count = getComponentCount();
          if (count == 0) {
              return;
          }
          for (int i = 0; i < count; i++) {
              Component component = getComponent(i);
              if (component instanceof AbstractComponent) {
                  ((AbstractComponent) component).buildIds();
              }
          }
      }
      
      protected void buildId(boolean fireChange) {
          String prevId = this.id;
          String computedId;
          if (getName() == null) {
              computedId = ClassUtilities.shortClassName(getClass()).toLowerCase() + "_" + Long.toHexString(ID_GENERATOR.getAndIncrement());
          } else {
              java.util.List<Component> parents = null;
              Component parent = getParent();
              if (parent != null) {
                  StringBuilder buider = new StringBuilder(80);
                  parents = new ArrayList<Component>();
                  while (parent != null) {
                      if (parent.getName() != null) {
                          parents.add(parent);
                      }
                      parent = parent.getParent();
                  }
                  Collections.reverse(parents);
                  if (parents.size() > 0) {
                      for (Component component : parents) {
                          if (buider.length() > 0) {
                              buider.append('.');
                          }
                          buider.append(component.getName());
                      }
                      buider.append('.');
                  }
                  buider.append(name);
                  computedId = buider.toString().toLowerCase();
              } else {
                  computedId = name;
              }
          }
          this.id = computedId;
          if (fireChange && prevId != null && !prevId.equals(computedId)) {
              componentIdChanged(this, prevId);
          }
      }
      

      【讨论】:

      • 如何为每个组件分配名称/密钥?
      • 对于每个具有非空名称的组件,包括当前组件,您将创建一个唯一的 ID,该 ID 将等效于 Java 类包命名空间。示例: login_dialog.userName.label=用户名 login_dialog.password.label=密码 login_dialog.login.text=登录 login_dialog.login.hint=按登录到 .... 等等。这样做的好处是它将在资源对话​​框中真正可见,在该上下文中将使用用户名(基于其父名称) login_dialog、用户名、密码是组件名称,login_dialog 是用户名和密码的父级。
      • userName 键绑定到 jTextfield1 的信息存储在哪里?
      • 好吧,在你的情况下,你不/不应该存储它。在我的情况下稍微复杂一些,因为我使用 UI 模型的抽象,并且默认情况下,此命名空间用于计算每个应用程序唯一的组件 ID。基于这个 id,每个组件都将查询 I18n 服务以请求国际化文本。如果您只是想应用相同的原则,只需迭代所有组件,创建 id,查询 ResourceBundle 并丢弃 id,因为您不需要它。
      • 我们也对 UI 组件使用抽象级别。你如何为每个组件生成唯一的 id?是某种无意义的哈希吗?
      【解决方案3】:

      除了 ResourceBundle,我不知道有什么办法。

      为什么要不断地重新生成代码?我想一旦你开始一个页面就可以了,但在那之后它基本上就没有必要了。听起来代码生成是你真正的问题。它没有为您节省任何东西。

      您是否尝试使用多个组件组成页面?我可以想象一个不需要一直更改的通用页眉、页脚和菜单。这可能是设计问题。

      Spring 对 I18N 的支持非常好。也许它可以在这里帮助你。

      【讨论】:

        【解决方案4】:

        使用 ResourceBundle 类并将语言设置为区域设置:

        以下是java中的代码

        private static Map<String, ResourceBundle> resourceBundles;
        
        private static ResourceBundle loadBundle(String language) {
            if (resourceBundles == null) {
                resourceBundles = new HashMap<String, ResourceBundle>();
            }
        
            ResourceBundle currentBundle = resourceBundles.get(language);
        
            if (currentBundle == null) {
        
                Locale locale = new Locale(language);
                currentBundle = ResourceBundle.getBundle("i18n.Messages", locale);
                resourceBundles.put(language, currentBundle);
            }
        
            return currentBundle;
        }
        
        public static String messageForKey(String key, String language) {
            ResourceBundle currentBundle = loadBundle(language);
            return currentBundle.getString(key);
        }
        

        【讨论】:

          猜你喜欢
          • 2023-03-06
          • 1970-01-01
          • 2012-04-11
          • 2012-03-05
          • 1970-01-01
          • 2015-07-19
          • 1970-01-01
          • 1970-01-01
          • 2012-07-22
          相关资源
          最近更新 更多