log

rails の i18n をフィーチャートグルで制御する

この記事は SmartHR AdventCalendar の7日目です。

最近は機能開発をする際にフィーチャートグルを利用しています。なぜフィーチャートグルを使うのかを書き始めるとそれだけで一記事消費してしまいそうなので多くは語りませんが、今ではなくてはならないものと感じています。

ですが実際にはフィーチャートグルの適用が難しいケースがあります。例えば railsi18n です。YAML で定義している翻訳をフィーチャートグルのON/OFFで差し替えたい、となるとなかなか面倒です。i18n は以下のように YAML で定義されているため、そこに Ruby のコードを差し込むことはできません。

config/locales/en.yml

en:
  hello: "Hello world"

ですが、実は i18nYAML だけでなく Ruby ファイルもサポートしています(参考:Rails 国際化 (i18n) API - Railsガイド)。

そこで、フィーチャートグルで翻訳を切り替えられないか試してみました。環境は Ruby 3.0.3, Rails 6.1.4.1 です。

ちなみに今回はフィーチャートグルっぽく動くものとして以下のようなクラスを準備しました。あくまで「それっぽいもの」です。

app/models/setting.rb

class Setting
  class << self
    def awesome_feature_enabled?
      unless defined?(@awesome_feature_enabled)
        @awesome_feature_enabled = false
      end

      @awesome_feature_enabled
    end

    def awesome_feature_enabled!
      @awesome_feature_enabled = true
    end

    def awesome_feature_disabled!
      @awesome_feature_enabled = false
    end
  end
end

とりあえず翻訳の定義はそのままに .rb に置き換えてみます。

config/locales/en.rb

{
  en: {
    hello: "Hello world"
  }
}

まずはこれで動くか確認します。

$ bin/rails c
irb(main):001:0> I18n.t('hello')
=> "Hello world"

動きますね。ですが、これだけだと記述量が増えただけで特に旨味はありません。そこで、フィーチャートグルの返り値で翻訳を切り替えてみます。

config/locales/en.rb

{
  en: {
    hello: -> { Setting.awesome_feature_enabled? ? "Hello feature toggle" : "Hello world" }
  }
}

動かしてみます。

$ bin/rails c
irb(main):001:0> I18n.t('hello')
/Users/yono/sample/config/locales/en.rb:3:in `block in load_rb': wrong number of arguments (given 1, expected 0) (ArgumentError)

引数が足りないというエラーですね。適当に足してみましょう。

config/locales/en.rb

{
  en: {
    hello: -> (x) { Setting.awesome_feature_enabled? ? "Hello feature toggle" : "Hello world" }
  }
}

これでどうでしょうか。

$ bin/rails c
irb(main):001:0> I18n.t('hello')
=> "Hello world"
irb(main):002:0> Setting.awesome_feature_enabled!
=> true
irb(main):003:0> I18n.t('hello')
=> "Hello feature toggle"
irb(main):004:0> Setting.awesome_feature_disabled!
=> false
irb(main):005:0> I18n.t('hello')
=> "Hello world"

動きました。フィーチャートグルのON/OFFで返り値の切り替えもできてますね。よさそうです。

ただ、引数の中身が何者かわからないのは気になりますね。確認しておきましょう。

config/locales/en.rb

{
  en: {
    hello: -> (x) { x }
  }
}

これで実行してみます。

$ bin/rails c
irb(main):001:0> I18n.t('hello')
=> "hello"

引数にはi18nのキーが含まれているようですね。変数名を直しておきます。

config/locales/en.rb

{
  en: {
    hello: -> (key) { Setting.awesome_feature_enabled? ? "Hello Feature toggle" : "Hello world" }
  }
}

というわけで、i18nもフィーチャートグルで切り替えられるようになりました。こちらからは以上です。