ActiveRecord モデルのフィールド名の国際化
2009/01/08
前回は、サンプルアプリケーション asagao にロケールを切り替える機能を加えました。
今回は、ActiveRecord 関連の国際化に挑戦します。
あるオブジェクトの中身や編集フォームを表示する際のフィールド名をロケールごとに切り替えられるようにします。
『基礎 Ruby on Rails』では、REAL_ATTRIBUTE_NAMES という定数と real_attribute_name というクラスメソッドをモデルごとに定義していました。
例えば、member.rb には次のような記述があります。
# 属性に対応する日本語名
REAL_ATTRIBUTE_NAMES = {
:member_number => '背番号',
:player => '選手登録',
:family_name => '名前(姓)',
:given_name => '名前(名)',
:furigana => 'ふりがな',
:email => 'メールアドレス',
:phone => '電話番号',
:birthday => '生年月日',
:sex => '性別',
:remarks => '備考',
:login_name => 'ログイン名',
:password => 'パスワードの変更',
:administrator => 'サイト管理者',
:uploaded_image => '画像'
}
def self.real_attribute_name(key)
REAL_ATTRIBUTE_NAMES[key.to_sym]
end
そして、テンプレートの中では次のように書いていたのです。
<%= Member.real_attribute_name(:phone) %>
Rails 2.2 からは、ActiveRecord::Base のクラスメソッド human_attribute_name が内部的に I18n モジュールを利用するようになりました。
新しい方法で書き換えることにします。
では、始めましょう。
まず、影響範囲を確かめるため、member.rb から上記のコードを削除して、テストを実行します。
単体テストではエラーは出ていません。これは必ずしもいいことではありません。real_attribute_name メソッドのテストが書かれていなかったことを意味します。要反省です。
機能テストでは、9 つのテストが失敗しています。
> rake test:functionals (省略) 95 tests, 320 assertions, 9 failures, 0 errors
accounts と members と admin/members コントローラで失敗しています。想定通りです。
real_attribute_name メソッドをすべて human_attribute_name で置換すれば、テストは通るでしょう。
お気に入りのエディタの「一括置換」機能で、app/views/accounts と app/views/members と app/views/admin/members ディレクトリ以下の全ファイルを対象に、real_attribute_name を human_attribute_name に置換してください。
再度、機能テストを実行します。
> rake test:functionals (省略) 95 tests, 320 assertions, 9 failures, 0 errors
ああ!ダメです。こんなエラーが出ています。
undefined method `humanize' for :member_number:Symbol
real_attribute_name メソッドはシンボルを取りましたが、human_attribute_name メソッドの場合は文字列でフィールド名を指定する必要があるんですね。
ということは、human_attribute_name(:foo) を human_attribute_name('foo') に置換する必要があるわけです。
こういう複雑な置換をしてくれるエディタもありますが、ここでは誰でもできるように小さな Ruby スクリプトを作ることにします。
次のようなスクリプトを作成して、scrpts ディレクトリの下に humanize.rb という名前で保存してください。
dir = ARGV[0]
Dir.glob("app/views/#{dir}/**/*.rhtml").each do |file|
code = File.open(file).read
code.gsub!(/real_attribute_name/, 'human_attribute_name')
code.gsub!(/human_attribute_name\(:(\w+)\)/, 'human_attribute_name("\1")')
File.open(file, 'w').write(code)
end
置換を実行します。
> ruby script/humanize.rb accounts > ruby script/humanize.rb members > ruby script/humanize.rb admin/members
再度、機能テストを実行します。
> rake test:functionals (省略) 95 tests, 338 assertions, 3 failures, 0 errors
あらら。まだ、エラーが出ますね。
app/views/admin/members/_errors.rhtml が原因です。
<strong><%= h(Member.human_attribute_name(attr.to_sym)) %></strong> <%= h(msg) %>
を次のように修正します(.to_sym を除去)。
<strong><%= h(Member.human_attribute_name(attr)) %></strong> <%= h(msg) %>
再度、機能テストを実行します。
> rake test:functionals (省略) 95 tests, 341 assertions, 0 failures, 0 errors
OK です。
> rake test:integration (省略) 2 tests, 67 assertions, 0 failures, 0 errors
統合テストも通りました。
次に、翻訳ファイルを作成します。
config/locales ディレクトリに activerecord_en.yml と activerecord_ja.yml を作成します。
activerecord_en.yml
en:
activerecord:
attributes:
member:
member_number: Member Number
player: Player
family_name: Family Name
given_name: Given Name
furigana: Furigana
email: E-mail address
phone: Phone Number
birthday: Birthday
sex: Sex
remarks: Remarks
login_name: Login Name
password: Change Password
administrator: Administrator
uploaded_image: Uploaded Image
activerecord_ja.yml
ja:
activerecord:
attributes:
member:
member_number: 背番号
player: 選手登録
family_name: 名前(姓)
given_name: 名前(名)
furigana: ふりがな
email: メールアドレス
phone: 電話番号
birthday: 生年月日
sex: 性別
remarks: 備考
login_name: ログイン名
password: パスワード
administrator: サイト管理者
uploaded_image: 画像'
サーバを起動して、メンバーとしてログインしてください。
自分のアカウントを変更したり、会員名簿や管理ページの会員管理機能を使ってみてください。
そして、日本語と英語を切り替えて、フィールド名が正しく表示されることを確認してください。
新しい翻訳ファイルを追加した時は、development 環境でもサーバの再起動が必要ですので注意してください。
単に翻訳ファイルを修正しただけなら、再起動は不要です。


前述したように、Rails 2.2 の human_attribute_name は内部的に I18n モジュールを利用しています。
Member.human_attribute_name('phone') と記述すると、t('activecord.attributes.member.phone') と書いたのと同じことになります。
本日はここまでとしましょう。
