はじめに
前回は
statusをenumへ として
- バリデーション
- enum
について学びました。
今回は
i18nで日本語化 として
- i18n
- enum_help
について学びます。
では、はじめていきましょう。
1. I18nを使って日本語対応をする
I18n
Railsには I18n
という翻訳のための情報を別記する機能があり、カラム名や指定した情報等任意の情報に対して、言語切替をする事ができます。
この機能を利用して、例え日本人向けのサービスだとしても、日本語を翻訳ファイルに切り出す事によって、コード内に日本語が入る事を防ぐ事ができたり、 表記ゆれを防ぐ事も出来るので慣れておくと良いでしょう。
config
翻訳ファイルで一番実装したいものとしては、各種のインフォメーションが英語だという事です。
例えば先程の空投稿のエラーですが
一見これを日本語に変換しようとするとちょっと大変そうです。
しかし、 I18n
によって別記の翻訳ファイルを置くだけで出来てしまいます。
config/application.rb
を開いてみましょう。
config/applicaiotn.rb【確認】
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【追記】
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
を指定しておきましょう。
翻訳ファイル
次に翻訳ファイルを用意しておきます。
こちらに用意されている内容と同一のものとなりますが、新たに config/locales/ja.yml
というファイルを作成し、下記の内容を記述します。
config/locales/ja.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
で一旦落として
todo_app % bin/dev
をやっておきます。
再び空投稿をすると
一部メッセージが日本語化されました。
改善の必要はありますが、一旦ここまでにしておきましょう。
2. Enumの日本語化
enum_help
Enumの日本語化には、 gem
を使っても良いでしょう。
こちらの enum_help
を使うと便利です。
Gemfile
に追記しておきます。
Gemfile【確認】
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【確認】
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" #追記分
書き足せたら
todo_app % bundle install
を実行しましょう。
enum.yml
また、翻訳ファイルですが、新たに Enum 用のファイルを作っておきましょう。
config/locales/enum_ja.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]}
と書き換えておきます。
I18n.t("enums.task.status.#{k}")
この部分が I18n の呼び出し部分となります。(詳細は次章で行います)
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.map {|k| [I18n.t("enums.task.status.#{k}"), k]}, {}, { class: "form-control" } %>
</div>
<% end %>
(略)
ここまで出来ると、このようになります。
無事翻訳ファイルが読めました。
View
次に、表示部分ですが、これも enum_help
のおかげで簡単に書き換えが可能です。
app/views/tasks/_task.html.erb【確認】
<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>
書き換えるのはこの部分
<tr>
<th>Status:</th>
<td><%= task.status %></td>
</tr>
<td><%= task.status %></td>
を
<td><%= task.status_i18n %></td>
とするだけです。
app/views/tasks/_task.html.erb【編集】
<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>
成功していたら
このようになります。
3. カラムの日本語化
では、今度はもう少し表示部分に手を加えたいと思います。
すでにお気づきかも知れませんが、
表のカラム名部分や
フォームのラベル等、ちょっと寂しい感じです。もちろんこれらも翻訳ファイルを用意する事ができますので、
モデル自体の i18n 化をやってみましょう。
models_ja.yml
今回もモデル用にファイルを作ります。下記のファイルを作っておきましょう。
config/locales/models_ja.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ファイルの階層を辿って引数として渡しておきます。
コンソールで確認する事も可能です。
ターミナルで実験してみて下さい。
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')
と書くことができます。
また、フォームに関しては、フォームヘルパー使っていると、勝手に翻訳しますので、特に変更はありません。
サーバーを起動して、先に確認しておきましょう。
todo_app % bin/dev
tasks/new
にアクセスします。
出来ていますね。
後は、 t
メソッドの必要な部分を編集していきましょう。
app/views/tasks/index.html.erb【確認】
<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【編集】
<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【確認】
<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【編集】
<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【確認】
<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【編集】
<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【確認】
<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【編集】
<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【確認】
<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【編集】
<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>
これで日本語化が出来ました。
エラー文のカラム名等も翻訳出来ていますね。
4. 日時のフォーマット
l
こうなると、日付の表記も気になります。
Rubyでは striftime
というメソッドがありますが、
Railsでは I18n.l
を使います。
そして、これはすでに翻訳が書かれていて、
config/locales/ja.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: :オプションのキー)
のように書きますので、
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【確認】
(略)
<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【確認】
(略)
<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エラーが出る事を防ぎます。
5. git
git
ここまでを保存しておきましょう。
todo_app % git add .
todo_app % git commit -m "i18nで日本語化"
GitHub
Githubの設定ができているのであれば、同名のリポジトリを作成し、pushしておきましょう。
おわりに
本チャプターはここまでとなります。
次回は
- Deviseの導入
を学びます。
ここまでお疲れ様でした。