[初学者]Railsのi18nによる日本語化対応

# 目的 
- 日本語化対応した時のメモ
- 今後、railsを学ぶ方に向けての参考に役立てる。

# 条件
- ruby 2.5.1
- Rails 5.0.7


# リスト

1. デフォルトの言語を日本語に設定する
2. gem 'rails-i18n'をインストール
3. 複数のロケールファイルが読み込まれるようpathを通す
4. `config/locales`以下にロケールファイルを配置
5. ja.ymlに日本語を設定する
6. 設定した日本を表示させる
7. 様々な記述方法



## 1. デフォルトの言語を日本語に設定する

```ruby:config/application.rb
require_relative 'boot'
require 'rails/all'

Bundler.require(*Rails.groups)

module BoardApp
  class Application < Rails::Application
    config.time_zone = 'Tokyo'
    config.active_record.default_timezone = :local

    #　以下の記述を追記する(設定必須)
    # デフォルトのlocaleを日本語(:ja)にする
    config.i18n.default_locale = :ja

  end
end
```

## 2. gem 'rails-i18n'をインストール

```ruby:Gemfile
# rails5系なら以下を記述
# For 5.0.x, 5.1.x and 5.2.x
gem 'rails-i18n', '~> 5.1' 

# rails4系なら以下を記述
# For 4.0.x
gem 'rails-i18n', '~> 4.0' 
```

上記のgemを導入することによって、
Railsを日本語で使う場合のデフォルトのロケールファイルを「[svenfuchs/rails-i18n](https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/ja.yml)」をダウンロードしなくても使えるようになります。

#### gemを使わない場合は下記コマンドを実行

```bash:config/locales/ja.ymlにダウンロード
curl -s https://raw.githubusercontent.com/svenfuchs/rails-i18n/master/rails/locale/ja.yml -o config/locales/ja.yml
```


### <font color='red'>1 の作業`config.i18n.default_locale = :ja` を設定しないと反映されないので設定必須！</font>


## 3. i18nの複数ロケールファイルが読み込まれるようpathを通す

```ruby:config/application.rb

require_relative 'boot'
require 'rails/all'

Bundler.require(*Rails.groups)

module BoardApp
  class Application < Rails::Application
    config.time_zone = 'Tokyo'
    config.active_record.default_timezone = :local
    config.i18n.default_locale = :ja # デフォルトのlocaleを日本語(:ja)にする

    #　#　以下の記述を追記する(設定必須)
    config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]

  end
end
```

上記を記述することによって、複数のローケルファイルが読み込まれるようになった


## 4. `config/locales`以下にロケールファイルを配置

次に、views / modelによってロケールファイルを分けます。(今回controllerは省略)


```text:ファイル構造(例)
config
└── locales
    ├── model.ja.yml  # modelは1つのファイルで管理します。
    └── views         # views関連のファイルはここで管理する
        ├── admin
        │   ├── dashboards
        │   │   └── ja.yml
        │   ├── ja.yml
        │   ├── user_sessions
        │   │   └── ja.yml
        │   └── users
        │       └── ja.yml
        ├── boards
        │   └── ja.yml
        ├── dashboards
        │   └── ja.yml
        ├── password_resets
        │   └── ja.yml
        ├── shared
        │   └── ja.yml
        ├── user_sessions
        │   └── ja.yml
        └── users
            └── ja.yml
```

## 5. ja.ymlに日本語を設定する

#### <font color='red'>views</font>の日本語化を設定する

```yaml
# app/views/users/index.html.erb
<%= t ".title" %>

# app/views/users/show.html.erb
<%= t ".title", user_name: current_user.full_name %>

# app/views/users/edit.html.erb
<%= t ".title", user_name: current_user.full_name %>
```

```yaml:config/locales/views/users/ja.yml

# ビューはビューを格納しているフォルダ名を起点にし、ビュー名毎に記述する。
# インデント(2space)でpathを制御している

ja:
  users:
    index:
      title: 'ユーザ一覧'
    show:
      # 引数の指定もできる。
      title: '%{user_name}さんのユーザ情報'
    edit:
      # view側で t(.titile), user_name: @user.name みたいな感じで設定できる
      title: '%{user_name}さんのユーザ情報を編集'
```

#### <font color='red'>model</font>の日本語化を設定する

```yaml:config/locales/model.ja.yml

# モデルは全て activerecord 以下に記述する。
# これにより、User.model_name.human / User.human_attribute_name({attr_name})で使用可能。

ja:
  activerecord:
    models:
      # view側： User.model_name.human => "ユーザ" / t("activerecord.models.user")と同じ
      user: ユーザー 
      board: 掲示板
    # model毎に定義したいattributesを記述
    attributes:
        user:
          id: ID
          # view側： User.human_attribute_name :name => "名前" /　t("activerecord.attributes.user.name")と同じ
          first_name: 名前
          last_name: 姓
          email: メールアドレス
          file: プロフィール画像
          crypted_password: パスワード
  # 全てのmodelで共通して使用するattributesを定義
  attributes:
    created_at: 作成日
    updated_at: 更新日
```

#### <font color='red'> Controllers </font>の日本語化を設定する

```ruby:app/controllers/messages_controller.rb
# app/controllers/messages_controller.rb
MessagesController < BaseController
  def update
    # Some business logic

    return redirect_to:index, notice: t(".notice") if @resource.save
    render :edit, alert: t(".alert")
  end
 end
```


```yaml:config/locales/model.ja.yml

ja:
  messages:
    update:
      notice: "メッセージの更新に成功しました。"
      alert: "メッセージの更新ができません。"
```

## 6. 設定した日本を表示させる


```erb:app/views/users/index.html.erb

#### viewで使う場合

# 対応するビューの中ではツリーを省略できる。
# 「ユーザ一覧」が表示される(users.index.titleを参照。)
# 「users.index.html.erb」に記述されているので
# ja.ymlの
# users:
    index:
部分を自動的に読み込んでいるから省略できる
<%= t '.title' %>

# 省略しない記述は以下のようになる。
# 「ユーザ一覧」が表示される
<%= t 'users.index.title' %>


# 日付・時刻(DateオブジェクトやTimeオブジェクト)変換するする場合
<%= l Time.now %>

# 翻訳対象がnilになる(変数とか)場合、defaultを設定しておく
<%= l nil %>
=> I18n::ArgumentError: Object must be a Date, DateTime or Time object. nil given.
↓
↓　nil対策
↓
<%= l nil, default: '' %>
=> ""

# t = translate (config/locales配下の訳文(ja.yml)を参照する)(I18n.t)
# l = localize (DateオブジェクトやTimeオブジェクトを現地のフォーマットに変換する)(I18n.l)

-----------------------------------------------

#### modelで使う場合

# 「ユーザー」が表示される。(activerecord.models.userを参照)
<li><%= User.model_name.human %></li>

# 「ID」が表示される。(activerecord.attributes.user.idを参照)
<li><%= User.human_attribute_name(:id) %></li>

# 「メールアドレス」が表示される。(activerecord.attributes.user.emailを参照)
<li><%= User.human_attribute_name(:email) %></li>
```

## 7. 様々な記述方法 （加えてYAMLの記法を学ぶと良い）

```yaml:ja.yml
# サンプルコード
# 全ファイル共通の使いまわす可能性のあるワードは dictionary を起点にする。
ja:
  dictionary:
    messages:
      # 呼び出し方
      # ■ 階層を.でつなげた文字列を渡す
      # 　　I18n.t("dictionary.messages.hello_user", user_name: "ヤマダ")で呼び出す
      # ■ scopeで階層を区切り(文字列でも配列でも可能)、対象のkeyを渡す
      # 　　I18n.t(:hello_user, scope: "dictionary.messages", user_name: "ヤマダ")
      # 　　I18n.t(:hello_user, scope: [:dictionary, :messages], user_name: "ヤマダ")
      hello_user: 'こんにちは%{user_name}さん'  
    words:
      user: &user 'ユーザ情報'          # &user はエイリアスで *user で参照できる。(同一ファイル内のみ有効)
      user_copy: *user                # 'ユーザ情報' となる。
```

## helpers
```yaml:ja.yml
# サンプルコード
# ヘルパー関数はhelpersを起点にする。
# ヘルパー関数内で tメソッドを使用すると、呼び出し元のビューに基づいたパスが呼び出される。
# 例えばusersのshowから呼ばれたヘルパー関数内で t('.hoge') を実行した場合 users.show.hoge が参照される。
# 呼び出し元によって文言を変えたい場合はビュー側に記述する。(そんなことあるかわからないけど。)

ja:
  helpers:
    submit:
      create: "%{model}を登録する"
      update: "%{model}を更新する"
      account:
        create: "保存する"
      login_form:
        create: "ログインする"
    select:
      prompt: "選択してください。"
    links:
      show: "詳細"
      back: "戻る"
      destroy: "削除"
      edit: "編集"
      new: "新規作成"
      cancel: "キャンセル"
```

## errors
```yaml:ja.yml
# サンプルコード
# グローバルな感じのエラーはerrorsを起点にする。
ja:
  errors:
    format: "%{message}"
    messages: &errors_messages
      inclusion: "%{attribute}が正しくありません。"
      exclusion: "%{attribute}は正しくありません。"
      invalid: "%{attribute}が正しくありません。"
      confirmation: "%{attribute}が一致しません。"
      accepted: "%{attribute}をチェックしてください。"
      empty: "%{attribute}を入力してください。"
      blank: "%{attribute}を入力してください。"
      required: "%{attribute}を入力してください。"
      too_long: "%{attribute}は%{count}文字以内で入力してください。"
      too_short: "%{attribute}は%{count}文字以上で入力してください。"
      wrong_length: "%{attribute}は%{count}文字で入力してください。"
      not_a_number: "%{attribute}は数値で入力してください。"
      not_an_integer: "%{attribute}は整数で入力してください。"
      greater_than: "%{attribute}は%{count}より大きい値を入力してください。"
      greater_than_or_equal_to: "%{attribute}は%{count}以上の値を入力してください。"
      equal_to: "%{attribute}は%{count}にしてください"
      less_than: "%{attribute}は%{count}より小さい値にしてください"
      less_than_or_equal_to: "%{attribute}は%{count}以下の値にしてください"
      odd: "%{attribute}は奇数を入力してください。"
      even: "%{attribute}は偶数を入力してください。"
      taken: "%{attribute}がすでに使用されています。"
      before: "%{attribute}は%{threshold}よりも前の%{type}を入力してください。"
      before_or_equal_to: "%{attribute}は%{threshold}以前の%{type}を入力してください。"
      after: "%{attribute}は%{threshold}よりも後の%{type}を入力してください。"
      after_or_equal_to: "%{attribute}は%{threshold}以降の%{type}を入力してください。"
      out_of_contract: "%{attribute}が契約期間外です。"
      file_size_exceed: "%{file_name}のファイルサイズが大きすぎます。"
      file_type_invalid: "アップロードできないファイル形式です。"
      file_name_too_long: "ファイル名が長すぎます、%{count}文字以内の名称のファイルを指定してください。"
      access_forbidden: "指定された情報にアクセスする権限がありません。"
      pixel_size_too_large: "画像ファイルの大きさは %{width} × %{height} ピクセル以内にしてください。"
      invalid_chars: "%{attribute}に使用できない文字が含まれています（%{chars}）。"
      in_between: "の容量は%{min}以上%{max}以下にしてください。"
      spoofed_media_type: "%{attribute}の拡張子と内容が一致していません。"
```

## flash
```yaml:ja.yml
# サンプルコード
# flashのi18nの設定方法

ja:
  flash:
    new: 作成しました！
    updated: 更新しました！
    failed: 失敗しました！
    destroy: 削除しました！
    login: ログインしました！
    logout: ログアウトしました！
    limited_access: 不正な侵入です！！
    tag_follow: タグをフォローしました！
    tag_not_follow: タグをフォローできませんでした。
    tag_remove_follow: タグのフォローを解除しました！
```

## 複数行テキスト

```yaml:config/locales/user_mailer/ja.yml
# サンプルコード
# 参考URL： https://qiita.com/jerrywdlee/items/d5d31c10617ec7342d56 (YAMLで複数行テキストを書きたい時のあれこれ)
# 基本形に「-」を追加することで最終行の改行を削除します。
ja:
  user_mailer:
    signature: |-
      株式会社Hoge
      営業時間：10:00-19:00
      営業日：月～金（土日祝除く）

# 基本形
ja:
  foo: |
    bar
    baz
```

## Placeholders

```erb
<%= f.input :name, placeholder: true %>
```

```yaml
ja:
  helpers:
    placeholder:
      message:
        name: "プレースホルダー"
```

## HTMLを使う
<font color='red'>_html</font>で終わるkeyは、HTMLとして表示されます。

https://railsguides.jp/i18n.html#%E5%AE%89%E5%85%A8%E3%81%AAhtml%E5%A4%89%E6%8F%9B
>名前が'html'であるキー、および名前が'_html'で終わるキーは、「HTML safe」とマークされます。これらのキーをビューで使うと、その部分のHTMLはエスケープされません。


```erb:app/views/dashboard/show.html.erb
# app/views/dashboard/show.html.erb
<%= t ".welcome_html", name: "山田" %>
```

```yaml:config/locales/views/dashboard/ja.yml
ja:
  dashboard:
    show:
      hello_html: "Welcome, <strong>%{name}</strong>"
```

## メールの件名

### 引数なし
```ruby:user_mailer.rb 
# user_mailer.rb 
class UserMailer < ActionMailer::Base
  def welcome(user)
    #...
  end
end
```

```yaml
ja:
  user_mailer:
    welcome:
      subject: "ようこそ！"
```

### 引数あり

`default_i18n_subject`を使う

```ruby:user_mailer.rb
# user_mailer.rb
class UserMailer < ActionMailer::Base
  def welcome(user)
    mail(to: user.email, subject: default_i18n_subject(user: user.name))
  end
end
```

```yaml
ja:
  user_mailer:
    welcome:
      subject: "%{user}さん, ようこそ！"
```

## 参考

[Rails国際化 (I18n) API](https://railsguides.jp/i18n.html)
[Ruby on RailsのI18nで使用する名前空間に関してのまとめと、ベストプラクティスの検討。 - 波打際のブログさん](http://alfa.hatenablog.jp/entry/2013/12/03/221308)