[Rails]国際化(i18n)について7/20
はじめに
rails-i18n
gemを使ってCRUDアプリを日本語化にしていきます。
環境:
Rails 6.1.7.3
ruby 3.0.0
tl;dr
-
rails-i18n
をインストールする - ローカライズファルを読み込む
- ローカライズファイルを作成する
- モデルのローカライズを行う
- ビューのローカライズを行う
- ヘルパー変数を使う
- 訳文に変数を渡す
i18nとは
Railsのi18nは、異なる言語や地域のフォーマットに簡単に対応できるようにするための機能です。アプリケーションのテキストコンテンツをコードから分離し、翻訳やメンテナンスを容易にします。
国際化に向けの設定
利用するロケールに対応する翻訳データのymlファイルをconfig/initializers/locales
の下に配置します。
デフォルトではen.yml
のファイルが用意されています、日本語の場合だったら、ja.yml
を作成しクラスや属性に対応する日本語の翻訳を記述していきます。
rails-i18nとは
rails-i18nのgemは、Railsアプリケーション内で国際化を行うための機能とリソースを提供するための特定のgemです。rails-i18n gemには、一般的なRailsのメッセージやラベルに対する事前定義された翻訳が含まれています。ActiveRecordモデル、日付や時刻のフォーマット、エラーメッセージなどの翻訳をカバーしています。これらの翻訳は、すぐに使用できる状態で提供されるため、手動で定義する手間や時間を節約できます。
インストール
gem 'rails-i18n'
bundle install
初期設定
config/application.rb
では次のように、デフォルトのロケールを変更し、訳文読み込みパスを設定していきます。
# I18nライブラリに訳文の探索場所を指示する
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]
# ロケールを:en以外に変更する
config.i18n.default_locale = :ja
# ロケールのリストを渡す
I18n.available_locales = [:en, :pt]
この設定の変更を反映させるには、サーバーを再起動させる必要があります。
ユーザごとに言語を切り替える
仮に、ユーザごとに利用言語を設定してDBに保存するとしますと、before_action
によって、リクエストごとにI18n.locale
の値を切り替えることができます。
これにより。日本語を使うと設定されたユーザには日本語、英語を使うと設定されたユーザには英語で画面を表示することができます。
class ApplicationController < ActionController::Base
before_action :set_locale
private
def set_locale
I18n.locale = Current.user&.locale || :ja # デフォルトがなければもしくはログインしていなければ日本語
end
end
ローカライズファイルを作成する
アプリケーションが大きくなると単一ファイルでの管理が難しくなるので、モデルとビューで分けて作成していきます。
config/locales/views/ja.yml
config/locales/activerecord/ja.yml
config/localesディレクトリ以下のファイル構造は以下のリンクからをご参考ください。
モデルのローカライズを行う
ドキュメントを参考しながらユーザモデルとarticleモデルの翻訳を入れていきます。
ja:
activerecord:
models:
user: 'ユーザー'
article: '投稿'
attributes:
user:
email: 'メールアドレス'
password: 'パスワード'
password_confirmation: 'パスワード確認'
user_name: 'ユーザー'
article:
title: 'タイトル'
body: '本文'
ビューのローカライズを行う
# views/ja.yml
ja:
defaults:
login: 'ログイン'
register: '登録'
logout: 'ログアウト'
sessions:
new:
title: 'ログイン'
to_register_page: '登録ページへ'
password_forget: 'パスワードをお忘れの方はこちら'
articles:
index:
title: '投稿一覧'
new:
title: '投稿作成'
edit:
title: '投稿編集'
signup:
new:
title: '新規登録'
t
ヘルパーを使ってビューにキーを渡す
tヘルパーは、Railsに組み込まれた国際化(i18n)機能を使用してビューで翻訳を行うための便利なメソッドです。
tヘルパーは、ビューファイル内で翻訳キーを指定し、対応する翻訳メッセージを取得するために使用されます。具体的には、I18n.tメソッドのショートカットとして機能します。
tヘルパーには他にも便利なオプションがあります。たとえば、変数を埋め込んだり、デフォルトの翻訳メッセージを指定したり、複数のオプションを渡したりすることができます。
ユーザ登録フォーム
Modelに紐付くform_with
のlabelでは、Railsが定義を読み込んで適用しますので自動的に反映されます。タイトルだけ記述していきます。
ja:
...
signup:
new:
title: '新規登録'
# lazy lookup
<h1><%= t('.title') %></h1>
<h1><%= t '.title' %></h1>
# もしくは
<h1><%= t('signup.new.title') %></h1>
登録フォームを日本語に翻訳されたことを確認します。
エラーメッセージも同じく日本語に翻訳されました。
ログインフォーム
ログインフォームはセッションの概念を用いてモデルを渡していないform_with
のlabelなので、i18nの記載を追加する必要があります。
Model.model_name.human
メソッドとModel.human_attribute_name(attribute)
メソッドを使うことで、モデル名と属性名を透過的に参照できるようになります。
Model.model_name.human
メソッドとModel.human_attribute_name(attribute)
メソッド
Model.model_name.human
メソッドとModel.human_attribute_name(attribute)
メソッドは、Active Recordモデルで国際化(i18n)をサポートするためのメソッドです。これらのメソッドを使用すると、モデル名や属性名の翻訳を取得することができます。
-
Model.model_name.human
メソッド:
このメソッドは、Active Recordモデルのモデル名(クラス名)の翻訳を取得します。例えば、モデル名がUser
の場合、User.model_name.human
はモデル名のデフォルトの翻訳を返します。User.model_name.human # => "ユーザー"
上記の例では、
"ユーザー"
がモデル名User
の日本語の翻訳です。これにより、モデル名を表示する際に国際化をサポートすることができます。 -
Model.human_attribute_name(attribute)
メソッド:
このメソッドは、Active Recordモデルの属性名の翻訳を取得します。属性名の翻訳は、属性名をキーとした翻訳ファイルで定義する必要があります。例えば、User
モデルのname
属性の翻訳を取得する場合は次のようになります。User.human_attribute_name(:name) # => "名前"
上記の例では、
"名前"
がUser
モデルのname
属性の日本語の翻訳です。これにより、属性名を表示する際にも国際化をサポートすることができます。
これらのメソッドを使用すると、モデル名や属性名の翻訳を手動で定義する必要がなくなります。代わりに、翻訳ファイルに対応するキーと翻訳メッセージを定義し、これらのメソッドを使用して翻訳を取得します。また、ロケールを変更することで、異なる言語に対応する翻訳を表示することもできます。
ja:
...
sessions:
new:
title: 'ログイン'
to_register_page: '登録ページへ'
password_forget: 'パスワードをお忘れの方はこちら'
<h1><%= t '.title' %></h1>
<%= form_with url:login_path do |form| %>
<div class="form-group">
<%= form.label :email, User.human_attribute_name(:email) %>
<%= form.text_field :email, placeholder: "user@example.com", class: "form-control mb-3" %>
</div>
<div class="form-group">
<%= form.label :password, User.human_attribute_name(:password) %>
<%= form.password_field :password, placeholder: "Please enter your password", class: "form-control mb-3" %>
</div>
<%= form.submit t('defaults.login'), class:'btn btn-primary' %>
<%= link_to t('.to_register_page'), signup_path, class: 'link-secondary d-inline-block ms-3' %>
<%= link_to t('.password_forget'), password_reset_path, class: 'link-secondary d-inline-block ms-3' %>
<% end %>
日本語の翻訳を反映されたことを確認します。
バリデーションのローカライズを行う
ログイン失敗の時のバリデーションを翻訳していきます。
ja:
...
sessions:
...
create:
success: 'ログインしました。'
danger: 'ログインに失敗しました。もう一度試してください。'
destroy:
success: 'ログアウトしました。'
class SessionsController < ApplicationController
def create
user = User.find_by(email: params[:email])
if user.present? && user.authenticate(params[:password])
session[:user_id] = user.id
flash[:success] = t('.success')
redirect_to root_path
else
flash[:danger] = t('.danger')
render :new
end
end
end
他のモデルとビューファイルも同じ手順でやっていきます。
- パスワード更新ページ
- パスワードリセットページ
- 投稿ページ
- 投稿更新ページ
訳文に変数を渡す
rails-I18n
gemには「変数の式展開」機能が含まれており、訳文定義で変数を使えるようにし、翻訳メソッドでそれらに値を渡せるようにします。
ユーザーと投稿のバリデーションメッセージを変数に変えてもっと簡潔にまとめていきます。
モデルを増やしたら翻訳文も増やされるため、共通化して管理できると便利です。
アクション名に沿ってネーミングすると分かりやすいでしょう。
ja:
defaults:
message:
require_login: 'ログインしてください'
created: '%{item}を作成しました'
not_created: '%{item}の作成に失敗しました。'
updated: '%{item}更新しました'
not_updated: '%{item}の更新に失敗しました'
destroyed: '%{item}を削除しました'
delete_confirm: '%{item}を削除してもよろしいでしょうか?'
not_authorized: '権限がありません'
コントローラーのバリデーションも変数に変えていきます。
class ArticlesController < ApplicationController
...
def create
@article = Current.user.articles.build(article_params)
if @article.save
# before
flash[:success] = "記事が作成できました。"
# after
flash[:success] = t('defaults.message.created', item: Article.model_name.human)
redirect_to @article
else
# before
flash[:danger] = "記事の作成が失敗しました。もう一度試してください。"
# after
flash.now[:danger] = t('defaults.message.not_created', item: Article.model_name.human)
render :new
end
end
...
end
タイムゾーン対応
投稿の作成時間を確認してみると日本時間ではないのでタイムゾーンを日本時間に変えます。
config.time_zone = 'Tokyo'
ちょっと分かりにくいので、日付と時間のフォーマットも追記していきます。
ja:
time:
formats:
long: "%Y年%m月%d日(%a) %H時%M分%"
ビューファイルを編集して日付と時間を反映させます
<%= l(article.created_at, format: :long) %>
l
ヘルパーメソッド
l
ヘルパーメソッドは、Railsのビューファイル内で使われる国際化(I18n)に関連したメソッドです。主に、日付や時刻などのオブジェクトをローカライズされた形式で表示するために使用されます。
l
ヘルパーメソッドの一般的な構文は次のとおりです:
l(object, options = {})
-
object
はローカライズされた形式に変換したいオブジェクトです。例えば、Time
オブジェクトやDate
オブジェクトなどです。 -
options
はオプションのハッシュであり、l
メソッドに渡される追加の設定を指定します。主なオプションは以下の通りです:-
:format
:ローカライズされた形式を指定します。例えば、:short
や:long
などのフォーマットキーを使用できます。 - その他のオプション:他にもフォーマットオプションを指定することができます。これには、日時のフォーマットに関連する指示子(例:
%d
、%m
、%Y
など)や、タイムゾーンの指定などが含まれます。
-
以下はいくつかの使用例です:
l(Time.now) # 現在の時刻をデフォルトのローカライズ形式で表示する
l(Date.today, format: :short) # 今日の日付をショートフォーマットで表示する
l(@event.start_time, format: :long) # @eventの開始時刻をロングフォーマットで表示する
l
ヘルパーメソッドは、ビューファイル内で日付や時刻のローカライズを容易にするための便利なメソッドです。設定されたフォーマットに基づいて、オブジェクトを適切なローカライズ形式で表示することができます。
$ bin/rails console
irb(main):001:0> Time.zone
=> #<ActiveSupport::TimeZone:0x00007fb4e7116568 @name="Tokyo", @utc_offset=nil, @tzinfo=#<TZInfo::DataTimezone: Asia/Tokyo>>
irb(main):002:0> Time.zone.now
=> Fri, 23 Jun 2023 15:23:47.960015000 JST +09:00
irb(main):003:0> Time.zone.now.class
=> ActiveSupport::TimeWithZone
irb(main):004:0> Time.current
=> Fri, 23 Jun 2023 15:24:54.964547000 JST +09:00
irb(main):005:0> Time.zone.today
=> Fri, 23 Jun 2023
irb(main):006:0> Date.current
=> Fri, 23 Jun 2023
time.zone.now
とTime.current
はどちらもRailsで現在の日時を表すメソッドですが、微妙な違いがあります。
time.zone.now
は、アプリケーションのタイムゾーンを考慮して現在の日時を返します。Railsアプリケーションはデフォルトでタイムゾーンが設定されており、time.zone.now
を使用することでそのタイムゾーンでの現在の日時が得られます。タイムゾーンの設定はconfig/application.rb
やconfig/time_zone.rb
で行うことができます。
一方、
Time.current
はRailsのTimeWithZoneクラスのインスタンスを返します。これは、time.zone.now
と同様にアプリケーションのタイムゾーンを考慮して現在の日時を表しますが、より直感的なAPIを提供します。Time.current
はTimeWithZoneオブジェクトを返すため、そのオブジェクトにはタイムゾーンに関連するメソッド(例:in_time_zone
やto_s
など)が利用できます。
終わりに
いかがでしょうか。
i18nでアプリを日本語化することができました。
i18nの仕組みをよく理解していきましょう。
Discussion