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')
と書いたのと同じことになります。
本日はここまでとしましょう。