通常DBに紐づくモデル、つまりActiveRecord::Base
を継承したクラスに対応するフォームを作成する場合、次のような$1ファイルを作成することで、バリデーションメッセージや表示される項目を多$1することができます。
一方DBへの保存だけではなく、複雑な$1を実装する場合にはFormオブジェクトを作って対処します。例えばフォームから入力されたデータを用いて、メール送信を行うような場合です。
Formオブジェクトは複数のモデルを扱ったり、DB以外の操作が伴うため、基本的にはActiveModel::Model
をincludeした形で実装します。
また、form_withからの$1判定を行うために、to_modelをオーバーライドし、メインとなるModelクラスに向けることもあります。
…こうなってくると、i18n用のi18nファイルをどうやって書いたらいいのかよくわからなくなってきたので、Railsがどのようにi18nファイルを解釈しているのか調べました。
要約
- ActiveModelとActiveRecordはそれぞれ
i18n_scope
を実装していて、これによりActiveRecordファイルのトッActiveRecordルの探索キーが決まる。
- Formオブジェクト側で行っている処理(例:バリデーション)は
activemodel
をキーにする
- to_modelをオーバーライドしてActiveRecord::Baseを継承したモデルを参照している場合、それらの表示に対する翻訳は
activerecord
をキーにする
前提
対象バージョン
- ActiveRecord:~> 7.0.0
- ActiveModel:~> 7.0.0
サンプルケース
モデル:User
フォームオブジェクト:UserForm
RailsがModelのi18nを探索する手順
バリデーションメッセージ
バリデーション用のエラーメッセージの組み立ては、ActiveModel::Error.generata_message
で行われています。
https://github.com/rails/rails/blob/main/activemodel/lib/active_model/error.rb#L64🔗
https://api.rubyonrails.org/classes/ActiveModel/Errors.html#method-i-generate_message🔗
抜粋するとこんな感じです。
ここで肝になるのはi18n_scope
というメソッドです。このメソッドにより、activerecord
を見にいくのか、activemodel
を見にいくのかが決まります。
ではその実装はどうなっているのかというと、ActiveModelの場合、次のようになっています。
https://github.com/rails/rails/blob/75a9e1be75769ae633a938d81d51e06852a69ea3/activemodel/lib/active_model/translation.rb#L26🔗
一方で、ActiveRecordでも同じメソッドがオーバーライドされており、次のように実装されています。
https://github.com/rails/rails/blob/75a9e1be75769ae633a938d81d51e06852a69ea3/activerecord/lib/active_record/translation.rb#L20🔗
これにより、翻訳対象のクラスが
- ActiveModelの場合は、
activemodel
- ActiveRecordの場合は、
activerecord
が翻訳キーとして採用されることになります。
ここで、バリデーションメッセージについては、Formオブジェクト、つまりActiveModelで実装されたものです。そのため、エラーメッセージの翻訳キーはactivemodel
始まりになります。
カラム(画面表示項目)
カラム(画面表示項目)の翻訳についても先のi18n_scopeで説明がつきます。
form_withでフォームを作成する際に、to_modelによって、ActiveRecordであるUser側にクラス判定が向くため、ActiveRecordのi18n_scopeが採用されます。
そのため、以下のような$1ファイルを記述します。
なおUserモデルに含まれない項目をFormオブジェクトに定義した場合も、翻訳ファイルはactiverecord下に記述することに注意が必要です。
以上Formオブジェクトでの翻訳キーの参照先についての調査でした。