Yield `Tags::Label::LabelBuilder#translations`
When translating a `<label>` element's contents, it is difficult (or "possible", yet undocumented) to make the translation text available to a block scope. For instance, when rendering a `rich_text_area`, passing the `aria-label` attribute might be important. Prior to this commit, doing so would require a double lookup of the translation key: ```erb <%# one time here, implicitly %> <%= form.label(:content) do %> <%= form.rich_text_area( :content, # one time here, explicitly "aria-label" => translate("helpers.label.post.content"), ) %> <% end %> ``` The current implementation of the `#label` helper method already yields an instance of `ActionView::Helpers::Tags::Label::LabelBuilder`, but that class is undocumented. Instance of that class respond to `#translation` calls, which will return the translated text content. By aliasing `#translation` to `#to_s`, we're able to expose that value without the burden of exposing an additional class to the public API. Instead, view-level interpolation (either `<%= %>`, `#{ }`, or direct calls to [`capture`][capture] will coerce the value to a String, and implicitly invoke `#translation`. The new view code might look something like this: ```erb <%= form.label(:content) do |label| %> <%= form.rich_text_area(:content, "aria-label" => label) %> <% end %> ``` Callers of the helper are still free to omit the block parameter. [capture]: https://api.rubyonrails.org/classes/ActionView/Helpers/CaptureHelper.html#method-i-capture
This commit is contained in:
parent
76b33aa3d1
commit
d38c214b75
|
@ -1,3 +1,8 @@
|
|||
* Alias `ActionView::Helpers::Tags::Label::LabelBuilder#translation` to
|
||||
`#to_s` so that `form.label` calls can yield that value to their blocks.
|
||||
|
||||
*Sean Doyle*
|
||||
|
||||
* Rename the new `TagHelper#class_names` method to `TagHelper#token_list`,
|
||||
and make the original available as an alias.
|
||||
|
||||
|
|
|
@ -1111,6 +1111,16 @@ module ActionView
|
|||
# label(:post, :privacy, "Public Post", value: "public")
|
||||
# # => <label for="post_privacy_public">Public Post</label>
|
||||
#
|
||||
# label(:post, :cost) do |translation|
|
||||
# content_tag(:span, translation, class: "cost_label")
|
||||
# end
|
||||
# # => <label for="post_cost"><span class="cost_label">Total cost</span></label>
|
||||
#
|
||||
# label(:post, :cost) do |builder|
|
||||
# content_tag(:span, builder.translation, class: "cost_label")
|
||||
# end
|
||||
# # => <label for="post_cost"><span class="cost_label">Total cost</span></label>
|
||||
#
|
||||
# label(:post, :terms) do
|
||||
# raw('Accept <a href="/terms">Terms</a>.')
|
||||
# end
|
||||
|
@ -2245,6 +2255,24 @@ module ActionView
|
|||
# label(:privacy, "Public Post", value: "public")
|
||||
# # => <label for="post_privacy_public">Public Post</label>
|
||||
#
|
||||
# label(:cost) do |translation|
|
||||
# content_tag(:span, translation, class: "cost_label")
|
||||
# end
|
||||
# # => <label for="post_cost"><span class="cost_label">Total cost</span></label>
|
||||
#
|
||||
# label(:cost) do |builder|
|
||||
# content_tag(:span, builder.translation, class: "cost_label")
|
||||
# end
|
||||
# # => <label for="post_cost"><span class="cost_label">Total cost</span></label>
|
||||
#
|
||||
# label(:cost) do |builder|
|
||||
# content_tag(:span, builder.translation, class: [
|
||||
# "cost_label",
|
||||
# ("error_label" if builder.object.errors.include?(:cost))
|
||||
# ])
|
||||
# end
|
||||
# # => <label for="post_cost"><span class="cost_label error_label">Total cost</span></label>
|
||||
#
|
||||
# label(:terms) do
|
||||
# raw('Accept <a href="/terms">Terms</a>.')
|
||||
# end
|
||||
|
|
|
@ -25,6 +25,10 @@ module ActionView
|
|||
|
||||
content
|
||||
end
|
||||
|
||||
def to_s
|
||||
translation
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(object_name, method_name, template_object, content_or_options = nil, options = nil)
|
||||
|
|
|
@ -945,6 +945,56 @@ class FormWithActsLikeFormForTest < FormWithTest
|
|||
assert_dom_equal expected, output_buffer
|
||||
end
|
||||
|
||||
def test_form_with_label_passes_translation_to_block_version
|
||||
form_with(model: Post.new) do |f|
|
||||
concat(
|
||||
f.label(:title) do |label|
|
||||
concat content_tag(:span, label)
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
expected = whole_form("/posts") do
|
||||
%(<label for="post_title"><span>Title</span></label>)
|
||||
end
|
||||
|
||||
assert_dom_equal expected, output_buffer
|
||||
end
|
||||
|
||||
def test_form_with_label_passes_label_tag_builder_to_block_version
|
||||
form_with(model: Post.new) do |f|
|
||||
concat(
|
||||
f.label(:title) do |builder|
|
||||
concat content_tag(:span, builder.translation)
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
expected = whole_form("/posts") do
|
||||
%(<label for="post_title"><span>Title</span></label>)
|
||||
end
|
||||
|
||||
assert_dom_equal expected, output_buffer
|
||||
end
|
||||
|
||||
def test_form_with_label_accesses_object_through_label_tag_builder
|
||||
form_with(model: Post.new) do |f|
|
||||
concat(
|
||||
f.label(:title) do |builder|
|
||||
concat tag.span(builder, {
|
||||
class: ("new_record" unless builder.object.persisted?)
|
||||
})
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
expected = whole_form("/posts") do
|
||||
%(<label for="post_title"><span class="new_record">Title</span></label>)
|
||||
end
|
||||
|
||||
assert_dom_equal expected, output_buffer
|
||||
end
|
||||
|
||||
def test_form_with_label_error_wrapping
|
||||
form_with(model: @post) do |f|
|
||||
concat f.label(:author_name, class: "label")
|
||||
|
|
Loading…
Reference in New Issue