From 8b028325003e91155d228882444199c1aedf31f7 Mon Sep 17 00:00:00 2001
From: Alex Robbin <alex.robbin@meyouhealth.com>
Date: Sat, 9 Aug 2014 00:10:54 -0400
Subject: add I18n support for `:placeholder` HTML option is passed to form
 fields

---
 actionview/CHANGELOG.md                            |   6 +
 .../action_view/helpers/tags/placeholderable.rb    |  32 ++++
 .../lib/action_view/helpers/tags/text_area.rb      |   4 +
 .../lib/action_view/helpers/tags/text_field.rb     |   4 +
 actionview/test/template/form_helper_test.rb       | 168 +++++++++++++++++++++
 5 files changed, 214 insertions(+)
 create mode 100644 actionview/lib/action_view/helpers/tags/placeholderable.rb

diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index 3fc2ab178c..552a902349 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,3 +1,9 @@
+*   Add I18n support for input/textarea placeholder text.
+
+    Placeholder I18n follows the same convention as `label` I18n.
+
+    *Alex Robbin*
+
 *   Fix that render layout: 'messages/layout' should also be added to the dependency tracker tree.
 
     *DHH*
diff --git a/actionview/lib/action_view/helpers/tags/placeholderable.rb b/actionview/lib/action_view/helpers/tags/placeholderable.rb
new file mode 100644
index 0000000000..313aa725c9
--- /dev/null
+++ b/actionview/lib/action_view/helpers/tags/placeholderable.rb
@@ -0,0 +1,32 @@
+module ActionView
+  module Helpers
+    module Tags # :nodoc:
+      module Placeholderable # :nodoc:
+        def initialize(*)
+          super
+
+          if tag_value = @options[:placeholder]
+            object_name = @object_name.gsub(/\[(.*)_attributes\]\[\d+\]/, '.\1')
+            method_and_value = tag_value.is_a?(TrueClass) ? @method_name : "#{@method_name}.#{tag_value}"
+
+            if object.respond_to?(:to_model)
+              key = object.class.model_name.i18n_key
+              i18n_default = ["#{key}.#{method_and_value}".to_sym, ""]
+            end
+
+            i18n_default ||= ""
+            placeholder = I18n.t("#{object_name}.#{method_and_value}", :default => i18n_default, :scope => "helpers.placeholder").presence
+
+            placeholder ||= if object && object.class.respond_to?(:human_attribute_name)
+                          object.class.human_attribute_name(method_and_value)
+                        end
+
+            placeholder ||= @method_name.humanize
+
+            @options[:placeholder] = placeholder
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/actionview/lib/action_view/helpers/tags/text_area.rb b/actionview/lib/action_view/helpers/tags/text_area.rb
index 9ee83ee7c2..69038c1498 100644
--- a/actionview/lib/action_view/helpers/tags/text_area.rb
+++ b/actionview/lib/action_view/helpers/tags/text_area.rb
@@ -1,7 +1,11 @@
+require 'action_view/helpers/tags/placeholderable'
+
 module ActionView
   module Helpers
     module Tags # :nodoc:
       class TextArea < Base # :nodoc:
+        include Placeholderable
+
         def render
           options = @options.stringify_keys
           add_default_name_and_id(options)
diff --git a/actionview/lib/action_view/helpers/tags/text_field.rb b/actionview/lib/action_view/helpers/tags/text_field.rb
index e0b80d81c2..5c576a20ca 100644
--- a/actionview/lib/action_view/helpers/tags/text_field.rb
+++ b/actionview/lib/action_view/helpers/tags/text_field.rb
@@ -1,7 +1,11 @@
+require 'action_view/helpers/tags/placeholderable'
+
 module ActionView
   module Helpers
     module Tags # :nodoc:
       class TextField < Base # :nodoc:
+        include Placeholderable
+
         def render
           options = @options.stringify_keys
           options["size"] = options["maxlength"] unless options.key?("size")
diff --git a/actionview/test/template/form_helper_test.rb b/actionview/test/template/form_helper_test.rb
index a9f137aec6..d944214961 100644
--- a/actionview/test/template/form_helper_test.rb
+++ b/actionview/test/template/form_helper_test.rb
@@ -59,6 +59,35 @@ class FormHelperTest < ActionView::TestCase
       }
     }
 
+    I18n.backend.store_translations 'placeholder', {
+      activemodel: {
+        attributes: {
+          post: {
+            cost: "Total cost"
+          },
+          :"post/cost" => {
+            uk: "Pounds"
+          }
+        }
+      },
+      helpers: {
+        placeholder: {
+          post: {
+            title: "What is this about?",
+            written_on: {
+              spanish: "Escrito en"
+            },
+            comments: {
+              body: "Write body here"
+            }
+          },
+          tag: {
+            value: "Tag"
+          }
+        }
+      }
+    }
+
     @post = Post.new
     @comment = Comment.new
     def @post.errors()
@@ -297,6 +326,68 @@ class FormHelperTest < ActionView::TestCase
     )
   end
 
+  def test_text_field_placeholder_without_locales
+    with_locale :placeholder do
+      assert_dom_equal('<input id="post_body" name="post[body]" placeholder="Body" type="text" value="Back to the hill and over it again!" />', text_field(:post, :body, placeholder: true))
+    end
+  end
+
+  def test_text_field_placeholder_with_locales
+    with_locale :placeholder do
+      assert_dom_equal('<input id="post_title" name="post[title]" placeholder="What is this about?" type="text" value="Hello World" />', text_field(:post, :title, placeholder: true))
+    end
+  end
+
+  def test_text_field_placeholder_with_human_attribute_name
+    with_locale :placeholder do
+      assert_dom_equal('<input id="post_cost" name="post[cost]" placeholder="Total cost" type="text" />', text_field(:post, :cost, placeholder: true))
+    end
+  end
+
+  def test_text_field_placeholder_with_human_attribute_name_and_value
+    with_locale :placeholder do
+      assert_dom_equal('<input id="post_cost" name="post[cost]" placeholder="Pounds" type="text" />', text_field(:post, :cost, placeholder: "uk"))
+    end
+  end
+
+  def test_text_field_placeholder_with_locales_and_value
+    with_locale :placeholder do
+      assert_dom_equal('<input id="post_written_on" name="post[written_on]" placeholder="Escrito en" type="text" value="2004-06-15" />', text_field(:post, :written_on, placeholder: "spanish"))
+    end
+  end
+
+  def test_text_field_placeholder_with_locales_and_nested_attributes
+    with_locale :placeholder do
+      form_for(@post, html: { id: 'create-post' }) do |f|
+        f.fields_for(:comments) do |cf|
+          concat cf.text_field(:body, placeholder: true)
+        end
+      end
+
+      expected = whole_form("/posts/123", "create-post", "edit_post", method: "patch") do
+        '<input id="post_comments_attributes_0_body" name="post[comments_attributes][0][body]" placeholder="Write body here" type="text" />'
+      end
+
+      assert_dom_equal expected, output_buffer
+    end
+  end
+
+  def test_text_field_placeholder_with_locales_fallback_and_nested_attributes
+    with_locale :placeholder do
+      form_for(@post, html: { id: 'create-post' }) do |f|
+        f.fields_for(:tags) do |cf|
+          concat cf.text_field(:value, placeholder: true)
+        end
+      end
+
+      expected = whole_form("/posts/123", "create-post", "edit_post", method: "patch") do
+        '<input id="post_tags_attributes_0_value" name="post[tags_attributes][0][value]" placeholder="Tag" type="text" value="new tag" />'
+      end
+
+      assert_dom_equal expected, output_buffer
+    end
+  end
+
   def test_text_field
     assert_dom_equal(
       '<input id="post_title" name="post[title]" type="text" value="Hello World" />',
@@ -665,6 +756,83 @@ class FormHelperTest < ActionView::TestCase
     )
   end
 
+  def test_text_area_placeholder_without_locales
+    with_locale :placeholder do
+      assert_dom_equal(
+        %{<textarea id="post_body" name="post[body]" placeholder="Body">\nBack to the hill and over it again!</textarea>},
+        text_area(:post, :body, placeholder: true)
+      )
+    end
+  end
+
+  def test_text_area_placeholder_with_locales
+    with_locale :placeholder do
+      assert_dom_equal(
+        %{<textarea id="post_title" name="post[title]" placeholder="What is this about?">\nHello World</textarea>},
+        text_area(:post, :title, placeholder: true)
+      )
+    end
+  end
+
+  def test_text_area_placeholder_with_human_attribute_name
+    with_locale :placeholder do
+      assert_dom_equal(
+        %{<textarea id="post_cost" name="post[cost]" placeholder="Total cost">\n</textarea>},
+        text_area(:post, :cost, placeholder: true)
+      )
+    end
+  end
+
+  def test_text_area_placeholder_with_human_attribute_name_and_value
+    with_locale :placeholder do
+      assert_dom_equal(
+        %{<textarea id="post_cost" name="post[cost]" placeholder="Pounds">\n</textarea>},
+        text_area(:post, :cost, placeholder: "uk")
+      )
+    end
+  end
+
+  def test_text_area_placeholder_with_locales_and_value
+    with_locale :placeholder do
+      assert_dom_equal(
+        %{<textarea id="post_written_on" name="post[written_on]" placeholder="Escrito en">\n2004-06-15</textarea>},
+        text_area(:post, :written_on, placeholder: "spanish")
+      )
+    end
+  end
+
+  def test_text_area_placeholder_with_locales_and_nested_attributes
+    with_locale :placeholder do
+      form_for(@post, html: { id: 'create-post' }) do |f|
+        f.fields_for(:comments) do |cf|
+          concat cf.text_area(:body, placeholder: true)
+        end
+      end
+
+      expected = whole_form("/posts/123", "create-post", "edit_post", method: "patch") do
+        %{<textarea id="post_comments_attributes_0_body" name="post[comments_attributes][0][body]" placeholder="Write body here">\n</textarea>}
+      end
+
+      assert_dom_equal expected, output_buffer
+    end
+  end
+
+  def test_text_area_placeholder_with_locales_fallback_and_nested_attributes
+    with_locale :placeholder do
+      form_for(@post, html: { id: 'create-post' }) do |f|
+        f.fields_for(:tags) do |cf|
+          concat cf.text_area(:value, placeholder: true)
+        end
+      end
+
+      expected = whole_form("/posts/123", "create-post", "edit_post", method: "patch") do
+        %{<textarea id="post_tags_attributes_0_value" name="post[tags_attributes][0][value]" placeholder="Tag">\nnew tag</textarea>}
+      end
+
+      assert_dom_equal expected, output_buffer
+    end
+  end
+
   def test_text_area
     assert_dom_equal(
       %{<textarea id="post_body" name="post[body]">\nBack to the hill and over it again!</textarea>},
-- 
cgit v1.2.3