LoginSignup
1
0

More than 1 year has passed since last update.

i18n-js を importmap-rails で使う

Last updated at Posted at 2022-02-18

はじめに

Rails アプリで使用される i18n の JavaScript 版のライブラリとして i18n-js があります。
自分の Rails プロジェクトで Webpacker -> importmap-rails の移行をするにあたって、 i18n-js の移行にかなり試行錯誤したので、自分の使い方を記載しようと思います。

Webpacker -> importmap-rails の移行については別記事を書きました。

前提

元々は、i18n-js のREADME の Rails with webpacker のセクションにある gist のリンク
を参考に使用していました。変更前のコードを一部分だけ記載しておきます。

Gemfile
gem 'i18n-js'
app/packs/src/i18n.js.erb
import I18n from 'i18n-js'
I18n.translations = <%= I18n::JS.filtered_translations.to_json %>
export default I18n
app/packs/src/foo.js
import I18n from './i18n.js.erb'

console.log(I18n.t('helpers.notice.processing'))

importmap-rails では js.erb のようなサーバ側でビルドが必要な JavaScript ファイルを扱えないので、これを使わない方法で対応します。

手順

config/application.rb に以下を追記

config/application.rb
module YourApp
  class Application < Rails::Application

  ...

  config.middleware.use I18n::JS::Middleware # ここを追加
  end
end

config/i18n-js.yml を作成

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.rbi18n-js を追記する

config/importmap.rb
pin "i18n-js", to: "https://ga.jspm.io/npm:i18n-js@3.8.0/app/assets/javascripts/i18n.js"

config/importmap.rb に以下を追記

config/importmap.rb
pin_all_from "app/javascript/i18n-js", under: "i18n-js"

app/packs/src/i18n.js.erb を削除し、呼び出し箇所も変更

app/packs/src/foo.js
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

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, suffixi18n-js の README に説明がありますが、生成される translations.js の最初と最後に文字を差し込むことができます。
この設定から、次のようなファイルが生成されます。

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 なので、そのファイルを含むディレクトリ以下を読み込むようにします。

config/importmap.rb
pin_all_from "app/javascript/i18n-js", under: "i18n-js"

ここが割と重要なのですが、ディレクトリ名を i18n-js としています。最初 i18n としたのですが、その場合 import I18n from 'i18n/translations' によって読み込むことができませんでした。しばらくハマったのですが、原因は i18n-js gem が全く同じパスで asset pipeline にファイルを配置しているため、そちらが読み込まれてしまっている、というものでした。
(ちなみにそっちのファイルの中身はこれ)

i18n-js が配置している translations.js
//= require i18n/shims
//= require i18n
//= require i18n/filtered

なので i18n 以外のディレクトリにしましょう。

ここまでの対応で、各 JavaScript ファイルから I18n.t() が使えるようになったはずです。

おまけ

i18n-js/translations.js ファイルは config/locales 以下のファイルから自動生成されるものなので、 git 管理配下から外しておいた方が良いでしょう。

  1. i18n-js ディレクトリに .keep を作成
  2. .gitignore に以下を追記
.gitignore
/app/javascript/i18n-js/*
!/app/javascript/i18n-js/.keep

本番環境にデプロイする際などは、rake i18n:js:export を実行して translations.js を生成しますが、毎回手で打つのは億劫なので、自分は assets:precompile タスクの直前に実行されるようにしました。

lib/tasks/i18n.rake
Rake::Task['assets:precompile'].enhance ['i18n:js:export']

参考記事

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0