Struts 2 > Transparent web-app I18N |

Struts 2
Transparent web-app I18N
Edit Page Browse Space Add Page Add News
Added by neuro, last edited by Ted Husted on Sep 03, 2006 (view change)

| As of WebWork 2.2, this interceptor is included with the normal distribution as the I18n Interceptor

Consider adding transparent i18 with simple on-the-fly locale switching to your appliction via I18NInterceptor.

The main idea:
Interceptor could track locale switch requests, persist selection in current session and set locale for all (or appropriate) actions invoked.

    package neuro.util.xwork;

    import com.opensymphony.xwork.ActionSupport;
    import com.opensymphony.xwork.ActionInvocation;
    import com.opensymphony.xwork.interceptor.Interceptor;

    import java.util.Locale;

    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;

    /**
     * I18nInterceptor
     * @author Aleksei Gopachenko
     */
    public class I18nInterceptor implements Interceptor
    {
        protected static final Log log = LogFactory.getLog(I18nInterceptor.class);

        public static final String DEFAULT_SESSION_ATTRIBUTE = "WW_TRANS_I18N_LOCALE";
        public static final String DEFAULT_PARAMETER = "request_locale";

        protected String parameterName = DEFAULT_PARAMETER;
        protected String attributeName = DEFAULT_SESSION_ATTRIBUTE;

        /**
         */
        public I18nInterceptor()
        {
            if(log.isDebugEnabled()) log.debug("new I18nInterceptor()");
        }

        public void setParameterName(String parameterName) {
            this.parameterName = parameterName;
        }

        public void setAttributeName(String attributeName) {
            this.attributeName = attributeName;
        }

        /**
         */
        public void init() {
            if(log.isDebugEnabled()) log.debug("init()");
        }

        /**
         */
        public void destroy() {
            if(log.isDebugEnabled()) log.debug("destroy()");
        }

        /**
         */
        public String intercept(ActionInvocation invocation) throws Exception {
            if(log.isDebugEnabled()) log.debug("intercept '"
                +invocation.getProxy().getNamespace()+"/"
                +invocation.getProxy().getActionName()+"' { ");

            //get requested locale
            Object requested_locale = invocation.getInvocationContext().getParameters().get(parameterName);
            if(requested_locale!=null && requested_locale.getClass().isArray() && ((Object[])requested_locale).length==1) {
                requested_locale=((Object[])requested_locale)[0];
            }
            if(log.isDebugEnabled()) log.debug("requested_locale="+requested_locale);
            //save it in session
            if (requested_locale!=null) {
                Locale locale = (requested_locale instanceof Locale)?
                  (Locale) requested_locale : localeFromString(requested_locale.toString());
                if(log.isDebugEnabled()) log.debug("store locale="+locale);
                if(locale!=null)invocation.getInvocationContext().getSession().put(attributeName,locale);
            }
            //set locale for action
            Object locale = invocation.getInvocationContext().getSession().get(attributeName);
            if (locale!=null && locale instanceof Locale) {
                if(log.isDebugEnabled()) log.debug("apply locale="+locale);
                invocation.getInvocationContext().setLocale((Locale)locale);
            }

            if(log.isDebugEnabled()) log.debug("before Locale="+((ActionSupport)invocation.getAction()).getLocale());
            final String result = invocation.invoke();
            if(log.isDebugEnabled()) log.debug("after Locale="+((ActionSupport)invocation.getAction()).getLocale());

            if(log.isDebugEnabled()) log.debug("intercept } ");
            return result;
        }

        Locale localeFromString(String localeStr) {
            if ((localeStr == null) || (localeStr.trim().length() == 0) || (localeStr.equals("_"))) {
                return Locale.getDefault();
            }
            int index = localeStr.indexOf('_');
            if (index < 0) {
                return new Locale(localeStr);
            }
            String language = localeStr.substring(0,index);
            if (index == localeStr.length()) {
                return new Locale(language);
            }
            localeStr = localeStr.substring(index +1);
            index = localeStr.indexOf('_');
            if (index < 0) {
                return new Locale(language,localeStr);
            }
            String country = localeStr.substring(0,index);
            if (index == localeStr.length()) {
                return new Locale(language,country);
            }
            localeStr = localeStr.substring(index +1);
            return new Locale(language,country,localeStr);
        }

    }

Can be enabled for whole package via something like:

    <interceptor name="i18n" class="neuro.util.xwork.I18nInterceptor">
        <!-- on which request parameter we should react, optional, defaults to "request_locale" ->
        <param name="parameterName">set_locale</param>
        <!- under which session attribute locale should be stored, optional, defaults to "WW_TRANS_I18N_LOCALE" ->
        <param name="attributeName">ww_locale</param>
    </interceptor>

    <interceptor-stack name="i18nStack">
        <interceptor-ref name="i18n"/>
        <interceptor-ref name="defaultStack"/>
    </interceptor-stack>

    <default-interceptor-ref name="i18nStack"/>

...and invoked in web-app just by adding few links to menu:

    <a href="?set_locale=en">EN</a>
    <a href="?set_locale=ru">RU</a>
    <!- etc -->

Of course you still need to move all explisitly defined messages or labels to appropriate ResourceBundles and make translations. Be sure to check out your

- Actions - to use getText(...)
- *-validation.xml files - to use <message key=...>
- results/views - to use WW i18n services by <webwork:text ...> tag, or directly by evaluating getText(...) OGNL expression on current stack.

If this Interceptor is generally useful, may be it should go into codebase?