【问题标题】:JSF2.0 multi-language composite componentJSF2.0多语言复合组件
【发布时间】:2012-12-04 19:26:48
【问题描述】:

要国际化复合组件,您必须将 .properties 文件与组件本身具有确切相同的名称并放在同一文件夹中。

在 xhtml 中,您可以通过 ${cc.resourceBundleMap.key} 访问这些翻译。

到目前为止,一切都很好,对我有用。当我为其他语言添加更多 .properties 文件时,问题就开始了。无论我的电脑在哪个本地,选择的语言都是默认语言(component.properties)。

这似乎是一个反复出现的问题,因为 Ziletka 在 How to localize JSF 2 composite components 中也报告了同样的问题,但仍未得到答复。

我已经尝试了各种可能性:

  • 没有默认的.properties文件

    component_fr.properties
    component_fr_CA.properties
    component_fr_FR.properties
    component_en.properties
    component_en_CA.properties
    component_en_US.properties
    

    但它会导致:

    javax.el.ELException: [...] /resources/component/component.xhtml default="${cc.resourceBundleMap.key}":    java.lang.NullPointerException
    
  • 带有默认的 .properties 文件和语言规范

    component.properties
    component_fr.properties
    component_en.properties
    

    仅加载默认值。

  • 带有默认的 .properties 文件以及语言和国家/地区规范

    component.properties
    component_fr_CA.properties
    component_fr_FR.properties
    component_en_CA.properties
    component_en_US.properties
    

    再说一遍:只加载默认值。

我很想避免不得不依赖支持 bean 来提供翻译,并且不能相信它不受支持。有人可以帮忙吗?

【问题讨论】:

    标签: jsf-2 localization composite-component


    【解决方案1】:

    这个功能很久以前就在 MyFaces Core 中实现了。请参阅:MYFACES-3308。完成的测试用例可以找到here

    应用于复合组件的语言环境取决于从 UIViewRoot.getLocale() 检索到的值。

    【讨论】:

      【解决方案2】:

      显然问题仍然存在,它的根源在javax.faces.component.UIComponent 类中,特别是在findComponentResourceBundleLocaleMatch 方法中。截图如下

          private Resource findComponentResourceBundleLocaleMatch(FacesContext context, 
              String resourceName, String libraryName) {
          Resource result = null;
          ResourceBundle resourceBundle = null;
          int i;
          if (-1 != (i = resourceName.lastIndexOf("."))) {
              resourceName = resourceName.substring(0, i) +
                      ".properties"; //THE PROBLEM IS HERE
              if (null != context) {
                  result = context.getApplication().getResourceHandler().
                          createResource(resourceName, libraryName);
                  InputStream propertiesInputStream = null;
                  try {
                      propertiesInputStream = result.getInputStream();
                      resourceBundle = new PropertyResourceBundle(propertiesInputStream);
                  } catch (IOException ex) {
                      Logger.getLogger(UIComponent.class.getName()).log(Level.SEVERE, null, ex);
                  } finally{
                      if(null != propertiesInputStream){
                          try{
                              propertiesInputStream.close();
                          } catch(IOException ioe){
                              if (LOGGER.isLoggable(Level.SEVERE)) {
                                  LOGGER.log(Level.SEVERE, null, ioe);
                              }
                          }
                      }
                  }
              }
          }
          result = (null != resourceBundle) ? result : null;
      
          return result;
      }
      

      您可以在带有“问题在这里”的注释的行中看到它。正是当它寻找要加载的属性文件时,它不尊重任何语言和/或国家代码。它总是加载一个默认资源。

      可能的解决方案 'problematic' 方法是从同一类的另一个方法 getResourceBundleMap 调用的,并且您感兴趣的部分代码用注释标记(第 1000 行)

      // Step 2: if this is a composite component, look for a 
       // ResourceBundle as a Resource
      

      这并不奇怪,因为您需要一个复合组件。因此解决方案是为您的复合组件定义一个支持组件类并重新定义resourceBundleMap 加载。您可能会在下面找到仅尊重语言的实现,这意味着它适用于 componentName_en.properties 和 componentName_de.properties 等文件,但不适用于 componentName_zh_CN.properties

      您的 .properties 文件应与组件定义位于同一目录中

      testComponent.properties
      testComponent_de.properties
      testComponent_en.properties
      testComponent_fr.properties
      

      在你的组件中testComponent.xhtmlcomponentType属性中指定一个定义类。

      <cc:interface componentType="test.component">
          ....
      </cc:interface>
      

      组件可能如下所示。我主要使用原始代码进行了几次更改。想法是覆盖有问题的方法,并使用代码尝试首先读取指定语言的属性文件,如果找不到,则读取默认的。

          @FacesComponent("test.component")
      public class TestComponent extends UINamingContainer {
      
          private static final String PROPERTIES_EXT = ".properties";
      
      
          private Logger LOGGER = <use one you like>;
      
          private Map<String, String> resourceBundleMap = null;
      
          @Override
          public Map<String, String> getResourceBundleMap() {
              ResourceBundle resourceBundle = null;
              if (null == resourceBundleMap) {
                  FacesContext context = FacesContext.getCurrentInstance();
                  UIViewRoot root = context.getViewRoot();
                  Locale currentLocale = null;
                  if (null != context) {
                      if (null != root) {
                          currentLocale = root.getLocale();
                      }
                  }
                  if (null == currentLocale) {
                      currentLocale = Locale.getDefault();
                  }
      
                  if (this.getAttributes().containsKey(Resource.COMPONENT_RESOURCE_KEY)) {
                      Resource ccResource = (Resource)
                              this.getAttributes().get(Resource.COMPONENT_RESOURCE_KEY);
                      if (null != ccResource) {
                          InputStream propertiesInputStream = null;
                          try {
                              propertiesInputStream = ccResource.getInputStream();
                              resourceBundle = findComponentResourceBundleLocaleMatch(ccResource.getResourceName(),
                                      ccResource.getLibraryName(), currentLocale.getLanguage());
                          } catch (IOException ex) {
                              LOGGER.error(null, ex);
                          } finally {
                              if (null != propertiesInputStream) {
                                  try {
                                      propertiesInputStream.close();
                                  } catch (IOException ioe) {
                                      LOGGER.error(null, ioe);
                                  }
                              }
                          }
                      }
                  }
      
                  if (null != resourceBundle) {
                      final ResourceBundle bundle = resourceBundle;
                      resourceBundleMap =
                              new Map() {
                                  // this is an immutable Map
      
                                  public String toString() {
                                      StringBuffer sb = new StringBuffer();
                                      Iterator<Map.Entry<String, Object>> entries =
                                              this.entrySet().iterator();
                                      Map.Entry<String, Object> cur;
                                      while (entries.hasNext()) {
                                          cur = entries.next();
                                          sb.append(cur.getKey()).append(": ").append(cur.getValue()).append('\n');
                                      }
      
                                      return sb.toString();
                                  }
      
                                  // Do not need to implement for immutable Map
                                  public void clear() {
                                      throw new UnsupportedOperationException();
                                  }
      
      
                                  public boolean containsKey(Object key) {
                                      boolean result = false;
                                      if (null != key) {
                                          result = (null != bundle.getObject(key.toString()));
                                      }
                                      return result;
                                  }
      
      
                                  public boolean containsValue(Object value) {
                                      Enumeration<String> keys = bundle.getKeys();
                                      boolean result = false;
                                      while (keys.hasMoreElements()) {
                                          Object curObj = bundle.getObject(keys.nextElement());
                                          if ((curObj == value) ||
                                                  ((null != curObj) && curObj.equals(value))) {
                                              result = true;
                                              break;
                                          }
                                      }
                                      return result;
                                  }
      
      
                                  public Set<Map.Entry<String, Object>> entrySet() {
                                      HashMap<String, Object> mappings = new HashMap<String, Object>();
                                      Enumeration<String> keys = bundle.getKeys();
                                      while (keys.hasMoreElements()) {
                                          String key = keys.nextElement();
                                          Object value = bundle.getObject(key);
                                          mappings.put(key, value);
                                      }
                                      return mappings.entrySet();
                                  }
      
      
                                  @Override
                                  public boolean equals(Object obj) {
                                      return !((obj == null) || !(obj instanceof Map))
                                              && entrySet().equals(((Map) obj).entrySet());
      
                                  }
      
      
                                  public Object get(Object key) {
                                      if (null == key) {
                                          return null;
                                      }
                                      try {
                                          return bundle.getObject(key.toString());
                                      } catch (MissingResourceException e) {
                                          return "???" + key + "???";
                                      }
                                  }
      
      
                                  public int hashCode() {
                                      return bundle.hashCode();
                                  }
      
      
                                  public boolean isEmpty() {
                                      Enumeration<String> keys = bundle.getKeys();
                                      return !keys.hasMoreElements();
                                  }
      
      
                                  public Set keySet() {
                                      Set<String> keySet = new HashSet<String>();
                                      Enumeration<String> keys = bundle.getKeys();
                                      while (keys.hasMoreElements()) {
                                          keySet.add(keys.nextElement());
                                      }
                                      return keySet;
                                  }
      
      
                                  // Do not need to implement for immutable Map
                                  public Object put(Object k, Object v) {
                                      throw new UnsupportedOperationException();
                                  }
      
      
                                  // Do not need to implement for immutable Map
                                  public void putAll(Map t) {
                                      throw new UnsupportedOperationException();
                                  }
      
      
                                  // Do not need to implement for immutable Map
                                  public Object remove(Object k) {
                                      throw new UnsupportedOperationException();
                                  }
      
      
                                  public int size() {
                                      int result = 0;
                                      Enumeration<String> keys = bundle.getKeys();
                                      while (keys.hasMoreElements()) {
                                          keys.nextElement();
                                          result++;
                                      }
                                      return result;
                                  }
      
      
                                  public java.util.Collection values() {
                                      ArrayList<Object> result = new ArrayList<Object>();
                                      Enumeration<String> keys = bundle.getKeys();
                                      while (keys.hasMoreElements()) {
                                          result.add(
                                                  bundle.getObject(keys.nextElement()));
                                      }
                                      return result;
                                  }
                              };
      
                  }
      
                  if (null == resourceBundleMap) {
                      resourceBundleMap = Collections.EMPTY_MAP;
                  }
              }
              return resourceBundleMap;
          }
      
          private ResourceBundle findComponentResourceBundleLocaleMatch(String resourceName, String libraryName, String lng) {
              FacesContext context = FacesContext.getCurrentInstance();
              ResourceBundle resourceBundle = null;
              int i;
              if (-1 != (i = resourceName.lastIndexOf("."))) {
                  if (null != context) {
                      InputStream propertiesInputStream = null;
                      try {
                          propertiesInputStream = getResourceInputStream(context, resourceName.substring(0, i), libraryName, lng);
                          resourceBundle = new PropertyResourceBundle(propertiesInputStream);
                      } catch (IOException ex) {
                          LOGGER.error(null, ex);
                      } finally {
                          if (null != propertiesInputStream) {
                              try {
                                  propertiesInputStream.close();
                              } catch (IOException ioe) {
                                  LOGGER.error(null, ioe);
                              }
                          }
                      }
                  }
              }
              return resourceBundle;
          }
      
          private InputStream getResourceInputStream(FacesContext context, final String resourceName, String libraryName, String lng) throws IOException {
              InputStream propertiesInputStream = null;
              propertiesInputStream = getPropertiesResourceInputStream(context, String.format("%s_%s%s", resourceName, lng, PROPERTIES_EXT), libraryName);
              if (null == propertiesInputStream) {
                  propertiesInputStream = getPropertiesResourceInputStream(context, resourceName + PROPERTIES_EXT, libraryName);
              }
              return propertiesInputStream;
          }
      
          private InputStream getPropertiesResourceInputStream(FacesContext context, final String resourceName, String libraryName) throws IOException {
              Resource result = context.getApplication().getResourceHandler().createResource(resourceName, libraryName);
              if (null == result) {
                  return null;
              }
              return result.getInputStream();
          }
      
      }
      

      完成。

      但这显然是 Mojarra 中的一个错误,我希望它会尽快修复。仔细查看与复合组件相关的代码会发现,组件的默认 .properties 文件被读取了两次,我想这也不是一个好主意,但这是另一回事了。

      附言。如果您愿意,您也可以轻松调整 te 代码以尊重国家/地区代码。

      【讨论】:

        猜你喜欢
        • 2023-04-01
        • 2023-03-23
        • 1970-01-01
        • 2014-07-22
        • 1970-01-01
        • 1970-01-01
        • 2013-03-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多