Deviseを適切に国際化するための究極のチェックリスト
最高のブログ記事は、自分自身の「痒いところ」を解決したいという欲求から生まれることがあります。今日の記事もまさにその一例です!
Railsアプリケーション向けの定番認証ソリューションであるDeviseをご存知の方は多いでしょう。私がDeviseを使って作業していたとき、翻訳を実際に動かすまでには、想像以上に多くの手順と工夫が必要だと気づきました。「こんなとき、チェックリストがあれば迷わずに済むのに」と過去の自分は思っていたものです。
というわけで、未来の自分と読者の皆さんのために——究極のDevise国際化チェックリストをご紹介します!
devise-i18n gemを使うべきか、使わないべきか?
まず前提として、Devise本体のポリシーでは、ビュー内の文字列は翻訳可能になっていません。すべての文字列がハードコードされているのです。そこで活躍するのがdevise-i18n gemです。このgemはDeviseのテンプレートをすべて翻訳可能にし、さらにコミュニティ提供の翻訳ファイルも同梱しています。多言語サポートが必要な国際的なアプリケーションにとっては、これが最も手軽な解決策となるでしょう。
しかし、devise-i18n gemはあくまで「Deviseの原文テキストにできる限り忠実に従う」という方針を採用しています。問題は、そもそもDeviseが提供するテキスト自体が一貫性に欠けていることです。直訳では決して自然な文章にはならないため、私は常に翻訳を微調整し、プロジェクト間でファイルをコピーして回る羽目になりました。一度に1つの文字列・1つのビューしか見ていない状態では、全体の一貫性を保つのが非常に難しいのです。
その結果、devise-i18n gemの翻訳品質は、単一言語(オランダ語のみ)の私のプロジェクトが求める水準には届きませんでした。
もう一つのデメリットは、カスタマイズしたビューとの相性です。見た目のスタイリングだけのためであっても、Devise側のビュー変更に追従するdevise-i18n gemのアップデートがあるたびに、修正作業が必要になります。ビューを再生成してカスタマイズを再適用するか、変更点を手動でコピペするか、どちらかを選ぶことになります。ちなみに、この問題は後述のチェックリストのアプローチでも解消されるわけではありませんが、devise-i18n gemなしでも解決難度は変わりません。🤷♀
🇳🇱 オランダ語の翻訳ファイルをひとつ作って終わりに
そこで私は、Devise用のオランダ語翻訳ファイルを1つきっちり整備し、二度と悩まなくて済むようにすることにしました。魅力的な話だと思いませんか?新しく改善された翻訳ファイルはGitHubで公開しています(チェックリストのステップ3を参照)。各翻訳判断の理由もファイル内で説明しているので、参考にしてください。
究極のチェックリスト
それでは、オランダ語(:nl)翻訳だけで独り立ちする準備ができたので、細部にわたって一つずつチェックボックスを埋めていきましょう。
なお、この手順は「Deviseがインストール済みでUserモデルがあり、Deviseのビューも生成済みのアプリ」がすでにあることを想定しています。一緒にコードを書いていく方は、ここが出発点です。また、*.nl.yml の nl は任意の言語コードに置き換えられますし、User / :user もあなたのプロジェクトでDeviseに使っているモデル名に置き換えてください。
ステップ1:ロケールを設定する
利用可能なロケールに :nl を追加しましょう(特にこだわりがなければ、まずは application.rb に記述しておけば十分です)。そうすればデフォルトロケールとして設定できます。
# application.rb
config.i18n.available_locales = [:nl, :en]
config.i18n.default_locale = :nlapplication.rb への記述以外にも、よりクリーンなロケール設定方法はいくつかあります。この記事を読み終えたら、Railsのi18nガイドを確認して、自分に合った方法を選びましょう。
ステップ2:Rails本体の翻訳を追加する
次に、Railsの :nl 翻訳ファイルを追加します。これはDevise固有ではないインターフェース文字列(特にRailsのバリデーションエラーメッセージ)をカバーするためです。
ステップ3:Deviseのキーを翻訳する
Deviseのキーを :nl 向けに翻訳します。前述の「新しく改善されたオランダ語翻訳ファイル」を追加してください(リンクは上記 🇳🇱 のセクションにあります)。
ステップ4:views.*.yml ファイルを作成する
ビュー用にオランダ語と英語の .yml ファイル(views.*.yml)を追加します。リポジトリには完成版の views.nl.yml の例があり、ステップ4・6・7の内容が反映されています。
# views.nl.yml の例
nl:
devise:
# 後ほどDeviseスコープで埋めます:
# registrations:
# new:
# forget_password: Wachtwoord vergeten?ステップ5:Active Record属性の翻訳
続いて、emailやpasswordといったActive Record属性のラベルに対する翻訳を追加します。実装したモジュールごとに、ユーザーと管理者ユーザーが目にする項目だけを翻訳すればOKです。トークン名などを翻訳する必要はありません(devise-i18n gemがやっているようなことは不要です)。私が「翻訳すべき」と考える項目は以下の通りです。
# active_record.nl.yml 内
# User属性にマッピングされるラベルを翻訳
nl:
activerecord:
attributes:
user:
current_password: Huidig wachtwoord
email: e-mailadres
password: wachtwoord
password_confirmation: Wachtwoord bevestigen
remember_me: Ingelogd blijven?
models:
user: Gebruiker注目ポイント::email と :password の値が小文字になっていますね。これはステップ7で行うRailsエラーメッセージの調整のためです。理由は後述します。
現時点では、これらのキーは active_record.*.yml に置いておきましょう。
ステップ6:すべてのDeviseビューを確認する
次に、Devise固有のテンプレートと文字列をすべてi18n化し、対応する翻訳を紐付けます。地道な作業ですが、その前に以下のショートカットが使えるか確認してみてください。
- devise-i18n gemをビューに使う:ただし、gemの
.ymlファイルからキーを自分のプロジェクトの.ymlにコピーする必要があります。gemはキーをdevise.*.ymlに混在させているため、せっかく整えた新しいオランダ語翻訳を上書きされたくない場合は注意が必要です。また、Deviseビューをスタイリング済みなら、スタイルもコピーが必要です。うんざりしますよね。 - 既存のi18n化済みプロジェクトからビューファイルをコピーする(前の選択肢と同じ欠点があります)。
- リポジトリのサンプルを参照する:私が最新プロジェクトで使ったいくつかのビュー例が公開されています。
あるいは、一度きり徹底的に解決してしまうのも手です。頭を下げて(比喩ですが)、今後ずっと使える、自分好みのファイル一式を作り上げましょう。前ステップのサンプルは私自身の初版であり、あなたのスタート地点の助けになるはずです。要件の詳細は以下のミニチェックリストを確認してください。
Deviseフォームのためのミニチェックリスト
- Active Record由来ではない文字列は、すべてi18n化し、適切なスコープを持つキーと翻訳を用意する(たとえば
views.*.ymlに保存——例を参照)。 - 独自の翻訳を追加するときは、新しい
devise.nl.ymlとの一貫性を保つこと。 - 小文字のラベルは無視してOK。ステップ7で正しく大文字化されます。
- メーラーをすでにi18n化しているなら問題ありません。まだなら、ステップ8まで放置して構いません。
- 以下のDeviseビューを、Railsのtranslateヘルパー(
t)で翻訳可能にする必要があります:devise/views/shared/_linksパーシャル:すべてのリンク名devise/views/shared/_errorsパーシャル(Devise 4.6以降)- 使用中の各モジュールのDeviseフォーム内:Active Record属性のラベルではないすべての文字列
ステップ7:Active Recordのエラーメッセージを調整する
次は、「password can't be blank」のような、Devise機能に関連するActive Recordエラーメッセージの調整です。
Devise翻訳をグレードアップしたことで、Active Record側のメッセージとのスタイル不一致が目立つようになりました。そこで、Devise翻訳と同じルールに従ってこちらも調整し、全体の一貫性を確保しました。
注目すべきは、メッセージ形式が「%{attribute} %{message}」から「%{message}」に変わった点です。属性名を文字列の先頭に強制的に配置する代わりに、翻訳文の中で属性を参照する形にすることで、オランダ語メッセージを美しく整えるのが格段に楽になりました。多少の重複よりも、奇妙なメッセージに我慢する方が嫌だったのです。
実は、ステップ5でemailとpasswordを小文字にしたのは、この新しいメッセージ形式が理由です。エラーメッセージ内では、属性名が文中のどこにでも現れ得るからです。
さらに、:taken メッセージも差し替えました。Deviseのポリシーでは、メールアドレスが「見つからない」のか「無効」なのかを明かさないようになっています。私はこのポリシーをRailsの taken メッセージにも拡張しました。
新しいメッセージスタイルに合わせたい方は、該当ファイルを参照し、元の nl.yml 内のRailsの error: messages: キーの対応部分を置き換えてください。ひとつ注意点:Deviseに関係しない入力へのバリデーションを追加する場合は、エラーメッセージが依然として意味をなすか必ず再確認してください(私はDevise関連のものしか検証していません。要調査です)。
ステップ8:壊れてしまったラベルを修正する
ステップ5で、新しいエラーメッセージのためにemailとpasswordの翻訳を小文字化しました。今度は、フォームのラベルでの表示を修正する番です。いくつか方法がありますが、私のお気に入りは「専用のlabelキー」を追加するやり方です。
userキーに多少の重複が生じますが、フォーム内のラベルはきれいなまま保たれます。
# active_record.nl.yml にlabelヘルパーキーを追加:
nl:
activerecord:
attributes:
user:
current_password: Huidig wachtwoord
email: e-mailadres
password: wachtwoord
password_confirmation: Herhaal het wachtwoord
remember_me: Wil je ingelogd blijven?
models:
user: Gebruiker
helpers:
label:
user:
email: Emailadres
password: Wachtwoordなお、元の nl.yml にはすでに :helpers スコープが存在します。一般的に、同じスコープのキーは1箇所にまとめておくと、人間が探しやすくなって良いでしょう。
残りの変更は素直な作業です。ここから先、大きな驚きはありません。🎉
ステップ9:ナビゲーションリンクを更新する
Deviseへ向かうすべてのリンク(ナビゲーションなど)を見つけて、Railsの t ヘルパーでi18n化しましょう。
私はこれらのキーを、.ymlファイルのDeviseスコープ内にまとめるのが好きです。たとえば t(".devise.sign_out") を追加すれば、:sign_out を :sign_up や :sign_in と同じスコープに置けます(サンプルファイルを参照)。
ステップ10:メーラーを翻訳する
最後に、メーラーのビューを翻訳します。選択肢は主に2つあります。
- すべての文字列とリンク名をi18n化する:ステップ6で他のビューに対してやったのと同じ方法です。必要なら独立した
mailer.*.ymlを追加するとよいでしょう。 - ロケールごとに個別のメーラービューを作る:
devise/mailer/reset_password.nl.html.erbとdevise/mailer/reset_password.en.html.erbのように、それぞれ独自のテキストを持つファイルを用意します。Railsは設定されたロケールに一致するファイルを自動的に選択してくれます。
お疲れさまです!これでDeviseの全文字列がきちんと翻訳されました。やった!🎉
仕上げ:整理整頓
私のビューのサンプルでは、共有キー(:forgot_password など)を抽出して、汎用のdeviseスコープに集約しました。変更が容易になりますが、Railsが自動的に見つけてくれないため、冗長な構文(t("devise.forgot_password"))を使う必要があります。ドット構文(t(".new_confirmation_mail"))は機能しません。
active_record.*.yml を採用するなら、active recordスコープのキーをすべてそのファイルに集約するのが理にかなっています。Railsの *.yml ファイルからActive Record関連のキーを、対応する active_record.*.yml へ移動しましょう。
また、devise: スコープが重複した *.yml ファイルが2組できているはずです。Deviseビュー由来のキーを devise.*.yml に統合することを検討してください。devise-i18n gemが採っているアプローチで、私も気に入っています。以下のように書きます。
# ビュースコープをdevise.nl.ymlに統合
nl:
devise:
confirmations:
...
registrations:
...
edit:
...
new:
...ちょっとした調整とヒント
- エラーメッセージのヘッダー(「x件のエラーにより保存できませんでした」的な文言)が好きではないので、
errorsパーシャルから削除しました。 default_localeを:nlに設定すると、翻訳が見つからなかった場合、Railsはキーを「humanize」して表示します。つまりt(:some_untranslated_key)はビュー上でSome Untranslated Keyのように表示されます。- i18n-tasks gemを使えば、未使用キーの掃除や不足キーの追加ができます。優れたツールです!ただし私の場合、IDEのi18nサポートが充実していたため、gemよりもIDEベースのワークフローの方が速かったという結果になりました。
お別れは甘美な悲しみ
最後にひと言だけ。この旅を始めたとき、これほどの工数になるとは思いませんでした。とはいえ、複雑さの正体がどこにあるのかを把握できた今はとても満足しています。そして未来の自分と皆さんは、必要な変更点を網羅したリストを手に入れたわけです。ウーフー!
ただし、このチェックリストを手にしても、行動の前に一度立ち止まって考えてみてください。完璧でない翻訳のまま、しばらく付き合っていくのも悪くないかもしれません……。
-
Windows 10の「付箋」アプリを使いこなす!知っておきたい便利技とショートカット大全
Windows 10に標準搭載されている「付箋(Sticky Notes)」アプリは、Webサイトで見つけた情報や職場で受け取った内容など、一時的・即時的なメモをさっと書き留めたいときに心強い味方となるツールです。ちょっとしたコツを覚えておけば、Windows 10の優れた機能のひとつであり、最高クラスのメモアプリとして活用できます。初心者の方にも、すでに日常的に使っている方にも、この記事で紹介するテクニックはきっと役立つはずです。 まずは基本操作をおさらい 付箋を追加するには、Windowsアイコンの横にある検索バーに「Sticky Notes」と入力し、右側のペインから「開く」をクリックし
-
TweakPass徹底解説:究極のパスワードマネージャーでアカウントを完全保護
付箋にパスワードを書き留めたり、誕生日や結婚記念日、身近な人の名前といった推測されやすいパスワードを「忘れないように」と使っていた時代は、もう終わりです。実は情報漏洩の約80%は、脆弱なパスワードや使い回しが原因だと言われています。だからこそ、すべてのアカウントに固有のパスワードを設定することが不可欠なのです。TweakPassがあれば、ログインごとに個別の強力なパスワードを、サイト数の制限なく持つことができます。Tweaking Technologiesが開発したTweakPassは、毎分新しいユーザーを獲得し続けている注目のパスワード管理ソフトウェアです。 パスワードマネージャーとは? パ