Простой способ использования параметризованных сообщений пользовательского интерфейса в Wicket?
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 способ сделать это (это не намного длиннее, чем указано выше) ?
Ответы
Ответ 1
Я думаю, что наиболее последовательный WICKETY способ может быть достигнут путем улучшения ответа Jonik с 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 и ничего больше
- Вы можете заменить столько значений, сколько хотите
- Работа с ярлыками, информация(), проверка и т.д.
- Это не полностью wickety, но это согласуется с калитки, поэтому вы можете повторно использовать эти свойства с помощью
StringResourceModel
.
Примечания:
если вы хотите использовать Модели, вам просто нужно создать простую модель, которая переопределяет функцию toString
модели следующим образом:
abstract class MyModel extends AbstractReadOnlyModel{
@Override
public String toString()
{
if(getObject()==null)return "";
return getObject().toString();
}
}
и передать его как аргумент MessageFormat
.
Я не знаю, почему Wicket не поддерживает Model
в сообщении обратной связи. но если он был поддержан, не было причин использовать эти решения, и вы могли бы использовать StringResourceModel
всюду.
Ответ 2
Взгляните на пример 4 в javaadoc StringResourceModel - вы можете передать нулевую модель и явные параметры:
add(new Label("message",
new StringResourceModel(
"msg", this, null, value)));
msg=Value is {0}
Ответ 3
Там путь, который, хотя все еще предполагает создание модели, не требует bean с геттером.
учитывая это сообщение в файле свойств:
msg=${} persons
Здесь, как заменить placeholder значением, будь то локальная переменная, поле или литерал:
add(new Label("label", new StringResourceModel("msg", new Model<Serializable>(5))));
Ответ 4
Когда вы столкнулись с чем-то вроде описанного в вопросе, я бы теперь использовал:
.properties
msg=Saving record %s with value %d
Java:
add(new Label("label", String.format(getString("msg"), record, value)));
Почему мне это нравится:
- Чистое, простое решение
- Использует обычная Java и ничего больше
- Вы можете заменить столько значений, сколько хотите (в отличие от трюка
${}
). Изменить: хорошо, если вам действительно нужно поддерживать многие языки, где замененные значения могут быть в другом порядке, String.format()
не подходит. Вместо этого с использованием MessageFormat - это аналогичный подход, который правильно поддерживает это.
Отказ от ответственности: это "слишком очевидно", но это проще других решений (и, безусловно, лучше, чем мой оригинальный replaceAll()
хак). Я изначально искал путь "калитки", в то время как этот вид обходит Wicket &mdash, а затем, кого это волнует?: -)
Ответ 5
Создание модели для вашей метки действительно 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 ) );
}
Детали, которые я затушевываю, следующие:
- Я создал свой собственный
ConvertingModel
, который автоматически преобразует объекты в их представление String на основе IConverters, доступных для данного компонента
- Я создал свой собственный
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% времени.
Ответ 6
Если в вашем Компоненте есть Модель, которая содержит объект со значениями, к которым вы хотите получить доступ из ваших заполнителей в качестве замены, вы можете написать:
new StringResourceModel("salutation.text", getModel());
Давайте представим, что тип возвращаемого значения getModel()
- IModel<User>
, а User
содержит такие поля, как firstName
и lastName
. В этом случае вы можете легко получить доступ к полям firstName
и lastName
внутри строки вашего свойства:
salutation.text=Hej ${firstName} ${lastName}, have a nice day!
Дополнительную информацию вы можете найти здесь: https://ci.apache.org/projects/wicket/apidocs/8.x/org/apache/wicket/model/StringResourceModel.html#StringResourceModel-java.lang.String-org.apache.wicket.model.IModel-