1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Merge pull request #43415 from rails/rm-translate-on-controllers

Treat html suffix in controller translation
This commit is contained in:
Rafael Mendonça França 2021-10-12 14:19:21 -04:00 committed by GitHub
commit fee61e3abc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 96 additions and 38 deletions

View file

@ -1,3 +1,7 @@
* Treat html suffix in controller translation.
*Rui Onodera*, *Gavin Miller*
* Allow permitting numeric params.
Previously it was impossible to permit different fields on numeric parameters.

View file

@ -1,5 +1,7 @@
# frozen_string_literal: true
require "active_support/html_safe_translation"
module AbstractController
module Translation
mattr_accessor :raise_on_missing_translations, default: false
@ -22,7 +24,8 @@ module AbstractController
end
i18n_raise = options.fetch(:raise, self.raise_on_missing_translations)
I18n.translate(key, **options, raise: i18n_raise)
ActiveSupport::HtmlSafeTranslation.translate(key, **options, raise: i18n_raise)
end
alias :t :translate

View file

@ -20,6 +20,10 @@ module AbstractController
translation: {
index: {
foo: "bar",
hello: "<a>Hello World</a>",
hello_html: "<a>Hello World</a>",
interpolated_html: "<a>Hello %{word}</a>",
nested: { html: "<a>nested</a>" }
},
no_action: "no_action_tr",
},
@ -95,6 +99,43 @@ module AbstractController
assert_equal expected, @controller.l(time)
end
end
def test_translate_does_not_mark_plain_text_as_safe_html
@controller.stub :action_name, :index do
translation = @controller.t(".hello")
assert_equal "<a>Hello World</a>", translation
assert_equal false, translation.html_safe?
end
end
def test_translate_marks_translations_with_a_html_suffix_as_safe_html
@controller.stub :action_name, :index do
translation = @controller.t(".hello_html")
assert_equal "<a>Hello World</a>", translation
assert_equal true, translation.html_safe?
end
end
def test_translate_marks_translation_with_nested_html_key
@controller.stub :action_name, :index do
translation = @controller.t(".nested.html")
assert_equal "<a>nested</a>", translation
assert_equal true, translation.html_safe?
end
end
def test_translate_escapes_interpolations_in_translations_with_a_html_suffix
word_struct = Struct.new(:to_s)
@controller.stub :action_name, :index do
translation = @controller.t(".interpolated_html", word: "<World>")
assert_equal "<a>Hello &lt;World&gt;</a>", translation
assert_equal true, translation.html_safe?
translation = @controller.t(".interpolated_html", word: word_struct.new("<World>"))
assert_equal "<a>Hello &lt;World&gt;</a>", translation
assert_equal true, translation.html_safe?
end
end
end
end
end

View file

@ -1,6 +1,7 @@
# frozen_string_literal: true
require "action_view/helpers/tag_helper"
require "active_support/html_safe_translation"
module ActionView
# = Action View Translation Helpers
@ -84,14 +85,9 @@ module ActionView
key = scope_key_by_partial(key)
if html_safe_translation_key?(key)
html_safe_options ||= html_escape_translation_options(options)
translated = I18n.translate(key, **html_safe_options, default: default)
break html_safe_translation(translated) unless translated.equal?(MISSING_TRANSLATION)
else
translated = I18n.translate(key, **options, default: default)
break translated unless translated.equal?(MISSING_TRANSLATION)
end
translated = ActiveSupport::HtmlSafeTranslation.translate(key, **options, default: default)
break translated unless translated.equal?(MISSING_TRANSLATION)
if alternatives.present? && !alternatives.first.is_a?(Symbol)
break alternatives.first && I18n.translate(**options, default: alternatives)
@ -126,10 +122,6 @@ module ActionView
NO_DEFAULT = [].freeze
private_constant :NO_DEFAULT
def self.i18n_option?(name)
(@i18n_option_names ||= I18n::RESERVED_KEYS.to_set).include?(name)
end
def scope_key_by_partial(key)
if key&.start_with?(".")
if @virtual_path
@ -144,31 +136,6 @@ module ActionView
end
end
def html_escape_translation_options(options)
return options if options.empty?
html_safe_options = options.dup
options.each do |name, value|
unless TranslationHelper.i18n_option?(name) || (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)
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(key, options)
keys = I18n.normalize_keys(options[:locale] || I18n.locale, key, options[:scope])

View file

@ -0,0 +1,43 @@
# frozen_string_literal: true
module ActiveSupport
module HtmlSafeTranslation # :nodoc:
extend self
def translate(key, **options)
if html_safe_translation_key?(key)
html_safe_options = html_escape_translation_options(options)
translation = I18n.translate(key, **html_safe_options)
html_safe_translation(translation)
else
I18n.translate(key, **options)
end
end
private
def html_safe_translation_key?(key)
/(?:_|\b)html\z/.match?(key)
end
def html_escape_translation_options(options)
options.each do |name, value|
unless i18n_option?(name) || (name == :count && value.is_a?(Numeric))
options[name] = ERB::Util.html_escape(value.to_s)
end
end
end
def i18n_option?(name)
(@i18n_option_names ||= I18n::RESERVED_KEYS.to_set).include?(name)
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
end
end