Localization 如何根据当前用户区域设置对Wicket下拉列表中的选项进行排序?

Localization 如何根据当前用户区域设置对Wicket下拉列表中的选项进行排序?,localization,wicket,Localization,Wicket,我有以下问题: 包含元素列表的下拉列表 这些元素中的每一个都有一个固定键,IChoiceRenderer实现使用该键来查找该键的本地化版本(它是在不同包中实现的标准实用程序呈现程序) 本地化关键点列表位于属性文件中,链接到实例化下拉列表的面板 是否有一个优雅的/可重用的解决方案可以让下拉列表按字母顺序显示其元素?我们公司使用的解决方案是基于Javascript的,我们在想要排序的下拉列表上设置了一个特殊的css类,一个小小的jQuery技巧就可以完成排序。如果您想要一个基于Wicket的解决

我有以下问题:

  • 包含元素列表的下拉列表
  • 这些元素中的每一个都有一个固定键,IChoiceRenderer实现使用该键来查找该键的本地化版本(它是在不同包中实现的标准实用程序呈现程序)
  • 本地化关键点列表位于属性文件中,链接到实例化下拉列表的面板

是否有一个优雅的/可重用的解决方案可以让下拉列表按字母顺序显示其元素?

我们公司使用的解决方案是基于Javascript的,我们在想要排序的下拉列表上设置了一个特殊的css类,一个小小的jQuery技巧就可以完成排序。

如果您想要一个基于Wicket的解决方案,您可以尝试使用类似的方法对列表进行排序:

public class ChoiceRendererComparator<T> implements Comparator<T> {

    private final IChoiceRenderer<T> renderer;

    public ChoiceRendererComparator(IChoiceRenderer<T> renderer) {
        this.renderer = renderer;
    }

    @SuppressWarnings("unchecked")
    public int compare(T o1, T o2) {
        return ((Comparable<Object>) renderer.getDisplayValue(o1)).compareTo(renderer.getDisplayValue(o2));
    }
}
公共类ChoiceRenderComparator实现Comparator{
私人最终ICHOICHENDERER渲染器;
公共选择渲染器比较程序(ICHOICerender渲染器){
this.renderer=渲染器;
}
@抑制警告(“未选中”)
公共整数比较(tO1,tO2){
返回((可比较的)renderer.getDisplayValue(o1)).compareTo(renderer.getDisplayValue(o2));
}
}
用法:

    List<Entity> list = ...
    IChoiceRenderer<Entity> renderer = ...
    Collections.sort(list, new ChoiceRendererComparator<Entity>(renderer));
    DropDownChoice<Entity> dropdown = new DropDownChoice<Entity>("dropdown", list, renderer);
List=。。。
IChoiceRenderer渲染器=。。。
排序(列表、新选项渲染器比较器(渲染器));
DropDownChoice dropdown=新的DropDownChoice(“下拉”,列表,渲染器);

面对同样的问题,我将部分本地化数据从XML移动到数据库,实现了一个匹配的解析器,并能够使用本地化字符串进行排序。 表设计和hibernate配置有点棘手,如下所述:

ResourceLoader遵循以下原则:

public class DataBaseStringResourceLoader extends ComponentStringResourceLoader {

    private static final transient Logger logger = Logger
            .getLogger(DataBaseStringResourceLoader.class);

    @Inject
    private ISomeDAO someDao;
    @Inject
    private IOtherDao otherDao;
    @Inject
    private IThisDAO thisDao;
    @Inject
    private IThatDAO thatDao;

    @Override
    public String loadStringResource(Class<?> clazz, String key, Locale locale,
            String style, String variation) {
        String resource = loadFromDB(key, new Locale(locale.getLanguage()));
        if (resource == null) {
            resource = super.loadStringResource(clazz, key, locale, style, variation);
        }
        return resource;
    }

    private String loadFromDB(String key, Locale locale) {
        String resource = null;
        if (locale.getLanguage() != Locale.GERMAN.getLanguage()
                && locale.getLanguage() != Locale.ENGLISH.getLanguage()) {
            locale = Locale.ENGLISH;
        }
        if (key.startsWith("some") || key.startsWith("other")
                || key.startsWith("this") || key.startsWith("that")) {
            Integer id = Integer.valueOf(key.substring(key.indexOf(".") + 1));
            ILocalizedObject master;
            if (key.startsWith("some")) {
                master = someDao.findById(id);
            } else if (key.startsWith("other")) {
                master = otherDao.findById(id);
            } else if (key.startsWith("this") ){
                master = thisDao.findById(id);
            } else {
                master = thatDao.findById(id);
            }
            if (master != null && master.getNames().get(locale) != null) {
                resource = master.getNames().get(locale).getName();
            } else if (master == null) {
                logger.debug("For key " + key + " there is no master.");
            }
        }
        return resource;
    }
[...]
    }
公共类数据库StringResourceLoader扩展组件StringResourceLoader{
专用静态最终瞬态记录器=记录器
.getLogger(DataBaseStringResourceLoader.class);
@注入
私家车;
@注入
私人IOtherDao otherDao;
@注入
二等兵伊士多此刀;
@注入
私人伊萨特道那道;
@凌驾
公共字符串loadStringResource(类clazz、字符串键、区域设置、,
字符串样式、字符串变体){
String resource=loadFromDB(键,新语言环境(Locale.getLanguage());
if(资源==null){
resource=super.loadStringResource(clazz、key、locale、style、variation);
}
返回资源;
}
私有字符串loadFromDB(字符串键、区域设置){
字符串资源=null;
if(locale.getLanguage()!=locale.derman.getLanguage()
&&locale.getLanguage()!=locale.ENGLISH.getLanguage()){
locale=locale.ENGLISH;
}
if(key.startsWith(“某些”)| | key.startsWith(“其他”)
||key.startsWith(“this”)| key.startsWith(“that”)){
整数id=Integer.valueOf(key.substring(key.indexOf(“.”+1));
ILocalizedObject master;
如果(键开始与(“部分”)){
master=someDao.findById(id);
}否则,如果(钥匙启动,带有(“其他”)){
master=otherDao.findById(id);
}else if(key.startsWith(“this”)){
master=thisDao.findById(id);
}否则{
master=thatDao.findById(id);
}
if(master!=null&&master.getNames().get(locale)!=null){
resource=master.getNames().get(locale.getName();
}else if(master==null){
调试(“对于键“+键+”没有主控键。”);
}
}
返回资源;
}
[...]
}

最后,我认为使用渲染可能是最好的方法。为了使其可重用和高效,我将其隔离在一个行为中

代码如下:

import org.apache.wicket.Component;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.markup.html.form.AbstractChoice;
import org.apache.wicket.markup.html.form.IChoiceRenderer;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import static java.util.Arrays.sort;

/**
 * This {@link Behavior} can only be used on {@link AbstractChoice} subclasses. It will sort the choices
 * according to their "natural display order" (i.e. the natural order of the display values of the choices).
 * This assumes that the display value implements {@link Comparable}. If this is not the case, you should
 * provide a comparator for the display value. An instance of this class <em>cannot be shared</em> between components.
 * Because the rendering can be costly, the sort-computation is done only once, by default,
 * unless you set to <code>false</code> the <code>sortOnlyOnce</code> argument in the constructor.
 *
 * @author donckels (created on 2012-06-07)
 */
@SuppressWarnings({"unchecked"})
public class OrderedChoiceBehavior extends Behavior {

    // ----- instance fields -----

    private Comparator displayValueComparator;
    private boolean sortOnlyOnce = true;
    private boolean sorted;

    // ----- constructors -----

    public OrderedChoiceBehavior() {
    }

    public OrderedChoiceBehavior(boolean sortOnlyOnce) {
        this.sortOnlyOnce = sortOnlyOnce;
    }

    public OrderedChoiceBehavior(boolean sortOnlyOnce, Comparator displayValueComparator) {
        this.sortOnlyOnce = sortOnlyOnce;
        this.displayValueComparator = displayValueComparator;
    }

    // ----- public methods -----

    @Override
    public void beforeRender(Component component) {
        if (this.sorted && this.sortOnlyOnce) { return;}
        AbstractChoice owner = (AbstractChoice) component;
        IChoiceRenderer choiceRenderer = owner.getChoiceRenderer();
        List choices = owner.getChoices();

        // Temporary data structure: store the actual rendered value with its initial index
        Object[][] displayValuesWithIndex = new Object[choices.size()][2];
        for (int i = 0, valuesSize = choices.size(); i < valuesSize; i++) {
            Object value = choices.get(i);
            displayValuesWithIndex[i][0] = choiceRenderer.getDisplayValue(value);
            displayValuesWithIndex[i][1] = i;
        }

        sort(displayValuesWithIndex, new DisplayValueWithIndexComparator());
        List valuesCopy = new ArrayList(choices);
        for (int i = 0, length = displayValuesWithIndex.length; i < length; i++) {
            Object[] displayValueWithIndex = displayValuesWithIndex[i];
            int originalIndex = (Integer) displayValueWithIndex[1];
            choices.set(i, valuesCopy.get(originalIndex));
        }
        this.sorted = true;
    }

    public Comparator getDisplayValueComparator() {
        return this.displayValueComparator;
    }

    // ----- inner classes -----

    private class DisplayValueWithIndexComparator implements Comparator<Object[]> {

        // ----- Comparator -----

        public int compare(Object[] left, Object[] right) {
            Object leftDisplayValue = left[0];
            Object rightDisplayValue = right[0];
            if (null == leftDisplayValue) { return -1;}
            if (null == rightDisplayValue) { return 1;}

            if (null == getDisplayValueComparator()) {
                return ((Comparable) leftDisplayValue).compareTo(rightDisplayValue);
            } else {
                return getDisplayValueComparator().compare(leftDisplayValue, rightDisplayValue);
            }
        }
    }
}

使用Java使用DropDownChoice的这个扩展(基本上是区域设置敏感的排序-考虑国家字符和国家排序规则)

使用Wicket 6和Java 5+测试的代码:

import java.text.Collator;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;

import org.apache.wicket.Session;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.IChoiceRenderer;
import org.apache.wicket.model.IModel;

import com.google.common.collect.Ordering;

/**
 * DropDownChoice which sort its choices (or in HTML's terminology select's options) according it's localized value
 * and using current locale based Collator so it's sorted how it should be in particular language (ie. including national characters, 
 * using right order).
 * 
 * @author Michal Bernhard michal@bernhard.cz 2013
 *
 * @param <T>
 */
public class OrderedDropDownChoice<T> extends DropDownChoice<T> {

    public OrderedDropDownChoice(String id, IModel<? extends List<? extends T>> choices, IChoiceRenderer<? super T> renderer) {
        super(id, choices, renderer);
    }

    public OrderedDropDownChoice(String id, IModel<? extends List<? extends T>> choices) {
        super(id, choices);
    }

    public OrderedDropDownChoice(String id) {
        super(id);
    }

    public OrderedDropDownChoice(
            String id,
            IModel<T> model,
            IModel<? extends List<? extends T>> choices,
                    IChoiceRenderer<? super T> renderer) {

        super(id, model, choices, renderer);
    }

    @Override
    public List<? extends T> getChoices() {
        List<? extends T> unsortedChoices = super.getChoices();
        List<? extends T> sortedChoices = Ordering.from(displayValueAlphabeticComparator()).sortedCopy(unsortedChoices);

        return sortedChoices;
    }

    private Collator localeBasedTertiaryCollator() {
        Locale currentLocale = Session.get().getLocale();
        Collator collator = Collator.getInstance(currentLocale);
        collator.setStrength(Collator.TERTIARY);

        return collator;
    }

    private Comparator<T> displayValueAlphabeticComparator() {

        final IChoiceRenderer<? super T> renderer = getChoiceRenderer();

        return new Comparator<T>() {

            @Override
            public int compare(T o1, T o2) {
                Object o1DisplayValue = renderer.getDisplayValue(o1);
                Object o2DisplayValue = renderer.getDisplayValue(o2);

                return localeBasedTertiaryCollator().compare(o1DisplayValue, o2DisplayValue);
            }
        };

    }


}
import java.text.Collator;
导入java.util.Comparator;
导入java.util.List;
导入java.util.Locale;
导入org.apache.wicket.Session;
导入org.apache.wicket.markup.html.form.DropDownChoice;
导入org.apache.wicket.markup.html.form.ichoicerender;
导入org.apache.wicket.model.IModel;
导入com.google.common.collect.Ordering;
/**
*DropDownChoice根据本地化值对其选项(或HTML术语中的select选项)进行排序
*并使用当前基于区域设置的拼贴器,以便对特定语言的拼贴方式进行排序(例如,包括国家字符,
*使用正确的顺序)。
* 
*@作者Michal Bernhardmichal@bernhard.cz2013
*
*@param
*/
公共类OrderedDropDownChoice扩展了DropDownChoice{

public OrderedDropDownChoice(字符串id,imodel这是我想要做的,但为了正确使用渲染器,您必须完全完成层次结构(否则wicket的localizer组件无法正确搜索翻译并将发出警告消息)。@FDO您应该覆盖onInitialize()不要在构造函数中工作。这是由于Wicket 1.5以来建议的。然后初始化层次结构。作为最后的方法,我正考虑这样做。此解决方案的问题是,在某些情况下,它会将错误的选择推到模型中。如果使用ChoiceRenderer,以便从Part索引中呈现选项的id属性选择(参见ChoiceRender#getIdValue)您正在使用一些ajax表单提交行为,然后它不会在PreRender之前调用,所以getChoices是旧的未排序的一个…我创建了这个解决方案:我将它作为可接受的解决方案,作为记录,所以您可以将代码完全放在您的解决方案中。也就是说,我认为作为一种行为更好,这样您仍然可以