在 Rails 中设置每个请求 i18n 回退?

Set per request i18n fallbacks in Rails?

我有一个多国 Rails 应用程序。我需要为每个请求设置 i18n 回退架构。这可能吗?如何实现?

UPD

class Country < ApplicationRecord
  # String attribute "languages" (array)
end

class CountriesController < ApplicationController

  def show
    @country = Country.find params[:id]

    I18n.fallbacks = {
      @country.languages.first => @country.languages.second
    } # This does not work

    render 'show'
  end
end

稍微试验一下(使用 Rails 6),可以使用简单(默认)后端更改回退,但这样做 不是 线程-安全,如果您根据每个请求执行此操作,则可能会导致问题。这有点违反直觉——设置 I18n.locale 是为每个请求动态设置区域设置的记录方式,因此很自然地假设回退会以相同的方式工作。但是,来自 i18n 来源:

The only configuration value that is not global and scoped to thread is :locale.

即便如此,措辞也不是很清楚。但确实locale定义为实例变量,其他所有配置属性都是@@class变量。

I18n 的 Rails 指南说简单(默认)后端被设计为只做“可能工作的最简单的事情”,但该框架允许插入超出此范围的自定义后端.因此,实现结果的最佳方法是找到(或创建)一个以线程安全方式支持每个请求回退的后端。


作为参考,如果有人确实需要在初始化程序之外更改语言后备(同样,这是全局的),fallbacks.map()会这样做:

I18n.fallbacks.map(:ca => :"es-ES")

我原来的回答提到直接摆弄 fallback 哈希,但使用 .map() 保留回退到默认语言环境。

除了 rmlockerd 所说的,由于 fallbacks 是一个 class 变量,我建议您在每次请求后恢复回退,以确保您不会不小心将其泄露给其他请求在同一个服务器实例中。你可以这样做:

around_action :restore_i18n_fallbacks

# ...

private

def restore_i18n_fallbacks(&action)
  original_fallbacks = I18n.fallbacks
  begin
    action.call
  ensure
    I18n.fallbacks = original_fallbacks
  end
end

(代码未经测试但应该可以工作或相当接近工作。)