日本語のRailsアプリケーションを作るときにしたほうがよさそうなこと

## はじめに
仕事で作っているRailsアプリケーションが複数の言語を扱っています。その関係であらためてRailsガイドの[Rails 国際化 (i18n) API](https://railsguides.jp/i18n.html)を読み直したのですが…今までいくつか日本語のアプリケーションを書いてきましたが、もっとラクにできたのでは…という気持ちになりました。国際化と書かれると、どうせ日本語しか使わないしな…と思ってしまいますが、よくよく考えれば、Railsの標準の言語の英語でないもの言語用ということは…必然的に国際化なんですよね。

ですので、**日本語のRailsアプリケーション**を書くのならば、**[この章](https://railsguides.jp/i18n.html)は必読**だと思います。読んでない方はぜひ読んでみてください。きっとプログラムの記述量が減ると思います。

（おしまい）

…だと、自分がおもしろくないので、こんなことができたよ、という簡単なサンプルを作りました。[ソースも公開](https://github.com/ken1flan/blog_i18n)していますので、気になる方は動かして遊んでみてください。

## 設定
国際化(i18n)の機能を使うので、設定をします。デフォルトでは置いていないので、新規作成します。（[ソース](https://github.com/ken1flan/blog_i18n/blob/master/config/initializers/locale.rb)）
詳しくはガイドの[I18nモジュールを設定する](https://railsguides.jp/i18n.html#i18n%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B)をみてください。

```ruby:config/initializers/locale.rb
# config/locales以下の〜.ymlや〜.rbを訳語ファイルとして読み込みます。
I18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]
# デフォルトの使用言語を日本語にします。
I18n.default_locale = :ja
```

### 訳語ファイルのディレクトリ構成

`config/locales/ja.yml`に全部書いても動くには動きますが、管理のしやすさから役割に応じてファイルを分割しておくほうがよいと思います。[Railsガイドに例が出ています](https://railsguides.jp/i18n.html#%E3%83%AD%E3%82%B1%E3%83%BC%E3%83%AB%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E7%B7%A8%E6%88%90)が自分もそれが一番しっくりきました。

日本語しか扱わないのであれば、モデル名のディレクトリは作らず、そのままモデル名のファイルにしてもよいと思います。

```
config/locales/
├── defaults.yml
├── models
│   └── blog.yml
└── views
    └── defaults.yml
```

## Railsのデフォルトのエラーメッセージや、日時などのフォーマットの日本語訳を手に入れる
Githubに有志による翻訳ファイル、[rails-i18n](https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/ja.yml)のがありますので、それを感謝しながら利用します。

```ruby:Gemfile
gem 'rails-i18n'
```

## フォームの項目名や、エラーメッセージを日本語化

ちゃんと日本語化をしたい理由がこれだと思います。
項目名をあちこちに書いたりするのは大変ですよね…。
先に書いた設定をして、モデルや属性の訳語を登録すれば、こんなふうに表示されるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14380/f1063821-4176-3783-0824-a7d682367d5a.png)

### モデルの訳語
ここでは[Blogモデル](https://github.com/ken1flan/blog_i18n/blob/master/app/models/blog.rb)の[訳語の例](https://github.com/ken1flan/blog_i18n/blob/master/config/locales/views/blogs/ja.yml)です。

```ruby:config/locales/models/blog/ja.yml
ja:
  activerecord:
    models:
      blog: 記事
    attributes:
      blog:
        title: タイトル
        body: 本文
        user_id: 著者
        status: 状態
        created_at: 作成日時
        updated_at: 更新日時
```

### エラーメッセージの表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14380/f1063821-4176-3783-0824-a7d682367d5a.png)

モデルに対して`save`や`valid?`を行うと、`errors.fullmessages`に項目名を含んだエラーメッセージが入っているので、それを表示しています。（[ソース](https://github.com/ken1flan/blog_i18n/blob/master/app/views/shared/_form_error_messages.html.erb#L5-L7)）

```erb:app/views/shared/_form_error_messages.html.erb
  :
<% model.errors.full_messages.each do |message| %>
  <li><%= message %></li>
<% end %>
  :
<% end %>
```

### モデルや属性の訳語の取得
#### フォーム
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14380/87e75330-2bdd-9dc6-8b5f-b33093903673.png)

入力項目のラベルを`#label`で翻訳された属性名で作れます。（[ソース](https://github.com/ken1flan/blog_i18n/blob/master/app/views/blogs/_form.html.erb#L5)）

#### フォーム以外
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14380/64c83959-e317-5d3c-2e96-1b0e02869da7.png)

確認画面などで入力フォームの項目名と合わせるのに、手書きでがんばらなくても`#human_attribute_name(属性名)`で訳語を呼び出せます。（[ソース](https://github.com/ken1flan/blog_i18n/blob/master/app/views/blogs/index.html.erb#L12-L13)）

```erb
  :  
<thead>
  <tr>
    <th><%= Blog.human_attribute_name(:title) %></th>
    <th><%= Blog.human_attribute_name(:user_id) %></th>
    <th></th>
  </tr>
</thead>
  :
```

`.model_name.human`で翻訳されたモデル名も取得できます。（…あんまり使いみちが思いつかず、コンソールですみません…。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14380/e292b6a2-14bc-f72a-3c09-733e6a369d2f.png)

### フォームオブジェクト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14380/57915eb8-7cc6-1ce8-99c5-a01c0380a7bd.png)

モデルじゃないけどモデルっぽいものや、複雑だったりするフォームを作るときにはActiveModelを使ったフォームオブジェクトを使いますが、同じようにできます。ただし、訳語ファイルの項目名が`active_record`ではなく`active_model`になっています。（[訳語のソース](https://github.com/ken1flan/blog_i18n/blob/master/config/locales/models/forms/session/ja.yml)、[フォームのソース](https://github.com/ken1flan/blog_i18n/blob/master/app/views/sessions/_form.html.erb)）

```yml:config/locales/models/forms/session/ja.yml
ja:
  activemodel:
    models:
      forms/session: セッション
    attributes:
      forms/session:
        login_id: ログインID
        password: パスワード
```

## 日時表示などの日本語化
日時などを文字列にしようとするときに、つい今だけよければ…と思って、テンプレート内で`#strftime`を使ってしまったりします…。こういうことを繰り返して、アプリケーション内でびみょーーーーーうな差異が散らばってしまって、あとで悶々としてしまうことが何度もありました。
`I18n.l`を使えば、もう少しまとまりを作ることができると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14380/4e5870a2-6e89-fe16-dc2f-c7363cffa2ba.png)

上の例で書いてあるフォーマットは、[rails-i18nのこのあたり](https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/ja.yml#L41-L44)に定義があります。
最後の`:nengetsu`はありませんが、これは訳語ファイルの中で定義したものです。
これらを使えば、多少バリエーションも固定化できると思います。（まだ成功体験はないです。）

```yml:config/locales/views/defaults/ja.yml
ja:
  date:
    formats:
      nengetsu: "%y年%m月"
```

## おわりに
[Railsガイド](https://railsguides.jp/)をあらためて読み直すと、実感できずにスルーしていた部分に気づけてよいな、と思いました。
用意されている便利な機能を使って、なるべくがんばらないようにしたいです。