From 45d41f0dadd9fa171f306ff356770c4492726f30 Mon Sep 17 00:00:00 2001
From: Sven Fuchs <svenfuchs@artweb-design.de>
Date: Thu, 19 Jun 2008 16:25:27 +0200
Subject: integrating I18n into Rails

---
 actionpack/lib/action_view.rb                      |  2 +
 .../action_view/helpers/active_record_helper.rb    | 33 +++++---
 actionpack/lib/action_view/helpers/date_helper.rb  | 81 ++++++++++--------
 .../lib/action_view/helpers/form_options_helper.rb | 52 +++---------
 .../lib/action_view/helpers/number_helper.rb       | 18 ++--
 actionpack/lib/action_view/lang/en-US.rb           | 93 ++++++++++++++++++++
 .../template/active_record_helper_i18n_test.rb     | 47 ++++++++++
 actionpack/test/template/date_helper_i18n_test.rb  | 99 ++++++++++++++++++++++
 .../test/template/form_options_helper_i18n_test.rb | 26 ++++++
 .../test/template/number_helper_i18n_test.rb       | 27 ++++++
 10 files changed, 390 insertions(+), 88 deletions(-)
 create mode 100644 actionpack/lib/action_view/lang/en-US.rb
 create mode 100644 actionpack/test/template/active_record_helper_i18n_test.rb
 create mode 100644 actionpack/test/template/date_helper_i18n_test.rb
 create mode 100644 actionpack/test/template/form_options_helper_i18n_test.rb
 create mode 100644 actionpack/test/template/number_helper_i18n_test.rb

(limited to 'actionpack')

diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb
index 973020a768..33d50a61c4 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -32,6 +32,8 @@ require 'action_view/base'
 require 'action_view/partials'
 require 'action_view/template_error'
 
+require 'action_view/lang/en-US.rb'
+
 ActionView::Base.class_eval do
   include ActionView::Partials
 
diff --git a/actionpack/lib/action_view/helpers/active_record_helper.rb b/actionpack/lib/action_view/helpers/active_record_helper.rb
index f3f204cc97..5ad9d5f76d 100644
--- a/actionpack/lib/action_view/helpers/active_record_helper.rb
+++ b/actionpack/lib/action_view/helpers/active_record_helper.rb
@@ -151,12 +151,17 @@ module ActionView
       # instance yourself and set it up. View the source of this method to see how easy it is.
       def error_messages_for(*params)
         options = params.extract_options!.symbolize_keys
+
         if object = options.delete(:object)
           objects = [object].flatten
         else
           objects = params.collect {|object_name| instance_variable_get("@#{object_name}") }.compact
         end
-        count   = objects.inject(0) {|sum, object| sum + object.errors.count }
+        
+        count  = objects.inject(0) {|sum, object| sum + object.errors.count }
+        locale = options[:locale]
+        locale ||= request.locale if respond_to?(:request)
+
         unless count.zero?
           html = {}
           [:id, :class].each do |key|
@@ -168,21 +173,29 @@ module ActionView
             end
           end
           options[:object_name] ||= params.first
-          options[:header_message] = "#{pluralize(count, 'error')} prohibited this #{options[:object_name].to_s.gsub('_', ' ')} from being saved" unless options.include?(:header_message)
-          options[:message] ||= 'There were problems with the following fields:' unless options.include?(:message)
-          error_messages = objects.sum {|object| object.errors.full_messages.map {|msg| content_tag(:li, msg) } }.join
 
-          contents = ''
-          contents << content_tag(options[:header_tag] || :h2, options[:header_message]) unless options[:header_message].blank?
-          contents << content_tag(:p, options[:message]) unless options[:message].blank?
-          contents << content_tag(:ul, error_messages)
+          I18n.with_options :locale => locale, :scope => [:active_record, :error] do |locale|
+            header_message = if options.include?(:header_message)
+              options[:header_message]
+            else 
+              object_name = options[:object_name].to_s.gsub('_', ' ')
+              locale.t :header_message, :count => count, :object_name => object_name
+            end
+            message = options.include?(:message) ? options[:message] : locale.t(:message)
+            error_messages = objects.sum {|object| object.errors.full_messages.map {|msg| content_tag(:li, msg) } }.join
+
+            contents = ''
+            contents << content_tag(options[:header_tag] || :h2, header_message) unless header_message.blank?
+            contents << content_tag(:p, message) unless message.blank?
+            contents << content_tag(:ul, error_messages)
 
-          content_tag(:div, contents, html)
+            content_tag(:div, contents, html)
+          end
         else
           ''
         end
       end
-
+      
       private
         def all_input_tags(record, record_name, options)
           input_block = options[:input_block] || default_input_block
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index 7ed6272898..0337be0744 100755
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -58,35 +58,43 @@ module ActionView
       #   distance_of_time_in_words(to_time, from_time, true)     # => over 6 years
       #   distance_of_time_in_words(Time.now, Time.now)           # => less than a minute
       #
-      def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false)
+      def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false, options = {})
+        locale = options[:locale] 
+        locale ||= request.locale if respond_to?(:request)
+
         from_time = from_time.to_time if from_time.respond_to?(:to_time)
         to_time = to_time.to_time if to_time.respond_to?(:to_time)
         distance_in_minutes = (((to_time - from_time).abs)/60).round
         distance_in_seconds = ((to_time - from_time).abs).round
 
-        case distance_in_minutes
-          when 0..1
-            return (distance_in_minutes == 0) ? 'less than a minute' : '1 minute' unless include_seconds
-            case distance_in_seconds
-              when 0..4   then 'less than 5 seconds'
-              when 5..9   then 'less than 10 seconds'
-              when 10..19 then 'less than 20 seconds'
-              when 20..39 then 'half a minute'
-              when 40..59 then 'less than a minute'
-              else             '1 minute'
-            end
+        I18n.with_options :locale => locale, :scope => :'datetime.distance_in_words' do |locale|
+          case distance_in_minutes
+            when 0..1
+              return distance_in_minutes == 0 ? 
+                     locale.t(:less_than_x_minutes, :count => 1) :
+                     locale.t(:x_minutes, :count => distance_in_minutes) unless include_seconds
+
+              case distance_in_seconds
+                when 0..4   then locale.t :less_than_x_seconds, :count => 5
+                when 5..9   then locale.t :less_than_x_seconds, :count => 10
+                when 10..19 then locale.t :less_than_x_seconds, :count => 20
+                when 20..39 then locale.t :half_a_minute
+                when 40..59 then locale.t :less_than_x_minutes, :count => 1
+                else             locale.t :x_minutes,           :count => 1
+              end
 
-          when 2..44           then "#{distance_in_minutes} minutes"
-          when 45..89          then 'about 1 hour'
-          when 90..1439        then "about #{(distance_in_minutes.to_f / 60.0).round} hours"
-          when 1440..2879      then '1 day'
-          when 2880..43199     then "#{(distance_in_minutes / 1440).round} days"
-          when 43200..86399    then 'about 1 month'
-          when 86400..525599   then "#{(distance_in_minutes / 43200).round} months"
-          when 525600..1051199 then 'about 1 year'
-          else                      "over #{(distance_in_minutes / 525600).round} years"
+            when 2..44           then locale.t :x_minutes,      :count => distance_in_minutes
+            when 45..89          then locale.t :about_x_hours,  :count => 1
+            when 90..1439        then locale.t :about_x_hours,  :count => (distance_in_minutes.to_f / 60.0).round
+            when 1440..2879      then locale.t :x_days,         :count => 1
+            when 2880..43199     then locale.t :x_days,         :count => (distance_in_minutes / 1440).round
+            when 43200..86399    then locale.t :about_x_months, :count => 1
+            when 86400..525599   then locale.t :x_months,       :count => (distance_in_minutes / 43200).round
+            when 525600..1051199 then locale.t :about_x_years,  :count => 1
+            else                      locale.t :over_x_years,   :count => (distance_in_minutes / 525600).round
+          end
         end
-      end
+      end      
 
       # Like distance_of_time_in_words, but where <tt>to_time</tt> is fixed to <tt>Time.now</tt>.
       #
@@ -498,13 +506,19 @@ module ActionView
       #   select_month(Date.today, :use_month_names => %w(Januar Februar Marts ...))
       #
       def select_month(date, options = {}, html_options = {})
+        locale = options[:locale] 
+        locale ||= request.locale if respond_to?(:request)
+
         val = date ? (date.kind_of?(Fixnum) ? date : date.month) : ''
         if options[:use_hidden]
           hidden_html(options[:field_name] || 'month', val, options)
         else
           month_options = []
-          month_names = options[:use_month_names] || (options[:use_short_month] ? Date::ABBR_MONTHNAMES : Date::MONTHNAMES)
+          month_names = options[:use_month_names] || begin
+            (options[:use_short_month] ? :'date.abbr_month_names' : :'date.month_names').t locale
+          end
           month_names.unshift(nil) if month_names.size < 13
+
           1.upto(12) do |month_number|
             month_name = if options[:use_month_numbers]
               month_number
@@ -522,7 +536,7 @@ module ActionView
           end
           select_html(options[:field_name] || 'month', month_options.join, options, html_options)
         end
-      end
+      end      
 
       # Returns a select tag with options for each of the five years on each side of the current, which is selected. The five year radius
       # can be changed using the <tt>:start_year</tt> and <tt>:end_year</tt> keys in the +options+. Both ascending and descending year
@@ -612,15 +626,17 @@ module ActionView
 
       private
         def date_or_time_select(options, html_options = {})
+          locale = options[:locale]
+
           defaults = { :discard_type => true }
           options  = defaults.merge(options)
           datetime = value(object)
           datetime ||= default_time_from_options(options[:default]) unless options[:include_blank]
-
+    
           position = { :year => 1, :month => 2, :day => 3, :hour => 4, :minute => 5, :second => 6 }
 
-          order = (options[:order] ||= [:year, :month, :day])
-
+          order = options[:order] ||= :'date.order'.t(locale)
+    
           # Discard explicit and implicit by not being included in the :order
           discard = {}
           discard[:year]   = true if options[:discard_year] or !order.include?(:year)
@@ -629,19 +645,19 @@ module ActionView
           discard[:hour]   = true if options[:discard_hour]
           discard[:minute] = true if options[:discard_minute] or discard[:hour]
           discard[:second] = true unless options[:include_seconds] && !discard[:minute]
-
+    
           # If the day is hidden and the month is visible, the day should be set to the 1st so all month choices are valid
           # (otherwise it could be 31 and february wouldn't be a valid date)
           if datetime && discard[:day] && !discard[:month]
             datetime = datetime.change(:day => 1)
           end
-
+    
           # Maintain valid dates by including hidden fields for discarded elements
           [:day, :month, :year].each { |o| order.unshift(o) unless order.include?(o) }
-
+    
           # Ensure proper ordering of :hour, :minute and :second
           [:hour, :minute, :second].each { |o| order.delete(o); order.push(o) }
-
+    
           date_or_time_select = ''
           order.reverse.each do |param|
             # Send hidden fields for discarded elements once output has started
@@ -656,9 +672,8 @@ module ActionView
                 when :second then options[:include_seconds] ? " : " : ""
                 else ""
               end)
-
           end
-
+    
           date_or_time_select
         end
 
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index b3f8e63c1b..c782c0a816 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -276,16 +276,25 @@ module ActionView
       # that they will be listed above the rest of the (long) list.
       #
       # NOTE: Only the option tags are returned, you have to wrap this call in a regular HTML select tag.
-      def country_options_for_select(selected = nil, priority_countries = nil)
+      def country_options_for_select(*args)
+        options = args.extract_options!
+        
+        locale = options[:locale]
+        locale ||= request.locale if respond_to?(:request)
+        
+        selected, priority_countries = *args        
+        countries = :'countries.names'.t options[:locale]
         country_options = ""
 
         if priority_countries
+          # TODO priority_countries need to be translated?
           country_options += options_for_select(priority_countries, selected)
           country_options += "<option value=\"\" disabled=\"disabled\">-------------</option>\n"
         end
 
-        return country_options + options_for_select(COUNTRIES, selected)
+        return country_options + options_for_select(countries, selected)
       end
+      
 
       # Returns a string of option tags for pretty much any time zone in the
       # world. Supply a TimeZone name as +selected+ to have it marked as the
@@ -340,43 +349,8 @@ module ActionView
         end
 
         # All the countries included in the country_options output.
-        COUNTRIES = ["Afghanistan", "Aland Islands", "Albania", "Algeria", "American Samoa", "Andorra", "Angola",
-          "Anguilla", "Antarctica", "Antigua And Barbuda", "Argentina", "Armenia", "Aruba", "Australia", "Austria",
-          "Azerbaijan", "Bahamas", "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin",
-          "Bermuda", "Bhutan", "Bolivia", "Bosnia and Herzegowina", "Botswana", "Bouvet Island", "Brazil",
-          "British Indian Ocean Territory", "Brunei Darussalam", "Bulgaria", "Burkina Faso", "Burundi", "Cambodia",
-          "Cameroon", "Canada", "Cape Verde", "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
-          "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
-          "Congo, the Democratic Republic of the", "Cook Islands", "Costa Rica", "Cote d'Ivoire", "Croatia", "Cuba",
-          "Cyprus", "Czech Republic", "Denmark", "Djibouti", "Dominica", "Dominican Republic", "Ecuador", "Egypt",
-          "El Salvador", "Equatorial Guinea", "Eritrea", "Estonia", "Ethiopia", "Falkland Islands (Malvinas)",
-          "Faroe Islands", "Fiji", "Finland", "France", "French Guiana", "French Polynesia",
-          "French Southern Territories", "Gabon", "Gambia", "Georgia", "Germany", "Ghana", "Gibraltar", "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guernsey", "Guinea",
-          "Guinea-Bissau", "Guyana", "Haiti", "Heard and McDonald Islands", "Holy See (Vatican City State)",
-          "Honduras", "Hong Kong", "Hungary", "Iceland", "India", "Indonesia", "Iran, Islamic Republic of", "Iraq",
-          "Ireland", "Isle of Man", "Israel", "Italy", "Jamaica", "Japan", "Jersey", "Jordan", "Kazakhstan", "Kenya",
-          "Kiribati", "Korea, Democratic People's Republic of", "Korea, Republic of", "Kuwait", "Kyrgyzstan",
-          "Lao People's Democratic Republic", "Latvia", "Lebanon", "Lesotho", "Liberia", "Libyan Arab Jamahiriya",
-          "Liechtenstein", "Lithuania", "Luxembourg", "Macao", "Macedonia, The Former Yugoslav Republic Of",
-          "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", "Martinique",
-          "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia, Federated States of", "Moldova, Republic of",
-          "Monaco", "Mongolia", "Montenegro", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia", "Nauru",
-          "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand", "Nicaragua", "Niger",
-          "Nigeria", "Niue", "Norfolk Island", "Northern Mariana Islands", "Norway", "Oman", "Pakistan", "Palau",
-          "Palestinian Territory, Occupied", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines",
-          "Pitcairn", "Poland", "Portugal", "Puerto Rico", "Qatar", "Reunion", "Romania", "Russian Federation",
-          "Rwanda", "Saint Barthelemy", "Saint Helena", "Saint Kitts and Nevis", "Saint Lucia",
-          "Saint Pierre and Miquelon", "Saint Vincent and the Grenadines", "Samoa", "San Marino",
-          "Sao Tome and Principe", "Saudi Arabia", "Senegal", "Serbia", "Seychelles", "Sierra Leone", "Singapore",
-          "Slovakia", "Slovenia", "Solomon Islands", "Somalia", "South Africa",
-          "South Georgia and the South Sandwich Islands", "Spain", "Sri Lanka", "Sudan", "Suriname",
-          "Svalbard and Jan Mayen", "Swaziland", "Sweden", "Switzerland", "Syrian Arab Republic",
-          "Taiwan, Province of China", "Tajikistan", "Tanzania, United Republic of", "Thailand", "Timor-Leste",
-          "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey", "Turkmenistan",
-          "Turks and Caicos Islands", "Tuvalu", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom",
-          "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan", "Vanuatu", "Venezuela",
-          "Viet Nam", "Virgin Islands, British", "Virgin Islands, U.S.", "Wallis and Futuna", "Western Sahara",
-          "Yemen", "Zambia", "Zimbabwe"] unless const_defined?("COUNTRIES")
+        # only included for backwards compatibility, please use the I18n interface
+        COUNTRIES = :'countries.names'.t 'en-US' unless const_defined?("COUNTRIES")
     end
 
     class InstanceTag #:nodoc:
diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb
index 120bb4cc1f..9d98036f2d 100644
--- a/actionpack/lib/action_view/helpers/number_helper.rb
+++ b/actionpack/lib/action_view/helpers/number_helper.rb
@@ -69,13 +69,19 @@ module ActionView
       #  number_to_currency(1234567890.50, :unit => "&pound;", :separator => ",", :delimiter => "", :format => "%n %u")
       #  # => 1234567890,50 &pound;
       def number_to_currency(number, options = {})
-        options   = options.stringify_keys
-        precision = options["precision"] || 2
-        unit      = options["unit"] || "$"
-        separator = precision > 0 ? options["separator"] || "." : ""
-        delimiter = options["delimiter"] || ","
-        format    = options["format"] || "%u%n"
+        options = options.symbolize_keys
+        
+        locale = options[:locale]
+        locale ||= request.locale if respond_to?(:request)
 
+        defaults  = :'currency.format'.t(locale) || {}
+        precision = options[:precision] || defaults[:precision]
+        unit      = options[:unit]      || defaults[:unit]
+        separator = options[:separator] || defaults[:separator]
+        delimiter = options[:delimiter] || defaults[:delimiter]
+        format    = options[:format]    || defaults[:format]
+        separator = '' if precision == 0
+        
         begin
           parts = number_with_precision(number, precision).split('.')
           format.gsub(/%n/, number_with_delimiter(parts[0], delimiter) + separator + parts[1].to_s).gsub(/%u/, unit)
diff --git a/actionpack/lib/action_view/lang/en-US.rb b/actionpack/lib/action_view/lang/en-US.rb
new file mode 100644
index 0000000000..659f96a5f3
--- /dev/null
+++ b/actionpack/lib/action_view/lang/en-US.rb
@@ -0,0 +1,93 @@
+I18n.backend.add_translations :'en-US', {
+  :date => {
+    :formats => {
+      :default => "%Y-%m-%d",
+      :short => "%b %d",
+      :long => "%B %d, %Y",
+    },
+    :day_names => Date::DAYNAMES,
+    :abbr_day_names => Date::ABBR_DAYNAMES,
+    :month_names => Date::MONTHNAMES,
+    :abbr_month_names => Date::ABBR_MONTHNAMES,
+    :order => [:year, :month, :day]
+  },
+  :time => {
+    :formats => {
+      :default => "%a, %d %b %Y %H:%M:%S %z",
+      :short => "%d %b %H:%M",
+      :long => "%B %d, %Y %H:%M",
+    },
+    :am => 'am',
+    :pm => 'pm'
+  },
+  :datetime => {
+    :distance_in_words => {
+      :half_a_minute       => 'half a minute',
+      :less_than_x_seconds => ['less than 1 second', 'less than {{count}} seconds'],
+      :x_seconds           => ['1 second', '{{count}} seconds'],
+      :less_than_x_minutes => ['less than a minute', 'less than {{count}} minutes'],
+      :x_minutes           => ['1 minute', '{{count}} minutes'],
+      :about_x_hours       => ['about 1 hour', 'about {{count}} hours'],
+      :x_days              => ['1 day', '{{count}} days'],
+      :about_x_months      => ['about 1 month', 'about {{count}} months'],
+      :x_months            => ['1 month', '{{count}} months'],
+      :about_x_years       => ['about 1 year', 'about {{count}} year'],
+      :over_x_years        => ['over 1 year', 'over {{count}} years']
+    }
+  },
+  :currency => {
+    :format => {
+      :unit => '$',
+      :precision => 2,
+      :separator => '.',
+      :delimiter => ',',
+      :format => '%u%n',
+    }
+  },
+  :countries => {
+    :names => ["Afghanistan", "Aland Islands", "Albania", "Algeria", "American Samoa", "Andorra", "Angola",
+      "Anguilla", "Antarctica", "Antigua And Barbuda", "Argentina", "Armenia", "Aruba", "Australia", "Austria",
+      "Azerbaijan", "Bahamas", "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin",
+      "Bermuda", "Bhutan", "Bolivia", "Bosnia and Herzegowina", "Botswana", "Bouvet Island", "Brazil",
+      "British Indian Ocean Territory", "Brunei Darussalam", "Bulgaria", "Burkina Faso", "Burundi", "Cambodia",
+      "Cameroon", "Canada", "Cape Verde", "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
+      "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
+      "Congo, the Democratic Republic of the", "Cook Islands", "Costa Rica", "Cote d'Ivoire", "Croatia", "Cuba",
+      "Cyprus", "Czech Republic", "Denmark", "Djibouti", "Dominica", "Dominican Republic", "Ecuador", "Egypt",
+      "El Salvador", "Equatorial Guinea", "Eritrea", "Estonia", "Ethiopia", "Falkland Islands (Malvinas)",
+      "Faroe Islands", "Fiji", "Finland", "France", "French Guiana", "French Polynesia",
+      "French Southern Territories", "Gabon", "Gambia", "Georgia", "Germany", "Ghana", "Gibraltar", "Greece", 
+      "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guernsey", "Guinea",
+      "Guinea-Bissau", "Guyana", "Haiti", "Heard and McDonald Islands", "Holy See (Vatican City State)",
+      "Honduras", "Hong Kong", "Hungary", "Iceland", "India", "Indonesia", "Iran, Islamic Republic of", "Iraq",
+      "Ireland", "Isle of Man", "Israel", "Italy", "Jamaica", "Japan", "Jersey", "Jordan", "Kazakhstan", "Kenya",
+      "Kiribati", "Korea, Democratic People's Republic of", "Korea, Republic of", "Kuwait", "Kyrgyzstan",
+      "Lao People's Democratic Republic", "Latvia", "Lebanon", "Lesotho", "Liberia", "Libyan Arab Jamahiriya",
+      "Liechtenstein", "Lithuania", "Luxembourg", "Macao", "Macedonia, The Former Yugoslav Republic Of",
+      "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", "Martinique",
+      "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia, Federated States of", "Moldova, Republic of",
+      "Monaco", "Mongolia", "Montenegro", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia", "Nauru",
+      "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand", "Nicaragua", "Niger",
+      "Nigeria", "Niue", "Norfolk Island", "Northern Mariana Islands", "Norway", "Oman", "Pakistan", "Palau",
+      "Palestinian Territory, Occupied", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines",
+      "Pitcairn", "Poland", "Portugal", "Puerto Rico", "Qatar", "Reunion", "Romania", "Russian Federation",
+      "Rwanda", "Saint Barthelemy", "Saint Helena", "Saint Kitts and Nevis", "Saint Lucia",
+      "Saint Pierre and Miquelon", "Saint Vincent and the Grenadines", "Samoa", "San Marino",
+      "Sao Tome and Principe", "Saudi Arabia", "Senegal", "Serbia", "Seychelles", "Sierra Leone", "Singapore",
+      "Slovakia", "Slovenia", "Solomon Islands", "Somalia", "South Africa",
+      "South Georgia and the South Sandwich Islands", "Spain", "Sri Lanka", "Sudan", "Suriname",
+      "Svalbard and Jan Mayen", "Swaziland", "Sweden", "Switzerland", "Syrian Arab Republic",
+      "Taiwan, Province of China", "Tajikistan", "Tanzania, United Republic of", "Thailand", "Timor-Leste",
+      "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey", "Turkmenistan",
+      "Turks and Caicos Islands", "Tuvalu", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom",
+      "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan", "Vanuatu", "Venezuela",
+      "Viet Nam", "Virgin Islands, British", "Virgin Islands, U.S.", "Wallis and Futuna", "Western Sahara",
+      "Yemen", "Zambia", "Zimbabwe"]
+  },
+  :active_record => {
+    :error => {
+      :header_message => ["1 error prohibited this {{object_name}} from being saved", "{{count}} errors prohibited this {{object_name}} from being saved"],
+      :message => "There were problems with the following fields:"
+    }            
+  }  
+}
diff --git a/actionpack/test/template/active_record_helper_i18n_test.rb b/actionpack/test/template/active_record_helper_i18n_test.rb
new file mode 100644
index 0000000000..057fb9bd1a
--- /dev/null
+++ b/actionpack/test/template/active_record_helper_i18n_test.rb
@@ -0,0 +1,47 @@
+require 'abstract_unit'
+
+class ActiveRecordHelperI18nTest < Test::Unit::TestCase
+  include ActionView::Helpers::ActiveRecordHelper
+  
+  attr_reader :request
+  def setup
+    @request = mock
+    @object = stub :errors => stub(:count => 1, :full_messages => ['full_messages'])
+    stubs(:content_tag).returns 'content_tag'
+    
+    I18n.stubs(:t).with(:'header_message', :locale => 'en-US', :scope => [:active_record, :error], :count => 1, :object_name => '').returns "1 error prohibited this  from being saved"
+    I18n.stubs(:t).with(:'message', :locale => 'en-US', :scope => [:active_record, :error]).returns 'There were problems with the following fields:'
+  end
+
+  def test_error_messages_for_given_a_locale_it_does_not_check_request_for_locale
+    request.expects(:locale).never
+    @object.errors.stubs(:count).returns 0
+    error_messages_for(:object => @object, :locale => 'en-US')
+  end
+  
+  def test_error_messages_for_given_no_locale_it_checks_request_for_locale
+    request.expects(:locale).returns 'en-US'
+    @object.errors.stubs(:count).returns 0
+    error_messages_for(:object => @object)
+  end
+  
+  def test_error_messages_for_given_a_header_message_option_it_does_not_translate_header_message
+    I18n.expects(:translate).with(:'header_message', :locale => 'en-US', :scope => [:active_record, :error], :count => 1, :object_name => '').never
+    error_messages_for(:object => @object, :header_message => 'header message', :locale => 'en-US')
+  end
+
+  def test_error_messages_for_given_no_header_message_option_it_translates_header_message
+    I18n.expects(:t).with(:'header_message', :locale => 'en-US', :scope => [:active_record, :error], :count => 1, :object_name => '').returns 'header message'
+    error_messages_for(:object => @object, :locale => 'en-US')
+  end
+  
+  def test_error_messages_for_given_a_message_option_it_does_not_translate_message
+    I18n.expects(:t).with(:'message', :locale => 'en-US', :scope => [:active_record, :error]).never
+    error_messages_for(:object => @object, :message => 'message', :locale => 'en-US')
+  end
+
+  def test_error_messages_for_given_no_message_option_it_translates_message
+    I18n.expects(:t).with(:'message', :locale => 'en-US', :scope => [:active_record, :error]).returns 'There were problems with the following fields:'
+    error_messages_for(:object => @object, :locale => 'en-US')
+  end
+end
\ No newline at end of file
diff --git a/actionpack/test/template/date_helper_i18n_test.rb b/actionpack/test/template/date_helper_i18n_test.rb
new file mode 100644
index 0000000000..9b7c03a400
--- /dev/null
+++ b/actionpack/test/template/date_helper_i18n_test.rb
@@ -0,0 +1,99 @@
+require 'abstract_unit'
+
+class DateHelperDistanceOfTimeInWordsI18nTests < Test::Unit::TestCase
+  include ActionView::Helpers::DateHelper
+  attr_reader :request
+  
+  def setup
+    @request = mock
+    @from = Time.mktime(2004, 6, 6, 21, 45, 0)
+  end
+  
+  # distance_of_time_in_words
+
+  def test_distance_of_time_in_words_given_a_locale_it_does_not_check_request_for_locale
+    request.expects(:locale).never
+    distance_of_time_in_words @from, @from + 1.second, false, :locale => 'en-US'
+  end
+  
+  def test_distance_of_time_in_words_given_no_locale_it_checks_request_for_locale
+    request.expects(:locale).returns 'en-US'
+    distance_of_time_in_words @from, @from + 1.second
+  end
+  
+  def test_distance_of_time_in_words_calls_i18n
+    { # with include_seconds
+      [2.seconds,  true]  => [:'less_than_x_seconds', 5],   
+      [9.seconds,  true]  => [:'less_than_x_seconds', 10],  
+      [19.seconds, true]  => [:'less_than_x_seconds', 20],  
+      [30.seconds, true]  => [:'half_a_minute',       nil], 
+      [59.seconds, true]  => [:'less_than_x_minutes', 1], 
+      [60.seconds, true]  => [:'x_minutes',           1], 
+      
+      # without include_seconds
+      [29.seconds, false] => [:'less_than_x_minutes', 1],
+      [60.seconds, false] => [:'x_minutes',           1],
+      [44.minutes, false] => [:'x_minutes',           44],
+      [61.minutes, false] => [:'about_x_hours',       1],
+      [24.hours,   false] => [:'x_days',              1],
+      [30.days,    false] => [:'about_x_months',      1],
+      [60.days,    false] => [:'x_months',            2],
+      [1.year,     false] => [:'about_x_years',       1],
+      [3.years,    false] => [:'over_x_years',        3]
+      
+      }.each do |passed, expected|
+      assert_distance_of_time_in_words_translates_key passed, expected
+    end
+  end
+  
+  def assert_distance_of_time_in_words_translates_key(passed, expected)
+    diff, include_seconds = *passed
+    key, count = *expected    
+    to = @from + diff
+
+    options = {:locale => 'en-US', :scope => :'datetime.distance_in_words'}
+    options[:count] = count if count
+    
+    I18n.expects(:t).with(key, options)
+    distance_of_time_in_words(@from, to, include_seconds, :locale => 'en-US')
+  end
+end
+  
+class DateHelperSelectTagsI18nTests < Test::Unit::TestCase
+  include ActionView::Helpers::DateHelper
+  attr_reader :request
+  
+  def setup
+    @request = mock
+    I18n.stubs(:translate).with(:'date.month_names', 'en-US').returns Date::MONTHNAMES
+  end
+  
+  # select_month
+  
+  def test_select_month_given_use_month_names_option_does_not_translate_monthnames
+    I18n.expects(:translate).never
+    select_month(8, :locale => 'en-US', :use_month_names => Date::MONTHNAMES)
+  end
+  
+  def test_select_month_translates_monthnames
+    I18n.expects(:translate).with(:'date.month_names', 'en-US').returns Date::MONTHNAMES
+    select_month(8, :locale => 'en-US')
+  end
+  
+  def test_select_month_given_use_short_month_option_translates_abbr_monthnames
+    I18n.expects(:translate).with(:'date.abbr_month_names', 'en-US').returns Date::ABBR_MONTHNAMES
+    select_month(8, :locale => 'en-US', :use_short_month => true)
+  end
+  
+  # date_or_time_select
+  
+  def test_date_or_time_select_given_an_order_options_does_not_translate_order
+    I18n.expects(:translate).never
+    datetime_select('post', 'updated_at', :order => [:year, :month, :day], :locale => 'en-US')
+  end
+  
+  def test_date_or_time_select_given_no_order_options_translates_order
+    I18n.expects(:translate).with(:'date.order', 'en-US').returns [:year, :month, :day]
+    datetime_select('post', 'updated_at', :locale => 'en-US')
+  end
+end
\ No newline at end of file
diff --git a/actionpack/test/template/form_options_helper_i18n_test.rb b/actionpack/test/template/form_options_helper_i18n_test.rb
new file mode 100644
index 0000000000..c9fc0768bb
--- /dev/null
+++ b/actionpack/test/template/form_options_helper_i18n_test.rb
@@ -0,0 +1,26 @@
+require 'abstract_unit'
+
+class FormOptionsHelperI18nTests < Test::Unit::TestCase
+  include ActionView::Helpers::FormOptionsHelper
+  attr_reader :request
+  
+  def setup
+    @request = mock
+  end
+
+  def test_country_options_for_select_given_a_locale_it_does_not_check_request_for_locale
+    request.expects(:locale).never
+    country_options_for_select :locale => 'en-US'
+  end
+  
+  def test_country_options_for_select_given_no_locale_it_checks_request_for_locale
+    request.expects(:locale).returns 'en-US'
+    country_options_for_select
+  end
+
+  def test_country_options_for_select_translates_country_names
+    countries = ActionView::Helpers::FormOptionsHelper::COUNTRIES
+    I18n.expects(:translate).with(:'countries.names', 'en-US').returns countries
+    country_options_for_select :locale => 'en-US'
+  end  
+end
\ No newline at end of file
diff --git a/actionpack/test/template/number_helper_i18n_test.rb b/actionpack/test/template/number_helper_i18n_test.rb
new file mode 100644
index 0000000000..47cb035f56
--- /dev/null
+++ b/actionpack/test/template/number_helper_i18n_test.rb
@@ -0,0 +1,27 @@
+require 'abstract_unit'
+
+class NumberHelperI18nTests < Test::Unit::TestCase
+  include ActionView::Helpers::NumberHelper
+  
+  attr_reader :request
+  def setup
+    @request = mock
+    @defaults = {:separator => ".", :unit => "$", :format => "%u%n", :delimiter => ",", :precision => 2}
+    I18n.backend.add_translations 'en-US', :currency => {:format => @defaults}
+  end
+
+  def test_number_to_currency_given_a_locale_it_does_not_check_request_for_locale
+    request.expects(:locale).never
+    number_to_currency(1, :locale => 'en-US')
+  end
+
+  def test_number_to_currency_given_no_locale_it_checks_request_for_locale
+    request.expects(:locale).returns 'en-US'
+    number_to_currency(1)
+  end
+
+  def test_number_to_currency_translates_currency_formats
+    I18n.expects(:translate).with(:'currency.format', 'en-US').returns @defaults
+    number_to_currency(1, :locale => 'en-US')
+  end
+end
\ No newline at end of file
-- 
cgit v1.2.3