diff --git a/CHANGELOG b/CHANGELOG index 577201a9c..3c9f74a37 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,7 +16,9 @@ * Changed date/time inputs to default to nil instead of Time.now when the object has no value (due to deprecation warning, #240) * Changed the behaviour of associations with a :class_name option to be more consistent with what Rails expects * Fixed issues with Ruby 1.9.1 and Haml +* Fixed inputs_for_nested_attributes only appending to the output buffer * Add the :disabled option to check_boxes input +* Changed I18n handling in spec tests to use I18n.backend.reload! instead of assigning nil 0.9.8 diff --git a/README.textile b/README.textile index a620af903..5057ce70b 100644 --- a/README.textile +++ b/README.textile @@ -337,7 +337,7 @@ Formtastic supports localized *labels*, *hints*, *legends*, *actions* using the title: "Choose a good title for you post." body: "Write something inspiring here." actions: - create: "Create my {{model}}" + create: "Create my %{model}" update: "Save changes" dummie: "Launch!" @@ -354,7 +354,7 @@ Formtastic supports localized *labels*, *hints*, *legends*, *actions* using the <%= form.input :section %> # => :label => I18n.t('activerecord.attributes.user.section') or 'Section' <% end %> <% form.buttons do %> - <%= form.commit_button %> # => "Create my {{model}}" + <%= form.commit_button %> # => "Create my %{model}" <% end %> <% end %> diff --git a/generators/formtastic/templates/formtastic.rb b/generators/formtastic/templates/formtastic.rb index ee76ff638..bb710efcc 100644 --- a/generators/formtastic/templates/formtastic.rb +++ b/generators/formtastic/templates/formtastic.rb @@ -28,7 +28,7 @@ # Formtastic::SemanticFormBuilder.inline_errors = :sentence # Set the method to call on label text to transform or format it for human-friendly -# reading when formtastic is user without object. Defaults to :humanize. +# reading when formtastic is used without object. Defaults to :humanize. # Formtastic::SemanticFormBuilder.label_str_method = :humanize # Set the array of methods to try calling on parent objects in :select and :radio inputs diff --git a/lib/formtastic.rb b/lib/formtastic.rb index 6ea708296..7319eedcb 100644 --- a/lib/formtastic.rb +++ b/lib/formtastic.rb @@ -1606,9 +1606,9 @@ def humanized_attribute_name(method) #:nodoc: # # Lookup priority: # - # 'formtastic.{{type}}.{{model}}.{{action}}.{{attribute}}' - # 'formtastic.{{type}}.{{model}}.{{attribute}}' - # 'formtastic.{{type}}.{{attribute}}' + # 'formtastic.%{type}.%{model}.%{action}.%{attribute}' + # 'formtastic.%{type}.%{model}.%{attribute}' + # 'formtastic.%{type}.%{attribute}' # # Example: # @@ -1627,15 +1627,16 @@ def localized_string(key, value, type, options = {}) #:nodoc: use_i18n = value.nil? ? @@i18n_lookups_by_default : (value != false) if use_i18n - model_name = self.model_name.underscore + model_name, nested_model_name = normalize_model_name(self.model_name.underscore) action_name = template.params[:action].to_s rescue '' attribute_name = key.to_s defaults = ::Formtastic::I18n::SCOPES.collect do |i18n_scope| i18n_path = i18n_scope.dup - i18n_path.gsub!('{{action}}', action_name) - i18n_path.gsub!('{{model}}', model_name) - i18n_path.gsub!('{{attribute}}', attribute_name) + i18n_path.gsub!('%{action}', action_name) + i18n_path.gsub!('%{model}', model_name) + i18n_path.gsub!('%{nested_model}', nested_model_name) unless nested_model_name.nil? + i18n_path.gsub!('%{attribute}', attribute_name) i18n_path.gsub!('..', '.') i18n_path.to_sym end @@ -1652,6 +1653,14 @@ def model_name @object.present? ? @object.class.name : @object_name.to_s.classify end + def normalize_model_name(name) + if name =~ /(.+)\[(.+)\]/ + [$1, $2] + else + [name] + end + end + def send_or_call(duck, object) if duck.is_a?(Proc) duck.call(object) diff --git a/lib/formtastic/i18n.rb b/lib/formtastic/i18n.rb index 97b05e4c2..5d917fdfb 100644 --- a/lib/formtastic/i18n.rb +++ b/lib/formtastic/i18n.rb @@ -6,13 +6,16 @@ module I18n :required => 'required', :yes => 'Yes', :no => 'No', - :create => 'Create {{model}}', - :update => 'Update {{model}}' + :create => 'Create %{model}', + :update => 'Update %{model}' }.freeze SCOPES = [ - '{{model}}.{{action}}.{{attribute}}', - '{{model}}.{{attribute}}', - '{{attribute}}' + '%{model}.%{nested_model}.%{action}.%{attribute}', + '%{model}.%{action}.%{attribute}', + '%{model}.%{nested_model}.%{attribute}', + '%{model}.%{attribute}', + '%{nested_model}.%{attribute}', + '%{attribute}' ] class << self diff --git a/spec/commit_button_spec.rb b/spec/commit_button_spec.rb index 18f4289e5..efe24cb9d 100644 --- a/spec/commit_button_spec.rb +++ b/spec/commit_button_spec.rb @@ -147,7 +147,7 @@ describe 'when no explicit label is provided' do describe 'when no I18n-localized label is provided' do before do - ::I18n.backend.store_translations :en, :formtastic => {:submit => 'Submit {{model}}'} + ::I18n.backend.store_translations :en, :formtastic => {:submit => 'Submit %{model}'} end after do @@ -183,7 +183,7 @@ :formtastic => { :actions => { :post => { - :submit => 'Custom Submit {{model}}' + :submit => 'Custom Submit %{model}' } } } @@ -225,7 +225,7 @@ describe 'when no explicit label is provided' do describe 'when no I18n-localized label is provided' do before do - ::I18n.backend.store_translations :en, :formtastic => {:create => 'Create {{model}}'} + ::I18n.backend.store_translations :en, :formtastic => {:create => 'Create %{model}'} end after do @@ -261,7 +261,7 @@ :formtastic => { :actions => { :post => { - :create => 'Custom Create {{model}}' + :create => 'Custom Create %{model}' } } } @@ -303,7 +303,7 @@ describe 'when no explicit label is provided' do describe 'when no I18n-localized label is provided' do before do - ::I18n.backend.store_translations :en, :formtastic => {:update => 'Save {{model}}'} + ::I18n.backend.store_translations :en, :formtastic => {:update => 'Save %{model}'} end after do @@ -340,7 +340,7 @@ :formtastic => { :actions => { :post => { - :update => 'Custom Save {{model}}' + :update => 'Custom Save %{model}' } } } diff --git a/spec/i18n_spec.rb b/spec/i18n_spec.rb index ee6f4a6ae..a19be951a 100644 --- a/spec/i18n_spec.rb +++ b/spec/i18n_spec.rb @@ -26,11 +26,11 @@ @formtastic_strings = { :yes => 'Default Yes', :no => 'Default No', - :create => 'Default Create {{model}}', - :update => 'Default Update {{model}}', + :create => 'Default Create %{model}', + :update => 'Default Update %{model}', :custom_scope => { :duck => 'Duck', - :duck_pond => '{{ducks}} ducks in a pond' + :duck_pond => '%{ducks} ducks in a pond' } } ::I18n.backend.store_translations :en, :formtastic => @formtastic_strings @@ -71,7 +71,7 @@ it "should use default strings" do (::Formtastic::I18n::DEFAULT_VALUES.keys).each do |key| - ::Formtastic::I18n.t(key, :model => '{{model}}').should == ::Formtastic::I18n::DEFAULT_VALUES[key] + ::Formtastic::I18n.t(key, :model => '%{model}').should == ::Formtastic::I18n::DEFAULT_VALUES[key] end end @@ -89,7 +89,8 @@ :labels => { :title => "Hello world!", :post => {:title => "Hello post!"}, - :project => {:title => "Hello project!"} + :project => {:title => "Hello project!", :task => {:name => "Hello task name!"}}, + :line_item => {:name => "Hello line item name!"} } } ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = true @@ -123,6 +124,25 @@ output_buffer.should have_tag("form label", /Hello project!/) end + it 'should be able to translate nested objects with nested translations' do + semantic_form_for(:project, :url => 'http://test.host') do |builder| + builder.semantic_fields_for(:task) do |f| + concat(f.input(:name)) + end + end + output_buffer.should have_tag("form label", /Hello task name!/) + end + + it 'should be able to translated nested objects with top level translations' do + semantic_form_for(:order, :url => 'http://test.host') do |builder| + builder.semantic_fields_for(:line_item) do |f| + concat(f.input(:name)) + end + end + output_buffer.should have_tag("form label", /Hello line item name!/) + end + + # TODO: Add spec for namespaced models? end diff --git a/spec/inputs/country_input_spec.rb b/spec/inputs/country_input_spec.rb index 514e1cc00..67570b32d 100644 --- a/spec/inputs/country_input_spec.rb +++ b/spec/inputs/country_input_spec.rb @@ -56,8 +56,8 @@ it "should be passed down to the country_select helper when provided" do priority_countries = ["Foo", "Bah"] semantic_form_for(@new_post) do |builder| - builder.stub!(:country_select).and_return("") - builder.should_receive(:country_select).with(:country, priority_countries, {}, {}).and_return("") + builder.stub!(:country_select).and_return(Formtastic::Util.html_safe("")) + builder.should_receive(:country_select).with(:country, priority_countries, {}, {}).and_return(Formtastic::Util.html_safe("")) concat(builder.input(:country, :as => :country, :priority_countries => priority_countries)) end @@ -69,8 +69,8 @@ priority_countries.should_not be_nil semantic_form_for(@new_post) do |builder| - builder.stub!(:country_select).and_return("") - builder.should_receive(:country_select).with(:country, priority_countries, {}, {}).and_return("") + builder.stub!(:country_select).and_return(Formtastic::Util.html_safe("")) + builder.should_receive(:country_select).with(:country, priority_countries, {}, {}).and_return(Formtastic::Util.html_safe("")) concat(builder.input(:country, :as => :country)) end @@ -84,7 +84,7 @@ before do @form = semantic_form_for(@new_post) do |builder| - builder.stub!(:country_select).and_return("") + builder.stub!(:country_select).and_return(Formtastic::Util.html_safe("")) concat(builder.input(:country)) end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 14f9cd0c4..27951146c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,8 +1,8 @@ # coding: utf-8 require 'rubygems' -gem 'activesupport', '>= 2.3.5' -gem 'actionpack', '>= 2.3.5' +gem 'activesupport', '>=2.3.7' +gem 'actionpack', '>=2.3.7' require 'active_support' require 'action_pack' require 'action_view' @@ -37,6 +37,7 @@ end require File.expand_path(File.join(File.dirname(__FILE__), '../lib/formtastic')) +require File.expand_path(File.join(File.dirname(__FILE__), '../lib/formtastic/util')) require File.expand_path(File.join(File.dirname(__FILE__), '../lib/formtastic/layout_helper')) module ActionView