Есть ли сокращение для <fmt: message key = "key" /">?
Это утомительно и уродливо писать такие вещи, как:
<input type="button" value="<fmt:message key="submitKey" />" />
И если вы хотите вложить тег сообщения в другой атрибут тега, это становится еще хуже.
Есть ли сокращение для этого. Например (например, в JSF):
<h:commandButton value="#{msg.shareKey}" />
(spring -mvc-only solutions)
Ответы
Ответ 1
Это похоже на хак, но вы можете написать пользовательскую реализацию java.util.Map
, которая при вызове get(key)
извлекает сообщение из Spring MessageSource
. Этот Map
может быть добавлен в модель под клавишей msg
, позволяя разыменовывать сообщения с помощью ${msg.myKey}
.
Возможно, есть какая-то другая динамическая структура, которая распознается JSP EL, которая не является Map
, но я не могу думать об одном из них.
public class I18nShorthandInterceptor extends HandlerInterceptorAdapter {
private static final Logger logger = Logger.getLogger(I18nShorthandInterceptor.class);
@Autowired
private MessageSource messageSource;
@Autowired
private LocaleResolver localeResolver;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
request.setAttribute("msg", new DelegationMap(localeResolver.resolveLocale(request)));
return true;
}
private class DelegationMap extends AbstractMap<String, String> {
private final Locale locale;
public DelegationMap(Locale locale) {
this.locale = locale;
}
@Override
public String get(Object key) {
try {
return messageSource.getMessage((String) key, null, locale);
} catch (NoSuchMessageException ex) {
logger.warn(ex.getMessage());
return (String) key;
}
}
@Override
public Set<Map.Entry<String, String>> entrySet() {
// no need to implement this
return null;
}
}
}
В качестве альтернативы:
<fmt:message key="key.name" var="var" />
Затем используйте ${var}
как обычный EL.
Ответ 2
Если все, что вам нужно, это ярлык, вы можете создать файл тега, скажем btn.tag
<%@tag%>
<%@ attribute name="key" required="true" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<input type="button" value="<fmt:message key="${key}" />" />
И используйте его вот так
<%@ taglib tagdir="/WEB-INF/tags" prefix="tags"%>
...
<tags:btn key="submitKey" >
...
Ответ 3
Нет. Поскольку я не делаю Spring, я оставлю это из контекста в этом ответе. Для ответа Spring -targeted см. @skaffman. Вы можете создать класс, который extends
ResourceBundle
, управлять загрузкой самостоятельно с помощью Filter
(на основе пути запроса? ) и сохраните его в области сеанса. ResourceBundle
доступен обычным способом JSP EL. Вы можете получить доступ к нему, как если бы он был Map
. Метод handleGetObject()
будет вызываться при каждом доступе.
Вот пример запуска:
package com.example;
import java.util.Enumeration;
import java.util.Locale;
import java.util.ResourceBundle;
import javax.servlet.http.HttpServletRequest;
public class Text extends ResourceBundle {
private static final String TEXT_ATTRIBUTE_NAME = "text";
private static final String TEXT_BASE_NAME = "com.example.i18n.text";
private Text(Locale locale) {
setLocale(locale);
}
public static void setFor(HttpServletRequest request) {
if (request.getSession().getAttribute(TEXT_ATTRIBUTE_NAME) == null) {
request.getSession().setAttribute(TEXT_ATTRIBUTE_NAME, new Text(request.getLocale()));
}
}
public static Text getCurrentInstance(HttpServletRequest request) {
return (Text) request.getSession().getAttribute(TEXT_ATTRIBUTE_NAME);
}
public void setLocale(Locale locale) {
if (parent == null || !parent.getLocale().equals(locale)) {
setParent(getBundle(TEXT_BASE_NAME, locale));
}
}
@Override
public Enumeration<String> getKeys() {
return parent.getKeys();
}
@Override
protected Object handleGetObject(String key) {
return parent.getObject(key);
}
}
Filter
:
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
Text.setFor((HttpServletRequest) request);
chain.doFilter(request, response);
}
JSP:
<p>${text['home.paragraph']}</p>
Если вы хотите изменить локаль изнутри какого-либо сервлета или фильтра:
Text.getCurrentInstance(request).setLocale(newLocale);
Относящиеся/интересно к ноу:
Ответ 4
Я нахожу способ без перехватчика:
${pageScope["org.springframework.web.servlet.tags.REQUEST_CONTEXT"]
.getMessage("hello")}
но он слишком длинный, и ключ "org.springframework.web.servlet.tags.REQUEST_CONTEXT" может быть несовместим для всех версий spring.
Ответ 5
Я использую файл свойств для каждого языка, и следующее работает хорошо:
<input type="button" value="${msg['myKey']}" />
Ответ 6
Вы можете установить переменную запроса msg
в сервлет или фильтр с помощью пакета ресурсов, чтобы получить сообщения через выражение EL в коде JSP таким образом ${msg.messageKey}
import javax.servlet.jsp.jstl.core.Config;
import java.util.ResourceBundle;
...
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
String STR_LOCALE = "es-MX"; // you can get this value from the http request to get the default browser locale.
String LOCALE_BASENAME = "my.package.basename";
Locale locale = Locale.forLanguageTag(STR_LOCALE);
req.setAttribute("msg", ResourceBundle.getBundle(LOCALE_BASENAME, locale));
// And you can setup the 'fmt' tag library from here to resolve parameterized messages.
Config.set(req, Config.FMT_LOCALE, locale);
Config.set(req, Config.FMT_LOCALIZATION_CONTEXT, LOCALE_BASENAME);
}
Пример:
...
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
...
<h1>${msg.header}</h1>
<h2>${msg[variableHeader]}</h2>
<fmt:message key='messageWithVariable'>
<fmt:param>The value</fmt:param>
</fmt:message>
Это работает в моей среде Java Servlet 2.5.