actionview 5.2.4.4 → 6.0.0.beta1
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 +106 -91
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/action_view.rb +1 -1
- data/lib/action_view/buffers.rb +15 -0
- data/lib/action_view/context.rb +5 -4
- data/lib/action_view/digestor.rb +7 -6
- data/lib/action_view/gem_version.rb +4 -4
- data/lib/action_view/helpers.rb +0 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +4 -27
- 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/csrf_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +69 -25
- data/lib/action_view/helpers/form_helper.rb +240 -8
- data/lib/action_view/helpers/form_options_helper.rb +23 -15
- data/lib/action_view/helpers/form_tag_helper.rb +9 -9
- data/lib/action_view/helpers/javascript_helper.rb +10 -11
- data/lib/action_view/helpers/number_helper.rb +5 -0
- data/lib/action_view/helpers/sanitize_helper.rb +3 -3
- data/lib/action_view/helpers/tag_helper.rb +7 -6
- data/lib/action_view/helpers/tags/base.rb +8 -4
- 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 +11 -18
- data/lib/action_view/helpers/url_helper.rb +14 -14
- data/lib/action_view/log_subscriber.rb +6 -6
- data/lib/action_view/lookup_context.rb +4 -4
- data/lib/action_view/railtie.rb +18 -0
- data/lib/action_view/record_identifier.rb +2 -2
- data/lib/action_view/renderer/partial_renderer.rb +2 -2
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +40 -1
- data/lib/action_view/renderer/streaming_template_renderer.rb +1 -1
- data/lib/action_view/rendering.rb +5 -4
- data/lib/action_view/routing_url_for.rb +12 -11
- data/lib/action_view/template.rb +25 -8
- data/lib/action_view/template/handlers/erb.rb +12 -2
- data/lib/action_view/template/resolver.rb +56 -16
- data/lib/action_view/test_case.rb +1 -1
- data/lib/action_view/testing/resolvers.rb +1 -1
- data/lib/assets/compiled/rails-ujs.js +39 -22
- metadata +14 -15
- data/lib/action_view/helpers/record_tag_helper.rb +0 -23
@@ -16,7 +16,7 @@ module ActionView
|
|
16
16
|
#
|
17
17
|
# * <tt>:include_blank</tt> - set to true or a prompt string if the first option element of the select element is a blank. Useful if there is not a default value required for the select element.
|
18
18
|
#
|
19
|
-
# select("post", "category", Post::CATEGORIES, {include_blank: true})
|
19
|
+
# select("post", "category", Post::CATEGORIES, { include_blank: true })
|
20
20
|
#
|
21
21
|
# could become:
|
22
22
|
#
|
@@ -30,7 +30,7 @@ module ActionView
|
|
30
30
|
#
|
31
31
|
# Example with <tt>@post.person_id => 2</tt>:
|
32
32
|
#
|
33
|
-
# select("post", "person_id", Person.all.collect {|p| [ p.name, p.id ] }, {include_blank: 'None'})
|
33
|
+
# select("post", "person_id", Person.all.collect { |p| [ p.name, p.id ] }, { include_blank: 'None' })
|
34
34
|
#
|
35
35
|
# could become:
|
36
36
|
#
|
@@ -43,7 +43,7 @@ module ActionView
|
|
43
43
|
#
|
44
44
|
# * <tt>:prompt</tt> - set to true or a prompt string. When the select element doesn't have a value yet, this prepends an option with a generic prompt -- "Please select" -- or the given prompt string.
|
45
45
|
#
|
46
|
-
# select("post", "person_id", Person.all.collect {|p| [ p.name, p.id ] }, {prompt: 'Select Person'})
|
46
|
+
# select("post", "person_id", Person.all.collect { |p| [ p.name, p.id ] }, { prompt: 'Select Person' })
|
47
47
|
#
|
48
48
|
# could become:
|
49
49
|
#
|
@@ -69,7 +69,7 @@ module ActionView
|
|
69
69
|
#
|
70
70
|
# * <tt>:disabled</tt> - can be a single value or an array of values that will be disabled options in the final output.
|
71
71
|
#
|
72
|
-
# select("post", "category", Post::CATEGORIES, {disabled: 'restricted'})
|
72
|
+
# select("post", "category", Post::CATEGORIES, { disabled: 'restricted' })
|
73
73
|
#
|
74
74
|
# could become:
|
75
75
|
#
|
@@ -82,7 +82,7 @@ module ActionView
|
|
82
82
|
#
|
83
83
|
# When used with the <tt>collection_select</tt> helper, <tt>:disabled</tt> can also be a Proc that identifies those options that should be disabled.
|
84
84
|
#
|
85
|
-
# collection_select(:post, :category_id, Category.all, :id, :name, {disabled: -> (category) { category.archived? }})
|
85
|
+
# collection_select(:post, :category_id, Category.all, :id, :name, { disabled: -> (category) { category.archived? } })
|
86
86
|
#
|
87
87
|
# If the categories "2008 stuff" and "Christmas" return true when the method <tt>archived?</tt> is called, this would return:
|
88
88
|
# <select name="post[category_id]" id="post_category_id">
|
@@ -107,7 +107,7 @@ module ActionView
|
|
107
107
|
#
|
108
108
|
# For example:
|
109
109
|
#
|
110
|
-
# select("post", "person_id", Person.all.collect {|p| [ p.name, p.id ] }, { include_blank: true })
|
110
|
+
# select("post", "person_id", Person.all.collect { |p| [ p.name, p.id ] }, { include_blank: true })
|
111
111
|
#
|
112
112
|
# would become:
|
113
113
|
#
|
@@ -323,12 +323,12 @@ module ActionView
|
|
323
323
|
#
|
324
324
|
# You can optionally provide HTML attributes as the last element of the array.
|
325
325
|
#
|
326
|
-
# options_for_select([ "Denmark", ["USA", {class: 'bold'}], "Sweden" ], ["USA", "Sweden"])
|
326
|
+
# options_for_select([ "Denmark", ["USA", { class: 'bold' }], "Sweden" ], ["USA", "Sweden"])
|
327
327
|
# # => <option value="Denmark">Denmark</option>
|
328
328
|
# # => <option value="USA" class="bold" selected="selected">USA</option>
|
329
329
|
# # => <option value="Sweden" selected="selected">Sweden</option>
|
330
330
|
#
|
331
|
-
# options_for_select([["Dollar", "$", {class: "bold"}], ["Kroner", "DKK", {onclick: "alert('HI');"}]])
|
331
|
+
# options_for_select([["Dollar", "$", { class: "bold" }], ["Kroner", "DKK", { onclick: "alert('HI');" }]])
|
332
332
|
# # => <option value="$" class="bold">Dollar</option>
|
333
333
|
# # => <option value="DKK" onclick="alert('HI');">Kroner</option>
|
334
334
|
#
|
@@ -463,7 +463,7 @@ module ActionView
|
|
463
463
|
option_tags = options_from_collection_for_select(
|
464
464
|
value_for_collection(group, group_method), option_key_method, option_value_method, selected_key)
|
465
465
|
|
466
|
-
content_tag("optgroup"
|
466
|
+
content_tag("optgroup", option_tags, label: value_for_collection(group, group_label_method))
|
467
467
|
end.join.html_safe
|
468
468
|
end
|
469
469
|
|
@@ -535,7 +535,7 @@ module ActionView
|
|
535
535
|
body = "".html_safe
|
536
536
|
|
537
537
|
if prompt
|
538
|
-
body.safe_concat content_tag("option"
|
538
|
+
body.safe_concat content_tag("option", prompt_text(prompt), value: "")
|
539
539
|
end
|
540
540
|
|
541
541
|
grouped_options.each do |container|
|
@@ -548,7 +548,7 @@ module ActionView
|
|
548
548
|
end
|
549
549
|
|
550
550
|
html_attributes = { label: label }.merge!(html_attributes)
|
551
|
-
body.safe_concat content_tag("optgroup"
|
551
|
+
body.safe_concat content_tag("optgroup", options_for_select(container, selected_key), html_attributes)
|
552
552
|
end
|
553
553
|
|
554
554
|
body
|
@@ -584,7 +584,7 @@ module ActionView
|
|
584
584
|
end
|
585
585
|
|
586
586
|
zone_options.safe_concat options_for_select(convert_zones[priority_zones], selected)
|
587
|
-
zone_options.safe_concat content_tag("option"
|
587
|
+
zone_options.safe_concat content_tag("option", "-------------", value: "", disabled: true)
|
588
588
|
zone_options.safe_concat "\n"
|
589
589
|
|
590
590
|
zones = zones - priority_zones
|
@@ -654,7 +654,7 @@ module ActionView
|
|
654
654
|
#
|
655
655
|
# ==== Gotcha
|
656
656
|
#
|
657
|
-
# The HTML specification says when nothing is
|
657
|
+
# The HTML specification says when nothing is selected on a collection of radio buttons
|
658
658
|
# web browsers do not send any value to server.
|
659
659
|
# Unfortunately this introduces a gotcha:
|
660
660
|
# if a +User+ model has a +category_id+ field and in the form no category is selected, no +category_id+ parameter is sent. So,
|
@@ -794,7 +794,7 @@ module ActionView
|
|
794
794
|
def extract_values_from_collection(collection, value_method, selected)
|
795
795
|
if selected.is_a?(Proc)
|
796
796
|
collection.map do |element|
|
797
|
-
element
|
797
|
+
public_or_deprecated_send(element, value_method) if selected.call(element)
|
798
798
|
end.compact
|
799
799
|
else
|
800
800
|
selected
|
@@ -802,7 +802,15 @@ module ActionView
|
|
802
802
|
end
|
803
803
|
|
804
804
|
def value_for_collection(item, value)
|
805
|
-
value.respond_to?(:call) ? value.call(item) : item
|
805
|
+
value.respond_to?(:call) ? value.call(item) : public_or_deprecated_send(item, value)
|
806
|
+
end
|
807
|
+
|
808
|
+
def public_or_deprecated_send(item, value)
|
809
|
+
item.public_send(value)
|
810
|
+
rescue NoMethodError
|
811
|
+
raise unless item.respond_to?(value, true) && !item.respond_to?(value)
|
812
|
+
ActiveSupport::Deprecation.warn "Using private methods from view helpers is deprecated (calling private #{item.class}##{value})"
|
813
|
+
item.send(value)
|
806
814
|
end
|
807
815
|
|
808
816
|
def prompt_text(prompt)
|
@@ -22,6 +22,8 @@ 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
|
+
mattr_accessor :default_enforce_utf8, default: true
|
26
|
+
|
25
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
|
#
|
@@ -144,15 +146,15 @@ module ActionView
|
|
144
146
|
end
|
145
147
|
|
146
148
|
if include_blank
|
147
|
-
option_tags = content_tag("option"
|
149
|
+
option_tags = content_tag("option", include_blank, options_for_blank_options_tag).safe_concat(option_tags)
|
148
150
|
end
|
149
151
|
end
|
150
152
|
|
151
153
|
if prompt = options.delete(:prompt)
|
152
|
-
option_tags = content_tag("option"
|
154
|
+
option_tags = content_tag("option", prompt, value: "").safe_concat(option_tags)
|
153
155
|
end
|
154
156
|
|
155
|
-
content_tag "select"
|
157
|
+
content_tag "select", option_tags, { "name" => html_name, "id" => sanitize_to_id(name) }.update(options.stringify_keys)
|
156
158
|
end
|
157
159
|
|
158
160
|
# Creates a standard text field; use these text fields to input smaller chunks of text like a username
|
@@ -163,8 +165,6 @@ module ActionView
|
|
163
165
|
# * <tt>:size</tt> - The number of visible characters that will fit in the input.
|
164
166
|
# * <tt>:maxlength</tt> - The maximum number of characters that the browser will allow the user to enter.
|
165
167
|
# * <tt>:placeholder</tt> - The text contained in the field by default which is removed when the field receives focus.
|
166
|
-
# If set to true, use a translation is found in the current I18n locale
|
167
|
-
# (through helpers.placeholders.<modelname>.<attribute>).
|
168
168
|
# * Any other key creates standard HTML attributes for the tag.
|
169
169
|
#
|
170
170
|
# ==== Examples
|
@@ -389,8 +389,8 @@ module ActionView
|
|
389
389
|
# * Any other key creates standard HTML options for the tag.
|
390
390
|
#
|
391
391
|
# ==== Examples
|
392
|
-
# radio_button_tag '
|
393
|
-
# # => <input id="
|
392
|
+
# radio_button_tag 'favorite_color', 'maroon'
|
393
|
+
# # => <input id="favorite_color_maroon" name="favorite_color" type="radio" value="maroon" />
|
394
394
|
#
|
395
395
|
# radio_button_tag 'receive_updates', 'no', true
|
396
396
|
# # => <input checked="checked" id="receive_updates_no" name="receive_updates" type="radio" value="no" />
|
@@ -577,7 +577,7 @@ module ActionView
|
|
577
577
|
# # => <fieldset class="format"><p><input id="name" name="name" type="text" /></p></fieldset>
|
578
578
|
def field_set_tag(legend = nil, options = nil, &block)
|
579
579
|
output = tag(:fieldset, options, true)
|
580
|
-
output.safe_concat(content_tag("legend"
|
580
|
+
output.safe_concat(content_tag("legend", legend)) unless legend.blank?
|
581
581
|
output.concat(capture(&block)) if block_given?
|
582
582
|
output.safe_concat("</fieldset>")
|
583
583
|
end
|
@@ -869,7 +869,7 @@ module ActionView
|
|
869
869
|
})
|
870
870
|
end
|
871
871
|
|
872
|
-
if html_options.delete("enforce_utf8") {
|
872
|
+
if html_options.delete("enforce_utf8") { default_enforce_utf8 }
|
873
873
|
utf8_enforcer_tag + method_tag
|
874
874
|
else
|
875
875
|
method_tag
|
@@ -12,13 +12,11 @@ module ActionView
|
|
12
12
|
"\n" => '\n',
|
13
13
|
"\r" => '\n',
|
14
14
|
'"' => '\\"',
|
15
|
-
"'" => "\\'"
|
16
|
-
"`" => "\\`",
|
17
|
-
"$" => "\\$"
|
15
|
+
"'" => "\\'"
|
18
16
|
}
|
19
17
|
|
20
|
-
JS_ESCAPE_MAP["\342\200\250".
|
21
|
-
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!] = "
"
|
22
20
|
|
23
21
|
# Escapes carriage returns and single and double quotes for JavaScript segments.
|
24
22
|
#
|
@@ -27,12 +25,13 @@ module ActionView
|
|
27
25
|
#
|
28
26
|
# $('some_element').replaceWith('<%= j render 'some/element_template' %>');
|
29
27
|
def escape_javascript(javascript)
|
30
|
-
|
31
|
-
|
32
|
-
|
28
|
+
javascript = javascript.to_s
|
29
|
+
if javascript.empty?
|
30
|
+
result = ""
|
33
31
|
else
|
34
|
-
"
|
32
|
+
result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"'])/u) { |match| JS_ESCAPE_MAP[match] }
|
35
33
|
end
|
34
|
+
javascript.html_safe? ? result.html_safe : result
|
36
35
|
end
|
37
36
|
|
38
37
|
alias_method :j, :escape_javascript
|
@@ -67,7 +66,7 @@ module ActionView
|
|
67
66
|
# <% end -%>
|
68
67
|
#
|
69
68
|
# If you have a content security policy enabled then you can add an automatic
|
70
|
-
# nonce value by passing
|
69
|
+
# nonce value by passing <tt>nonce: true</tt> as part of +html_options+. Example:
|
71
70
|
#
|
72
71
|
# <%= javascript_tag nonce: true do -%>
|
73
72
|
# alert('All is good')
|
@@ -85,7 +84,7 @@ module ActionView
|
|
85
84
|
html_options[:nonce] = content_security_policy_nonce
|
86
85
|
end
|
87
86
|
|
88
|
-
content_tag("script"
|
87
|
+
content_tag("script", javascript_cdata_section(content), html_options)
|
89
88
|
end
|
90
89
|
|
91
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
|
@@ -10,7 +10,7 @@ module ActionView
|
|
10
10
|
# These helper methods extend Action View making them callable within your template files.
|
11
11
|
module SanitizeHelper
|
12
12
|
extend ActiveSupport::Concern
|
13
|
-
# Sanitizes HTML input, stripping all tags and attributes
|
13
|
+
# Sanitizes HTML input, stripping all but known-safe tags and attributes.
|
14
14
|
#
|
15
15
|
# It also strips href/src attributes with unsafe protocols like
|
16
16
|
# <tt>javascript:</tt>, while also protecting against attempts to use Unicode,
|
@@ -40,7 +40,7 @@ module ActionView
|
|
40
40
|
#
|
41
41
|
# <%= sanitize @comment.body %>
|
42
42
|
#
|
43
|
-
# Providing custom
|
43
|
+
# Providing custom lists of permitted tags and attributes:
|
44
44
|
#
|
45
45
|
# <%= sanitize @comment.body, tags: %w(strong em a), attributes: %w(href) %>
|
46
46
|
#
|
@@ -126,7 +126,7 @@ module ActionView
|
|
126
126
|
attr_writer :full_sanitizer, :link_sanitizer, :white_list_sanitizer
|
127
127
|
|
128
128
|
# Vendors the full, link and white list sanitizers.
|
129
|
-
# Provided strictly for compatibility and can be removed in Rails
|
129
|
+
# Provided strictly for compatibility and can be removed in Rails 6.
|
130
130
|
def sanitizer_vendor
|
131
131
|
Rails::Html::Sanitizer
|
132
132
|
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) : 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
|
|
@@ -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(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.
|
@@ -79,19 +77,14 @@ module ActionView
|
|
79
77
|
|
80
78
|
if html_safe_translation_key?(key)
|
81
79
|
html_safe_options = options.dup
|
82
|
-
|
83
80
|
options.except(*I18n::RESERVED_KEYS).each do |name, value|
|
84
81
|
unless name == :count && value.is_a?(Numeric)
|
85
82
|
html_safe_options[name] = ERB::Util.html_escape(value.to_s)
|
86
83
|
end
|
87
84
|
end
|
88
|
-
|
89
|
-
html_safe_options[:default] = MISSING_TRANSLATION unless html_safe_options[:default].blank?
|
90
|
-
|
91
85
|
translation = I18n.translate(scope_key_by_partial(key), html_safe_options.merge(raise: i18n_raise))
|
92
|
-
|
93
|
-
|
94
|
-
options[:default].first
|
86
|
+
if translation.respond_to?(:map)
|
87
|
+
translation.map { |element| element.respond_to?(:html_safe) ? element.html_safe : element }
|
95
88
|
else
|
96
89
|
translation.respond_to?(:html_safe) ? translation.html_safe : translation
|
97
90
|
end
|
@@ -105,7 +98,7 @@ module ActionView
|
|
105
98
|
raise e if raise_error
|
106
99
|
|
107
100
|
keys = I18n.normalize_keys(e.locale, e.key, e.options[:scope])
|
108
|
-
title = "translation missing: #{keys.join('.')}"
|
101
|
+
title = +"translation missing: #{keys.join('.')}"
|
109
102
|
|
110
103
|
interpolations = options.except(:default, :scope)
|
111
104
|
if interpolations.any?
|
@@ -129,13 +122,13 @@ module ActionView
|
|
129
122
|
alias :l :localize
|
130
123
|
|
131
124
|
private
|
132
|
-
MISSING_TRANSLATION = Object.new
|
133
|
-
private_constant :MISSING_TRANSLATION
|
134
|
-
|
135
125
|
def scope_key_by_partial(key)
|
136
|
-
|
126
|
+
stringified_key = key.to_s
|
127
|
+
if stringified_key.first == "."
|
137
128
|
if @virtual_path
|
138
|
-
@
|
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}"
|
139
132
|
else
|
140
133
|
raise "Cannot use t(#{key.inspect}) shortcut because path is not available"
|
141
134
|
end
|