第32章|今さら学ぶ「国際化(i18n)」
📚 シリーズ目次はこちら → 「今さら学ぶ」シリーズ — はじめに
🗺️ KnowledgeNoteの設計を確認 → 設計マップ
この章でわかること
- i18nとは — アプリに「翻訳辞書」を持たせる仕組み
- なぜ日本語専用アプリでもi18nを使うのか
- ロケールファイルの管理 — 日本語・英語の辞書を分けて管理
- 翻訳キーの設計 — 辞書の引き方にルールを決める
- モデルのバリデーションメッセージを日本語化する
- 日時フォーマットのローカライズ
🏠 たとえ話で掴む「i18n」
i18n(internationalizationの略。iとnの間の18文字を省略した略称) は、アプリに 翻訳辞書 を持たせる仕組みです。
旅行ガイドブックを想像してください。「こんにちは」を英語で言いたいとき、和英辞書を引けば「Hello」と出てきます。i18nも同じで、アプリのコードに直接「こんにちは」と書く代わりに、 辞書キー で引くようにします。
# ❌ コードに直接日本語を書く
flash[:notice] = "記事を投稿しました"
# ✅ 辞書キーで引く
flash[:notice] = t("articles.create.success")
# → 日本語辞書なら「記事を投稿しました」
# → 英語辞書なら「Article has been posted」
辞書を切り替えるだけで、コードを変えずに多言語対応できます。
i18nとは何か — 技術的な定義
Railsの i18n(Internationalization) は、アプリケーションのテキストをコードから分離し、外部のロケールファイル(YAML)で管理する仕組みです。Rails標準で組み込まれており、追加gemなしで使えます。
なぜi18nが必要なのか
「多言語対応しないから関係ない」と思われがちですが、日本語専用のアプリでもi18nが必要になる場面があります。
1. バリデーションエラーメッセージの日本語化
Railsのバリデーションエラーは、デフォルトでは英語で表示されます。
# デフォルト(英語)
Name can't be blank
Email address has already been taken
# i18nで日本語化した場合
ユーザー名を入力してください
メールアドレスはすでに使用されています
ユーザーに見えるエラーメッセージが英語のままでは、日本語のアプリとして不自然です。バリデーションの仕組みについては(→ 第12章で詳しく扱います)。
2. モデル名・属性名の統一管理
フォームのラベル、エラーメッセージ、管理画面での表記を一箇所で管理できます。属性名を変更したいとき、ロケールファイルの1行を変えるだけで全画面に反映されます。
3. 日時フォーマットの統一
2025-02-15 10:30:00 を 2025年2月15日 10:30 のように表示するフォーマットも、ロケールファイルで一元管理できます。
i18nの仕組み
i18nは次の3つの要素で構成されています。
| 要素 | 役割 | たとえ |
|---|---|---|
| ロケールファイル | 翻訳データを保存するYAMLファイル | 辞書そのもの |
t() メソッド |
キーを指定して翻訳を取得する | 辞書を引く動作 |
I18n.locale |
どの言語の辞書を使うかの設定 | 「今は和英辞書を使う」という切り替え |
# ロケール設定 → t() で辞書を引く → 対応する翻訳が返る
I18n.locale = :ja
t("articles.create.success") # => "記事を投稿しました"
I18n.locale = :en
t("articles.create.success") # => "Article has been posted"
📖 ロケールファイル — 辞書を作る
日本語ロケールファイル
# config/locales/ja.yml
ja:
activerecord:
models:
user: ユーザー
article: 記事
comment: コメント
attributes:
user:
name: ユーザー名
email_address: メールアドレス
password: パスワード
password_confirmation: パスワード(確認)
article:
title: タイトル
body: 本文
status: ステータス
comment:
body: コメント本文
errors:
messages:
blank: を入力してください
too_long: は%{count}文字以内で入力してください
too_short: は%{count}文字以上で入力してください
taken: はすでに使用されています
invalid: は不正な値です
articles:
index:
title: 記事一覧
create:
success: 記事を投稿しました
failure: 記事の投稿に失敗しました
update:
success: 記事を更新しました
destroy:
success: 記事を削除しました
layouts:
header:
home: ホーム
articles: 記事一覧
users: ユーザー
login: ログイン
logout: ログアウト
signup: 新規登録
英語ロケールファイル
# config/locales/en.yml
en:
activerecord:
models:
user: User
article: Article
comment: Comment
attributes:
user:
name: Username
email_address: Email address
password: Password
password_confirmation: Password confirmation
article:
title: Title
body: Body
status: Status
comment:
body: Comment body
articles:
index:
title: Articles
create:
success: Article has been posted
failure: Failed to post article
update:
success: Article has been updated
destroy:
success: Article has been deleted
layouts:
header:
home: Home
articles: Articles
users: Users
login: Log in
logout: Log out
signup: Sign up
デフォルトロケールの設定
# config/application.rb
config.i18n.default_locale = :ja
# → デフォルトの言語を日本語に
config.i18n.available_locales = [:ja, :en]
# → 利用可能な言語を日本語と英語に制限
config.i18n.fallbacks = true
# → 翻訳が見つからないとき、デフォルトロケールにフォールバック
rails-i18n gem — 日本語のデフォルト翻訳
Railsが内部で使うメッセージ(曜日名、月名、バリデーションのデフォルトメッセージ等)は、自分で全て書く必要はありません。rails-i18n gemが各言語のデフォルト翻訳を提供しています。
# Gemfile
gem "rails-i18n", "~> 8.0"
# → 日本語の曜日名(日曜日〜土曜日)、月名、エラーメッセージの
# デフォルト翻訳がまとめて入る
$ bundle install
このgemを入れると、date.day_names や errors.messages.blank といった基本的な翻訳が自動で日本語になります。アプリ固有の翻訳(モデル名、フラッシュメッセージ等)だけ自分で書けば済みます。
🔑 翻訳キーの設計ルール
ビューでの使い方
<%# t("キー") で翻訳を呼び出す %>
<h1><%= t("articles.index.title") %></h1>
<%# → 「記事一覧」(日本語)or 「Articles」(英語) %>
<%# 省略記法(Lazy Lookup)— ビューのパスから自動でキーを推定 %>
<%# app/views/articles/index.html.erb 内で %>
<h1><%= t(".title") %></h1>
<%# → articles.index.title として解釈される %>
省略記法( Lazy Lookup)は便利ですが、どの翻訳キーが使われているかがコードから読み取りにくくなる面もあります。チームで方針を決めておくのが無難です。
コントローラでの使い方
# app/controllers/articles_controller.rb
def create
@article = current_user.articles.build(article_params)
if @article.save
redirect_to @article, notice: t("articles.create.success")
else
flash.now[:alert] = t("articles.create.failure")
render :new, status: :unprocessable_entity
end
end
モデル名・属性名の日本語化
# ロケールファイルの activerecord.models / .attributes を設定すると…
Article.model_name.human # => "記事"
Article.human_attribute_name(:title) # => "タイトル"
# バリデーションエラーメッセージが自動で日本語になる
# "Title can't be blank" → "タイトルを入力してください"
# form_with のラベルも自動で日本語になる
# <%= f.label :title %> → <label>タイトル</label>
翻訳が見つからなかったとき
存在しないキーを指定すると、画面に translation missing: ja.some.key と赤文字で表示されます。
<%= t("articles.nonexistent_key") %>
<%# → "translation missing: ja.articles.nonexistent_key" %>
開発中にこの表示を見かけたら、ロケールファイルにキーの追加が必要です。default オプションでフォールバック値を指定することもできます。
t("articles.nonexistent_key", default: "記事")
# → キーが見つからなければ "記事" を返す
📅 日時フォーマットのローカライズ
# config/locales/ja.yml
ja:
time:
formats:
default: "%Y年%m月%d日 %H:%M"
short: "%m/%d %H:%M"
long: "%Y年%m月%d日(%A) %H:%M"
date:
formats:
default: "%Y年%m月%d日"
<%= l(@article.created_at) %>
<%# → "2025年02月15日 10:30" %>
<%= l(@article.created_at, format: :short) %>
<%# → "02/15 10:30" %>
<%= l(@article.created_at, format: :long) %>
<%# → "2025年02月15日(土曜日) 10:30" %>
<%# ※ 曜日名は rails-i18n gem で日本語が提供される %>
l( localize の略)メソッドで、日時をロケールに応じたフォーマットで表示します。t が翻訳テキスト用、l が日時・日付用です。
🌐 URLでロケールを切り替える
多言語対応する場合は、URLにロケールを含めてどの言語で表示するかを指定する方法が一般的です。
# config/routes.rb
scope "(:locale)", locale: /ja|en/ do
resources :articles
end
# → /ja/articles(日本語)
# → /en/articles(英語)
# → /articles(デフォルト = 日本語)
# app/controllers/application_controller.rb
around_action :switch_locale
private
def switch_locale(&action)
locale = params[:locale] || I18n.default_locale
I18n.with_locale(locale, &action)
end
# URLヘルパーにlocaleパラメータを自動で含める
def default_url_options
{ locale: I18n.locale == I18n.default_locale ? nil : I18n.locale }
# → デフォルトロケール(日本語)のときはlocaleパラメータを省略
# → /articles(日本語), /en/articles(英語)
end
I18n.with_locale はブロック内だけロケールを変更するメソッドです。リクエスト処理が終わると元に戻るため、他のリクエストに影響を与えません。
🛠️ KnowledgeNoteでの具体例
enum の翻訳
# config/locales/ja.yml
ja:
enums:
article:
status:
draft: 下書き
published: 公開中
archived: アーカイブ
<%# app/views/articles/show.html.erb %>
<h1><%= @article.title %></h1>
<p>
by <%= @article.user.name %> ·
<%= l(@article.created_at, format: :short) %>
</p>
<% if @article.published? %>
<span class="bg-green-100 text-green-800 px-2 py-1 rounded">
<%= t("enums.article.status.published") %>
</span>
<% end %>
ロケールファイルの分割管理
ファイルが大きくなったら、ディレクトリで分割できます。Railsは config/locales/ 以下のYAMLファイルを自動で読み込みます。
config/locales/
├── ja.yml # 共通翻訳(レイアウト等)
├── en.yml
├── models/
│ ├── ja.yml # ActiveRecordのモデル名・属性名
│ └── en.yml
└── views/
├── articles/
│ ├── ja.yml # 記事関連の翻訳
│ └── en.yml
└── users/
├── ja.yml
└── en.yml
# config/application.rb
# サブディレクトリのYAMLも自動読み込みする設定
config.i18n.load_path += Dir[Rails.root.join("config", "locales", "**", "*.yml")]
💼 面接で聞かれたら?
Q:Railsのi18nについて説明してください。
「i18nはRails標準の国際化機能で、アプリの表示テキストをロケールファイル(YAML)で管理します。コードに直接テキストを書く代わりに
t("キー")で辞書を引くことで、ロケールを切り替えるだけで多言語対応できます。日本語専用のアプリでも、バリデーションエラーメッセージの日本語化やモデル属性名の一元管理にi18nを使います。」深掘りされたら:
- 「日本語専用でもi18nを使う理由は?」→ Railsのバリデーションエラーはデフォルトで英語。
activerecord.attributesでモデル属性名を定義すると、エラーメッセージやフォームラベルが自動で日本語になる。表記の一元管理にもなる。- 「
tとlの違いは?」→t(translate)はテキストの翻訳に使い、l(localize)は日時のフォーマットに使う。l(@article.created_at)で「2025年02月15日 10:30」のようにロケールに応じた表示になる。- 「翻訳が見つからないときはどうなる?」→
translation missing: ja.xxx.yyyという文字列が表示される。config.i18n.fallbacks = trueを設定すると、見つからない場合にデフォルトロケールの翻訳にフォールバックする。
🔗 もっと深く知りたい人へ(1次情報リンク)
- Rails ガイド:Rails 国際化(I18n)API — i18nの全機能を網羅した公式ガイド
- rails-i18n(GitHub) — 各言語のデフォルトロケールファイル集
-
Rails API:I18n —
t/lメソッドのリファレンス
まとめ
- ✅ i18nは「翻訳辞書」。コードにテキストを直接書かず、
t("キー")で辞書を引く仕組み - ✅ 日本語専用アプリでも、バリデーションエラーの日本語化・属性名の一元管理にi18nを使う
- ✅ ロケールファイル(YAML)で日本語・英語等の辞書を分けて管理する
- ✅
rails-i18ngemを入れると、曜日名やデフォルトエラーメッセージの日本語翻訳がまとめて入る - ✅
l()メソッドで日時をロケールに応じたフォーマットで表示する - ✅ URLにロケールを含める方式で、言語の切り替えに対応できる
📚 シリーズ目次:「今さら学ぶ」シリーズ — はじめに