はじめに
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']