はじめに
Rails アプリで使用される i18n の JavaScript 版のライブラリとして i18n-js があります。
自分の Rails プロジェクトで Webpacker -> importmap-rails の移行をするにあたって、 i18n-js の移行にかなり試行錯誤したので、自分の使い方を記載しようと思います。
Webpacker -> importmap-rails の移行については別記事を書きました。
前提
元々は、i18n-js のREADME の Rails with webpacker のセクションにある gist のリンク
を参考に使用していました。変更前のコードを一部分だけ記載しておきます。
gem 'i18n-js'
import I18n from 'i18n-js'
I18n.translations = <%= I18n::JS.filtered_translations.to_json %>
export default I18n
import I18n from './i18n.js.erb'
console.log(I18n.t('helpers.notice.processing'))
importmap-rails では js.erb のようなサーバ側でビルドが必要な JavaScript ファイルを扱えないので、これを使わない方法で対応します。
手順
config/application.rb に以下を追記
module YourApp
class Application < Rails::Application
...
config.middleware.use I18n::JS::Middleware # ここを追加
end
end
config/i18n-js.yml を作成
translations:
- file: "app/javascript/i18n-js/translations.js"
prefix: "import I18n from 'i18n-js'\n"
suffix: "export default I18n\n"
bin/importmap pin i18n-js を実行して config/importmap.rb に i18n-js を追記する
pin "i18n-js", to: "https://ga.jspm.io/npm:i18n-js@3.8.0/app/assets/javascripts/i18n.js"
config/importmap.rb に以下を追記
pin_all_from "app/javascript/i18n-js", under: "i18n-js"
app/packs/src/i18n.js.erb を削除し、呼び出し箇所も変更
import I18n from 'i18n-js/translations'
console.log(I18n.t('helpers.notice.processing'))
解説
config/application.rb
config.middleware.use I18n::JS::Middleware によって、Rails サーバを起動中に、ページ更新などリクエストを行うタイミングで translations.js ファイルが自動的に生成されます。これは開発環境で役立つ機能で、 config/locales 配下の i18n ファイルを編集したあと、ページリロードするだけで、 i18n-js 側に反映してくれます。
これ以外に translations.js ファイルを生成する rake タスクが用意されており、rake i18n:js:export で生成されます。本番環境にデプロイする際などはこのタスクを使います。
config/i18n-js.yml
translations:
- file: "app/javascript/i18n-js/translations.js"
prefix: "import I18n from 'i18n-js'\n"
suffix: "export default I18n\n"
file に指定したパスに変換した翻訳ファイルが出力されます。
prefix, suffix は i18n-js の README に説明がありますが、生成される translations.js の最初と最後に文字を差し込むことができます。
この設定から、次のようなファイルが生成されます。
import I18n from 'i18n-js'
I18n.translations || (I18n.translations = {});
I18n.translations["en"] = I18n.extend((I18n.translations["en"] || {}), JSON.parse('{"activemodel":{"attributes":{
...
'));
export default I18n
これで import I18n from 'i18n-js/translations' すれば I18n.t() でロケールごとに翻訳済みの文章が取得できます。
また、この例では全てのロケールを1つのファイルに出力していますが、ロケールごとに別のファイルに分割することも可能です。そちらについては i18n-js の GitHub レポジトリの README に記載があるのでそちらを参照ください。
config/importmap.rb
生成したファイルは app/javascript/i18n-js/translations.js なので、そのファイルを含むディレクトリ以下を読み込むようにします。
pin_all_from "app/javascript/i18n-js", under: "i18n-js"
ここが割と重要なのですが、ディレクトリ名を i18n-js としています。最初 i18n としたのですが、その場合 import I18n from 'i18n/translations' によって読み込むことができませんでした。しばらくハマったのですが、原因は i18n-js gem が全く同じパスで asset pipeline にファイルを配置しているため、そちらが読み込まれてしまっている、というものでした。
(ちなみにそっちのファイルの中身はこれ)
//= require i18n/shims
//= require i18n
//= require i18n/filtered
なので i18n 以外のディレクトリにしましょう。
ここまでの対応で、各 JavaScript ファイルから I18n.t() が使えるようになったはずです。
おまけ
i18n-js/translations.js ファイルは config/locales 以下のファイルから自動生成されるものなので、 git 管理配下から外しておいた方が良いでしょう。
-
i18n-jsディレクトリに.keepを作成 -
.gitignoreに以下を追記
/app/javascript/i18n-js/*
!/app/javascript/i18n-js/.keep
本番環境にデプロイする際などは、rake i18n:js:export を実行して translations.js を生成しますが、毎回手で打つのは億劫なので、自分は assets:precompile タスクの直前に実行されるようにしました。
Rake::Task['assets:precompile'].enhance ['i18n:js:export']