Ruby on Rails チュートリアル 拡張機能 ( 1 .エラーメッセージの i18n対応(日本語対応))
前置き
私は普段はインフラエンジニアなのですが、仕事でWebアプリケーションを触る機会があり、Webアプリケーションの基本を勉強しなおそうということで、ある講座でRuby On Rails チュートリアルを受講しました。Rubyを触る機会は仕事ではほぼ無いので、なかなか良い経験になりました。
Railsチュートリアルは14の章からなる構成で、TwitterライクなWebサイトを1から作成するものです。ユーザーのログイン機能や投稿機能などを1から学べるため、Webアプリケーション機能の基礎を学びたい人にとっては良い教材だと思います。
拡張機能内容
14章まで終えると一通りのサイトはできるのですが、講座の最後に課題として機能を追加してみようというのがあり、私は以下の2つの機能を追加してみました。
(1) エラーメッセージの i18n対応(日本語対応)
(1) のi18n (国際化・多言語化を意味する internationalization を短縮したもの)対応というのは、Rubyのデフォルトは英語なので、エラーメッセージなども全て英語です。それを極力日本語にするための対応です。
(2) のユーザー検索・マイクロポスト検索機能追加については、その名の通り、ユーザーとマイクロポストの投稿内容(ツイート内容)を検索できるようにした機能追加です。
動作イメージ
https://yusuke-sampleapp2.herokuapp.com/
testユーザーでログインして動作が確認できます。
- メールアドレス:test@gmail.com
- パスワード: foobar
実装
railsのバージョンは6.0.0です
$ rails version Rails 6.0.0
こんな感じで日本語のエラー or 成功メッセージが出るようにします。また、フォームも日本語に置き換えます。所々コードや実装で抜けていろところがありますが、ご容赦ください。。。
小さくて見にくくてすみません。。
Gemをインストール
i18n対応にはymlファイルで翻訳する語彙を作っていくのですが、一つ一つ単語や文をymlに書いても良いのですが、基本的なところは反映させてしまいたいので、Gemで rails-i18n
というGemを入れます。
gem 'rails-i18n', '6.0.0'
bundle install
実施します。
$ bundle install
これでGemが入りました。なお、ymlファイルの階層はこんな感じにしました。これは拡張機能を全て実装した場合の最終的なものです。コントローラやviewごとに階層化します。
$ tree -A config/locales/ config/locales/ ├── controllers │ ├── account_activations_controller │ │ └── ja.yml │ ├── microposts │ │ └── ja.yml │ ├── password_resets_controller │ │ └── ja.yml │ ├── sessions_controller │ │ └── ja.yml │ └── users │ └── ja.yml ├── en.yml ├── ja.yml ├── models │ ├── micropost │ │ └── ja.yml │ └── user │ └── ja.yml └── views ├── sessions │ └── ja.yml ├── shared │ └── ja.yml └── users └── ja.yml
初期設定
ロケールや言語の設定をしておく。また、読み込みファイルの設定もしておきます。
module SampleApp2 class Application < Rails::Application 【中略】 # i18n対応 # デフォルトのlocaleを日本語(:ja)にする config.i18n.default_locale = :ja config.time_zone = 'Tokyo' config.active_record.default_timezone = :local # 複数のロケールが読み込まれるようにする config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s] end end
テスト
まずテストを書きます。基本的にflashやエラーメッセージの部分の表示を変更します。エラーメッセージは意外と色々なところに出てくるので、インテグレーションテストの追記が多くなります。
test "micropost interface" do log_in_as(@user) 【中略】 # 無効な送信 assert_no_difference 'Micropost.count' do post microposts_path, params: { micropost: { content: "" } } end assert_select 'div#error_explanation' assert_select 'div.alert-danger','1個のエラーがあります。' assert_select 'a[href=?]', '/?page=2' # 正しいページネーションリンク # 有効な送信 content = "This micropost really ties the room together" assert_difference 'Micropost.count', 1 do post microposts_path, params: { micropost: { content: content } } assert_equal '投稿しました!',flash[:success] end 【中略】 # 投稿を削除する assert_select 'a', text: 'delete' first_micropost = @user.microposts.paginate(page: 1).first assert_difference 'Micropost.count', -1 do delete micropost_path(first_micropost) assert_equal '投稿が削除されました。',flash[:success] end 【中略】
test "password resets" do get new_password_reset_path 【中略】 # メールアドレスが無効 post password_resets_path, params: { password_reset: { email: "" } } assert_not flash.empty? assert_select 'div.alert-danger','有効なメールアドレスが見つかりません。' assert_template 'password_resets/new' # メールアドレスが有効 assert_not flash.empty? assert_equal 'パスワード再設定用のメールを送信しました。',flash[:info] 【中略】 assert_equal 'パスワードが更新されました。',flash[:success] assert_redirected_to user end end
test "successful edit with friendly forwarding" do 【中略】 patch user_path(@user), params: { user: { name: name, email: email, password: "", password_confirmation: "" } } assert_not flash.empty? assert_equal 'プロフィールが更新されました。',flash[:success] assert_redirected_to @user 【中略】
test "index as admin including pagination and delete links" do log_in_as(@admin) 【中略】 assert_difference 'User.count', -1 do delete user_path(@non_admin) assert_equal 'ユーザーが削除されました。',flash[:success] end
#誤っているデータ ログインできないはず test "login with valid email/invalid password" do 【中略】 assert_not flash.empty? assert_select 'div.alert-danger','メールアドレスとパスワードの組み合わせが間違っています。' get root_path assert flash.empty? end
test "invalid signup information" do get signup_path 【中略】 assert_select 'div.alert-danger','4個のエラーがあります。' assert_select 'div.field_with_errors' end 【中略】 test "valid signup information with account activation" do get signup_path assert_equal 1, ActionMailer::Base.deliveries.size assert_equal 'アカウント有効化に関するメールを確認してください。',flash[:info] user = assigns(:user) 【中略】
コントローラーの日本語化
コントローラーに翻訳場所指定するためには、Railsの #tヘルパー
を使います 。この #tヘルパー
に、各訳文の意味を適切に表すキーを与えます(Rails ガイド参照)。
こんな感じでエラーメッセージが日本語化されます。後ほど記載しますが、modelも日本語化しておきます。
基本的にコントローラー内でflashを使うところは全て書き換えます。
【中略】 flash[:danger] = t('.please log in') redirect_to login_url end end
【中略】 flash[:success] = t('.micropost created') 【中略】 flash[:success] = t('.micropost deleted') 【中略】
【中略】 flash[:info] = t('.sent email') 【中略】 flash[:success] = t('.password reset success') 【中略】
【中略】 flash[:info] = t('.check email') 【中略】 flash[:success] = t('.profile updated') 【中略】 flash[:success] = t('.user deleted') 【中略】
これらに対して以下のようにymlファイルを作成して対応させる
usersコントローラに対して
config/locales/controllers/users/ja.yml
ja: users: create: check email: 'アカウント有効化に関するメールを確認してください。' edit: please log in: 'ログインしてください。' update: profile updated: 'プロフィールが更新されました。' please log in: 'ログインしてください。' destroy: user deleted: 'ユーザーが削除されました。'
password_resets_コントローラに対して
ja: password_resets: create: sent email: 'パスワード再設定用のメールを送信しました。' cannot sent email: '有効なメールアドレスが見つかりません。' update: password reset success: 'パスワードが更新されました。'
micropostsコントローラに対して
ja: microposts: create: micropost created: '投稿しました!' destroy: micropost deleted: '投稿が削除されました。'
account_activationsコントローラに対して
ja: account_activations: edit: activated: 'アカウントが有効化されました' invalid activation link: 'アカウント有効化用のリンクが誤っています'
sessionsコントローラに対して
ja: sessions: create: not activated: 'アカウントが有効化されていません。 ' check email: 'アカウント有効化に関するメールを確認してください。' invalid combination: 'メールアドレスとパスワードの組み合わせが間違っています。'
ビューの日本語化
ビューもコントローラーと同じようにRailsの #tヘルパー
を使って日本語化します。また、フォームの部分も書き換えておきます。
【中略】 <%= f.label :email , t('.email')%> <%= f.email_field :email, class: 'form-control' %> <%= f.label :password , t('.password')%> <%= link_to t('.forgot password'), new_password_reset_path %> <%= f.password_field :password, class: 'form-control' %> <%= f.label :remember_me, class: "checkbox inline" do %> <%= f.check_box :remember_me %> <span> <%= t('.remember me') %> </span> <% end %> <%= f.submit t('.log in'), class: "btn btn-primary" %> <% end %> 【中略】
<% if object.errors.any? %> <div id="error_explanation"> <div class="alert alert-danger"> <%= t('.errors count', errors_count: object.errors.count) %> </div> 【中略】
f.label :password_confirmation, "Confirmation"
の , "Confirmation"
を削除しておく。
<%= f.label :password_confirmation %> <%= f.password_field :password_confirmation, class: 'form-control' %> <%= f.submit t('.Create my account'), class: "btn btn-primary" %>
モデルの日本語化
ついでにモデルも日本語化してフォームを日本語にしておきます。
ja: activerecord: models: # view側: User.model_name.human => "ユーザ" / t("activerecord.models.user")と同じ micropost: '投稿' attributes: micropost: content: '投稿内容' image: '画像' invalid format: 'jpeg,gif,png以外のフォーマットは使用できません' invalid size: '1MB以上の画像は投稿できません' errors: messages: less_than_xmb: 'は1MBより小さいファイルをアップロードしてください'
ja: activerecord: models: user: 'ユーザー' attributes: user: name: '名前' email: 'メールアドレス' password: 'パスワード' password_confirmation: 'パスワード(確認用)'
以上で実装が完了です。
お役に立てれば幸いです。