Localeによるdispatch先の選択2

この記事のコードには問題があります。正しくは Localeによるリソース選択Interceptorの問題解消 - Struts 2+Spring 2+Tiles+Acegi+iBatis+GWT+JUnit 4+JMockit でフルスタックJAVAフレームワークを参照してください。
Localeの設定によって選択可能にはなったけど、言語対応のファイルが無い場合は fallback用の場所へdispatchできるようにする。
こうすると、国際化で全く違うページだけそれぞれ用意して、メッセージが完全に外部リソース化されていてJSPが言語に依存しない共用できるページは共用部においておく事ができる。

LocaleResourceInterceptor.java

package jp.co.hershe.struts2.util;

import java.net.URL;
import java.text.MessageFormat;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.util.ValueStack;


/**
 * 国際化対応アプリケーション用のインターセプタ
 * 
 * 結果を Locale 設定に従いそれぞれ固有のページで表示をする場合に
 * 利用する。
 * 
 *  <result>$( localed.resource( "{0}/edit.jsp" ) }</result>
 *  とすると Locale の Language が ja の場合 /ja/edit.jsp を探し
 *  あればそちら、無ければ /edit.jsp を表示する。
 * @author mikuni
 *
 */
public class LocaleResourceInterceptor extends AbstractInterceptor {

    public void destroy() {
        // TODO 自動生成されたメソッド・スタブ
    }

    public void init() {
        // TODO 自動生成されたメソッド・スタブ
    }

    // スタックに localed として自分を登録
    public String intercept(ActionInvocation invocation) throws Exception {
        final ValueStack stack =  invocation.getStack();
        stack.set( "localed", this );
        return invocation.invoke();
    }

    // 置き換え処理を行う
    public String resource( String url ) throws Exception {
        Locale loc = ActionContext.getContext().getLocale();
        String ans = MessageFormat.format(url, new Object[]{ "/"+loc.getLanguage(), "/"+loc.getCountry() } ); 
        HttpServletRequest request = ServletActionContext.getRequest();
        URL u = ServletActionContext.getServletContext().getResource(ans);
        if (u!=null) {
            return ans;
        }
        ans = MessageFormat.format(url, new Object[]{ "", "" } );
        return ans;
    }
}

こうして、Struts.xml に Interceptorを登録して

            <interceptor name="locale"
                         class="jp.co.hershe.struts2.util.LocaleResourceInterceptor"/>

さらにアクションで参照すると

            <interceptor-ref name="locale" />

resultには次のように書く事で、 fallback付きでLocaleに応じたリソース選択ができる

  <result>$( localed.resource( "{0}/list.jsp" )</result>

なので、TemplateResultと併せて result typeに次のように登録して

<result-types>
    <result-type name="templ" class="jp.co.hershe.struts2.util.TemplateResult"  default="true">
       <param name="template">${ localed.resource( "{0}#file#" ) }</param>
       <param name="key">#file#</param>
    </result-type>
</result-types>

次のように書くと、 Localeが ja で /ja/list.jsp が存在する場合は /ja/list.jsp 無い場合は /list.jsp に dispatch する。

  <result>/list.jsp</result>

2007-12-25: 問題が発覚したため、注意書きを加えました