背景
Railsの多言語化にはi18nがよく利用されます。
通常下記のように設定をしますよね
config/locales/*.yml
ja:
activemodel:
# モデル名
models:
user: "ユーザー"
attributes:
# モデル毎の属性名
user:
name: "名前"
# 共通の属性名
attributes:
gender: "性別"
# バリデーションエラー
errors:
# テンプレート
format: "%{attribute}%{message}"
# エラー毎のメッセージ
messages:
blank: "を入力してください"
en:
# 同じ構造なので略
User.rb
class User < ApplicationRecord
validates :name, presence: true
end
この時、フォームでname
に空白のままsubmitを実行すると、名前を入力してください
と表示されます。
ですが、例えばname
が空白の時に名前はフルネームで入力してください
とか、名前は姓・名で分けてください
と表示したかった場合どうしますか?
*.yml
のmodels.attributes.user.name
とerrors.messages.blank
を書き換える力技もありますが、これでは保守性0です。
美しくありません。また、
User.rb
class User < ApplicationRecord
validates :name, presence: { message: '名前はフルネームで入力してください' }
end
上記も悪くないけど、多言語化に対応できていない。
そこで、i18n
を用いた、メッセージのカスタマイズ方法を紹介いたします。
解決策
Proc
を組み合わせます。lambda
でも可能です。
config/locales/*.yml
ja:
activemodel:
# 同じ構造なので略
# バリデーションエラー
errors:
messages:
blank: "を入力してください"
models:
user:
fullname_blank: "名前はフルネームで入力してください"
en:
# 同じ構造なので略
User.rb
class User < ApplicationRecord
validates :name, presence: {
message: -> (rec, data) {
I18n.t('activemodel.errors.models.user.fullname_blank')
}
}
end
これを実行すると、うまく多言語化されると思います。
ちなみに、Proc
を使わないとうまく多言語化されないので気をつけてください。下記が悪い例です。
User.rb
class User < ApplicationRecord
validates :name, presence: {
message: I18n.t('activemodel.errors.models.user.fullname_blank')
}
end