diff --git a/actionview/lib/action_view/helpers/translation_helper.rb b/actionview/lib/action_view/helpers/translation_helper.rb index 89f984bc7f71890df26aa09e4e93af3f2f3c65b6..f292b475ef977f9fb5e0896ed38f0619480ba8b6 100644 --- a/actionview/lib/action_view/helpers/translation_helper.rb +++ b/actionview/lib/action_view/helpers/translation_helper.rb @@ -88,24 +88,15 @@ def translate(key, **options) fully_resolved_key = scope_key_by_partial(key) if html_safe_translation_key?(key) - html_safe_options = options.dup - - options.except(*I18n::RESERVED_KEYS).each do |name, value| - unless name == :count && value.is_a?(Numeric) - html_safe_options[name] = ERB::Util.html_escape(value.to_s) - end - end - + html_safe_options = html_escape_translation_options(options) html_safe_options[:default] = MISSING_TRANSLATION unless html_safe_options[:default].blank? translation = I18n.translate(fully_resolved_key, **html_safe_options.merge(raise: i18n_raise)) if translation.equal?(MISSING_TRANSLATION) translated_text = options[:default].first - elsif translation.respond_to?(:map) - translated_text = translation.map { |element| element.respond_to?(:html_safe) ? element.html_safe : element } else - translated_text = translation.respond_to?(:html_safe) ? translation.html_safe : translation + translated_text = html_safe_translation(translation) end else translated_text = I18n.translate(fully_resolved_key, **options.merge(raise: i18n_raise)) @@ -122,18 +113,7 @@ def translate(key, **options) else raise e if raise_error - keys = I18n.normalize_keys(e.locale, e.key, e.options[:scope]) - title = +"translation missing: #{keys.join('.')}" - - interpolations = options.except(:default, :scope) - - if interpolations.any? - title << ", " << interpolations.map { |k, v| "#{k}: #{ERB::Util.html_escape(v)}" }.join(", ") - end - - return title unless ActionView::Base.debug_missing_translation - - translated_fallback = content_tag("span", keys.last.to_s.titleize, class: "translation_missing", title: title) + translated_fallback = missing_translation(e, options) if block_given? yield(translated_fallback, scope_key_by_partial(key)) @@ -172,9 +152,46 @@ def scope_key_by_partial(key) end end + def html_escape_translation_options(options) + html_safe_options = options.dup + + options.except(*I18n::RESERVED_KEYS).each do |name, value| + unless name == :count && value.is_a?(Numeric) + html_safe_options[name] = ERB::Util.html_escape(value.to_s) + end + end + + html_safe_options + end + def html_safe_translation_key?(key) /(?:_|\b)html\z/.match?(key.to_s) end + + def html_safe_translation(translation) + if translation.respond_to?(:map) + translation.map { |element| element.respond_to?(:html_safe) ? element.html_safe : element } + else + translation.respond_to?(:html_safe) ? translation.html_safe : translation + end + end + + def missing_translation(error, options) + keys = I18n.normalize_keys(error.locale, error.key, error.options[:scope]) + + title = +"translation missing: #{keys.join(".")}" + + interpolations = options.except(:default, :scope) + if interpolations.any? + title << ", " << interpolations.map { |k, v| "#{k}: #{ERB::Util.html_escape(v)}" }.join(", ") + end + + if ActionView::Base.debug_missing_translation + content_tag("span", keys.last.to_s.titleize, class: "translation_missing", title: title) + else + title + end + end end end end diff --git a/actionview/test/template/translation_helper_test.rb b/actionview/test/template/translation_helper_test.rb index 9b0b2e3faa6054013e90223278507bb3b322b79b..29c5af6a60ea7dea614a2e8fcd2f449944ffceb8 100644 --- a/actionview/test/template/translation_helper_test.rb +++ b/actionview/test/template/translation_helper_test.rb @@ -102,6 +102,15 @@ def test_raises_missing_translation_message_with_raise_config_option ActionView::Base.raise_on_missing_translations = false end + def test_raise_arg_overrides_raise_config_option + ActionView::Base.raise_on_missing_translations = true + + expected = "translation missing: en.translations.missing" + assert_equal expected, translate(:"translations.missing", raise: false) + ensure + ActionView::Base.raise_on_missing_translations = false + end + def test_raises_missing_translation_message_with_raise_option assert_raise(I18n::MissingTranslationData) do translate(:"translations.missing", raise: true) @@ -164,6 +173,16 @@ def test_missing_translation_scoped_by_partial_yield_block assert_equal expected, view.render(template: "translations/templates/missing_yield_block").strip end + def test_missing_translation_scoped_by_partial_yield_block_without_debug_wrapper + old_debug_missing_translation = ActionView::Base.debug_missing_translation + ActionView::Base.debug_missing_translation = false + + expected = "translations.templates.missing_yield_block.missing: translation missing: en.translations.templates.missing_yield_block.missing" + assert_equal expected, view.render(template: "translations/templates/missing_yield_block").strip + ensure + ActionView::Base.debug_missing_translation = old_debug_missing_translation + end + def test_missing_translation_with_default_scoped_by_partial_yield_block expected = "translations.templates.missing_with_default_yield_block.missing: Default" assert_equal expected, view.render(template: "translations/templates/missing_with_default_yield_block").strip @@ -229,6 +248,12 @@ def test_translate_with_missing_default_and_raise_option end end + def test_translate_with_html_key_and_missing_default_and_raise_option + assert_raise(I18n::MissingTranslationData) do + translate(:"translations.missing_html", default: :"translations.missing_html", raise: true) + end + end + def test_translate_with_two_defaults_named_html translation = translate(:'translations.missing', default: [:'translations.missing_html', :'translations.hello_html']) assert_equal "Hello World", translation @@ -289,6 +314,11 @@ def test_translate_with_nil_default assert_nil translation end + def test_translate_bulk_lookup + translations = translate([:"translations.foo", :"translations.foo"]) + assert_equal ["Foo", "Foo"], translations + end + def test_translate_does_not_change_options options = {} if RUBY_VERSION >= "2.7"