actionview 6.1.4 → 7.0.0.rc1
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 +188 -244
- data/MIT-LICENSE +1 -1
- data/lib/action_view/base.rb +4 -7
- data/lib/action_view/buffers.rb +2 -2
- data/lib/action_view/cache_expiry.rb +46 -32
- data/lib/action_view/dependency_tracker/erb_tracker.rb +154 -0
- data/lib/action_view/dependency_tracker/ripper_tracker.rb +59 -0
- data/lib/action_view/dependency_tracker.rb +6 -147
- data/lib/action_view/digestor.rb +7 -4
- data/lib/action_view/flows.rb +4 -4
- data/lib/action_view/gem_version.rb +4 -4
- data/lib/action_view/helpers/active_model_helper.rb +2 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +84 -29
- data/lib/action_view/helpers/asset_url_helper.rb +9 -9
- data/lib/action_view/helpers/atom_feed_helper.rb +3 -4
- data/lib/action_view/helpers/cache_helper.rb +52 -3
- data/lib/action_view/helpers/capture_helper.rb +2 -2
- data/lib/action_view/helpers/controller_helper.rb +2 -2
- data/lib/action_view/helpers/csp_helper.rb +1 -1
- data/lib/action_view/helpers/csrf_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +62 -7
- data/lib/action_view/helpers/debug_helper.rb +3 -1
- data/lib/action_view/helpers/form_helper.rb +190 -75
- data/lib/action_view/helpers/form_options_helper.rb +68 -33
- data/lib/action_view/helpers/form_tag_helper.rb +126 -36
- data/lib/action_view/helpers/javascript_helper.rb +3 -5
- data/lib/action_view/helpers/number_helper.rb +3 -4
- data/lib/action_view/helpers/output_safety_helper.rb +2 -2
- data/lib/action_view/helpers/rendering_helper.rb +1 -1
- data/lib/action_view/helpers/sanitize_helper.rb +2 -2
- data/lib/action_view/helpers/tag_helper.rb +34 -6
- data/lib/action_view/helpers/tags/base.rb +4 -24
- data/lib/action_view/helpers/tags/check_box.rb +2 -2
- data/lib/action_view/helpers/tags/collection_select.rb +1 -1
- data/lib/action_view/helpers/tags/hidden_field.rb +4 -0
- data/lib/action_view/helpers/tags/time_field.rb +10 -1
- data/lib/action_view/helpers/tags/weekday_select.rb +28 -0
- data/lib/action_view/helpers/tags.rb +3 -2
- data/lib/action_view/helpers/text_helper.rb +24 -13
- data/lib/action_view/helpers/translation_helper.rb +10 -41
- data/lib/action_view/helpers/url_helper.rb +166 -91
- data/lib/action_view/helpers.rb +25 -25
- data/lib/action_view/lookup_context.rb +33 -52
- data/lib/action_view/model_naming.rb +2 -2
- data/lib/action_view/path_set.rb +16 -22
- data/lib/action_view/railtie.rb +19 -7
- data/lib/action_view/render_parser.rb +188 -0
- data/lib/action_view/renderer/abstract_renderer.rb +2 -2
- data/lib/action_view/renderer/partial_renderer.rb +0 -34
- data/lib/action_view/renderer/renderer.rb +4 -4
- data/lib/action_view/renderer/streaming_template_renderer.rb +3 -3
- data/lib/action_view/renderer/template_renderer.rb +6 -2
- data/lib/action_view/rendering.rb +2 -2
- data/lib/action_view/ripper_ast_parser.rb +198 -0
- data/lib/action_view/routing_url_for.rb +1 -1
- data/lib/action_view/template/error.rb +108 -13
- data/lib/action_view/template/handlers/erb.rb +6 -0
- data/lib/action_view/template/handlers.rb +3 -3
- data/lib/action_view/template/html.rb +3 -3
- data/lib/action_view/template/inline.rb +3 -3
- data/lib/action_view/template/raw_file.rb +3 -3
- data/lib/action_view/template/resolver.rb +84 -311
- data/lib/action_view/template/text.rb +3 -3
- data/lib/action_view/template/types.rb +14 -12
- data/lib/action_view/template.rb +18 -2
- data/lib/action_view/template_details.rb +66 -0
- data/lib/action_view/template_path.rb +64 -0
- data/lib/action_view/test_case.rb +6 -2
- data/lib/action_view/testing/resolvers.rb +11 -12
- data/lib/action_view/unbound_template.rb +33 -7
- data/lib/action_view.rb +3 -4
- metadata +23 -15
@@ -1,15 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/enumerable"
|
3
4
|
require "active_support/core_ext/string/output_safety"
|
4
5
|
require "set"
|
6
|
+
require "action_view/helpers/capture_helper"
|
7
|
+
require "action_view/helpers/output_safety_helper"
|
5
8
|
|
6
9
|
module ActionView
|
7
10
|
# = Action View Tag Helpers
|
8
|
-
module Helpers
|
11
|
+
module Helpers # :nodoc:
|
9
12
|
# Provides methods to generate HTML tags programmatically both as a modern
|
10
13
|
# HTML5 compliant builder style and legacy XHTML compliant tags.
|
11
14
|
module TagHelper
|
12
|
-
extend ActiveSupport::Concern
|
13
15
|
include CaptureHelper
|
14
16
|
include OutputSafetyHelper
|
15
17
|
|
@@ -39,23 +41,33 @@ module ActionView
|
|
39
41
|
PRE_CONTENT_STRINGS[:textarea] = "\n"
|
40
42
|
PRE_CONTENT_STRINGS["textarea"] = "\n"
|
41
43
|
|
42
|
-
class TagBuilder
|
44
|
+
class TagBuilder # :nodoc:
|
43
45
|
include CaptureHelper
|
44
46
|
include OutputSafetyHelper
|
45
47
|
|
46
|
-
|
48
|
+
HTML_VOID_ELEMENTS = %i(area base br col circle embed hr img input keygen link meta param source track wbr).to_set
|
49
|
+
SVG_VOID_ELEMENTS = %i(animate animateMotion animateTransform circle ellipse line path polygon polyline rect set stop use view).to_set
|
47
50
|
|
48
51
|
def initialize(view_context)
|
49
52
|
@view_context = view_context
|
50
53
|
end
|
51
54
|
|
55
|
+
# Transforms a Hash into HTML Attributes, ready to be interpolated into
|
56
|
+
# ERB.
|
57
|
+
#
|
58
|
+
# <input <%= tag.attributes(type: :text, aria: { label: "Search" }) %> >
|
59
|
+
# # => <input type="text" aria-label="Search">
|
60
|
+
def attributes(attributes)
|
61
|
+
tag_options(attributes.to_h).to_s.strip.html_safe
|
62
|
+
end
|
63
|
+
|
52
64
|
def p(*arguments, **options, &block)
|
53
65
|
tag_string(:p, *arguments, **options, &block)
|
54
66
|
end
|
55
67
|
|
56
68
|
def tag_string(name, content = nil, escape_attributes: true, **options, &block)
|
57
69
|
content = @view_context.capture(self, &block) if block_given?
|
58
|
-
if
|
70
|
+
if (HTML_VOID_ELEMENTS.include?(name) || SVG_VOID_ELEMENTS.include?(name)) && content.nil?
|
59
71
|
"<#{name.to_s.dasherize}#{tag_options(options, escape_attributes)}>".html_safe
|
60
72
|
else
|
61
73
|
content_tag_string(name.to_s.dasherize, content || "", options, escape_attributes)
|
@@ -119,6 +131,8 @@ module ActionView
|
|
119
131
|
when Array, Hash
|
120
132
|
value = TagHelper.build_tag_values(value) if key.to_s == "class"
|
121
133
|
value = escape ? safe_join(value, " ") : value.join(" ")
|
134
|
+
when Regexp
|
135
|
+
value = escape ? ERB::Util.unwrapped_html_escape(value.source) : value.source
|
122
136
|
else
|
123
137
|
value = escape ? ERB::Util.unwrapped_html_escape(value) : value.to_s
|
124
138
|
end
|
@@ -221,6 +235,20 @@ module ActionView
|
|
221
235
|
# # A void element:
|
222
236
|
# tag.br # => <br>
|
223
237
|
#
|
238
|
+
# === Building HTML attributes
|
239
|
+
#
|
240
|
+
# Transforms a Hash into HTML attributes, ready to be interpolated into
|
241
|
+
# ERB. Includes or omits boolean attributes based on their truthiness.
|
242
|
+
# Transforms keys nested within
|
243
|
+
# <tt>aria:</tt> or <tt>data:</tt> objects into `aria-` and `data-`
|
244
|
+
# prefixed attributes:
|
245
|
+
#
|
246
|
+
# <input <%= tag.attributes(type: :text, aria: { label: "Search" }) %>>
|
247
|
+
# # => <input type="text" aria-label="Search">
|
248
|
+
#
|
249
|
+
# <button <%= tag.attributes id: "call-to-action", disabled: false, aria: { expanded: false } %> class="primary">Get Started!</button>
|
250
|
+
# # => <button id="call-to-action" aria-expanded="false" class="primary">Get Started!</button>
|
251
|
+
#
|
224
252
|
# === Legacy syntax
|
225
253
|
#
|
226
254
|
# The following format is for legacy syntax support. It will be deprecated in future versions of Rails.
|
@@ -345,7 +373,7 @@ module ActionView
|
|
345
373
|
# cdata_section("hello]]>world")
|
346
374
|
# # => <![CDATA[hello]]]]><![CDATA[>world]]>
|
347
375
|
def cdata_section(content)
|
348
|
-
splitted = content.to_s.gsub(/\]\]
|
376
|
+
splitted = content.to_s.gsub(/\]\]>/, "]]]]><![CDATA[>")
|
349
377
|
"<![CDATA[#{splitted}]]>".html_safe
|
350
378
|
end
|
351
379
|
|
@@ -105,31 +105,11 @@ module ActionView
|
|
105
105
|
end
|
106
106
|
|
107
107
|
def tag_name(multiple = false, index = nil)
|
108
|
-
|
109
|
-
case
|
110
|
-
when @object_name.empty?
|
111
|
-
"#{sanitized_method_name}#{multiple ? "[]" : ""}"
|
112
|
-
when index
|
113
|
-
"#{@object_name}[#{index}][#{sanitized_method_name}]#{multiple ? "[]" : ""}"
|
114
|
-
else
|
115
|
-
"#{@object_name}[#{sanitized_method_name}]#{multiple ? "[]" : ""}"
|
116
|
-
end
|
108
|
+
@template_object.field_name(@object_name, sanitized_method_name, multiple: multiple, index: index)
|
117
109
|
end
|
118
110
|
|
119
111
|
def tag_id(index = nil)
|
120
|
-
|
121
|
-
case
|
122
|
-
when @object_name.empty?
|
123
|
-
sanitized_method_name.dup
|
124
|
-
when index
|
125
|
-
"#{sanitized_object_name}_#{index}_#{sanitized_method_name}"
|
126
|
-
else
|
127
|
-
"#{sanitized_object_name}_#{sanitized_method_name}"
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
def sanitized_object_name
|
132
|
-
@sanitized_object_name ||= @object_name.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").delete_suffix("_")
|
112
|
+
@template_object.field_id(@object_name, @method_name, index: index)
|
133
113
|
end
|
134
114
|
|
135
115
|
def sanitized_method_name
|
@@ -137,7 +117,7 @@ module ActionView
|
|
137
117
|
end
|
138
118
|
|
139
119
|
def sanitized_value(value)
|
140
|
-
value.to_s.gsub(/[\s
|
120
|
+
value.to_s.gsub(/[\s.]/, "_").gsub(/[^-[[:word:]]]/, "").downcase
|
141
121
|
end
|
142
122
|
|
143
123
|
def select_content_tag(option_tags, options, html_options)
|
@@ -153,7 +133,7 @@ module ActionView
|
|
153
133
|
select = content_tag("select", add_options(option_tags, options, value), html_options)
|
154
134
|
|
155
135
|
if html_options["multiple"] && options.fetch(:include_hidden, true)
|
156
|
-
tag("input", disabled: html_options["disabled"], name: html_options["name"], type: "hidden", value: "") + select
|
136
|
+
tag("input", disabled: html_options["disabled"], name: html_options["name"], type: "hidden", value: "", autocomplete: "off") + select
|
157
137
|
else
|
158
138
|
select
|
159
139
|
end
|
@@ -5,7 +5,7 @@ require "action_view/helpers/tags/checkable"
|
|
5
5
|
module ActionView
|
6
6
|
module Helpers
|
7
7
|
module Tags # :nodoc:
|
8
|
-
class CheckBox < Base
|
8
|
+
class CheckBox < Base # :nodoc:
|
9
9
|
include Checkable
|
10
10
|
|
11
11
|
def initialize(object_name, method_name, template_object, checked_value, unchecked_value, options)
|
@@ -57,7 +57,7 @@ module ActionView
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def hidden_field_for_checkbox(options)
|
60
|
-
@unchecked_value ? tag("input", options.slice("name", "disabled", "form").merge!("type" => "hidden", "value" => @unchecked_value)) : "".html_safe
|
60
|
+
@unchecked_value ? tag("input", options.slice("name", "disabled", "form").merge!("type" => "hidden", "value" => @unchecked_value, "autocomplete" => "off")) : "".html_safe
|
61
61
|
end
|
62
62
|
end
|
63
63
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module ActionView
|
4
4
|
module Helpers
|
5
5
|
module Tags # :nodoc:
|
6
|
-
class CollectionSelect < Base
|
6
|
+
class CollectionSelect < Base # :nodoc:
|
7
7
|
def initialize(object_name, method_name, template_object, collection, value_method, text_method, options, html_options)
|
8
8
|
@collection = collection
|
9
9
|
@value_method = value_method
|
@@ -4,9 +4,18 @@ module ActionView
|
|
4
4
|
module Helpers
|
5
5
|
module Tags # :nodoc:
|
6
6
|
class TimeField < DatetimeField # :nodoc:
|
7
|
+
def initialize(object_name, method_name, template_object, options = {})
|
8
|
+
@include_seconds = options.delete(:include_seconds) { true }
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
7
12
|
private
|
8
13
|
def format_date(value)
|
9
|
-
|
14
|
+
if @include_seconds
|
15
|
+
value&.strftime("%T.%L")
|
16
|
+
else
|
17
|
+
value&.strftime("%H:%M")
|
18
|
+
end
|
10
19
|
end
|
11
20
|
end
|
12
21
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionView
|
4
|
+
module Helpers
|
5
|
+
module Tags # :nodoc:
|
6
|
+
class WeekdaySelect < Base # :nodoc:
|
7
|
+
def initialize(object_name, method_name, template_object, options, html_options)
|
8
|
+
@html_options = html_options
|
9
|
+
|
10
|
+
super(object_name, method_name, template_object, options)
|
11
|
+
end
|
12
|
+
|
13
|
+
def render
|
14
|
+
select_content_tag(
|
15
|
+
weekday_options_for_select(
|
16
|
+
value || @options[:selected],
|
17
|
+
index_as_value: @options.fetch(:index_as_value, false),
|
18
|
+
day_format: @options.fetch(:day_format, :day_names),
|
19
|
+
beginning_of_week: @options.fetch(:beginning_of_week, Date.beginning_of_week)
|
20
|
+
),
|
21
|
+
@options,
|
22
|
+
@html_options
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActionView
|
4
|
-
module Helpers
|
5
|
-
module Tags
|
4
|
+
module Helpers # :nodoc:
|
5
|
+
module Tags # :nodoc:
|
6
6
|
extend ActiveSupport::Autoload
|
7
7
|
|
8
8
|
eager_autoload do
|
@@ -38,6 +38,7 @@ module ActionView
|
|
38
38
|
autoload :TimeZoneSelect
|
39
39
|
autoload :UrlField
|
40
40
|
autoload :WeekField
|
41
|
+
autoload :WeekdaySelect
|
41
42
|
end
|
42
43
|
end
|
43
44
|
end
|
@@ -1,11 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/string/filters"
|
4
|
+
require "active_support/core_ext/string/access"
|
4
5
|
require "active_support/core_ext/array/extract_options"
|
6
|
+
require "action_view/helpers/sanitize_helper"
|
7
|
+
require "action_view/helpers/tag_helper"
|
8
|
+
require "action_view/helpers/output_safety_helper"
|
5
9
|
|
6
10
|
module ActionView
|
7
11
|
# = Action View Text Helpers
|
8
|
-
module Helpers
|
12
|
+
module Helpers # :nodoc:
|
9
13
|
# The TextHelper module provides a set of methods for filtering, formatting
|
10
14
|
# and transforming strings, which can reduce the amount of inline Ruby code in
|
11
15
|
# your views. These helper methods extend Action View making them callable
|
@@ -129,7 +133,7 @@ module ActionView
|
|
129
133
|
#
|
130
134
|
# highlight('<a href="javascript:alert(\'no!\')">ruby</a> on rails', 'rails', sanitize: false)
|
131
135
|
# # => <a href="javascript:alert('no!')">ruby</a> on <mark>rails</mark>
|
132
|
-
def highlight(text, phrases, options = {})
|
136
|
+
def highlight(text, phrases, options = {}, &block)
|
133
137
|
text = sanitize(text) if options.fetch(:sanitize, true)
|
134
138
|
|
135
139
|
if text.blank? || phrases.blank?
|
@@ -140,7 +144,7 @@ module ActionView
|
|
140
144
|
end.join("|")
|
141
145
|
|
142
146
|
if block_given?
|
143
|
-
text.gsub(/(#{match})(?![^<]*?>)/i)
|
147
|
+
text.gsub(/(#{match})(?![^<]*?>)/i, &block)
|
144
148
|
else
|
145
149
|
highlighter = options.fetch(:highlighter, '<mark>\1</mark>')
|
146
150
|
text.gsub(/(#{match})(?![^<]*?>)/i, highlighter)
|
@@ -403,7 +407,7 @@ module ActionView
|
|
403
407
|
cycle.reset if cycle
|
404
408
|
end
|
405
409
|
|
406
|
-
class Cycle
|
410
|
+
class Cycle # :nodoc:
|
407
411
|
attr_reader :values
|
408
412
|
|
409
413
|
def initialize(first_value, *values)
|
@@ -467,18 +471,25 @@ module ActionView
|
|
467
471
|
radius = options.fetch(:radius, 100)
|
468
472
|
omission = options.fetch(:omission, "...")
|
469
473
|
|
470
|
-
|
471
|
-
|
472
|
-
|
474
|
+
if separator != ""
|
475
|
+
part = part.split(separator)
|
476
|
+
part.delete("")
|
477
|
+
end
|
473
478
|
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
+
affix = part.length > radius ? omission : ""
|
480
|
+
|
481
|
+
part =
|
482
|
+
if part_position == :first
|
483
|
+
part.last(radius)
|
484
|
+
else
|
485
|
+
part.first(radius)
|
486
|
+
end
|
487
|
+
|
488
|
+
if separator != ""
|
489
|
+
part = part.join(separator)
|
479
490
|
end
|
480
491
|
|
481
|
-
return affix, part
|
492
|
+
return affix, part
|
482
493
|
end
|
483
494
|
end
|
484
495
|
end
|
@@ -1,16 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "action_view/helpers/tag_helper"
|
4
|
-
require "active_support/
|
4
|
+
require "active_support/html_safe_translation"
|
5
5
|
|
6
6
|
module ActionView
|
7
7
|
# = Action View Translation Helpers
|
8
|
-
module Helpers
|
8
|
+
module Helpers # :nodoc:
|
9
9
|
module TranslationHelper
|
10
10
|
extend ActiveSupport::Concern
|
11
11
|
|
12
12
|
include TagHelper
|
13
13
|
|
14
|
+
# Specify whether an error should be raised for missing translations
|
15
|
+
singleton_class.attr_accessor :raise_on_missing_translations
|
16
|
+
|
14
17
|
included do
|
15
18
|
mattr_accessor :debug_missing_translation, default: true
|
16
19
|
end
|
@@ -37,7 +40,7 @@ module ActionView
|
|
37
40
|
#
|
38
41
|
# If you would prefer missing translations to raise an error, you can
|
39
42
|
# opt out of span-wrapping behavior globally by setting
|
40
|
-
# <tt>
|
43
|
+
# <tt>config.i18n.raise_on_missing_translations = true</tt> or
|
41
44
|
# individually by passing <tt>raise: true</tt> as an option to
|
42
45
|
# <tt>translate</tt>.
|
43
46
|
#
|
@@ -75,7 +78,7 @@ module ActionView
|
|
75
78
|
options[:default].is_a?(Array) ? options.delete(:default).compact : [options.delete(:default)]
|
76
79
|
end
|
77
80
|
|
78
|
-
options[:raise] = true if options[:raise].nil? &&
|
81
|
+
options[:raise] = true if options[:raise].nil? && TranslationHelper.raise_on_missing_translations
|
79
82
|
default = MISSING_TRANSLATION
|
80
83
|
|
81
84
|
translation = while key || alternatives.present?
|
@@ -85,14 +88,9 @@ module ActionView
|
|
85
88
|
|
86
89
|
key = scope_key_by_partial(key)
|
87
90
|
|
88
|
-
|
89
|
-
|
90
|
-
|
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)
|
95
|
-
end
|
91
|
+
translated = ActiveSupport::HtmlSafeTranslation.translate(key, **options, default: default)
|
92
|
+
|
93
|
+
break translated unless translated.equal?(MISSING_TRANSLATION)
|
96
94
|
|
97
95
|
if alternatives.present? && !alternatives.first.is_a?(Symbol)
|
98
96
|
break alternatives.first && I18n.translate(**options, default: alternatives)
|
@@ -127,10 +125,6 @@ module ActionView
|
|
127
125
|
NO_DEFAULT = [].freeze
|
128
126
|
private_constant :NO_DEFAULT
|
129
127
|
|
130
|
-
def self.i18n_option?(name)
|
131
|
-
(@i18n_option_names ||= I18n::RESERVED_KEYS.to_set).include?(name)
|
132
|
-
end
|
133
|
-
|
134
128
|
def scope_key_by_partial(key)
|
135
129
|
if key&.start_with?(".")
|
136
130
|
if @virtual_path
|
@@ -145,31 +139,6 @@ module ActionView
|
|
145
139
|
end
|
146
140
|
end
|
147
141
|
|
148
|
-
def html_escape_translation_options(options)
|
149
|
-
return options if options.empty?
|
150
|
-
html_safe_options = options.dup
|
151
|
-
|
152
|
-
options.each do |name, value|
|
153
|
-
unless TranslationHelper.i18n_option?(name) || (name == :count && value.is_a?(Numeric))
|
154
|
-
html_safe_options[name] = ERB::Util.html_escape(value.to_s)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
html_safe_options
|
159
|
-
end
|
160
|
-
|
161
|
-
def html_safe_translation_key?(key)
|
162
|
-
/(?:_|\b)html\z/.match?(key)
|
163
|
-
end
|
164
|
-
|
165
|
-
def html_safe_translation(translation)
|
166
|
-
if translation.respond_to?(:map)
|
167
|
-
translation.map { |element| element.respond_to?(:html_safe) ? element.html_safe : element }
|
168
|
-
else
|
169
|
-
translation.respond_to?(:html_safe) ? translation.html_safe : translation
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
142
|
def missing_translation(key, options)
|
174
143
|
keys = I18n.normalize_keys(options[:locale] || I18n.locale, key, options[:scope])
|
175
144
|
|