Простой способ использовать параметризованные сообщения пользовательского интерфейса в Wicket? - PullRequest
11 голосов
/ 20 октября 2010

Wicket имеет гибкую систему интернационализации , которая поддерживает параметризацию сообщений пользовательского интерфейса многими способами.Есть примеры, например, в StringResourceModel javadocs, например:

WeatherStation ws = new WeatherStation();
add(new Label("weatherMessage", new StringResourceModel(
    "weather.${currentStatus}", this, new Model<String>(ws)));

Но я хочу что-то действительно простое , и не смог найти хороший пример этого.

Рассмотрим этот вид сообщения пользовательского интерфейса в файле .properties:

msg=Value is {0}

В частности, я бы не хотел создавать объект модели (с геттерами для заменяемых значений;как WeatherStation в приведенном выше примере) только для этой цели.Это просто излишне, если у меня уже есть значения в локальных переменных, и в противном случае такой объект не нужен.

Вот глупый способ "грубой силы" заменить {0} на правильное значение:

String value = ... // contains the dynamic value to use
add(new Label("message", getString("msg").replaceAll("\\{0\\}", value)));

Есть ли чистый, более Wicket-y способ сделать это (это не намного длиннее, чем выше) ?

Ответы [ 5 ]

12 голосов
/ 21 апреля 2012

Посмотрите на Пример 4 в javadoc StringResourceModel - вы можете передать нулевую модель и явные параметры:

add(new Label("message",
         new StringResourceModel(
             "msg", this, null, value)));

msg=Value is {0}
5 голосов
/ 21 октября 2010

Есть способ, который, хотя все еще включает создание модели, не требует bean-компонента с геттером.

, учитывая это сообщение в файле свойств:

msg=${} persons

Вот какзаменить заполнитель значением, будь то локальная переменная, поле или литерал:

add(new Label("label", new StringResourceModel("msg", new Model<Serializable>(5))));
4 голосов
/ 25 апреля 2015

Я думаю, что наиболее последовательный WICKETY способ может быть достигнут путем улучшения ответа Джоника с MessageFormat:

.properties:

msg=Saving record {0} with value {1}

.java:

add(new Label("label", MessageFormat.format(getString("msg"),obj1,obj2)));
//or
info(MessageFormat.format(getString("msg"),obj1,obj2));

Почему мне это нравится:

  • Чистое, простое решение
  • Использует простую Java и ничего больше
  • Вы можете заменить столько значений, сколько хотите
  • Работа с метками, информация (), проверка и т. Д.
  • Это не совсем вежливо, но это согласуется с калиткой, поэтому вы можете повторно использовать эти свойства с StringResourceModel.

Примечания:

Если вы хотите использовать Модели, вам просто нужно создать простую модель, которая переопределяет toString функцию модели следующим образом:

abstract class MyModel extends AbstractReadOnlyModel{
    @Override
    public String toString()
    {
        if(getObject()==null)return "";
        return getObject().toString();
    }
}

и передать его как MessageFormat аргумент.

Я не знаю, почему Wicket не поддерживает Model в сообщении обратной связи. но если это было поддержано, не было никакой причины использовать эти решения, и вы могли бы использовать StringResourceModel везде.

2 голосов
/ 20 апреля 2012

Столкнувшись с чем-то вроде описанного в вопросе, я бы теперь использовал:

.properties:

msg=Saving record %s with value %d

Java:

add(new Label("label", String.format(getString("msg"), record, value)));

Почему мне нравитсяit:

  • Чистое, простое решение
  • Использование обычная Java и ничего больше
  • Вы можете заменить столько значений, сколько хотите (в отличие отс трюком ${} ). Редактировать : ну, если вам действительно нужно поддерживать много языков , где замененные значения могут быть в другом порядке, String.format() не годится.Вместо этого с использованием MessageFormat является аналогичным подходом , который должным образом поддерживает это.

Отказ от ответственности: это "слишком очевидно", но это проще, чем другие решения (и определенно лучше, чем мойоригинал replaceAll() взломать).Первоначально я искал способ "Wicket-y", в то время как этот тип обходит Wicket - опять же, кого это волнует?: -)

0 голосов
/ 09 декабря 2010

Создание модели для вашего ярлыка действительно Wicket Way . Тем не менее, вы можете упростить для себя время от времени функцию полезности. Вот один я использую:

/**
 * Creates a resource-based label with fixed arguments that will never change. Arguments are wrapped inside of a
 * ConvertingModel to provide for automatic conversion and translation, if applicable.
 * 
 * @param The component id
 * @param resourceKey The StringResourceModel resource key to use
 * @param component The component from which the resourceKey should be resolved
 * @param args The values to use for StringResourceModel property substitutions ({0}, {1}, ...).
 * @return the new static label
 */
public static Label staticResourceLabel(String id, String resourceKey, Component component, Serializable... args) {
    @SuppressWarnings("unchecked")
    ConvertingModel<Serializable>[] models = new ConvertingModel[args.length];
    for ( int i = 0; i < args.length; i++ ) {
        models[i] = new ConvertingModel<Serializable>( new Model<Serializable>( args[i] ), component );
    }
    return new CustomLabel( id, new StringResourceModel( resourceKey, component, null, models ) );
}

Здесь я привожу подробности:

  1. Я создал свой собственный ConvertingModel, который будет автоматически преобразовывать объекты в их строковое представление на основе IConverters, доступных для данного компонента
  2. Я создал собственный CustomLabel, в котором применяется постобработка текста пользовательской метки (как подробно описано в в этом ответе )

Имея собственный IConverter для, скажем, объекта Temperature, вы можете получить что-то вроде:

Properties key:
temperature=The current temperature is ${0}.

Page.java code:
// Simpler version of method where wicket:id and resourceKey are the same
add( staticResourceLabel( "temperature", new Temperature(5, CELSIUS) ) );

Page.html:
<span wicket:id='temperature'>The current temperature is 5 degrees Celsius.</span>

Недостатком этого подхода является то, что у вас больше нет прямого доступа к классу Label, вы не можете создать его подкласс для переопределения isVisible() или подобных вещей. Но для моих целей это работает в 99% случаев.

...