【问题标题】:i18n translations in rspecrspec 中的 i18n 翻译
【发布时间】:2012-10-09 09:43:35
【问题描述】:

我想将我的测试与内化隔离开来。我使用 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

结束

RSpec.configure do |config|
  config.include I18nHelpers
end

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

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

但是这个测试是有消息的

Failure/Error: assert_select 'span', text: /foo/
     MiniTest::Assertion:
        </foo/> expected but was
        <"Messages">.

'Messages'来自我的真实config/locales/en.yml 我从控制台测试#store_translations 并且它有效。但是当我在帮助模块中将p I18n.t(translations.key.first) 放在ensure 之前的行时,它会显示旧的翻译。

感谢您的帮助!

【问题讨论】:

  • 这是你在这里偶然发现的一件非常奇怪的事情。我一直在控制台中玩耍,但不确定发生了什么。 ensureyield 调用之后的任何内容之前被调用,这不应该发生......
  • 您还在为此苦苦挣扎吗?我一直在摸索,但还没有一个明确的答案。
  • @shioyama,现在我在Messages word 上测试我的模块,现在也不知道如何修复它。
  • 我明白了。我对这个问题很感兴趣,因为我想以这种方式将我的测试与国际化隔离开来。这应该工作......非常奇怪。我会继续努力的。

标签: ruby-on-rails internationalization rspec


【解决方案1】:

要与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

【讨论】:

    【解决方案2】:

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

    这有点旧,但仍然相关:

    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
    

    发生的事情与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
    

    即使没有重新加载,它仍然会吐出原始字符串,因为在调用I18n.t 时,I18n.backend.store_translations 调用中的翻译被原始字符串覆盖。但是,如果您在上述代码之前调用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
    

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

    【讨论】:

      【解决方案3】:

      在遇到类似问题后,我最终写了一个这样的助手:

      助手

      module TranslationSupport
        def with_translation(replacement_translation)
          I18n.t(".").deep_merge!(replacement_translation)
          begin
            yield
          ensure
            I18n.reload!
          end
        end
      end
      

      这里的快捷方式是先用I18n.t(".") 初始化后端,然后合并所需的值。

      正如其他答案所暗示的那样,或者可以初始化 i18n 后端,然后使用 I18n.backend.store_translations 更新值。这种方法的缺点是需要将语言环境作为参数传递。

      用法

      这个助手可以像这样使用它:

      require "rails_helper"
      require "support/translation"
      
      RSpec.describe "testing a view with overridden translations" do
        include TranslationSupport
      
        it "works" do
          translations = {
            homepage: {
              index: {
                label: "Overridden"
              }
            }
          }
      
          with_translation(translations) do
            # Your action
          end
      
          # Expectations
        end
      end
      

      如果您不想每次都包含帮助器:

      RSpec.configure do |config|
        config.include TranslationSupport
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-11-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-22
        • 1970-01-01
        • 1970-01-01
        • 2012-11-11
        相关资源
        最近更新 更多