4.8. 国際化


4.8.1. Overview

国際化とは、アプリケーションで表示するラベルやメッセージを、特定の言語のみに固定せず、ロケール(Locale)と呼ばれる言語や国・地域を表す単位の指定により、複数言語の切り替えに対応させることである。

本節では、画面に表示するメッセージを国際化する方法について説明する。

国際化するためには、以下の対応が必要となる。

  • 画面内のテキスト要素(コード値の名称、メッセージ、GUIコンポーネントのラベルなど)は、プログラム内でハードコードせずに、プロパティファイルなどの外部定義から取得する。

  • クライアントからLocaleを指定する仕組みを提供する。

クライアントからLocaleを指定する方法は以下の通りである。

  • 標準のリクエストヘッダを使用する。(ブラウザの言語設定で指定)

  • リクエストパラメータを使用してCookieに保存する。

  • リクエストパラメータを使用してSessionに保存する。

Localeの切り替えイメージを以下に示す。

locale change image

Note

Codelistの国際化方法については、コードリストを参照されたい。

Note

エラー画面を国際化する必要がある場合、Spring MVCのControllerを使用してエラー画面に遷移すること。

Spring MVCを介さずエラー画面に直接遷移した場合、メッセージが意図した言語で出力されない場合がある。

詳細については国際化が適用されない場合の対処方法を参照されたい。

Note

Java SE 17ではJava SE 8と日付の文字列表現が異なる場合がある。

Java SE 8と同様に表現するにはデフォルトで使用されるロケール・データの変更を参照されたい。

Tip

国際化はi18nという略称が広く知られている。

i18n という記述は、internationalization の先頭の i と語尾の n の間に nternationalizatio の18文字があることに起因する。


4.8.2. How to use

4.8.2.1. メッセージ定義の設定

画面に表示するメッセージを国際化する場合は、メッセージを管理するためのコンポーネント(MessageSource)として、

  • org.springframework.context.support.ResourceBundleMessageSource

  • org.springframework.context.support.ReloadableResourceBundleMessageSource

のどちらかを使用する。

ここでは、ResourceBundleMessageSourceを使用する場合の設定例を紹介する。

ApplicationContextConfig.java

@Bean("messageSource")
public MessageSource messageSource() {
    ResourceBundleMessageSource bean = new ResourceBundleMessageSource();
    bean.setBasenames("i18n/application-messages"); // (1)
    return bean;
}
項番
説明
(1)
プロパティファイルの基底名として、i18n/application-messagesを指定する。
国際化対応を行う場合、i18nディレクトリ配下にメッセージプロパティファイルを格納することを推奨する。

MessageSourceの詳細や定義方法は、メッセージ管理を参照されたい。

プロパティファイルの格納例

properties filepath

プロパティファイルは、以下のルールに則って作成する。

  • Locale毎のファイル名は、application-messages_XX.propertiesという形式で作成する。(XX部分はLocaleを指定)

  • application-messages.properties必ず作成する。もし存在しない場合、MessageSourceからメッセージを取得できず以下の様な状態となる。

    • JSPにメッセージを設定する際にJspTagExceptionが発生する。

    • Thymeleafでは、MessageSourceからメッセージを取得できず、??メッセージID??という形式でメッセージIDが出力される。

  • application-messages.propertiesに定義するメッセージは、デフォルトで使用する言語で作成する。

上記ルールに則ってプロパティファイルを作成すると、以下のような動作になる。

  • クライアントのLocaleがzhの場合、application-messages_zh.propertiesが使用される。

  • クライアントのLocaleがjaの場合、application-messages_ja.propertiesが使用される。

  • クライアントのLocaleに対応するプロパティファイルが存在しない場合、デフォルトとして、application-messages.propertiesが使用される。(ファイル名に”_XX”部分が存在しないファイル)

Note

Localeの判別方法は、以下の順番で該当するLocaleのプロパティファイルが発見されるまで、Localeを確認していくことである。

  1. クライアントから指定されたLocale

  2. アプリケーションサーバのJVMに指定されているLocale(設定されていない場合あり)

  3. アプリケーションサーバのOSに指定されているLocale

よく間違える例として、 クライアントから指定されたLocaleのプロパティファイルが存在しない場合、デフォルトのプロパティファイルが使用されるとの誤解が挙げられる。

実際は、次にアプリケーションサーバに指定されているLocaleを確認して、それでも該当するLocaleのプロパティファイルが見つからない場合に、デフォルトのプロパティファイルが使用されるので注意する。

Tip

メッセージプロパティファイルの記載方法については、メッセージ管理を参照されたい。


4.8.2.2. Localeをブラウザの設定により切り替える

4.8.2.2.1. AcceptHeaderLocaleResolverの設定

ブラウザの設定を使用してLocaleを切り替える場合は、AcceptHeaderLocaleResolverを使用する。

SpringMvcConfig.java

// (1)
@Bean("localeResolver")
public AcceptHeaderLocaleResolver localeResolver() {
    AcceptHeaderLocaleResolver bean = new AcceptHeaderLocaleResolver();
    bean.setDefaultLocale(Locale.ENGLISH); // (2)
    List<Locale> locales = new ArrayList<Locale>();
    locales.add(Locale.ENGLISH);
    locales.add(Locale.JAPANESE);
    bean.setSupportedLocales(locales); // (3)
    return bean;
}
項番
説明
(1)
org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolverをbean定義する。
このLocaleResolverを使用すると、リクエスト毎に設定されるHTTPヘッダー(”accept-language”)に指定されているLocaleが使用される。
(2)
デフォルトのLocaleを設定するため、defaultLocaleプロパティを設定する。
上記の例では、アプリケーションがサポートしていないLocaleがリクエストされた場合、Localeは”en”に設定される。
(3)
アプリケーションがサポートするLocaleを設定するため、supportedLocalesプロパティを設定する。
リクエストが要求するLocaleと、サポートするLocaleが一致する場合はそのLocaleが使用される。
国と言語を組み合わせたLocale(例:ja_JP)が要求され、サポートするLocaleと一致しない場合、対応する言語のみのLocale(例:ja)で一致を確認する。
上記の例では、アプリケーションがサポートするLocaleとして、”en”と”ja”を指定している。

Note

LocaleResolverが設定されていない場合、デフォルトでorg.springframework.web.servlet.i18n.AcceptHeaderLocaleResolverが使用されるため、LocaleResolverの設定は、省略することもできる。


4.8.2.2.2. メッセージの設定

以下に、メッセージの設定例を示す。

application-messages.properties

title.admin.top = Admin Top

application-messages_ja.properties

title.admin.top = 管理画面 Top

4.8.2.2.3. 実装

include.jsp(インクルード用の共通jspファイル)

<%@ page session="false"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>  <!-- (1) -->
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@ taglib uri="http://www.springframework.org/security/tags" prefix="sec"%>
<%@ taglib uri="http://terasoluna.org/functions" prefix="f"%>
<%@ taglib uri="http://terasoluna.org/tags" prefix="t"%>
項番
説明
(1)
JSPで出力する場合、Springのタグライブラリを用いてメッセージ出力を行うため、カスタムタグを定義する必要がある。
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>を定義すること。

Note

インクルード用の共通jspファイルの詳細はインクルード用の共通JSPの作成を参照されたい。


画面表示用JSPファイル

<spring:message code="title.admin.top" />  <!-- (2) -->
項番
説明
(2)
JSPでは、Springのタグライブラリである、<spring:message>を用いてメッセージ出力を行う。
code属性に、プロパティで指定したキーを設定する。
本例では、Localeがjaの場合”管理画面 Top”、それ以外のLocaleの場合”Admin Top”が出力される。

4.8.2.3. Localeを画面操作等で動的に変更する

Localeを画面操作等で動的に変更する方法は、ユーザ端末(ブラウザ)の設定に関係なく、特定の言語を選択させたい場合に有効である。

画面操作でLocaleを変更する場合のイメージを以下に示す。

i18n change locale on screen

ユーザが使用する言語を選択する場合は、org.springframework.web.servlet.i18n.LocaleChangeInterceptorを用いることで実現する事ができる。

LocaleChangeInterceptorは、リクエストパラメータに指定されたLocaleの値を、org.springframework.web.servlet.LocaleResolverのAPIを使用してサーバ又はクライアントに保存するためのインタセプターである。

使用するLocaleResolverの実装クラスを、以下の表から選択する。

LocaleResolverの種類

No

実装クラス

Localeの保存方法

org.springframework.web.servlet.i18n.SessionLocaleResolver

サーバーに保存(HttpSessionを使用)

org.springframework.web.servlet.i18n.CookieLocaleResolver

クライアントに保存(Cookieを使用)

Note

LocaleResolverorg.springframework.web.servlet.i18n.AcceptHeaderLocaleResolverを使用する場合、 org.springframework.web.servlet.i18n.LocaleChangeInterceptorを使用してLocaleを動的に変更することはできない。


4.8.2.3.1. LocaleChangeInterceptorの設定

リクエストパラメータを使用してLocaleを切り替える場合は、LocaleChangeInterceptorを使用する。

SpringMvcConfig.java

@EnableAspectJAutoProxy
@EnableWebMvc
@Configuration
public class SpringMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        // omitted

        registry.addInterceptor(localeChangeInterceptor()).addPathPatterns("/**") // (1)
              .excludePathPatterns("/resources/**");
    }

    // (1)
    @Bean("localeChangeInterceptor")
    public LocaleChangeInterceptor localeChangeInterceptor() {
        return new LocaleChangeInterceptor();
    }
項番
説明
(1)
Spring MVCのインタセプターに、org.springframework.web.servlet.i18n.LocaleChangeInterceptorを定義する。
この設定により、”リクエストURL?locale=xx”で使用可能となる。

Note

Localeを指定するリクエストパラメータ名の変更方法

@Bean("localeChangeInterceptor")
public LocaleChangeInterceptor localeChangeInterceptor() {
    LocaleChangeInterceptor bean = new LocaleChangeInterceptor();
    bean.setParamName("lang"); // (2)
    return bean;
}
項番
説明
(2)
paramNameプロパティにリクエストパラメータ名を指定する。上記例では、”リクエストURL?lang=xx”となる。

Note

LocaleChangeInterceptorはSpring MVCのControllerの処理実行時に呼ばれるインターセプタであるため、Controllerを経由しない遷移の場合は適用されないことに注意されたい。

なお、LocaleChangeInterceptorだけでなくViewResolver(ThymeleafViewResolverなど)も同様にControllerを経由しない遷移の場合は適用されない。

詳細は「ブランクプロジェクトの設定」を参照されたい。

Note

リクエストパラメータにLocaleとして使用できない文字(半角スペース、ハイフン、アンダースコア、英数字以外)を含む値が指定された場合、例外がスローされる。この時、前回のリクエストまでのLocaleが継続して有効になる。例外については、ignoreInvalidLocaleプロパティにtrueを指定することでスローされなくなる。

リクエストパラメータにLocaleとして指定された値はJDKでサポートされないLocaleでも、そのままLocaleとして有効になる。LocaleChangeInterceptorにはAcceptHeaderLocaleResolversupportedLocalesのように、サポートするLocaleを限定する仕組みはないため、注意されたい。

空文字が指定された場合はLocaleResolverに予め設定されたdefaultLocaleが有効になる。defaultLocaleが設定されていない場合はユーザ端末(ブラウザ)に設定されたLocaleが有効になる。

このため、defaultLocaleを設定することを推奨する。


4.8.2.3.2. SessionLocaleResolverの設定

Localeをサーバに保存する場合は、SessionLocaleResolverを使用する。

SpringMvcConfig.java

// (1)
@Bean("localeResolver")
public SessionLocaleResolver localeResolver() {
    SessionLocaleResolver bean = new SessionLocaleResolver();
    bean.setDefaultLocale(Locale.ENGLISH); // (2)
    return bean;
}
項番
説明
(1)
org.springframework.web.servlet.LocaleResolverをBean定義する。
本例では、セッションにLocaleを保存するorg.springframework.web.servlet.i18n.SessionLocaleResolverを指定している。
bean名は”localeResolver”と設定すること。
この設定により、LocaleChangeInterceptor内の処理でSessionLocaleResolverが使用される。
(2)
defaultLocaleプロパティにLocaleを指定する。セッションからLocaleが取得できない場合、valueの設定値が有効になる。

Note

defaultLocaleプロパティを省略した場合、ユーザ端末(ブラウザ)に設定されたLocaleが有効になる。


4.8.2.3.3. CookieLocaleResolverの設定

Localeをクライアントに保存する場合は、CookieLocaleResolverを使用する。

SpringMvcConfig.java

// (1)
@Bean("localeResolver")
public CookieLocaleResolver localeResolver() {
    CookieLocaleResolver bean = new CookieLocaleResolver("localeCookie"); // (2)
    bean.setDefaultLocale(Locale.ENGLISH); // (3)
    return bean;
}
項番
説明
(1)
org.springframework.web.servlet.LocaleResolverをBean定義する。
本例では、CookieにLocaleを保存するorg.springframework.web.servlet.i18n.CookieLocaleResolverを指定している。
beanタグのid属性は”localeResolver”と設定すること。
この設定により、LocaleChangeInterceptor内の処理でCookieLocaleResolverが使用される。
(2)
コンストラクタ引数に指定した値が、cookie名となる。指定しない場合、org.springframework.web.servlet.i18n.CookieLocaleResolver.LOCALEとなる。Spring Frameworkを使用していることがわかるため、変更することを推奨する。
(3)
defaultLocaleプロパティにLocaleを指定する。CookieからLocaleが取得できない場合、valueの設定値が有効になる。

Note

defaultLocaleプロパティを省略した場合、ユーザ端末(ブラウザ)に設定されたLocaleが有効になる。


4.8.2.3.4. メッセージの設定

以下に、メッセージの設定例を示す。

application-messages.properties

i.xx.yy.0001 = changed locale
i.xx.yy.0002 = Confirm change of locale at next screen

application-messages_ja.properties

i.xx.yy.0001 = Localeを変更しました。
i.xx.yy.0002 = 次の画面でのLocale変更を確認

4.8.2.3.5. 実装

画面表示用JSPファイル

<a href='${pageContext.request.contextPath}?locale=en'>English</a>  <!-- (1) -->
<a href='${pageContext.request.contextPath}?locale=ja'>Japanese</a>
<spring:message code="i.xx.yy.0001" />
項番
説明
(1)
Localeを切り替えるためのパラメータを送信する。
リクエストパラメータ名は、LocaleChangeInterceptorparamNameプロパティに指定した値となる。(上記例では、デフォルトのパラメータ名を使用している)
上記例の場合、Englishリンクで英語Locale、Japaneseリンクで日本語Localeに変更している。
以降は、選択したLocaleが有効になる。
英語Localeは”en”用のプロパティファイルが存在しないため、デフォルトのプロパティファイルから読み込まれる。

Tip

  • インクルード用の共通jspにSpringのタグライブラリを定義する必要がある。

  • インクルード用の共通jspファイルの詳細はインクルード用の共通JSPの作成を参照されたい。


4.8.2.3.6. 国際化が適用されない場合の対処方法

LocaleChangeInterceptorはSpring MVCのControllerの処理実行時に呼ばれるインターセプタであるため、Controllerを経由しない遷移の場合は国際化が適用されないことに注意されたい。

例えば、エラー画面への遷移設定に直接JSPファイルを指定するような場合、エラー画面への遷移にはControllerが使用されない。
この場合、エラー画面を国際化するには、エラー画面へ遷移するためのControllerを作成し、エラー画面への遷移に使用することでLocaleChangeInterceptorが使用されるように設定する必要がある。

設定方法について、Spring Securityの認可の実装を例に以下に示す。


LocaleChangeInterceptorが適用されないエラー画面への遷移例

  • SpringSecurityConfig.java

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

    // omitted

    http.exceptionHandling(ex -> ex.accessDeniedHandler(
            accessDeniedHandler()));

    return http.build();
}

@Bean("accessDeniedHandler")
public AccessDeniedHandler accessDeniedHandler() {
    LinkedHashMap<Class<? extends AccessDeniedException>, AccessDeniedHandler> errorHandlers = new LinkedHashMap<>();

    // omitted

    AccessDeniedHandlerImpl accessDeniedHandler = new AccessDeniedHandlerImpl();
    accessDeniedHandler.setErrorPage(
            "/WEB-INF/views/common/error/accessDeniedError.jsp"); // (1)

    return new DelegatingAccessDeniedHandler(errorHandlers, accessDeniedHandler);
}

項番

説明

(1)
AccessDeniedHandlerImplクラスに認可エラー用のエラー画面をJSPで指定する。

LocaleChangeInterceptorが適用されるエラー画面への遷移例

  • SpringSecurityConfig.java

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

    // omitted

    http.exceptionHandling(ex -> ex.accessDeniedHandler(
            accessDeniedHandler()));

    return http.build();
}

@Bean("accessDeniedHandler")
public AccessDeniedHandler accessDeniedHandler() {
    LinkedHashMap<Class<? extends AccessDeniedException>, AccessDeniedHandler> errorHandlers = new LinkedHashMap<>();

    // omitted

    AccessDeniedHandlerImpl accessDeniedHandler = new AccessDeniedHandlerImpl();
    accessDeniedHandler.setErrorPage(
            "/common/error/accessDeniedError"); // (1)

    return new DelegatingAccessDeniedHandler(errorHandlers, accessDeniedHandler);
}

項番

説明

(1)
AccessDeniedHandlerImplクラスに認可エラー用のエラー画面のパスを設定する。
  • Controllerクラス

@Controller
@RequestMapping("/common/error") // (1)
public class ErrorController {

    @RequestMapping(value = "accessDeniedError", method = { RequestMethod.GET,
            RequestMethod.POST }) // (1)
    public String accessDeniedError() {
        return "common/error/accessDeniedError"; // (2)
    }

}

項番

説明

(1)
エラー画面へ遷移するためにリクエストマッピングを定義する。
(2)
遷移するエラー画面のView名を返却する。

Warning

一般的に、エラー画面にはGETリクエストだけでなくPOSTリクエストからも遷移する可能性があるため、<mvc:view-controller>は使用しないことを推奨する。

<mvc:view-controller>使用時の留意点については HTMLを応答するを参照されたい。