在资源束中本地枚举枚举值 [英] Localizing enum values in resource bundle
问题描述
我的一个枚举示例:
public enum OrderStatus实现CustomEnum {
PENDING(enum.orderstatus.pending),
CANCELED(enum.orderstatus.canceled);
/ **
*邮件束中的密钥
* /
private String name;
OrderStatus(String name){
this.name = name;
}
@Override
public String getName(){
return name;
}
}
在视图层中,我使用像:
<! - 输入 - >
< h:selectOneMenu value =#{order.status}>
< f:selectItems value =#{flowUtils.orderStatuses}/>
< / h:selectOneMenu>
<! - 输出 - >
< h:outputText value =#{order.status}/>
和Java:
public class FlowUtils {
public List< SelectItem> getOrderStatuses(){
ArrayList< SelectItem> l = new ArrayList< SelectItem>();
for(OrderStatus c:OrderStatus.values()){
// before i18n
// l.add(new SelectItem(c,c.getName()));
// after i18n
l.add(new SelectItem(c,FacesUtil.getMessageValue(c.getName())));
}
return l;
}
}
public class FacesUtil {
public static String getMessageValue(String name){
FacesContext context = FacesContext.getCurrentInstance();
return context.getApplication()。getResourceBundle(context,m)。getString(name);
}
}
它运行良好,但是当我需要输出#{order.status}
,我需要转换它。
所以我实现了一个转换器,但是将 String
转换为 Object
在 getAsObject()
方法。
web.xml:
<变换器>
< converter-for-class> model.helpers.OrderStatus< / converter-for-class>
< converter-class> model.helpers.EnumTypeConverter< / converter-class>
< / converter>
Java:
code> public class EnumTypeConverter implements Converter {
@Override
public Object getAsObject(FacesContext context,UIComponent comp,
String value)throws ConverterException {
/ / value =本地化值(
Class enumType = comp.getValueBinding(value)。getType(context);
return Enum.valueOf(enumType,value);
}
@Override
public String getAsString(FacesContext context,UIComponent component,
Object object)throws ConverterException {
if(object == null){
return null;
}
CustomEnum type =(CustomEnum)object;
ResourceBundle messages = context.getApplication()。getResourceBundle(context,m);
String text = messages.getString type.getName());
返回文本;
}
}
我现在纠缠在一起。任何人都知道如何有效地使多个枚举国际化?
通过转换器传递的值不是你看起来的选项标签期望,但期权价值。最好的做法是在模型方面不要这样做,但在视图方面,因为模型不应该是i18n的意识。
关于方法你基本上是不必要的过度复杂的事情。由于JSF 1.2有一个内置的 EnumConverter
,这将自动启动,自JSF 2.0以来,您可以遍历通用数组或列表
在 f :selectItems
通过新的 var
属性,而不需要通过列表< SelectItem>
< c $ c> public class Bean {
private OrderStatus orderStatus;
private OrderStatus [] orderStatuses = OrderStatus.values();
// ...
}
这里是如何视图可以看起来像(假设 msg
指的是< var>
,如您在<$ faces-config.xml
中的c $ c>< resource-bundle> ):
< h:selectOneMenu value =#{bean.orderStatus}>
< f:selectItems value =#{bean.orderStatuses}var =orderStatus
itemValue =#{orderStatus}itemLabel =#{msg [orderStatus.name]} >
< / h:selectOneMenu>
这就是全部。
与问题无关,您在枚举名称和消息键中输入错误,应该是:
PENDING(enum.orderstatus.pending),
CANCELED(enum.orderstatus.cancelled);
而且,更干净的是将捆绑密钥保存在枚举中,并将枚举本身作为捆绑键。例如
PENDING,
取消;
< h:selectOneMenu值= #{bean.orderStatus} >
< f:selectItems value =#{bean.orderStatuses}var =orderStatus
itemValue =#{orderStatus}itemLabel =#{msg ['enum.orderstatus。 = orderStatus]}/>
< / h:selectOneMenu>
enum.orderstatus.PENDING =待定
enum.orderstatus.CANCELLED =已取消
I have a problem with i18n enums in my JSF application. When I started, I had enums with the text defined inside. But now, I have keys tied to message bundles in the enum.
Example one of my enums:
public enum OrderStatus implements CustomEnum {
PENDING("enum.orderstatus.pending"),
CANCELED("enum.orderstatus.canceled");
/**
* key in message bundle
*/
private String name;
OrderStatus(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
}
In the view layer, I use something like:
<!-- input -->
<h:selectOneMenu value="#{order.status}">
<f:selectItems value="#{flowUtils.orderStatuses}"/>
</h:selectOneMenu>
<!-- output -->
<h:outputText value="#{order.status}"/>
and in Java:
public class FlowUtils {
public List<SelectItem> getOrderStatuses() {
ArrayList<SelectItem> l = new ArrayList<SelectItem>();
for(OrderStatus c: OrderStatus.values()) {
// before i18n
// l.add(new SelectItem(c, c.getName()));
// after i18n
l.add(new SelectItem(c, FacesUtil.getMessageValue(c.getName())));
}
return l;
}
}
public class FacesUtil {
public static String getMessageValue(String name) {
FacesContext context = FacesContext.getCurrentInstance();
return context.getApplication().getResourceBundle(context, "m").getString(name);
}
}
It worked well, but when I needed to output #{order.status}
, I needed to convert it.
So I implemented a converter, but got in trouble with conversion of String
to Object
in the getAsObject()
method.
web.xml:
<converter>
<converter-for-class>model.helpers.OrderStatus</converter-for-class>
<converter-class>model.helpers.EnumTypeConverter</converter-class>
</converter>
Java:
public class EnumTypeConverter implements Converter {
@Override
public Object getAsObject(FacesContext context, UIComponent comp,
String value) throws ConverterException {
// value = localized value :(
Class enumType = comp.getValueBinding("value").getType(context);
return Enum.valueOf(enumType, value);
}
@Override
public String getAsString(FacesContext context, UIComponent component,
Object object) throws ConverterException {
if (object == null) {
return null;
}
CustomEnum type = (CustomEnum) object;
ResourceBundle messages = context.getApplication().getResourceBundle(context, "m");
String text = messages.getString(type.getName());
return text;
}
}
I'm entangled now with that. Anybody know how to internationalize multiple Enums efficiently?
The value which is passed through the converter is not the option label as you seem to expect, but the option value. The best practice is to not do this in the model side, but in the view side, because the model shouldn't need to be i18n aware.
As to the approach, you're basically unnecessarily overcomplicating things. Since JSF 1.2 there's a builtin EnumConverter
which will kick in automatically and since JSF 2.0 you can iterate over a generic array or List
in f:selectItems
by the new var
attribute without the need to duplicate the values over a List<SelectItem>
in the model.
Here's how the bean can look like:
public class Bean {
private OrderStatus orderStatus;
private OrderStatus[] orderStatuses = OrderStatus.values();
// ...
}
And here's how the view can look like (assuming that msg
refers to the <var>
as you've definied in <resource-bundle>
in faces-config.xml
):
<h:selectOneMenu value="#{bean.orderStatus}">
<f:selectItems value="#{bean.orderStatuses}" var="orderStatus"
itemValue="#{orderStatus}" itemLabel="#{msg[orderStatus.name]}" />
</h:selectOneMenu>
That's all.
Unrelated to the problem, you've typos in the enum name and message keys, it should be:
PENDING("enum.orderstatus.pending"),
CANCELLED("enum.orderstatus.cancelled");
And, more clean would be to keep the bundle keys out the enum and use enum itself as part of bundle key. E.g.
PENDING,
CANCELLED;
<h:selectOneMenu value="#{bean.orderStatus}">
<f:selectItems value="#{bean.orderStatuses}" var="orderStatus"
itemValue="#{orderStatus}" itemLabel="#{msg['enum.orderstatus.' += orderStatus]}" />
</h:selectOneMenu>
enum.orderstatus.PENDING = Pending
enum.orderstatus.CANCELLED = Cancelled
这篇关于在资源束中本地枚举枚举值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!