translate.js をフロントエンドでバンドルするようにする
Carely は企業労務のための SaaS で、利用するのは導入企業の「人事労務担当者」と「従業員」の方たちです。特に「従業員」に関してはすべてのユーザーがきちんと使える事が前提となっており、 i18n への対応を行っています
もともとが Ruby on Rails のアプリだったため、locale の設定は i18n を使ってなされているんですが、これはフロントエンド側ではそのままでは利用する事ができません。そのため、 i18n-js を利用してフロントエンド向けの locale を生成しています
ここまでは良くある実装だと思うのですが、この locale 情報が Ruby on Rails から window.I18n オブジェクトを経由して渡されているためフロントエンドが Rails と密結合になるポイントになっていました
まずは app/assets/javascripts/application.js など Rails の sprockets で読み込んでいる箇所を削除します
- //= require i18n
- //= require i18n/translations
また slim 上で I18n のロケールを指定している箇所もあったので削除します
- javascript:
- I18n.defaultLocale = "#{I18n.default_locale}";
- I18n.locale = "#{I18n.locale}";
あとはドキュメントの通りに Vue.js のアプリケーション上で読み込んでいきます。以下のようなファイルを共通部分に追加します
// App.ts
import I18n from 'i18n-js'
I18n.defaultLocale = 'ja'
I18n.locale = I18n.defaultLocale
require('@/gen/i18n/translations') // `rake i18n:js:export` で出力されたものを読み込む
また、 Rails 側で読み込むと window.I18n が登録されます。フロントエンドのアプリケーション側でもそれを直接参照していたため、以下のように Vue.js 側で設定します。また、リントエラーが発生しないように .eslintrc の globals に I18n を追加します
// App.ts
window.I18n = window.I18n || I18n
# .eslint
{
...
"globals": {
"I18n": true,
...
},
...
}
このグローバルの I18n はいずれ消したいので型定義に @deprecated のアノテーションをつけます
// global.d.ts
/**
* i18n-js がグローバルに設定する Rails の他言語対応を取り扱うためのオブジェクト
*
* @deprecated
*/
declare var I18n: typeof import('i18n-js')
このような感じで剥がす事ができました。実際はもう少しレガシーコードを削除したり、言語設定を Rails から slim 経由で渡したりとゴニョゴニョしましたが、大枠はこんな感じです
互換性のために window.I18n は残っていますし、型情報なども利用できていません。ひとまず webpack の世界で完結できるようになったので、さらに改善していきます
この記事は iCARE の技術顧問がどんな事をやっているか - 2021アドベントカレンダー の18日目の記事です