顯然問題仍然存在,其根源在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;
}
你可以看到它的評論,指出'問題在這裏'。正是在查找屬性文件來加載它不尊重任何語言和/或國家代碼。它總是加載一個默認資源。
可能的解決方法 的「問題」的方法是同一類的另一種方法getResourceBundleMap
,你感興趣的是標有註釋(行號1000)
// Step 2: if this is a composite component, look for a
// ResourceBundle as a Resource
代碼的一部分被稱爲
因爲您需要複合組件,所以這並不令人意外。因此,解決方案將是爲您的複合組件定義一個支持組件類,並重新定義加載的resourceBundleMap
。下面你會發現,只有尊重語言,這意味着它會爲文件的工作就像組件名_en的.properties和組件名稱_de的.properties但執行不會對類似組件名_en_US的.properties
你的.properties文件應在同一目錄中的組件testComponent.xhtml
的你的組件
testComponent.properties
testComponent_de.properties
testComponent_en.properties
testComponent_fr.properties
的定義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();
}
}
完成。
但是,這顯然是莫哈拉的一個錯誤,我希望它很快就會解決。仔細觀察與複合組件相關的代碼可以發現組件的默認.properties文件被讀取兩次,我猜這也不是一個好主意,但這是另一回事。
PS。如果您願意,您可以輕鬆調整te代碼以尊重國家代碼。