Rails7 で TODOアプリを作ろう ⑤ (i18nで日本語化)

## はじめに

### 前回は

#### statusをenumへ として

https://qiita.com/tomoaki-kimura/items/94c167b438e0485e2262

- バリデーション
- enum

について学びました。

### 今回は

#### i18nで日本語化 として

- i18n
- enum_help

について学びます。

では、はじめていきましょう。

## １. I18nを使って日本語対応をする

### I18n

Railsには `I18n` という翻訳のための情報を別記する機能があり、カラム名や指定した情報等任意の情報に対して、言語切替をする事ができます。

この機能を利用して、例え日本人向けのサービスだとしても、日本語を翻訳ファイルに切り出す事によって、コード内に日本語が入る事を防ぐ事ができたり、 表記ゆれを防ぐ事も出来るので慣れておくと良いでしょう。

### config

翻訳ファイルで一番実装したいものとしては、各種のインフォメーションが英語だという事です。

例えば先程の空投稿のエラーですが

[![Image from Gyazo](https://i.gyazo.com/484ecb05801063a65ee5a8cb5ec9917a.png)](https://gyazo.com/484ecb05801063a65ee5a8cb5ec9917a)

一見これを日本語に変換しようとするとちょっと大変そうです。

しかし、 `I18n` によって別記の翻訳ファイルを置くだけで出来てしまいます。

`config/application.rb` を開いてみましょう。

config/applicaiotn.rb【確認】
```ruby
require_relative "boot"

require "rails/all"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module TodoApp
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 7.1

    # Please, add to the `ignore` list any other `lib` subdirectories that do
    # not contain `.rb` files, or that should not be reloaded or eager loaded.
    # Common ones are `templates`, `generators`, or `middleware`, for example.
    config.autoload_lib(ignore: %w(assets tasks))

    # Configuration for the application, engines, and railties goes here.
    #
    # These settings can be overridden in specific environments using the files
    # in config/environments, which are processed later.
    #
    # config.time_zone = "Central Time (US & Canada)"
    # config.eager_load_paths << Rails.root.join("extras")
  end
end
```

ここにデフォルトで何語用の翻訳ファイルを読むのか設定を書いておきます。

config/applicaiotn.rb【追記】
```ruby
require_relative "boot"

require "rails/all"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module TodoApp
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 7.1

    # Please, add to the `ignore` list any other `lib` subdirectories that do
    # not contain `.rb` files, or that should not be reloaded or eager loaded.
    # Common ones are `templates`, `generators`, or `middleware`, for example.
    config.autoload_lib(ignore: %w(assets tasks))

    # Configuration for the application, engines, and railties goes here.
    #
    # These settings can be overridden in specific environments using the files
    # in config/environments, which are processed later.
    #
    # config.time_zone = "Central Time (US & Canada)"
    # config.eager_load_paths << Rails.root.join("extras")
    config.i18n.default_locale = :ja #追記分
  end
end
```

このように日本語の `:ja` を指定しておきましょう。

### 翻訳ファイル

次に翻訳ファイルを用意しておきます。

https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/ja.yml

こちらに用意されている内容と同一のものとなりますが、新たに `config/locales/ja.yml` というファイルを作成し、下記の内容を記述します。

config/locales/ja.yml【新規作成】

```yml
ja:
  activerecord:
    errors:
      messages:
        record_invalid: 'バリデーションに失敗しました: %{errors}'
        restrict_dependent_destroy:
          has_one: "%{record}が存在しているので削除できません"
          has_many: "%{record}が存在しているので削除できません"
  date:
    abbr_day_names:
      - 日
      - 月
      - 火
      - 水
      - 木
      - 金
      - 土
    abbr_month_names:
      -
      - 1月
      - 2月
      - 3月
      - 4月
      - 5月
      - 6月
      - 7月
      - 8月
      - 9月
      - 10月
      - 11月
      - 12月
    day_names:
      - 日曜日
      - 月曜日
      - 火曜日
      - 水曜日
      - 木曜日
      - 金曜日
      - 土曜日
    formats:
      default: "%Y/%m/%d"
      long: "%Y年%m月%d日(%a)"
      short: "%m/%d"
    month_names:
      -
      - 1月
      - 2月
      - 3月
      - 4月
      - 5月
      - 6月
      - 7月
      - 8月
      - 9月
      - 10月
      - 11月
      - 12月
    order:
      - :year
      - :month
      - :day
  datetime:
    distance_in_words:
      about_x_hours: 約%{count}時間
      about_x_months: 約%{count}ヶ月
      about_x_years: 約%{count}年
      almost_x_years: "%{count}年弱"
      half_a_minute: 30秒前後
      less_than_x_seconds: "%{count}秒未満"
      less_than_x_minutes: "%{count}分未満"
      over_x_years: "%{count}年以上"
      x_seconds: "%{count}秒"
      x_minutes: "%{count}分"
      x_days: "%{count}日"
      x_months: "%{count}ヶ月"
      x_years: "%{count}年"
    prompts:
      second: 秒
      minute: 分
      hour: 時
      day: 日
      month: 月
      year: 年
  errors:
    format: "%{attribute}%{message}"
    messages:
      accepted: を受諾してください
      blank: を入力してください
      confirmation: と%{attribute}の入力が一致しません
      empty: を入力してください
      equal_to: は%{count}にしてください
      even: は偶数にしてください
      exclusion: は予約されています
      greater_than: は%{count}より大きい値にしてください
      greater_than_or_equal_to: は%{count}以上の値にしてください
      in: は%{count}の範囲に含めてください
      inclusion: は一覧にありません
      invalid: は不正な値です
      less_than: は%{count}より小さい値にしてください
      less_than_or_equal_to: は%{count}以下の値にしてください
      model_invalid: 'バリデーションに失敗しました: %{errors}'
      not_a_number: は数値で入力してください
      not_an_integer: は整数で入力してください
      odd: は奇数にしてください
      other_than: は%{count}以外の値にしてください
      present: は入力しないでください
      required: を入力してください
      taken: はすでに存在します
      too_long: は%{count}文字以内で入力してください
      too_short: は%{count}文字以上で入力してください
      wrong_length: は%{count}文字で入力してください
    template:
      body: 次の項目を確認してください
      header: "%{model}に%{count}個のエラーが発生しました"
  helpers:
    select:
      prompt: 選択してください
    submit:
      create: 登録する
      submit: 保存する
      update: 更新する
  number:
    currency:
      format:
        delimiter: ","
        format: "%n%u"
        precision: 0
        separator: "."
        significant: false
        strip_insignificant_zeros: false
        unit: 円
    format:
      delimiter: ","
      precision: 3
      round_mode: default
      separator: "."
      significant: false
      strip_insignificant_zeros: false
    human:
      decimal_units:
        format: "%n %u"
        units:
          billion: 十億
          million: 百万
          quadrillion: 千兆
          thousand: 千
          trillion: 兆
          unit: ''
      format:
        delimiter: ''
        precision: 3
        significant: true
        strip_insignificant_zeros: true
      storage_units:
        format: "%n%u"
        units:
          byte: バイト
          eb: EB
          gb: GB
          kb: KB
          mb: MB
          pb: PB
          tb: TB
    percentage:
      format:
        delimiter: ''
        format: "%n%"
    precision:
      format:
        delimiter: ''
  support:
    array:
      last_word_connector: "、"
      two_words_connector: "、"
      words_connector: "、"
  time:
    am: 午前
    formats:
      default: "%Y年%m月%d日(%a) %H時%M分%S秒 %z"
      long: "%Y/%m/%d %H:%M"
      short: "%m/%d %H:%M"
    pm: 午後
```

これで翻訳の準備は完了です。

注意点ですが、 `config` 系のファイルを触ったときには、必ずサーバーを `再起動` しておきましょう。

`ctrl` + `c` で一旦落として

```zsh
todo_app % bin/dev
```

をやっておきます。

再び空投稿をすると

[![Image from Gyazo](https://i.gyazo.com/5c6600744b9ea14290c78e76435b5501.png)](https://gyazo.com/5c6600744b9ea14290c78e76435b5501)

一部メッセージが日本語化されました。

改善の必要はありますが、一旦ここまでにしておきましょう。

## 2. Enumの日本語化

### enum_help

Enumの日本語化には、 `gem` を使っても良いでしょう。

https://github.com/zmbacker/enum_help

こちらの `enum_help`を使うと便利です。

`Gemfile` に追記しておきます。

Gemfile【確認】
```ruby
source "https://rubygems.org"

ruby "3.2.2"

# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
gem "rails", "~> 7.1.1"

# The original asset pipeline for Rails [https://github.com/rails/sprockets-rails]
gem "sprockets-rails"

# Use sqlite3 as the database for Active Record
gem "sqlite3", "~> 1.4"

# Use the Puma web server [https://github.com/puma/puma]
gem "puma", ">= 5.0"

# Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]
gem "importmap-rails"

# Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]
gem "turbo-rails"

# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]
gem "stimulus-rails"

# Bundle and process CSS [https://github.com/rails/cssbundling-rails]
gem "cssbundling-rails"

# Build JSON APIs with ease [https://github.com/rails/jbuilder]
gem "jbuilder"

# Use Redis adapter to run Action Cable in production
gem "redis", ">= 4.0.1"

# Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis]
# gem "kredis"

# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
# gem "bcrypt", "~> 3.1.7"

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem "tzinfo-data", platforms: %i[ windows jruby ]

# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", require: false

# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
# gem "image_processing", "~> 1.2"

group :development, :test do
  # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
  gem "debug", platforms: %i[ mri windows ]
end

group :development do
  # Use console on exceptions pages [https://github.com/rails/web-console]
  gem "web-console"

  # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler]
  # gem "rack-mini-profiler"

  # Speed up commands on slow machines / big apps [https://github.com/rails/spring]
  # gem "spring"

end

group :test do
  # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing]
  gem "capybara"
  gem "selenium-webdriver"
end
```

この最終行に

Gemfile【確認】
```ruby
source "https://rubygems.org"

ruby "3.2.2"

# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
gem "rails", "~> 7.1.1"

# The original asset pipeline for Rails [https://github.com/rails/sprockets-rails]
gem "sprockets-rails"

# Use sqlite3 as the database for Active Record
gem "sqlite3", "~> 1.4"

# Use the Puma web server [https://github.com/puma/puma]
gem "puma", ">= 5.0"

# Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]
gem "importmap-rails"

# Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]
gem "turbo-rails"

# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]
gem "stimulus-rails"

# Bundle and process CSS [https://github.com/rails/cssbundling-rails]
gem "cssbundling-rails"

# Build JSON APIs with ease [https://github.com/rails/jbuilder]
gem "jbuilder"

# Use Redis adapter to run Action Cable in production
gem "redis", ">= 4.0.1"

# Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis]
# gem "kredis"

# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
# gem "bcrypt", "~> 3.1.7"

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem "tzinfo-data", platforms: %i[ windows jruby ]

# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", require: false

# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
# gem "image_processing", "~> 1.2"

group :development, :test do
  # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
  gem "debug", platforms: %i[ mri windows ]
end

group :development do
  # Use console on exceptions pages [https://github.com/rails/web-console]
  gem "web-console"

  # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler]
  # gem "rack-mini-profiler"

  # Speed up commands on slow machines / big apps [https://github.com/rails/spring]
  # gem "spring"

end

group :test do
  # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing]
  gem "capybara"
  gem "selenium-webdriver"
end

gem "enum_help" #追記分
```

書き足せたら

```zsh
todo_app % bundle install
```

を実行しましょう。

### enum.yml

また、翻訳ファイルですが、新たに Enum 用のファイルを作っておきましょう。

config/locales/enum_ja.yml【新規作成】
```yml
ja:
  enums:
    task:
      status:
        not_started: 未着手
        in_progress: 進行中
        closed: 完了
```

現状特にファイルを分ける必要はないですが、プロジェクトの規模によってはMVCそれぞれに分けておく事も必要になってくるでしょう。

`ja:` でデフォルトの言語設定を

`enums:`(複数形) で `Enum` の項目

`task:` で　`モデル` 名

`status:` で `カラム` 名

を指しています。

### _form.html.erb

再びフォームの書き換えとなりますが、

app/views/tasks/_form.html.erb
```
（略）
      <% if params[:action] == "edit" %>
        <div class="mb-3">
          <%= form.label :status, style: "display: block" %>
          <%= form.select :status, Task.statuses.keys, {}, { class: "form-control" } %>
        </div>
      <% end %>
（略）
```

`Task.statuses.keys` の部分を `Task.statuses.keys.map {|k| [I18n.t("enums.task.status.#{k}"), k]}` と書き換えておきます。

```ruby
I18n.t("enums.task.status.#{k}")
```

この部分が I18n の呼び出し部分となります。（詳細は次章で行います）

app/views/tasks/_form.html.erb【編集】
```html
（略）
<% if params[:action] == "edit" %>
<div class="mb-3">
	<%= form.label :status, style: "display: block" %>
	<%= form.select :status, Task.statuses.keys.map {|k| [I18n.t("enums.task.status.#{k}"), k]}, {}, { class: "form-control" } %>
</div>
<% end %>
（略）
```

ここまで出来ると、このようになります。

[![Image from Gyazo](https://i.gyazo.com/8b0ed59d6138cd4b1f2933a04d6a9bb2.png)](https://gyazo.com/8b0ed59d6138cd4b1f2933a04d6a9bb2)

無事翻訳ファイルが読めました。

### View

次に、表示部分ですが、これも `enum_help` のおかげで簡単に書き換えが可能です。

app/views/tasks/_task.html.erb【確認】
```html
<div class="row">
	<div class="col-md-8">
		<table id="<%= dom_id task %>" class="table table-bordered">
			<tr>
				<th>Title:</th>
				<td><%= link_to_if params[:action] == "index", task.title, task %></td>
			</tr>
			<tr>
				<th>Description:</th>
				<td><%= task.description %></td>
			</tr>
			<tr>
				<th>Start time:</th>
				<td><%= task.start_time %></td>
			</tr>
			<tr>
				<th>End time:</th>
				<td><%= task.end_time %></td>
			</tr>
			<tr>
				<th>Status:</th>
				<td><%= task.status %></td>
			</tr>
		</table>
	</div>
</div>
```

書き換えるのはこの部分

```html
      <tr>
	<th>Status:</th>
	<td><%= task.status %></td>
</tr>
```

`<td><%= task.status %></td>` を

`<td><%= task.status_i18n %></td>` とするだけです。

app/views/tasks/_task.html.erb【編集】
```html
<div class="row">
	<div class="col-md-8">
		<table id="<%= dom_id task %>" class="table table-bordered">
			<tr>
				<th>Title:</th>
				<td><%= link_to_if params[:action] == "index", task.title, task %></td>
			</tr>
			<tr>
				<th>Description:</th>
				<td><%= task.description %></td>
			</tr>
			<tr>
				<th>Start time:</th>
				<td><%= task.start_time %></td>
			</tr>
			<tr>
				<th>End time:</th>
				<td><%= task.end_time %></td>
			</tr>
			<tr>
				<th>Status:</th>
				<td><%= task.status_i18n %></td>
			</tr>
		</table>
	</div>
</div>
```

成功していたら

[![Image from Gyazo](https://i.gyazo.com/9f536f01eb593c2a76c0b4f468d438b8.png)](https://gyazo.com/9f536f01eb593c2a76c0b4f468d438b8)

[![Image from Gyazo](https://i.gyazo.com/2212c323497584e59b2158b7386b3efa.png)](https://gyazo.com/2212c323497584e59b2158b7386b3efa)

このようになります。

## 3. カラムの日本語化

では、今度はもう少し表示部分に手を加えたいと思います。

すでにお気づきかも知れませんが、

[![Image from Gyazo](https://i.gyazo.com/63eb957d77f19a1460b772521306501d.png)](https://gyazo.com/63eb957d77f19a1460b772521306501d)

表のカラム名部分や

[![Image from Gyazo](https://i.gyazo.com/05a33fb48aa800c4b04d2b304c23295a.png)](https://gyazo.com/05a33fb48aa800c4b04d2b304c23295a)

フォームのラベル等、ちょっと寂しい感じです。もちろんこれらも翻訳ファイルを用意する事ができますので、

モデル自体の i18n 化をやってみましょう。

### models_ja.yml

今回もモデル用にファイルを作ります。下記のファイルを作っておきましょう。

config/locales/models_ja.yml【新規作成】

```yml
ja:
  activerecord:
    models:
      task: ToDo
    attributes:
      task:
        title: タイトル
        description: 概要
        start_time: 開始日
        end_time: 期限
        status: 進捗
```

### t

これらの日本語表示表示呼び出す為には、 I18n.t('ymlファイルの階層') という記述をします。

例えば、 `タイトル` を呼ぶ時は、 `I18n.t('activerecord.attributes.task.title')` のようにymlファイルの階層を辿って引数として渡しておきます。

コンソールで確認する事も可能です。

ターミナルで実験してみて下さい。

```zsh
 todo_app % rails c
Loading development environment (Rails 7.1.1)
irb(main):001> I18n.t('activerecord.attributes.task.title')  
=> "タイトル"
irb(main):002>
```

このように見られます。

コンソール内では `I18n` の記述が必要ですが、 `view` 内では省いて、  `t('activerecord.attributes.task.title')` と書くことができます。

また、フォームに関しては、フォームヘルパー使っていると、勝手に翻訳しますので、特に変更はありません。

サーバーを起動して、先に確認しておきましょう。

```zsh
todo_app % bin/dev
```

`tasks/new` にアクセスします。

[![Image from Gyazo](https://i.gyazo.com/82d1dde68dc985fe58b4b2733a19b9df.png)](https://gyazo.com/82d1dde68dc985fe58b4b2733a19b9df)

出来ていますね。

後は、 `t` メソッドの必要な部分を編集していきましょう。

app/views/tasks/index.html.erb【確認】
```html
<p style="color: green"><%= notice %></p>

<h1>Tasks</h1>

<div id="tasks">
  <% @tasks.each do |task| %>
    <%= render task %>
  <% end %>
</div>

<%= link_to "New task", new_task_path, class: "btn btn-primary me-2" %>
```

app/views/tasks/index.html.erb【編集】
```html
<p style="color: green"><%= notice %></p>

<h1><%= t "activerecord.models.task" %>リスト</h1>

<div id="tasks">
  <% @tasks.each do |task| %>
    <%= render task %>
  <% end %>
</div>

<%= link_to "新規#{ t "activerecord.models.task"}の作成", new_task_path, class: "btn btn-primary me-2" %>
```

app/views/tasks/show.html.erb【確認】
```html
<p style="color: green"><%= notice %></p>

<%= render @task %>

<div class="d-flex">
	<%= link_to "Edit this task", edit_task_path(@task), class: "btn btn-warning me-2" %>
	<%= link_to "Back to tasks", tasks_path, class: "btn btn-secondary me-2" %>
	<%= button_to "Destroy this task", @task, method: :delete, class: "btn btn-danger me-2", data: { turbo_confirm: "本当に削除しますか？" } %>
</div>
```

app/views/tasks/show.html.erb【編集】
```html
<p style="color: green"><%= notice %></p>

<h1><%= t "activerecord.models.task" %>詳細</h1>

<%= render @task %>

<div class="d-flex">
	<%= link_to "この#{ t "activerecord.models.task" }を編集", edit_task_path(@task), class: "btn btn-warning me-2" %>
	<%= link_to "リストへ戻る", tasks_path, class: "btn btn-secondary me-2" %>
	<%= button_to "この#{ t "activerecord.models.task" }を削除", @task, method: :delete, class: "btn btn-danger me-2", data: { turbo_confirm: "本当に削除しますか？" } %>
</div>
```

app/views/tasks/new.html.erb【確認】
```html
<h1>New task</h1>
<%= render "form", task: @task %>
<br>

<div>
	<%= link_to "Back to tasks", tasks_path, class: "btn btn-secondary me-2" %>
</div>
```

app/views/tasks/new.html.erb【編集】
```html
<h1>新規<%= t "activerecord.models.task" %></h1>

<%= render "form", task: @task %>

<div>
	<%= link_to "リストへ戻る", tasks_path, class: "btn btn-secondary me-2" %>
</div>
```

app/views/tasks/edit.html.erb【確認】
```html
<h1>Editing task</h1>

<%= render @task %>
<%= render "form", task: @task %>

<br>

<div class="d-flex">
	<%= link_to "Show this task", @task, class: "btn btn-primary me-2" %>
	<%= link_to "Back to tasks", tasks_path, class: "btn btn-secondary me-2" %>
</div>
```

app/views/tasks/edit.html.erb【編集】
```html
<h1><%= t "activerecord.models.task" %>編集</h1>

<%= render @task %>
<%= render "form", task: @task %>

<div class="d-flex">
	<%= link_to "#{ t "activerecord.models.task"}詳細", @task, class: "btn btn-primary me-2" %>
	<%= link_to "リストへ戻る", tasks_path, class: "btn btn-secondary me-2" %>
</div>
```

app/views/tasks/_task.html.erb【確認】
```html
<div class="row">
	<div class="col-md-8">
		<table id="<%= dom_id task %>" class="table table-bordered">
			<tr>
				<th>Title:</th>
				<td><%= link_to_if params[:action] == "index", task.title, task %></td>
			</tr>
			<tr>
				<th>Description:</th>
				<td><%= task.description %></td>
			</tr>
			<tr>
				<th>Start time:</th>
				<td><%= task.start_time %></td>
			</tr>
			<tr>
				<th>End time:</th>
				<td><%= task.end_time %></td>
			</tr>
			<tr>
				<th>Status:</th>
				<td><%= task.status_i18n %></td>
			</tr>
		</table>
	</div>
</div>
```

app/views/tasks/_task.html.erb【編集】
```html
<div class="row">
	<div class="col-md-8">
		<table id="<%= dom_id task %>" class="table table-bordered">
			<tr>
				<th><%= t "activerecord.attributes.task.title" %></th>
				<td><%= link_to_if params[:action] == "index", task.title, task %></td>
			</tr>
			<tr>
				<th><%= t "activerecord.attributes.task.description" %></th>
				<td><%= task.description %></td>
			</tr>
			<tr>
				<th><%= t "activerecord.attributes.task.start_time" %></th>
				<td><%= task.start_time %></td>
			</tr>
			<tr>
				<th><%= t "activerecord.attributes.task.end_time" %></th>
				<td><%= task.end_time %></td>
			</tr>
			<tr>
				<th><%= t "activerecord.attributes.task.status" %></th>
				<td><%= task.status_i18n %></td>
			</tr>
		</table>
	</div>
</div>
```

これで日本語化が出来ました。

[![Image from Gyazo](https://i.gyazo.com/94f453c50863b5cac3a095cd57e46ecb.png)](https://gyazo.com/94f453c50863b5cac3a095cd57e46ecb)

エラー文のカラム名等も翻訳出来ていますね。

[![Image from Gyazo](https://i.gyazo.com/6bd2cb2a060b8810978e2ee19c8bfdfa.png)](https://gyazo.com/6bd2cb2a060b8810978e2ee19c8bfdfa)

## 4. 日時のフォーマット

### l

こうなると、日付の表記も気になります。

[![Image from Gyazo](https://i.gyazo.com/219930380bcff83eafa8bcaf86b04118.png)](https://gyazo.com/219930380bcff83eafa8bcaf86b04118)

Rubyでは `striftime` というメソッドがありますが、

https://docs.ruby-lang.org/ja/latest/method/Time/i/strftime.html

Railsでは `I18n.l` を使います。

そして、これはすでに翻訳が書かれていて、

config/locales/ja.yml【確認】
```yml
（略）
      words_connector: "、"
  time:
    am: 午前
    formats:
      default: "%Y年%m月%d日(%a) %H時%M分%S秒 %z"
      long: "%Y/%m/%d %H:%M"
      short: "%m/%d %H:%M"
    pm: 午後
```

以前作成した `ja.yml` の中に存在します。

また、この `time` という階層に対して、　`I18n.l(時間, format: :オプションのキー)`　のように書きますので、

```zsh
 todo_app % rails c
Loading development environment (Rails 7.1.1)
irb(main):001> I18n.l(Time.current)
=> "2023年11月07日(火) 06時48分09秒 +0000"
irb(main):002> I18n.l(Time.current, format: :long)
=> "2023/11/07 06:48"
irb(main):003> I18n.l(Time.current, format: :short)
=> "11/07 06:48"
```

表示を切り替える事が可能です。 `format` はオプションなので指定しない場合 `default` が呼び出されます。

では、ファイルを書き換えていきましょう。

start_time とend_time の部分ですね。

app/views/tasks/_task.html.erb【確認】
```html
（略）
      <tr>
        <th><%= t "activerecord.attributes.task.description" %></th>
        <td><%= task.description %></td>
      </tr>
      <tr>
        <th><%= t "activerecord.attributes.task.start_time" %></th>
        <td><%= task.start_time %></td>
      </tr>
（略）
```

これが、以下のようになります。

app/views/tasks/_task.html.erb【確認】
```html
（略）
        <tr>
          <th><%= t "activerecord.attributes.task.start_time" %></th>
          <td><%= l task.start_time, format: :long %></td>
        </tr>
        <tr>
          <th><%= t "activerecord.attributes.task.end_time" %></th>
          <td><%= l task.end_time, format: :long if task.end_time.present? %></td>
        </tr>
（略）
```

条件式 `if task.end_time.present?` は、lメソッドによって、nilエラーが出る事を防ぎます。

[![Image from Gyazo](https://i.gyazo.com/821b6c76184fb8ddb2933e19a2143e2f.png)](https://gyazo.com/821b6c76184fb8ddb2933e19a2143e2f)

## 5. git

### git

ここまでを保存しておきましょう。

```zsh
todo_app % git add .
todo_app % git commit -m "i18nで日本語化"
```

### GitHub

Githubの設定ができているのであれば、同名のリポジトリを作成し、pushしておきましょう。

## おわりに

本チャプターはここまでとなります。

### 次回は

https://qiita.com/tomoaki-kimura/items/463afb2ef68afcf2fdb1

- Deviseの導入

を学びます。

ここまでお疲れ様でした。