actionview 5.2.1.1 → 6.0.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 +4 -4
- data/CHANGELOG.md +222 -61
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -2
- data/lib/action_view.rb +3 -2
- data/lib/action_view/base.rb +107 -10
- data/lib/action_view/buffers.rb +15 -0
- data/lib/action_view/cache_expiry.rb +54 -0
- data/lib/action_view/context.rb +5 -9
- data/lib/action_view/digestor.rb +13 -23
- data/lib/action_view/gem_version.rb +3 -3
- data/lib/action_view/helpers.rb +0 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +7 -30
- data/lib/action_view/helpers/asset_url_helper.rb +4 -3
- data/lib/action_view/helpers/cache_helper.rb +18 -10
- data/lib/action_view/helpers/capture_helper.rb +4 -0
- data/lib/action_view/helpers/csp_helper.rb +4 -2
- data/lib/action_view/helpers/csrf_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +69 -25
- data/lib/action_view/helpers/form_helper.rb +241 -9
- data/lib/action_view/helpers/form_options_helper.rb +27 -18
- data/lib/action_view/helpers/form_tag_helper.rb +14 -9
- data/lib/action_view/helpers/javascript_helper.rb +9 -8
- data/lib/action_view/helpers/number_helper.rb +5 -0
- data/lib/action_view/helpers/output_safety_helper.rb +1 -1
- data/lib/action_view/helpers/rendering_helper.rb +6 -4
- data/lib/action_view/helpers/sanitize_helper.rb +12 -18
- data/lib/action_view/helpers/tag_helper.rb +7 -6
- data/lib/action_view/helpers/tags/base.rb +9 -5
- data/lib/action_view/helpers/tags/color_field.rb +1 -1
- data/lib/action_view/helpers/tags/translator.rb +1 -6
- data/lib/action_view/helpers/text_helper.rb +3 -3
- data/lib/action_view/helpers/translation_helper.rb +16 -12
- data/lib/action_view/helpers/url_helper.rb +15 -15
- data/lib/action_view/layouts.rb +5 -5
- data/lib/action_view/log_subscriber.rb +6 -6
- data/lib/action_view/lookup_context.rb +73 -31
- data/lib/action_view/path_set.rb +5 -10
- data/lib/action_view/railtie.rb +24 -1
- data/lib/action_view/record_identifier.rb +2 -2
- data/lib/action_view/renderer/abstract_renderer.rb +56 -3
- data/lib/action_view/renderer/partial_renderer.rb +66 -55
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +62 -16
- data/lib/action_view/renderer/renderer.rb +16 -4
- data/lib/action_view/renderer/streaming_template_renderer.rb +5 -5
- data/lib/action_view/renderer/template_renderer.rb +24 -18
- data/lib/action_view/rendering.rb +51 -31
- data/lib/action_view/routing_url_for.rb +12 -11
- data/lib/action_view/template.rb +102 -70
- data/lib/action_view/template/error.rb +21 -1
- data/lib/action_view/template/handlers.rb +27 -1
- data/lib/action_view/template/handlers/builder.rb +2 -2
- data/lib/action_view/template/handlers/erb.rb +17 -7
- data/lib/action_view/template/handlers/erb/erubi.rb +7 -3
- data/lib/action_view/template/handlers/html.rb +1 -1
- data/lib/action_view/template/handlers/raw.rb +2 -2
- data/lib/action_view/template/html.rb +14 -5
- data/lib/action_view/template/inline.rb +22 -0
- data/lib/action_view/template/raw_file.rb +28 -0
- data/lib/action_view/template/resolver.rb +136 -133
- 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 -3
- data/lib/action_view/test_case.rb +1 -1
- data/lib/action_view/testing/resolvers.rb +33 -20
- data/lib/action_view/unbound_template.rb +32 -0
- data/lib/action_view/view_paths.rb +25 -1
- data/lib/assets/compiled/rails-ujs.js +55 -16
- metadata +26 -19
- data/lib/action_view/helpers/record_tag_helper.rb +0 -23
@@ -22,7 +22,9 @@ module ActionView
|
|
22
22
|
mattr_accessor :embed_authenticity_token_in_remote_forms
|
23
23
|
self.embed_authenticity_token_in_remote_forms = nil
|
24
24
|
|
25
|
-
|
25
|
+
mattr_accessor :default_enforce_utf8, default: true
|
26
|
+
|
27
|
+
# Starts a form tag that points the action to a URL configured with <tt>url_for_options</tt> just like
|
26
28
|
# ActionController::Base#url_for. The method for the form defaults to POST.
|
27
29
|
#
|
28
30
|
# ==== Options
|
@@ -135,7 +137,8 @@ module ActionView
|
|
135
137
|
html_name = (options[:multiple] == true && !name.to_s.ends_with?("[]")) ? "#{name}[]" : name
|
136
138
|
|
137
139
|
if options.include?(:include_blank)
|
138
|
-
include_blank = options
|
140
|
+
include_blank = options[:include_blank]
|
141
|
+
options = options.except(:include_blank)
|
139
142
|
options_for_blank_options_tag = { value: "" }
|
140
143
|
|
141
144
|
if include_blank == true
|
@@ -144,15 +147,15 @@ module ActionView
|
|
144
147
|
end
|
145
148
|
|
146
149
|
if include_blank
|
147
|
-
option_tags = content_tag("option"
|
150
|
+
option_tags = content_tag("option", include_blank, options_for_blank_options_tag).safe_concat(option_tags)
|
148
151
|
end
|
149
152
|
end
|
150
153
|
|
151
154
|
if prompt = options.delete(:prompt)
|
152
|
-
option_tags = content_tag("option"
|
155
|
+
option_tags = content_tag("option", prompt, value: "").safe_concat(option_tags)
|
153
156
|
end
|
154
157
|
|
155
|
-
content_tag "select"
|
158
|
+
content_tag "select", option_tags, { "name" => html_name, "id" => sanitize_to_id(name) }.update(options.stringify_keys)
|
156
159
|
end
|
157
160
|
|
158
161
|
# Creates a standard text field; use these text fields to input smaller chunks of text like a username
|
@@ -163,6 +166,8 @@ module ActionView
|
|
163
166
|
# * <tt>:size</tt> - The number of visible characters that will fit in the input.
|
164
167
|
# * <tt>:maxlength</tt> - The maximum number of characters that the browser will allow the user to enter.
|
165
168
|
# * <tt>:placeholder</tt> - The text contained in the field by default which is removed when the field receives focus.
|
169
|
+
# If set to true, use a translation is found in the current I18n locale
|
170
|
+
# (through helpers.placeholders.<modelname>.<attribute>).
|
166
171
|
# * Any other key creates standard HTML attributes for the tag.
|
167
172
|
#
|
168
173
|
# ==== Examples
|
@@ -387,8 +392,8 @@ module ActionView
|
|
387
392
|
# * Any other key creates standard HTML options for the tag.
|
388
393
|
#
|
389
394
|
# ==== Examples
|
390
|
-
# radio_button_tag '
|
391
|
-
# # => <input id="
|
395
|
+
# radio_button_tag 'favorite_color', 'maroon'
|
396
|
+
# # => <input id="favorite_color_maroon" name="favorite_color" type="radio" value="maroon" />
|
392
397
|
#
|
393
398
|
# radio_button_tag 'receive_updates', 'no', true
|
394
399
|
# # => <input checked="checked" id="receive_updates_no" name="receive_updates" type="radio" value="no" />
|
@@ -575,7 +580,7 @@ module ActionView
|
|
575
580
|
# # => <fieldset class="format"><p><input id="name" name="name" type="text" /></p></fieldset>
|
576
581
|
def field_set_tag(legend = nil, options = nil, &block)
|
577
582
|
output = tag(:fieldset, options, true)
|
578
|
-
output.safe_concat(content_tag("legend"
|
583
|
+
output.safe_concat(content_tag("legend", legend)) unless legend.blank?
|
579
584
|
output.concat(capture(&block)) if block_given?
|
580
585
|
output.safe_concat("</fieldset>")
|
581
586
|
end
|
@@ -867,7 +872,7 @@ module ActionView
|
|
867
872
|
})
|
868
873
|
end
|
869
874
|
|
870
|
-
if html_options.delete("enforce_utf8") {
|
875
|
+
if html_options.delete("enforce_utf8") { default_enforce_utf8 }
|
871
876
|
utf8_enforcer_tag + method_tag
|
872
877
|
else
|
873
878
|
method_tag
|
@@ -15,8 +15,8 @@ module ActionView
|
|
15
15
|
"'" => "\\'"
|
16
16
|
}
|
17
17
|
|
18
|
-
JS_ESCAPE_MAP["\342\200\250".
|
19
|
-
JS_ESCAPE_MAP["\342\200\251".
|
18
|
+
JS_ESCAPE_MAP[(+"\342\200\250").force_encoding(Encoding::UTF_8).encode!] = "
"
|
19
|
+
JS_ESCAPE_MAP[(+"\342\200\251").force_encoding(Encoding::UTF_8).encode!] = "
"
|
20
20
|
|
21
21
|
# Escapes carriage returns and single and double quotes for JavaScript segments.
|
22
22
|
#
|
@@ -25,12 +25,13 @@ module ActionView
|
|
25
25
|
#
|
26
26
|
# $('some_element').replaceWith('<%= j render 'some/element_template' %>');
|
27
27
|
def escape_javascript(javascript)
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
javascript = javascript.to_s
|
29
|
+
if javascript.empty?
|
30
|
+
result = ""
|
31
31
|
else
|
32
|
-
"
|
32
|
+
result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"'])/u) { |match| JS_ESCAPE_MAP[match] }
|
33
33
|
end
|
34
|
+
javascript.html_safe? ? result.html_safe : result
|
34
35
|
end
|
35
36
|
|
36
37
|
alias_method :j, :escape_javascript
|
@@ -65,7 +66,7 @@ module ActionView
|
|
65
66
|
# <% end -%>
|
66
67
|
#
|
67
68
|
# If you have a content security policy enabled then you can add an automatic
|
68
|
-
# nonce value by passing
|
69
|
+
# nonce value by passing <tt>nonce: true</tt> as part of +html_options+. Example:
|
69
70
|
#
|
70
71
|
# <%= javascript_tag nonce: true do -%>
|
71
72
|
# alert('All is good')
|
@@ -83,7 +84,7 @@ module ActionView
|
|
83
84
|
html_options[:nonce] = content_security_policy_nonce
|
84
85
|
end
|
85
86
|
|
86
|
-
content_tag("script"
|
87
|
+
content_tag("script", javascript_cdata_section(content), html_options)
|
87
88
|
end
|
88
89
|
|
89
90
|
def javascript_cdata_section(content) #:nodoc:
|
@@ -100,6 +100,9 @@ module ActionView
|
|
100
100
|
# absolute value of the number.
|
101
101
|
# * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
|
102
102
|
# the argument is invalid.
|
103
|
+
# * <tt>:strip_insignificant_zeros</tt> - If +true+ removes
|
104
|
+
# insignificant zeros after the decimal separator (defaults to
|
105
|
+
# +false+).
|
103
106
|
#
|
104
107
|
# ==== Examples
|
105
108
|
#
|
@@ -117,6 +120,8 @@ module ActionView
|
|
117
120
|
# # => R$1234567890,50
|
118
121
|
# number_to_currency(1234567890.50, unit: "R$", separator: ",", delimiter: "", format: "%n %u")
|
119
122
|
# # => 1234567890,50 R$
|
123
|
+
# number_to_currency(1234567890.50, strip_insignificant_zeros: true)
|
124
|
+
# # => "$1,234,567,890.5"
|
120
125
|
def number_to_currency(number, options = {})
|
121
126
|
delegate_number_helper_method(:number_to_currency, number, options)
|
122
127
|
end
|
@@ -38,7 +38,7 @@ module ActionView #:nodoc:
|
|
38
38
|
|
39
39
|
# Converts the array to a comma-separated sentence where the last element is
|
40
40
|
# joined by the connector word. This is the html_safe-aware version of
|
41
|
-
# ActiveSupport's {Array#to_sentence}[
|
41
|
+
# ActiveSupport's {Array#to_sentence}[https://api.rubyonrails.org/classes/Array.html#method-i-to_sentence].
|
42
42
|
#
|
43
43
|
def to_sentence(array, options = {})
|
44
44
|
options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale)
|
@@ -27,10 +27,12 @@ module ActionView
|
|
27
27
|
def render(options = {}, locals = {}, &block)
|
28
28
|
case options
|
29
29
|
when Hash
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
in_rendering_context(options) do |renderer|
|
31
|
+
if block_given?
|
32
|
+
view_renderer.render_partial(self, options.merge(partial: options[:layout]), &block)
|
33
|
+
else
|
34
|
+
view_renderer.render(self, options)
|
35
|
+
end
|
34
36
|
end
|
35
37
|
else
|
36
38
|
view_renderer.render_partial(self, partial: options, locals: locals, &block)
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/object/try"
|
4
3
|
require "rails-html-sanitizer"
|
5
4
|
|
6
5
|
module ActionView
|
@@ -10,14 +9,14 @@ module ActionView
|
|
10
9
|
# These helper methods extend Action View making them callable within your template files.
|
11
10
|
module SanitizeHelper
|
12
11
|
extend ActiveSupport::Concern
|
13
|
-
# Sanitizes HTML input, stripping all tags and attributes
|
12
|
+
# Sanitizes HTML input, stripping all but known-safe tags and attributes.
|
14
13
|
#
|
15
14
|
# It also strips href/src attributes with unsafe protocols like
|
16
15
|
# <tt>javascript:</tt>, while also protecting against attempts to use Unicode,
|
17
16
|
# ASCII, and hex character references to work around these protocol filters.
|
18
17
|
# All special characters will be escaped.
|
19
18
|
#
|
20
|
-
# The default sanitizer is Rails::Html::
|
19
|
+
# The default sanitizer is Rails::Html::SafeListSanitizer. See {Rails HTML
|
21
20
|
# Sanitizers}[https://github.com/rails/rails-html-sanitizer] for more information.
|
22
21
|
#
|
23
22
|
# Custom sanitization rules can also be provided.
|
@@ -40,7 +39,7 @@ module ActionView
|
|
40
39
|
#
|
41
40
|
# <%= sanitize @comment.body %>
|
42
41
|
#
|
43
|
-
# Providing custom
|
42
|
+
# Providing custom lists of permitted tags and attributes:
|
44
43
|
#
|
45
44
|
# <%= sanitize @comment.body, tags: %w(strong em a), attributes: %w(href) %>
|
46
45
|
#
|
@@ -80,12 +79,12 @@ module ActionView
|
|
80
79
|
# config.action_view.sanitized_allowed_tags = ['strong', 'em', 'a']
|
81
80
|
# config.action_view.sanitized_allowed_attributes = ['href', 'title']
|
82
81
|
def sanitize(html, options = {})
|
83
|
-
self.class.
|
82
|
+
self.class.safe_list_sanitizer.sanitize(html, options)&.html_safe
|
84
83
|
end
|
85
84
|
|
86
85
|
# Sanitizes a block of CSS code. Used by +sanitize+ when it comes across a style attribute.
|
87
86
|
def sanitize_css(style)
|
88
|
-
self.class.
|
87
|
+
self.class.safe_list_sanitizer.sanitize_css(style)
|
89
88
|
end
|
90
89
|
|
91
90
|
# Strips all HTML tags from +html+, including comments and special characters.
|
@@ -123,20 +122,18 @@ module ActionView
|
|
123
122
|
end
|
124
123
|
|
125
124
|
module ClassMethods #:nodoc:
|
126
|
-
attr_writer :full_sanitizer, :link_sanitizer, :
|
125
|
+
attr_writer :full_sanitizer, :link_sanitizer, :safe_list_sanitizer
|
127
126
|
|
128
|
-
# Vendors the full, link and white list sanitizers.
|
129
|
-
# Provided strictly for compatibility and can be removed in Rails 5.1.
|
130
127
|
def sanitizer_vendor
|
131
128
|
Rails::Html::Sanitizer
|
132
129
|
end
|
133
130
|
|
134
131
|
def sanitized_allowed_tags
|
135
|
-
|
132
|
+
safe_list_sanitizer.allowed_tags
|
136
133
|
end
|
137
134
|
|
138
135
|
def sanitized_allowed_attributes
|
139
|
-
|
136
|
+
safe_list_sanitizer.allowed_attributes
|
140
137
|
end
|
141
138
|
|
142
139
|
# Gets the Rails::Html::FullSanitizer instance used by +strip_tags+. Replace with
|
@@ -145,7 +142,6 @@ module ActionView
|
|
145
142
|
# class Application < Rails::Application
|
146
143
|
# config.action_view.full_sanitizer = MySpecialSanitizer.new
|
147
144
|
# end
|
148
|
-
#
|
149
145
|
def full_sanitizer
|
150
146
|
@full_sanitizer ||= sanitizer_vendor.full_sanitizer.new
|
151
147
|
end
|
@@ -156,20 +152,18 @@ module ActionView
|
|
156
152
|
# class Application < Rails::Application
|
157
153
|
# config.action_view.link_sanitizer = MySpecialSanitizer.new
|
158
154
|
# end
|
159
|
-
#
|
160
155
|
def link_sanitizer
|
161
156
|
@link_sanitizer ||= sanitizer_vendor.link_sanitizer.new
|
162
157
|
end
|
163
158
|
|
164
|
-
# Gets the Rails::Html::
|
159
|
+
# Gets the Rails::Html::SafeListSanitizer instance used by sanitize and +sanitize_css+.
|
165
160
|
# Replace with any object that responds to +sanitize+.
|
166
161
|
#
|
167
162
|
# class Application < Rails::Application
|
168
|
-
# config.action_view.
|
163
|
+
# config.action_view.safe_list_sanitizer = MySpecialSanitizer.new
|
169
164
|
# end
|
170
|
-
|
171
|
-
|
172
|
-
@white_list_sanitizer ||= sanitizer_vendor.white_list_sanitizer.new
|
165
|
+
def safe_list_sanitizer
|
166
|
+
@safe_list_sanitizer ||= sanitizer_vendor.safe_list_sanitizer.new
|
173
167
|
end
|
174
168
|
end
|
175
169
|
end
|
@@ -58,7 +58,7 @@ module ActionView
|
|
58
58
|
|
59
59
|
def tag_options(options, escape = true)
|
60
60
|
return if options.blank?
|
61
|
-
output = ""
|
61
|
+
output = +""
|
62
62
|
sep = " "
|
63
63
|
options.each_pair do |key, value|
|
64
64
|
if TAG_PREFIXES.include?(key) && value.is_a?(Hash)
|
@@ -86,11 +86,12 @@ module ActionView
|
|
86
86
|
|
87
87
|
def tag_option(key, value, escape)
|
88
88
|
if value.is_a?(Array)
|
89
|
-
value = escape ? safe_join(value, " "
|
89
|
+
value = escape ? safe_join(value, " ") : value.join(" ")
|
90
90
|
else
|
91
|
-
value = escape ? ERB::Util.unwrapped_html_escape(value) : value.to_s
|
91
|
+
value = escape ? ERB::Util.unwrapped_html_escape(value).dup : value.to_s.dup
|
92
92
|
end
|
93
|
-
|
93
|
+
value.gsub!('"', """)
|
94
|
+
%(#{key}="#{value}")
|
94
95
|
end
|
95
96
|
|
96
97
|
private
|
@@ -227,10 +228,10 @@ module ActionView
|
|
227
228
|
# tag("img", src: "open & shut.png")
|
228
229
|
# # => <img src="open & shut.png" />
|
229
230
|
#
|
230
|
-
# tag("img", {src: "open & shut.png"}, false, false)
|
231
|
+
# tag("img", { src: "open & shut.png" }, false, false)
|
231
232
|
# # => <img src="open & shut.png" />
|
232
233
|
#
|
233
|
-
# tag("div", data: {name: 'Stephen', city_state: %w(Chicago IL)})
|
234
|
+
# tag("div", data: { name: 'Stephen', city_state: %w(Chicago IL) })
|
234
235
|
# # => <div data-name="Stephen" data-city-state="["Chicago","IL"]" />
|
235
236
|
def tag(name = nil, options = nil, open = false, escape = true)
|
236
237
|
if name.nil?
|
@@ -109,11 +109,11 @@ module ActionView
|
|
109
109
|
# a little duplication to construct less strings
|
110
110
|
case
|
111
111
|
when @object_name.empty?
|
112
|
-
"#{sanitized_method_name}#{"[]"
|
112
|
+
"#{sanitized_method_name}#{multiple ? "[]" : ""}"
|
113
113
|
when index
|
114
|
-
"#{@object_name}[#{index}][#{sanitized_method_name}]#{"[]"
|
114
|
+
"#{@object_name}[#{index}][#{sanitized_method_name}]#{multiple ? "[]" : ""}"
|
115
115
|
else
|
116
|
-
"#{@object_name}[#{sanitized_method_name}]#{"[]"
|
116
|
+
"#{@object_name}[#{sanitized_method_name}]#{multiple ? "[]" : ""}"
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
@@ -138,7 +138,7 @@ module ActionView
|
|
138
138
|
end
|
139
139
|
|
140
140
|
def sanitized_value(value)
|
141
|
-
value.to_s.gsub(
|
141
|
+
value.to_s.gsub(/[\s\.]/, "_").gsub(/[^-[[:word:]]]/, "").downcase
|
142
142
|
end
|
143
143
|
|
144
144
|
def select_content_tag(option_tags, options, html_options)
|
@@ -170,7 +170,11 @@ module ActionView
|
|
170
170
|
option_tags = tag_builder.content_tag_string("option", options[:include_blank].kind_of?(String) ? options[:include_blank] : nil, value: "") + "\n" + option_tags
|
171
171
|
end
|
172
172
|
if value.blank? && options[:prompt]
|
173
|
-
|
173
|
+
tag_options = { value: "" }.tap do |prompt_opts|
|
174
|
+
prompt_opts[:disabled] = true if options[:disabled] == ""
|
175
|
+
prompt_opts[:selected] = true if options[:selected] == ""
|
176
|
+
end
|
177
|
+
option_tags = tag_builder.content_tag_string("option", prompt_text(options[:prompt]), tag_options) + "\n" + option_tags
|
174
178
|
end
|
175
179
|
option_tags
|
176
180
|
end
|
@@ -16,13 +16,8 @@ module ActionView
|
|
16
16
|
translated_attribute || human_attribute_name
|
17
17
|
end
|
18
18
|
|
19
|
-
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
20
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
21
|
-
protected
|
22
|
-
|
23
|
-
attr_reader :object_name, :method_and_value, :scope, :model
|
24
|
-
|
25
19
|
private
|
20
|
+
attr_reader :object_name, :method_and_value, :scope, :model
|
26
21
|
|
27
22
|
def i18n_default
|
28
23
|
if model
|
@@ -188,7 +188,7 @@ module ActionView
|
|
188
188
|
|
189
189
|
unless separator.empty?
|
190
190
|
text.split(separator).each do |value|
|
191
|
-
if value.match(regex)
|
191
|
+
if value.match?(regex)
|
192
192
|
phrase = value
|
193
193
|
break
|
194
194
|
end
|
@@ -228,7 +228,7 @@ module ActionView
|
|
228
228
|
# pluralize(2, 'Person', locale: :de)
|
229
229
|
# # => 2 Personen
|
230
230
|
def pluralize(count, singular, plural_arg = nil, plural: plural_arg, locale: I18n.locale)
|
231
|
-
word = if
|
231
|
+
word = if count == 1 || count.to_s =~ /^1(\.0+)?$/
|
232
232
|
singular
|
233
233
|
else
|
234
234
|
plural || singular.pluralize(locale)
|
@@ -259,7 +259,7 @@ module ActionView
|
|
259
259
|
# # => Once\r\nupon\r\na\r\ntime
|
260
260
|
def word_wrap(text, line_width: 80, break_sequence: "\n")
|
261
261
|
text.split("\n").collect! do |line|
|
262
|
-
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
|
263
263
|
end * break_sequence
|
264
264
|
end
|
265
265
|
|
@@ -59,11 +59,9 @@ module ActionView
|
|
59
59
|
# they can provide HTML values for.
|
60
60
|
def translate(key, options = {})
|
61
61
|
options = options.dup
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
if has_default && !remaining_defaults.first.kind_of?(Symbol)
|
66
|
-
options[:default] = remaining_defaults
|
62
|
+
if options.has_key?(:default)
|
63
|
+
remaining_defaults = Array.wrap(options.delete(:default)).compact
|
64
|
+
options[:default] = remaining_defaults unless remaining_defaults.first.kind_of?(Symbol)
|
67
65
|
end
|
68
66
|
|
69
67
|
# If the user has explicitly decided to NOT raise errors, pass that option to I18n.
|
@@ -85,8 +83,11 @@ module ActionView
|
|
85
83
|
end
|
86
84
|
end
|
87
85
|
translation = I18n.translate(scope_key_by_partial(key), html_safe_options.merge(raise: i18n_raise))
|
88
|
-
|
89
|
-
|
86
|
+
if translation.respond_to?(:map)
|
87
|
+
translation.map { |element| element.respond_to?(:html_safe) ? element.html_safe : element }
|
88
|
+
else
|
89
|
+
translation.respond_to?(:html_safe) ? translation.html_safe : translation
|
90
|
+
end
|
90
91
|
else
|
91
92
|
I18n.translate(scope_key_by_partial(key), options.merge(raise: i18n_raise))
|
92
93
|
end
|
@@ -97,7 +98,7 @@ module ActionView
|
|
97
98
|
raise e if raise_error
|
98
99
|
|
99
100
|
keys = I18n.normalize_keys(e.locale, e.key, e.options[:scope])
|
100
|
-
title = "translation missing: #{keys.join('.')}"
|
101
|
+
title = +"translation missing: #{keys.join('.')}"
|
101
102
|
|
102
103
|
interpolations = options.except(:default, :scope)
|
103
104
|
if interpolations.any?
|
@@ -113,7 +114,7 @@ module ActionView
|
|
113
114
|
|
114
115
|
# Delegates to <tt>I18n.localize</tt> with no additional functionality.
|
115
116
|
#
|
116
|
-
# See
|
117
|
+
# See https://www.rubydoc.info/github/svenfuchs/i18n/master/I18n/Backend/Base:localize
|
117
118
|
# for more information.
|
118
119
|
def localize(*args)
|
119
120
|
I18n.localize(*args)
|
@@ -122,9 +123,12 @@ module ActionView
|
|
122
123
|
|
123
124
|
private
|
124
125
|
def scope_key_by_partial(key)
|
125
|
-
|
126
|
+
stringified_key = key.to_s
|
127
|
+
if stringified_key.first == "."
|
126
128
|
if @virtual_path
|
127
|
-
@
|
129
|
+
@_scope_key_by_partial_cache ||= {}
|
130
|
+
@_scope_key_by_partial_cache[@virtual_path] ||= @virtual_path.gsub(%r{/_?}, ".")
|
131
|
+
"#{@_scope_key_by_partial_cache[@virtual_path]}#{stringified_key}"
|
128
132
|
else
|
129
133
|
raise "Cannot use t(#{key.inspect}) shortcut because path is not available"
|
130
134
|
end
|
@@ -134,7 +138,7 @@ module ActionView
|
|
134
138
|
end
|
135
139
|
|
136
140
|
def html_safe_translation_key?(key)
|
137
|
-
/(
|
141
|
+
/(?:_|\b)html\z/.match?(key.to_s)
|
138
142
|
end
|
139
143
|
end
|
140
144
|
end
|