1

複合コンポーネントを国際化するには、コンポーネント自体とまったく同じ名前の.propertiesファイルを同じフォルダーに配置する必要があります。

xhtmlから、${cc.resourceBundleMap.key}を介してこれらの翻訳にアクセスできます。

今まで、すべてがうまく、私のために働きます。問題が発生するのは、他の言語の.propertiesファイルを追加するときです。私のコンピューターがどのローカルにあるかに関係なく、選択された言語がデフォルトの言語(component.properties)です。

ZiletkaはJSF2複合コンポーネントをローカライズする方法でも同じ問題を報告しているため、これは再発する問題のようですが、未回答のままです。

私はあらゆる種類の可能性を試しました:

  • デフォルトの.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に依存する必要がないようにしたいので、サポートされていないと信じることができません。誰か助けてもらえますか?

4

2 に答える 2

1

この機能は、MyFaces Core でかなり前に実装されました。参照: MYFACES-3308。完了したテストケースはここにあります

複合コンポーネントに適用されるロケールは、UIViewRoot.getLocale() から取得した値に依存します。

于 2012-12-04T23:55:12.203 に答える
0

どうやら問題はまだ残っており、その根本は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;
}

「THE PROBLEM IS HERE」というコメントのある行で確認できます。ロードするプロパティ ファイルを正確に探すときに、言語や国コードを考慮しません。常にデフォルトのリソースをロードします。

考えられる解決策 「問題のある」メソッドが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 _en_US .propertiesなどのファイルでは機能しません。

.properties ファイルは、コンポーネントの定義と同じディレクトリにある必要があります

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

コンポーネントで、属性testComponent.xhtmlに定義クラスを指定しcomponentTypeます。

<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 ファイルが 2 回読み込まれていることがわかります。これもあまり良い考えではないと思いますが、これは別の話です。

PS。必要に応じて、国コードも尊重するように te コードを簡単に調整できます。

于 2016-02-26T16:46:45.823 に答える