Site cover image
i18n-tasks 動的キーに配列やハッシュを使うと認識されない問題

Ruby on Rails アプリケーションにおいて i18n gem を使って翻訳を導入しているケースは少なくないでしょう。

i18n gem と一緒に採用されるケースが多いのが i18n-tasks gem です。この gem は未定義の翻訳キー(missing keys)や、定義しているのに使用していない翻訳キー(unused keys)をチェックしてくれます。

i18n-tasks を使っているとき、ある特定のキーで下記のような正規表現のエラーが起きたり unused として認識されないケースがありました。

RegexpError: premature end of char-class: /\A...\z/

このエントリでは、i18n-tasks で特定のキーで正規表現のエラーとなったり unused となってしまう原因をライブラリのコードを読みながら解説します。

premature end of char-class は、正規表現の character class [] において、閉じ括弧 ] が無い場合に起こるエラーです。

この問題はすでに報告されていて、動的キー(dynamic keys)として string interplation #{} の中で下記のようにハッシュ形式の呼び出しを行うと発生します。

t("loopup.something.in.#{somearray["element"]}")

Issue で報告されているエラーをよく見てみると、 (lookup\.something\.in\.somearray[|) のように、中途半端な正規表現の character class が混じっていることに気が付きます。

これが premature end of char-class の原因ですね。

次の疑問は、なぜ somearray[ のように中途半端なところで切れてしまったのかということです。

推理を働かせてみると、どうやらダブルクォート " が怪しそうです。前から順に " を見ていって、2個目の " が出てきたところで切れば末尾が somearray[ となるからです。

お気付きの通り、この問題はハッシュキーとしてダブルクォート " を使っている場合に発生します。

したがって、とりあえずこの問題を回避するには、ハッシュキーをシングルクォート ' に変更するか、下記のようにハッシュの内容をいったん変数に入れてから渡すことが有効です。

<% some_key = somearray["element"] %>
<%= t("loopup.something.in.#{some_key}") %>

原因をコードで探しに行く前に i18n-tasks の仕様を把握しておきます。

dynamic keys によると i18n-tasks には strict モードと no-strict モードがあるようで、 t "cats.#{cat}.name" のような形で動的キーを使い、翻訳キーとして cats.tenderlove.name が存在する場合、

  • strict モードでは翻訳キーは未使用と認識する(unused としてレポートする)
  • no-strict モードでは翻訳キーは使用済みと認識する(unused としてレポートしない)

という違いがあるようです。今回は no-strict モードでの話なので no-strict として話を続けます。

バックトレースを追ってコードを読んでいくと、やがてそれらしい正規表現に行き着きます。

module I18n::Tasks::Scanners
  module RubyKeyLiterals
    LITERAL_RE = /:?".+?"|:?'.+?'|:\w+/.freeze

この正規表現パターンでは、3つのパターンを OR で結合しています。すなわち :?".+?":?'.+?':\w+ です。

前から順に、

  1. "some_key":"some_key"
  2. 'some_key':'some_key'
  3. :some_key

のようなキーを想定しています。

このパターンに今回問題となっている "loopup.something.in.#{somearray["element"]}" を渡すと、末尾が somearray[" のようになります。どうやらここが原因で間違いないようです。

以上です。

このエントリでは、i18n-tasks で特定のキーで正規表現のエラーとなったり unused となってしまう原因をライブラリのコードを読みながら解説しました。

Thank you!
Thank you!
URLをコピーしました

コメントを送る

コメントはブログオーナーのみ閲覧できます