はじめに
railsでUser.find(9999)などで検索して指定したIDのデータがなかった場合、ActiveRecord::RecordNotFoundという例外が発生し、 "Couldn't find User with 'id'=9999"というエラーメッセージが出ます。
そのエラーメッセージをI18nで翻訳したいと思って調査したのですが、ソースを確認すると直接エラーメッセージを書いているのでI18nのキーワードで翻訳出来ません。
ということで力技で翻訳してみました。
ActiveRecord::RecordNotFoundをrescueする。
とりあえず今回はわかりやすくControllerのactionで直接例外をキャッチする例を使います。例外が発生した場合に統一した方法でレスポンスを返したい場合は独自のMiddlewareを作っても良いと思います。
class UserController < ApplicationController
def show
begin
@user = User.find(9999)
rescue ActiveRecord::RecordNotFound => e
# 翻訳処理を書く。
end
end
end
例外メッセージを翻訳する
例外メッセージを翻訳するためのtranslate_record_not_foundメソッドを定義します。
def translate_record_not_found(error_msg)
match = error_msg.match(/^Couldn't find ([\S].*) with '([\S]*)'=([\S].*)$/)
# モデル名を翻訳する
t_model = I18n.t('activerecord.models.' + match[1].underscore)
# 属性名を翻訳する
t_attr = I18n.t('activerecord.attributes.' + match[1].underscore + '.' + match[2])
I18n.t('errors.messages.not_found',
{ klass: t_model, attribute: t_attr, value: match[3] })
end
翻訳用のja.ymlファイルを用意します。
ja:
activerecord:
models:
user: ユーザー
attributes:
user:
id: "ID"
errors:
messages:
not_found: "%{klass}の%{attribute}=`%{value}`は見つかりません"
そして、先ほど例外をキャッチしていたactionにtranslate_record_not_foundメソッドを使って翻訳した例外メッセージで再度例外を発生させます。
class UserController < ApplicationController
def show
begin
@user = User.find(9999)
rescue ActiveRecord::RecordNotFound => e
raise ActiveRecord::RecordNotFound, translate_record_not_found(error_msg)
end
end
end
あとはほかの箇所で例外を補足してエラーメッセージを表示するとメッセージが翻訳されているはずです。