【问题标题】:Is there a shorthand for <fmt:message key="key" />?<fmt:message key="key" /> 有简写吗?
【发布时间】:2011-03-11 14:28:30
【问题描述】:

这样写既乏味又丑陋:

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

如果您想将消息标签嵌套在另一个标签的属性中,情况会变得更糟。

有没有什么速记。例如(如在 JSF 中):

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

(spring-mvc-only 解决方案适用)

【问题讨论】:

    标签: java jsp jstl el


    【解决方案1】:

    这感觉有点像 hack,但您可以编写 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】:

    没有。由于我不使用 Spring,因此我将在此答案中将其排除在上下文之外。有关以 Spring 为目标的答案,请参阅@skaffman。您可以创建一个extendsResourceBundle 的类,在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>
    

    如果您想从某个 servlet 或过滤器中更改语言环境:

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

    相关/有趣的知识:

    【讨论】:

      【解决方案3】:

      如果你想要的只是一个快捷方式,你可以创建一个标签文件,比如 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" >
      ...
      

      【讨论】:

      • 这是个好主意,但需要重新定义太多标签。 +1 虽然
      【解决方案4】:

      我找到了没有任何拦截器的方法:

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

      但是太长了,key“org.springframework.web.servlet.tags.REQUEST_CONTEXT”可能不兼容所有版本的spring。

      【讨论】:

      • 是的,但这很乏味
      【解决方案5】:

      我为每种语言都使用了一个属性文件,下面的效果很好:

      &lt;input type="button" value="${msg['myKey']}" /&gt;

      【讨论】:

        【解决方案6】:

        您可以在 servlet 中设置 msg 请求变量或使用资源包过滤以通过这种方式在 JSP 代码中通过 EL 表达式获取消息 ${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 环境中工作。

        【讨论】:

          猜你喜欢
          • 2014-11-03
          • 2022-11-30
          • 2021-04-30
          • 1970-01-01
          • 2015-08-12
          • 1970-01-01
          • 1970-01-01
          • 2018-05-31
          • 2012-12-08
          相关资源
          最近更新 更多