actionview 5.1.4 → 6.1.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionview might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +199 -168
- data/MIT-LICENSE +1 -1
- data/README.rdoc +7 -5
- data/lib/action_view.rb +10 -4
- data/lib/action_view/base.rb +87 -23
- data/lib/action_view/buffers.rb +17 -0
- data/lib/action_view/cache_expiry.rb +52 -0
- data/lib/action_view/context.rb +7 -11
- data/lib/action_view/dependency_tracker.rb +12 -4
- data/lib/action_view/digestor.rb +24 -23
- data/lib/action_view/flows.rb +2 -1
- data/lib/action_view/gem_version.rb +4 -2
- data/lib/action_view/helpers.rb +4 -2
- data/lib/action_view/helpers/active_model_helper.rb +9 -4
- data/lib/action_view/helpers/asset_tag_helper.rb +220 -57
- data/lib/action_view/helpers/asset_url_helper.rb +28 -23
- data/lib/action_view/helpers/atom_feed_helper.rb +5 -2
- data/lib/action_view/helpers/cache_helper.rb +39 -28
- data/lib/action_view/helpers/capture_helper.rb +13 -7
- data/lib/action_view/helpers/controller_helper.rb +3 -1
- data/lib/action_view/helpers/csp_helper.rb +26 -0
- data/lib/action_view/helpers/csrf_helper.rb +5 -3
- data/lib/action_view/helpers/date_helper.rb +78 -33
- data/lib/action_view/helpers/debug_helper.rb +4 -2
- data/lib/action_view/helpers/form_helper.rb +357 -106
- data/lib/action_view/helpers/form_options_helper.rb +45 -39
- data/lib/action_view/helpers/form_tag_helper.rb +42 -27
- data/lib/action_view/helpers/javascript_helper.rb +28 -12
- data/lib/action_view/helpers/number_helper.rb +16 -8
- data/lib/action_view/helpers/output_safety_helper.rb +3 -1
- data/lib/action_view/helpers/rendering_helper.rb +20 -9
- data/lib/action_view/helpers/sanitize_helper.rb +15 -19
- data/lib/action_view/helpers/tag_helper.rb +100 -24
- data/lib/action_view/helpers/tags.rb +3 -1
- data/lib/action_view/helpers/tags/base.rb +30 -21
- data/lib/action_view/helpers/tags/check_box.rb +3 -2
- data/lib/action_view/helpers/tags/checkable.rb +4 -2
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +2 -1
- data/lib/action_view/helpers/tags/collection_helpers.rb +2 -1
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +2 -1
- data/lib/action_view/helpers/tags/collection_select.rb +3 -1
- data/lib/action_view/helpers/tags/color_field.rb +4 -3
- data/lib/action_view/helpers/tags/date_field.rb +3 -2
- data/lib/action_view/helpers/tags/date_select.rb +5 -4
- data/lib/action_view/helpers/tags/datetime_field.rb +3 -2
- data/lib/action_view/helpers/tags/datetime_local_field.rb +3 -2
- data/lib/action_view/helpers/tags/datetime_select.rb +2 -0
- data/lib/action_view/helpers/tags/email_field.rb +2 -0
- data/lib/action_view/helpers/tags/file_field.rb +2 -0
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +3 -1
- data/lib/action_view/helpers/tags/hidden_field.rb +2 -0
- data/lib/action_view/helpers/tags/label.rb +6 -5
- data/lib/action_view/helpers/tags/month_field.rb +3 -2
- data/lib/action_view/helpers/tags/number_field.rb +2 -0
- data/lib/action_view/helpers/tags/password_field.rb +2 -0
- data/lib/action_view/helpers/tags/placeholderable.rb +2 -0
- data/lib/action_view/helpers/tags/radio_button.rb +3 -2
- data/lib/action_view/helpers/tags/range_field.rb +2 -0
- data/lib/action_view/helpers/tags/search_field.rb +2 -0
- data/lib/action_view/helpers/tags/select.rb +4 -3
- data/lib/action_view/helpers/tags/tel_field.rb +2 -0
- data/lib/action_view/helpers/tags/text_area.rb +3 -1
- data/lib/action_view/helpers/tags/text_field.rb +3 -2
- data/lib/action_view/helpers/tags/time_field.rb +3 -2
- data/lib/action_view/helpers/tags/time_select.rb +2 -0
- data/lib/action_view/helpers/tags/time_zone_select.rb +3 -1
- data/lib/action_view/helpers/tags/translator.rb +3 -6
- data/lib/action_view/helpers/tags/url_field.rb +2 -0
- data/lib/action_view/helpers/tags/week_field.rb +3 -2
- data/lib/action_view/helpers/text_helper.rb +11 -10
- data/lib/action_view/helpers/translation_helper.rb +102 -52
- data/lib/action_view/helpers/url_helper.rb +150 -32
- data/lib/action_view/layouts.rb +15 -15
- data/lib/action_view/log_subscriber.rb +32 -15
- data/lib/action_view/lookup_context.rb +67 -39
- data/lib/action_view/model_naming.rb +2 -0
- data/lib/action_view/path_set.rb +5 -12
- data/lib/action_view/railtie.rb +46 -21
- data/lib/action_view/record_identifier.rb +4 -3
- data/lib/action_view/renderer/abstract_renderer.rb +144 -11
- data/lib/action_view/renderer/collection_renderer.rb +196 -0
- data/lib/action_view/renderer/object_renderer.rb +34 -0
- data/lib/action_view/renderer/partial_renderer.rb +33 -283
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +64 -17
- data/lib/action_view/renderer/renderer.rb +61 -4
- data/lib/action_view/renderer/streaming_template_renderer.rb +14 -8
- data/lib/action_view/renderer/template_renderer.rb +36 -26
- data/lib/action_view/rendering.rb +57 -38
- data/lib/action_view/routing_url_for.rb +15 -12
- data/lib/action_view/tasks/cache_digests.rake +2 -0
- data/lib/action_view/template.rb +69 -76
- data/lib/action_view/template/error.rb +32 -18
- data/lib/action_view/template/handlers.rb +4 -2
- data/lib/action_view/template/handlers/builder.rb +5 -6
- data/lib/action_view/template/handlers/erb.rb +20 -19
- data/lib/action_view/template/handlers/erb/erubi.rb +17 -9
- data/lib/action_view/template/handlers/html.rb +3 -1
- data/lib/action_view/template/handlers/raw.rb +4 -2
- data/lib/action_view/template/html.rb +8 -7
- data/lib/action_view/template/inline.rb +22 -0
- data/lib/action_view/template/raw_file.rb +25 -0
- data/lib/action_view/template/renderable.rb +24 -0
- data/lib/action_view/template/resolver.rb +194 -152
- data/lib/action_view/template/sources.rb +13 -0
- data/lib/action_view/template/sources/file.rb +17 -0
- data/lib/action_view/template/text.rb +5 -4
- data/lib/action_view/template/types.rb +3 -1
- data/lib/action_view/test_case.rb +38 -30
- data/lib/action_view/testing/resolvers.rb +20 -27
- data/lib/action_view/unbound_template.rb +31 -0
- data/lib/action_view/version.rb +2 -0
- data/lib/action_view/view_paths.rb +61 -40
- data/lib/assets/compiled/rails-ujs.js +84 -23
- metadata +34 -23
- data/lib/action_view/helpers/record_tag_helper.rb +0 -21
- data/lib/action_view/template/handlers/erb/deprecated_erubis.rb +0 -9
- data/lib/action_view/template/handlers/erb/erubis.rb +0 -81
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "action_view/helpers/tags/checkable"
|
2
4
|
|
3
5
|
module ActionView
|
@@ -15,13 +17,12 @@ module ActionView
|
|
15
17
|
options = @options.stringify_keys
|
16
18
|
options["type"] = "radio"
|
17
19
|
options["value"] = @tag_value
|
18
|
-
options["checked"] = "checked" if input_checked?(
|
20
|
+
options["checked"] = "checked" if input_checked?(options)
|
19
21
|
add_default_name_and_id_for_value(@tag_value, options)
|
20
22
|
tag("input", options)
|
21
23
|
end
|
22
24
|
|
23
25
|
private
|
24
|
-
|
25
26
|
def checked?(value)
|
26
27
|
value.to_s == @tag_value.to_s
|
27
28
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionView
|
2
4
|
module Helpers
|
3
5
|
module Tags # :nodoc:
|
@@ -13,7 +15,7 @@ module ActionView
|
|
13
15
|
|
14
16
|
def render
|
15
17
|
option_tags_options = {
|
16
|
-
selected: @options.fetch(:selected) { value
|
18
|
+
selected: @options.fetch(:selected) { value.nil? ? "" : value },
|
17
19
|
disabled: @options[:disabled]
|
18
20
|
}
|
19
21
|
|
@@ -27,13 +29,12 @@ module ActionView
|
|
27
29
|
end
|
28
30
|
|
29
31
|
private
|
30
|
-
|
31
32
|
# Grouped choices look like this:
|
32
33
|
#
|
33
34
|
# [nil, []]
|
34
35
|
# { nil => [] }
|
35
36
|
def grouped_choices?
|
36
|
-
!@choices.
|
37
|
+
!@choices.blank? && @choices.first.respond_to?(:last) && Array === @choices.first.last
|
37
38
|
end
|
38
39
|
end
|
39
40
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "action_view/helpers/tags/placeholderable"
|
2
4
|
|
3
5
|
module ActionView
|
@@ -14,7 +16,7 @@ module ActionView
|
|
14
16
|
options["cols"], options["rows"] = size.split("x") if size.respond_to?(:split)
|
15
17
|
end
|
16
18
|
|
17
|
-
content_tag("textarea", options.delete("value") { value_before_type_cast
|
19
|
+
content_tag("textarea", options.delete("value") { value_before_type_cast }, options)
|
18
20
|
end
|
19
21
|
end
|
20
22
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "action_view/helpers/tags/placeholderable"
|
2
4
|
|
3
5
|
module ActionView
|
@@ -10,7 +12,7 @@ module ActionView
|
|
10
12
|
options = @options.stringify_keys
|
11
13
|
options["size"] = options["maxlength"] unless options.key?("size")
|
12
14
|
options["type"] ||= field_type
|
13
|
-
options["value"] = options.fetch("value") { value_before_type_cast
|
15
|
+
options["value"] = options.fetch("value") { value_before_type_cast } unless field_type == "file"
|
14
16
|
add_default_name_and_id(options)
|
15
17
|
tag("input", options)
|
16
18
|
end
|
@@ -22,7 +24,6 @@ module ActionView
|
|
22
24
|
end
|
23
25
|
|
24
26
|
private
|
25
|
-
|
26
27
|
def field_type
|
27
28
|
self.class.field_type
|
28
29
|
end
|
@@ -1,11 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionView
|
2
4
|
module Helpers
|
3
5
|
module Tags # :nodoc:
|
4
6
|
class TimeField < DatetimeField # :nodoc:
|
5
7
|
private
|
6
|
-
|
7
8
|
def format_date(value)
|
8
|
-
value
|
9
|
+
value&.strftime("%T.%L")
|
9
10
|
end
|
10
11
|
end
|
11
12
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionView
|
2
4
|
module Helpers
|
3
5
|
module Tags # :nodoc:
|
@@ -11,7 +13,7 @@ module ActionView
|
|
11
13
|
|
12
14
|
def render
|
13
15
|
select_content_tag(
|
14
|
-
time_zone_options_for_select(value
|
16
|
+
time_zone_options_for_select(value || @options[:default], @priority_zones, @options[:model] || ActiveSupport::TimeZone), @options, @html_options
|
15
17
|
)
|
16
18
|
end
|
17
19
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionView
|
2
4
|
module Helpers
|
3
5
|
module Tags # :nodoc:
|
@@ -14,13 +16,8 @@ module ActionView
|
|
14
16
|
translated_attribute || human_attribute_name
|
15
17
|
end
|
16
18
|
|
17
|
-
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
18
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
19
|
-
protected
|
20
|
-
|
21
|
-
attr_reader :object_name, :method_and_value, :scope, :model
|
22
|
-
|
23
19
|
private
|
20
|
+
attr_reader :object_name, :method_and_value, :scope, :model
|
24
21
|
|
25
22
|
def i18n_default
|
26
23
|
if model
|
@@ -1,11 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionView
|
2
4
|
module Helpers
|
3
5
|
module Tags # :nodoc:
|
4
6
|
class WeekField < DatetimeField # :nodoc:
|
5
7
|
private
|
6
|
-
|
7
8
|
def format_date(value)
|
8
|
-
value
|
9
|
+
value&.strftime("%Y-W%V")
|
9
10
|
end
|
10
11
|
end
|
11
12
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/string/filters"
|
2
4
|
require "active_support/core_ext/array/extract_options"
|
3
5
|
|
@@ -11,9 +13,9 @@ module ActionView
|
|
11
13
|
#
|
12
14
|
# ==== Sanitization
|
13
15
|
#
|
14
|
-
# Most text helpers
|
15
|
-
# This means HTML tags will appear in the page but all malicious
|
16
|
-
# Let's look at some examples using the +simple_format+ method:
|
16
|
+
# Most text helpers that generate HTML output sanitize the given input by default,
|
17
|
+
# but do not escape it. This means HTML tags will appear in the page but all malicious
|
18
|
+
# code will be removed. Let's look at some examples using the +simple_format+ method:
|
17
19
|
#
|
18
20
|
# simple_format('<a href="http://example.com/">Example</a>')
|
19
21
|
# # => "<p><a href=\"http://example.com/\">Example</a></p>"
|
@@ -126,7 +128,7 @@ module ActionView
|
|
126
128
|
# # => You searched for: <a href="search?q=rails">rails</a>
|
127
129
|
#
|
128
130
|
# highlight('<a href="javascript:alert(\'no!\')">ruby</a> on rails', 'rails', sanitize: false)
|
129
|
-
# # =>
|
131
|
+
# # => <a href="javascript:alert('no!')">ruby</a> on <mark>rails</mark>
|
130
132
|
def highlight(text, phrases, options = {})
|
131
133
|
text = sanitize(text) if options.fetch(:sanitize, true)
|
132
134
|
|
@@ -186,7 +188,7 @@ module ActionView
|
|
186
188
|
|
187
189
|
unless separator.empty?
|
188
190
|
text.split(separator).each do |value|
|
189
|
-
if value.match(regex)
|
191
|
+
if value.match?(regex)
|
190
192
|
phrase = value
|
191
193
|
break
|
192
194
|
end
|
@@ -226,7 +228,7 @@ module ActionView
|
|
226
228
|
# pluralize(2, 'Person', locale: :de)
|
227
229
|
# # => 2 Personen
|
228
230
|
def pluralize(count, singular, plural_arg = nil, plural: plural_arg, locale: I18n.locale)
|
229
|
-
word = if
|
231
|
+
word = if count == 1 || count.to_s.match?(/^1(\.0+)?$/)
|
230
232
|
singular
|
231
233
|
else
|
232
234
|
plural || singular.pluralize(locale)
|
@@ -257,7 +259,7 @@ module ActionView
|
|
257
259
|
# # => Once\r\nupon\r\na\r\ntime
|
258
260
|
def word_wrap(text, line_width: 80, break_sequence: "\n")
|
259
261
|
text.split("\n").collect! do |line|
|
260
|
-
line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1#{break_sequence}").
|
262
|
+
line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1#{break_sequence}").rstrip : line
|
261
263
|
end * break_sequence
|
262
264
|
end
|
263
265
|
|
@@ -420,11 +422,10 @@ module ActionView
|
|
420
422
|
def to_s
|
421
423
|
value = @values[@index].to_s
|
422
424
|
@index = next_index
|
423
|
-
|
425
|
+
value
|
424
426
|
end
|
425
427
|
|
426
428
|
private
|
427
|
-
|
428
429
|
def next_index
|
429
430
|
step_index(1)
|
430
431
|
end
|
@@ -444,7 +445,7 @@ module ActionView
|
|
444
445
|
# uses an instance variable of ActionView::Base.
|
445
446
|
def get_cycle(name)
|
446
447
|
@_cycles = Hash.new unless defined?(@_cycles)
|
447
|
-
|
448
|
+
@_cycles[name]
|
448
449
|
end
|
449
450
|
|
450
451
|
def set_cycle(name, cycle_object)
|
@@ -1,18 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "action_view/helpers/tag_helper"
|
2
|
-
require "active_support/core_ext/
|
3
|
-
require "i18n/exceptions"
|
4
|
+
require "active_support/core_ext/symbol/starts_ends_with"
|
4
5
|
|
5
6
|
module ActionView
|
6
7
|
# = Action View Translation Helpers
|
7
|
-
module Helpers
|
8
|
+
module Helpers #:nodoc:
|
8
9
|
module TranslationHelper
|
9
10
|
extend ActiveSupport::Concern
|
10
11
|
|
11
12
|
include TagHelper
|
12
13
|
|
13
14
|
included do
|
14
|
-
mattr_accessor :debug_missing_translation
|
15
|
-
self.debug_missing_translation = true
|
15
|
+
mattr_accessor :debug_missing_translation, default: true
|
16
16
|
end
|
17
17
|
|
18
18
|
# Delegates to <tt>I18n#translate</tt> but also performs three additional
|
@@ -56,74 +56,85 @@ module ActionView
|
|
56
56
|
# that include HTML tags so that you know what kind of output to expect
|
57
57
|
# when you call translate in a template and translators know which keys
|
58
58
|
# they can provide HTML values for.
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
59
|
+
#
|
60
|
+
# To access the translated text along with the fully resolved
|
61
|
+
# translation key, <tt>translate</tt> accepts a block:
|
62
|
+
#
|
63
|
+
# <%= translate(".relative_key") do |translation, resolved_key| %>
|
64
|
+
# <span title="<%= resolved_key %>"><%= translation %></span>
|
65
|
+
# <% end %>
|
66
|
+
#
|
67
|
+
# This enables annotate translated text to be aware of the scope it was
|
68
|
+
# resolved against.
|
69
|
+
#
|
70
|
+
def translate(key, **options)
|
71
|
+
return key.map { |k| translate(k, **options) } if key.is_a?(Array)
|
72
|
+
key = key&.to_s unless key.is_a?(Symbol)
|
63
73
|
|
64
|
-
|
65
|
-
options[:default]
|
74
|
+
alternatives = if options.key?(:default)
|
75
|
+
options[:default].is_a?(Array) ? options.delete(:default).compact : [options.delete(:default)]
|
66
76
|
end
|
67
77
|
|
68
|
-
|
69
|
-
|
70
|
-
# Note: `raise_error` refers to us re-raising the error in this method. I18n is forced to raise by default.
|
71
|
-
if options[:raise] == false
|
72
|
-
raise_error = false
|
73
|
-
i18n_raise = false
|
74
|
-
else
|
75
|
-
raise_error = options[:raise] || ActionView::Base.raise_on_missing_translations
|
76
|
-
i18n_raise = true
|
77
|
-
end
|
78
|
+
options[:raise] = true if options[:raise].nil? && ActionView::Base.raise_on_missing_translations
|
79
|
+
default = MISSING_TRANSLATION
|
78
80
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
unless name == :count && value.is_a?(Numeric)
|
83
|
-
html_safe_options[name] = ERB::Util.html_escape(value.to_s)
|
84
|
-
end
|
81
|
+
translation = while key || alternatives.present?
|
82
|
+
if alternatives.blank? && !options[:raise].nil?
|
83
|
+
default = NO_DEFAULT # let I18n handle missing translation
|
85
84
|
end
|
86
|
-
translation = I18n.translate(scope_key_by_partial(key), html_safe_options.merge(raise: i18n_raise))
|
87
85
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
keys = I18n.normalize_keys(e.locale, e.key, e.options[:scope])
|
99
|
-
title = "translation missing: #{keys.join('.')}"
|
100
|
-
|
101
|
-
interpolations = options.except(:default, :scope)
|
102
|
-
if interpolations.any?
|
103
|
-
title << ", " << interpolations.map { |k, v| "#{k}: #{ERB::Util.html_escape(v)}" }.join(", ")
|
86
|
+
key = scope_key_by_partial(key)
|
87
|
+
|
88
|
+
if html_safe_translation_key?(key)
|
89
|
+
html_safe_options ||= html_escape_translation_options(options)
|
90
|
+
translated = I18n.translate(key, **html_safe_options, default: default)
|
91
|
+
break html_safe_translation(translated) unless translated.equal?(MISSING_TRANSLATION)
|
92
|
+
else
|
93
|
+
translated = I18n.translate(key, **options, default: default)
|
94
|
+
break translated unless translated.equal?(MISSING_TRANSLATION)
|
104
95
|
end
|
105
96
|
|
106
|
-
|
97
|
+
break alternatives.first if alternatives.present? && !alternatives.first.is_a?(Symbol)
|
107
98
|
|
108
|
-
|
99
|
+
first_key ||= key
|
100
|
+
key = alternatives&.shift
|
109
101
|
end
|
102
|
+
|
103
|
+
if key.nil? && !first_key.nil?
|
104
|
+
translation = missing_translation(first_key, options)
|
105
|
+
key = first_key
|
106
|
+
end
|
107
|
+
|
108
|
+
block_given? ? yield(translation, key) : translation
|
110
109
|
end
|
111
110
|
alias :t :translate
|
112
111
|
|
113
112
|
# Delegates to <tt>I18n.localize</tt> with no additional functionality.
|
114
113
|
#
|
115
|
-
# See
|
114
|
+
# See https://www.rubydoc.info/github/svenfuchs/i18n/master/I18n/Backend/Base:localize
|
116
115
|
# for more information.
|
117
|
-
def localize(
|
118
|
-
I18n.localize(
|
116
|
+
def localize(object, **options)
|
117
|
+
I18n.localize(object, **options)
|
119
118
|
end
|
120
119
|
alias :l :localize
|
121
120
|
|
122
121
|
private
|
122
|
+
MISSING_TRANSLATION = Object.new
|
123
|
+
private_constant :MISSING_TRANSLATION
|
124
|
+
|
125
|
+
NO_DEFAULT = [].freeze
|
126
|
+
private_constant :NO_DEFAULT
|
127
|
+
|
128
|
+
def self.i18n_option?(name)
|
129
|
+
(@i18n_option_names ||= I18n::RESERVED_KEYS.to_set).include?(name)
|
130
|
+
end
|
131
|
+
|
123
132
|
def scope_key_by_partial(key)
|
124
|
-
if key
|
133
|
+
if key&.start_with?(".")
|
125
134
|
if @virtual_path
|
126
|
-
@
|
135
|
+
@_scope_key_by_partial_cache ||= {}
|
136
|
+
@_scope_key_by_partial_cache[@virtual_path] ||= @virtual_path.gsub(%r{/_?}, ".")
|
137
|
+
"#{@_scope_key_by_partial_cache[@virtual_path]}#{key}"
|
127
138
|
else
|
128
139
|
raise "Cannot use t(#{key.inspect}) shortcut because path is not available"
|
129
140
|
end
|
@@ -132,8 +143,47 @@ module ActionView
|
|
132
143
|
end
|
133
144
|
end
|
134
145
|
|
146
|
+
def html_escape_translation_options(options)
|
147
|
+
return options if options.empty?
|
148
|
+
html_safe_options = options.dup
|
149
|
+
|
150
|
+
options.each do |name, value|
|
151
|
+
unless TranslationHelper.i18n_option?(name) || (name == :count && value.is_a?(Numeric))
|
152
|
+
html_safe_options[name] = ERB::Util.html_escape(value.to_s)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
html_safe_options
|
157
|
+
end
|
158
|
+
|
135
159
|
def html_safe_translation_key?(key)
|
136
|
-
/(
|
160
|
+
/(?:_|\b)html\z/.match?(key)
|
161
|
+
end
|
162
|
+
|
163
|
+
def html_safe_translation(translation)
|
164
|
+
if translation.respond_to?(:map)
|
165
|
+
translation.map { |element| element.respond_to?(:html_safe) ? element.html_safe : element }
|
166
|
+
else
|
167
|
+
translation.respond_to?(:html_safe) ? translation.html_safe : translation
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def missing_translation(key, options)
|
172
|
+
keys = I18n.normalize_keys(options[:locale] || I18n.locale, key, options[:scope])
|
173
|
+
|
174
|
+
title = +"translation missing: #{keys.join(".")}"
|
175
|
+
|
176
|
+
options.each do |name, value|
|
177
|
+
unless name == :scope
|
178
|
+
title << ", " << name.to_s << ": " << ERB::Util.html_escape(value)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
if ActionView::Base.debug_missing_translation
|
183
|
+
content_tag("span", keys.last.to_s.titleize, class: "translation_missing", title: title)
|
184
|
+
else
|
185
|
+
title
|
186
|
+
end
|
137
187
|
end
|
138
188
|
end
|
139
189
|
end
|