はじめに
Spring Frameworkでの多国語対応について調べていたがいくつか詰まったところがあったのでメモ。
なおSpring Bootのバージョンは2.1.2。
基本
基本的にはorg.springframework.context.MessageSource
を使う。
設定ファイル例
src/main/resources
の直下に以下のようなファイルを作成する。
hello=hello
hello=こんにちは
messages.properties
がデフォルトのファイルで、messages_ja.properties
が日本語用のファイル(アンダーバー以降でロケールを指定)。
呼び出し例
@CrossOrigin
@RestController
@RequestMapping("/messages")
public class MessageController {
@Autowired
private MessageSource messageSource;
@GetMapping("/hello")
public String hello(Locale locale) {
return messageSource.getMessage("hello", new String[] {}, locale);
}
}
MessageSource
をインジェクションしてメッセージを呼び出す。上記サンプルでは基本的なやつを使っているが、公式ではデフォルトメッセージを指定するメソッドなんかもある。
実行例
Accept-Language
をja
にしてGET
リクエストを送信してやればこんにちは
が、それ以外の言語(en-US
やzh-CN
等)でリクエストを送信してやればhello
が返ってくる。
ただし環境によってはja
以外にしてもhello
が返ってこない場合がある(後述)。
応用
設定ファイルの場所や名前を変更したい
デフォルトだとmessages.properties
を参照するが、ファイルの場所を変更したり複数用意したりしたい場合がある。
その場合はインジェクションされるMessageSource
を修正してやればいい。
設定ファイル例
messages.properties
の内容はそのままで、保存場所をsrc/main/resources/i18n
にしたとする。
また、新規で以下のファイルをsrc/main/resources/i18n/hoge
に保存したとする。
hoge=hoge
hoge=ほげ
Spring Framework側での設定例
@Configuration
public class MessageSourceConfig {
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasenames("i18n/messages", "i18n/hoge/hoge");
messageSource.setDefaultEncoding(StandardCharsets.UTF_8.name());
return messageSource;
}
}
ResourceBundleMessageSource
がMessageSource
を実装したクラス。他にもメッセージファイルをリロードできるReloadableResourceBundleMessageSource
なんかがあるらしい。
setBasenames
でメッセージファイルの場所や名前を指定する。
application.properties
でメッセージファイルを指定する方法もあるらしいが未確認。
呼び出し例
@CrossOrigin
@RestController
@RequestMapping("/messages")
public class MessageController {
@Autowired
private MessageSource messageSource;
@GetMapping("/hello")
public String hello(Locale locale) {
return messageSource.getMessage("hello", new String[] {}, locale);
}
@GetMapping("/hoge")
public String hoge(Locale locale) {
return messageSource.getMessage("hoge", new String[] {}, locale);
}
}
実行例
基本のときと同じでAccept-Language
の値によって日本語(こんにちは
やほげ
)が返ってきたり、hello
やhoge
が返ってくる。
補足
常に日本語でメッセージが返る場合
大抵どのサイトでMessageSource
のことを調べても指定されたロケールがなければデフォルトファイルのメッセージが返されるとあるが、ローカルPCで確認すると常に日本語でメッセージが返ってきた。
調べた限りロケールが存在しなかった場合デフォルトだとシステムロケールにフォールバックされるらしい(参考)。ローカルPCで確認したときはシステムロケールが日本語で、かつ日本語のプロパティファイルを用意していたため常に日本語でメッセージが返ってきたのだと予想。
対策
@Configuration
public class MessageSourceConfig {
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasenames("i18n/messages", "i18n/hoge/hoge");
messageSource.setDefaultEncoding(StandardCharsets.UTF_8.name());
messageSource.setFallbackToSystemLocale(false);
return messageSource;
}
}
setFallbackToSystemLocale
をfalse
にしてやれば指定されたロケールのファイルが存在しなかった場合(システムロケール等関係なく)デフォルトのファイルのメッセージが返ってくるようになる。
おわりに
ja
だと日本語で返ってくるがja_JP
だと日本語で返ってこなかったり等まだいじれそうなところはあったのでどこかで調査したい。