我想将我的测试与内化隔离开来。我使用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
时,它会显示旧的翻译。
感谢您的帮助!
答案 0 :(得分: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.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
我只是在控制台中试过这个,但我相信它也适用于你的rspec测试。如果有人对这个问题有更深入的了解,我会很想听到它们。
答案 1 :(得分:3)
要与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
yeild
ensure
I18n.backend = original_backend
end
答案 2 :(得分:0)
在遇到类似问题之后,我最终写了一个这样的帮手:
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