Play Frameworkで日付・数値のローカライズ!i18n対応の決定版ガイド
生徒
「Play Frameworkで作ったサイトで、日付や金額の表示を国に合わせて変えたいです。日本なら『円』、アメリカなら『ドル』のように自動で切り替えることはできますか?」
先生
「はい、それがローカライズという仕組みです。Play Frameworkの国際化(i18n)機能を使えば、その言語に最適な日付形式や数値の区切り方を簡単に表現できますよ。」
生徒
「日付の並び順も国によって違いますよね。それも自動でやってくれるんですか?」
先生
「その通りです!Javaの標準的なライブラリとPlayのメッセージ機能を組み合わせるのがコツです。具体的な実装方法を見ていきましょう!」
1. 日付や数値のローカライズが必要な理由
Webアプリケーションを世界中の人に使ってもらうためには、単に言葉を翻訳するだけでは不十分です。例えば、日付の書き方は日本では「年/月/日」ですが、アメリカでは「月/日/年」、イギリスでは「日/月/年」が一般的です。また、数値の区切りも、カンマを使う国とドットを使う国があります。
これらの文化的な違いに合わせて表示を調整することをローカライズと呼びます。Play Frameworkでは、ユーザーのリクエストに含まれる言語設定(Locale)を自動で判別し、それに合わせたフォーマットを適用する仕組みが整っています。これにより、ユーザーにとって直感的で分かりやすいインターフェースを提供できるようになります。プログラミングの初心者こそ、こうした細かい配慮を学ぶことが大切です。
2. メッセージファイルでフォーマットを定義する
日付や数値の形式をプログラムの中に直接書くと、後で変更するのが大変です。そこで、Play Frameworkの国際化機能である messages ファイルを活用します。言語ごとに異なる「日付の型」を定義しておき、それをプログラムから呼び出す方法が最も効率的です。
具体的には、messages.ja には日本の形式を、messages.en には英語圏の形式を記述します。こうすることで、一つのソースコードで複数の国の表示形式を管理できるようになります。まずは設定ファイルの書き方の例を確認しましょう。ドット記法を使って管理するのがプロの現場のコツです。
# conf/messages.ja
format.date = yyyy年MM月dd日
format.money = {0,number,currency}
# conf/messages.en
format.date = MM/dd/yyyy
format.money = {0,number,currency}
3. JavaのDateTimeFormatterを使った日付の変換
コントローラー側で日付を扱う際は、Java 8から導入された java.time パッケージを使用します。特に DateTimeFormatter を使うことで、先ほど messages ファイルに定義した書式に基づいて日付を文字列に変換できます。
Play Frameworkの MessagesApi から現在の言語設定(Locale)を取得し、その地域に最適なフォーマッターを作成します。これにより、同じ日付データでもアクセスしたユーザーの国に合わせて「2026年4月2日」や「04/02/2026」と表示が切り替わるようになります。基本となるJavaのプログラムコードを見てみましょう。
package controllers;
import play.mvc.*;
import play.i18n.MessagesApi;
import javax.inject.Inject;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class FormatController extends Controller {
private final MessagesApi messagesApi;
@Inject
public FormatController(MessagesApi messagesApi) {
this.messagesApi = messagesApi;
}
public Result showDate(Http.Request request) {
// 現在のユーザー設定(Locale)を取得
Locale locale = messagesApi.preferred(request).lang().toLocale();
// メッセージファイルから書式を取得
String pattern = messagesApi.get(messagesApi.preferred(request).lang(), "format.date");
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(pattern, locale);
String formattedDate = LocalDate.now().format(dtf);
return ok("今日の日付: " + formattedDate);
}
}
実行結果は以下のようになります。言語設定が日本語なら、日本の形式で表示されます。
今日の日付: 2026年04月02日
4. メッセージ引数機能による数値と通貨の整形
数値をローカライズする際、特に便利なのがメッセージファイルの引数機能です。Javaの MessageFormat という仕組みを利用しており、数値に対して「通貨(currency)」や「パーセント」などの属性を指定するだけで、自動的に適切な記号や区切り位置を適用してくれます。
例えば、{0,number,currency} と書くと、ユーザーの地域が日本なら「¥」、アメリカなら「$」が自動的に付与されます。さらに、桁区切りのカンマなども自動で挿入されるため、非常に親切な設計です。初心者の方でも、この特殊な書き方を覚えるだけで一気にプロらしい実装ができます。
public Result showPrice(Http.Request request) {
play.i18n.Messages messages = messagesApi.preferred(request);
double price = 1250.50;
// messagesファイルに定義した「format.money」を使って数値を整形
// 日本語設定なら「¥1,251」(四捨五入などの挙動は設定次第)のように表示されます
String localizedPrice = messages.at("format.money", price);
return ok("商品価格: " + localizedPrice);
}
5. Scalaテンプレートでの日付表示と多言語対応
コントローラーで加工するだけでなく、HTML画面(Scalaテンプレート)で直接日付を整形して表示したいこともあります。この場合も、テンプレートに Messages オブジェクトを渡しておくことで、簡単にローカライズされた日付を表示できます。
あらかじめ定義したキーを利用するだけでなく、Javaの標準ライブラリをテンプレート内で直接呼び出すことも可能です。ただし、見た目とロジックを分離するために、書式パターン自体は messages ファイルから取得するのがベストな練習方法です。以下のコードは、テンプレートでの具体的な実装方法です。
@* 日付表示のテンプレート例 *@
@(currentDate: java.time.LocalDate)(implicit messages: play.i18n.Messages)
<div class="alert alert-primary" role="alert">
<i class="bi bi-calendar-check"></i>
@* messagesファイルからパターンを取得して整形 *@
@currentDate.format(java.time.format.DateTimeFormatter.ofPattern(messages.at("format.date")))
</div>
6. 数値の区切り文字と小数の取り扱い
数値のローカライズで注意が必要なのが、小数点の記号です。日本では「1,000.5」のようにカンマを桁区切り、ドットを小数点に使いますが、フランスやドイツなどではこれらが逆になることがあります(1.000,5)。
Play Frameworkで {0,number} を使えば、こうした国ごとの違いを勝手に判別してくれます。手動で文字列を連結して「.」を打つようなコードを書くと、多言語対応の際にバグの原因となるため注意しましょう。常にフレームワークが提供する Messages の at メソッドを経由して数値を出す習慣を付けることが、初心者から脱出する第一歩です。
7. タイムゾーンを考慮した時刻表示の重要性
日付だけでなく、時刻(タイムゾーン)の取り扱いも重要です。日本にいるユーザーとアメリカにいるユーザーでは、同じ瞬間でも時計の指す時間が異なります。グローバルなアプリケーションでは、サーバーの時間はUTC(協定世界時)で保持し、表示する瞬間にユーザーの地域設定に合わせて変換するのが一般的です。
Play Frameworkでは、ユーザーのリクエストからタイムゾーン情報を直接取得するのは難しいため、ブラウザ側でJavaScriptを使ってタイムゾーンを判定し、それをサーバーに伝えるといった工夫が必要になることもあります。時刻のローカライズは奥が深いですが、まずは基本の「24時間表記か12時間表記か」を messages ファイルで使い分けるところから始めてみましょう。
8. 複数形への対応とChoiceFormat
英語などの言語では、数値が「1」の時と「2以上」の時で名詞が変化(複数形)します。これもローカライズの一部です。Play Frameworkが採用しているメッセージ形式では choice という機能を使うことで、「1個」なら「1 item」、「2個」なら「2 items」と表示を切り替えることができます。
日本語では名詞が変化しないため意識しにくいですが、多言語化を前提とするなら、こうした数値に応じた文章の変化も messages ファイルの中に集約させることが可能です。これにより、プログラムのソースコード内にif文を大量に書く必要がなくなり、非常にスッキリとした設計になります。
9. ローカライズ機能のテストと動作確認
実装が終わったら、必ず複数の言語で動作確認を行いましょう。ブラウザの設定で言語の優先順位を変えるか、あるいはPlayの withLang メソッドを使ってCookieの言語を強制的に切り替えてみます。日付の区切り文字や通貨記号が正しく変わっていれば成功です。
また、数値が非常に大きい場合や、負の数の場合の表示も確認しておきましょう。地域によってはマイナス記号の付き方が異なる場合もあります。こうした細部まで作り込まれたアプリは、ユーザーからの信頼が高まります。プログラミングの学習において、こうした「動くのは当たり前、その上でどう見せるか」を考えるフェーズは非常に楽しく、やりがいのある部分です。ぜひ楽しみながら挑戦してみてください。