5

テストを内面化から分離したい。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">.

「メッセージ」は私の実際のものでconfig/locales/en.yml 、コンソールから #store_translations をテストすると動作します。しかし、ヘルパーモジュールで単語のp I18n.t(translations.key.first)前に行を置くと、古い翻訳が表示されます。ensure

助けてくれてありがとう!

4

3 に答える 3

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
于 2013-03-26T10:16:40.867 に答える
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

何が起こっているかは、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.backend.store_translations呼び出し時の翻訳が元の文字列で上書きされるため、元の文字列が吐き出されますI18n.tI18n.t ただし、上記のコードの前に呼び出した場合は機能します (翻訳ensureをリロードするブロックがないため、翻訳は終了します)。

したがって、基本的には、実際の翻訳文字列を呼び出してレールをトリガーし、変更したい翻訳をオーバーライドするI18n.tに既存の翻訳をロードするだけです。

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 テストでも機能すると思います。誰かがこの問題についてより深い洞察を持っているなら、私は彼らの話を聞きたいと思っています.

于 2012-10-22T01:18:03.700 に答える