首頁>Program>source

我的JSF應用程式中的i18n列舉有問题.開始時,我使用內部定義的列舉列舉.但是現在,我已经將密钥繫結到列舉中的訊息包。

示例之一:

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;
    }
}

在视圖層中,我使用類似的东西:

<!-- input -->
<h:selectOneMenu value="#{order.status}">
    <f:selectItems value="#{flowUtils.orderStatuses}"/>
</h:selectOneMenu>
<!-- output -->
<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轉換的麻煩 到 ObjectgetAsObject() 方法。

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;
    }
}

我現在對此很纠結.有人知道如何有效地国際化多个列舉吗?

最新回復
  • 5月前
    1 #

    通過轉換器傳遞的值不是您期望的選項標簽,而是選項值.最佳做法是不要在模型端執行此操作,而在视圖端執行此操作,因為模型不需要知道i18n。

    對於這種方法,您基本上不必要地使事情複雜化.从JSF 1.2開始,內建了 EnumConverter 它会自動啟動,並且自JSF 2.0起,您可以遍歷通用陣列或 Listf:selectItems 由新的 var 屬性,而無需在 List<SelectItem>上重複這些值 在模型中。

    這是豆子的樣子:

    public class Bean {
        private OrderStatus orderStatus;
        private OrderStatus[] orderStatuses = OrderStatus.values();
        // ...
    }
    

    這是视圖的外观(假設 msg<var> 正如您在 <resource-bundle>中定義的 在 faces-config.xml ):

    <h:selectOneMenu value="#{bean.orderStatus}">
        <f:selectItems value="#{bean.orderStatuses}" var="orderStatus" 
            itemValue="#{orderStatus}" itemLabel="#{msg[orderStatus.name]}" />
    </h:selectOneMenu>
    

    仅此而已。


    与問题無關,您在列舉名稱和訊息键中輸入錯了,應该是:

    PENDING("enum.orderstatus.pending"),
    CANCELLED("enum.orderstatus.cancelled");
    

    而且,更干净的方法是將捆绑密钥保留在列舉之外,並將列舉本身用作捆绑密钥的一部分.例如

    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
    

  • 5月前
    2 #

    我在這裏發佈了我的解決方案:多个列舉的国際化(列舉值的轉換)-但仍希望进一步增強。

    編輯:在@Joop Eggen的帮助下,我们提出了一个非常酷的解決方案:

    再次編輯:完整且可使用的解決方案:

    上Class

    public final class EnumTranslator {
      public static String getMessageKey(Enum<?> e) {
        return e.getClass().getSimpleName() + '.' + e.name();
      }
    }
    

    使其具有自定義的EL功能

    <?xml version="1.0" encoding="UTF-8"?>
    <facelet-taglib 
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd"
    version="2.0">
    <namespace>http://example.com/enumi18n</namespace>
    <function>
        <function-name>xlate</function-name>
        <function-class>your.package.EnumTranslator</function-class>
        <function-signature>String getMessageKey(java.lang.Enum)</function-signature>
    </function>
    </facelet-taglib>
    

    將標簽庫添加到您的web.xml

    <context-param>
        <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
        <param-value>/WEB-INF/enumi18n.taglib.xml</param-value>
    </context-param>
    

    具有這樣的屬性檔案enum_en.properties和enum_yourlanguage.properties

    TransferStatus.NOT_TRANSFERRED = Not transferred
    TransferStatus.TRANSFERRED = Transferred
    

    將屬性檔案作為資源包添加到您的faces-config.xml

       <resource-bundle>
            <base-name>kk.os.obj.jsf.i18n.enum</base-name>
            <var>enum</var>
        </resource-bundle>
    

    將自定義標簽庫添加到您的xhtml檔案中

    <html ... xmlns:l="http://example.com/enumi18n">
    

    And - voilà - you can now access the translated enum values in jsf:

    <h:outputText value="#{enum[l:xlate(order.transferStatus)]}" />
    

  • 5月前
    3 #

    嗯,列舉只是另一个類.没有什麼可以阻止您添加解析和字元串轉換方法的,這些方法將解析和輸出對語言環境敏感的訊息。

    也许它违反了"單一责任原則"(是吗?),但是我认為让列舉負责解析和返迴區域感知的值是正確的事情。

    只需添加两个這樣的方法:

    public String toString(FacesContext context) {
       // need to modify the method   
       FacesUtil.getMessageValue(context, name);
    }
    public OrderStatus parse(FacesContext context, String theName) {
      for (OrderStatus value : values()) {
        if (value.toString(context).equals(theName) {
          return value;
        }
      }
      // think of something better
      return null;
    }
    

    我希望我的代碼正確,因為我現在不使用IDE进行檢查...這是您要找的內容吗?

  • 5月前
    4 #

    我按如下所示計算列舉中的訊息密钥 下面; 因此無需在列舉中維護帶有其他屬性的键

    public String getMessageKey() {
        return String.format("enum_%s_%s", this.getClass().getSimpleName(),
                this.name());
    }
    

    然後我像這樣使用它

        <p:selectOneMenu id="type"
            value="#{xyzBean.type}" required="true">
                <f:selectItems
                    value="#{xyzBean.possibleTypes}"
                    var="type" itemLabel="#{msg[type.messageKey]}">
                </f:selectItems>
         </p:selectOneMenu>
    

    在應用上下文中配置了org.springframework.context.support.ReloadableResourceBundleMessageSource

    <bean id="msg"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="/resources/locale/messages" />
        <property name="useCodeAsDefaultMessage" value="true" />
        <property name="cacheSeconds" value="1" />
    </bean>
    

  • 5月前
    5 #

    如果有人正在尋找一个簡單的實用程式庫来處理列舉国際化,請查看https://github.com/thiagowolff/litefaces-enum-i18n

    该工件也可以在Maven Central中使用:

    <dependency>
        <groupId>br.com.litecode</groupId>
        <artifactId>litefaces-enum-i18n</artifactId>
        <version>1.0.1</version>
    </dependency>
    

    基本上,您只需要按照所描述的列舉命名約定將工件添加到專案中並定義列舉各自的键即可.可以使用提供的EL函式来檢索翻译(以及CSS類名稱)。

相似問題

  • c#:selenium網路驅動程式中的弹出視窗
  • c++:用constexpr查詢表