Is there a shorthand for <fmt:message key="key" />?
Asked Answered
A

6

18

It's tedious and ugly to write things like:

<input type="button" value="<fmt:message key="submitKey" />" />

And in case you want to nest the message tag in another tag's attribute it becomes even worse.

Is there any shorthand for that. For example (like in JSF):

<h:commandButton value="#{msg.shareKey}" />

(spring-mvc-only solutions applicable)

Alkyd answered 4/7, 2010 at 10:28 Comment(0)
O
12

This feels like a bit of a hack, but you could write a custom implementation of java.util.Map which, when get(key) is called, fetches the message from the Spring MessageSource. This Map could be added to the model under the msg key, allowing you to dereference the messages using ${msg.myKey}.

Perhaps there's some other dynamic structure than is recognised by JSP EL that isn't a Map, but I can't think of one offhand.

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

    }
}

As an alternative:

<fmt:message key="key.name" var="var" />

Then use ${var} as a regular EL.

Owings answered 4/7, 2010 at 11:1 Comment(2)
yes, I thought of something like that, but hoped something ready exists.Alkyd
I added the code that implements your answer more or less. If you see something not good in it, please correct it :)Alkyd
C
4

If all you want is a shortcut, you can create a tag file, say 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}" />" />

And use it like this

<%@ taglib tagdir="/WEB-INF/tags" prefix="tags"%>
...
<tags:btn key="submitKey" >
...
Criticaster answered 9/7, 2010 at 18:51 Comment(1)
that's a good idea, but it will require too many tags to re-define. +1 thoughAlkyd
U
3

There isn't. Since I don't do Spring, I'll leave it out of the context in this answer. For the Spring-targeted answer, see @skaffman. You can create a class which extendsResourceBundle, manage the loading yourself with help of a Filter (based on request path?) and store it in the session scope. The ResourceBundle is accessible the usual JSP EL way. You can access it as if it's a Map. The handleGetObject() method will be invoked on every access.

Here's a kickoff example:

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

}

The 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>

If you want to change the locale from inside some servlet or filter:

Text.getCurrentInstance(request).setLocale(newLocale);

Related/interesting-to-know:

Urey answered 4/7, 2010 at 13:16 Comment(0)
F
0

I find a way without any interceptor:

${pageScope["org.springframework.web.servlet.tags.REQUEST_CONTEXT"]
    .getMessage("hello")}

but it's too long, and the key "org.springframework.web.servlet.tags.REQUEST_CONTEXT" may not be compatible for all versions of spring.

Flagellant answered 7/12, 2011 at 8:38 Comment(1)
yeah, but that's pretty tediousAlkyd
R
0

I use a properties file for each language, and the following works well:

<input type="button" value="${msg['myKey']}" />

Roncesvalles answered 25/6, 2013 at 7:15 Comment(0)
E
0

You can set the msg request variable in a servlet or filter with the resource bundle to get the messages via EL expression in JSP code by this way ${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);

}

Example:

 ...
 <%@ 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>

This is working in my java servlet 2.5 environment.

Echinoid answered 20/4, 2014 at 23:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.