rspec 中的 i18n 翻译

cau*_*eld 5 rspec ruby-on-rails internationalization

我想将我的测试与内化隔离开来。我使用 rails 3.2.8 和 rspec 2.11.1

我把这段代码 spec/support/translations.rb

module I18nHelpers
  def with_translations(locale, translations)
    I18n.backend.store_translations locale, translations
    yield
  ensure
    I18n.reload!
  end
Run Code Online (Sandbox Code Playgroud)

结尾

RSpec.configure do |config|
  config.include I18nHelpers
end
Run Code Online (Sandbox Code Playgroud)

然后我测试应用程序助手:

describe ApplicationHelper do
  context "messages" do
    it "show body" do
       with_translations :en, navigation: {messages: 'foo'} do
           concat messages_navigation
           assert_test 'span', 'foo'
       end
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

但是这个测试随着消息而下降

Failure/Error: assert_select 'span', text: /foo/
     MiniTest::Assertion:
        </foo/> expected but was
        <"Messages">.
Run Code Online (Sandbox Code Playgroud)

“消息”来自我真实的config/locales/en.yml 我从控制台测试 #store_translations 并且它有效。但是当我在 helper 模块中的 wordp I18n.t(translations.key.first)之前放一行时ensure,它显示了旧的翻译。

谢谢你的帮助!

Ant*_*gun 5

要与I18n您完全隔离,可能需要像这样切换后端:

def with_translations(locale, translations)
  original_backend = I18n.backend

  I18n.backend = I18n::Backend::KeyValue.new Hash.new, true
  I18n.backend.store_translations locale, translations

  yield
ensure
  I18n.backend = original_backend
end
Run Code Online (Sandbox Code Playgroud)


Chr*_*erg 3

我已经深入研究了这个问题,我想我有一个粗略的答案。该问题似乎是由以下事实引起的:在第一次调用之前,rails 不会在语言环境文件中加载翻译I18n.t

这有点旧,但仍然相关:

https://groups.google.com/forum/?fromgroups=#!msg/rails-i18n/QFe0GDVRIa0/G7K09NAgqJMJ

我们考虑了很多不同的方法,最终我们的解决方案是将实际翻译加载推迟到最新的可能点。因此,客户端(如 Rails)只会将翻译源注册到 I18n,并且当需要查找第一个翻译时,后端实际上会延迟加载它们。

所以基本上,现有的翻译仅在您调用 时才会加载I18n.t。我在控制台中玩耍时发现了这一点,当时我注意到非常奇怪的行为:

irb(main):001:0> def with_translations(locale, translations)
irb(main):002:1>   I18n.backend.store_translations locale, translations
irb(main):003:1>   yield
irb(main):004:1> ensure
irb(main):005:1*   I18n.reload!
irb(main):006:1> end
=> nil
irb(main):007:0> I18n.reload!
=> false
irb(main):008:0> with_translations(:en, { :messages => "foo" }) { puts I18n.t :messages }
Messages
=> nil
irb(main):009:0> I18n.t :some_other_string
=> "Some translation"
irb(main):010:0> with_translations(:en, { :messages => "foo" }) { puts I18n.t :messages }
foo
=> nil
Run Code Online (Sandbox Code Playgroud)

发生的事情与块无关ensure。我们可以删除它,同样的事情也会发生:

irb(main):011:0> I18n.reload!
=> false
irb(main):012:0> def with_translations(locale, translations)
irb(main):013:1>   I18n.backend.store_translations locale, translations
irb(main):014:1>   yield
irb(main):015:1> end    
=> nil
irb(main):016:0> with_translations(:en, { :messages => "foo" }) { puts I18n.t :messages }
Messages
Run Code Online (Sandbox Code Playgroud)

即使没有重新加载,它仍然会输出原始字符串,因为I18n.backend.store_translations调用时调用中的翻译会被原始字符串覆盖I18n.t。但是,如果您在上述代码I18n.t 之前调用,它将起作用(并保留翻译,因为没有ensure块重新加载翻译)。

所以基本上,答案就是调用I18n.t一个实际的翻译字符串来触发 Rails 加载现有的翻译,然后覆盖您想要更改的翻译:

def with_translations(locale, translations)
  I18n.t translations.keys.first         # to make sure translations are loaded
  I18n.backend.store_translations locale, translations
  yield
ensure
  I18n.reload!
end
Run Code Online (Sandbox Code Playgroud)

我只在控制台中尝试过此操作,但我相信它也适用于您的 rspec 测试。如果有人对这个问题有更深入的见解,我很想听听他们的意见。