Skip to content

Commit

Permalink
integrating I18n into Rails
Browse files Browse the repository at this point in the history
  • Loading branch information
Sven Fuchs committed Jun 19, 2008
1 parent 40557e1 commit 45d41f0
Show file tree
Hide file tree
Showing 17 changed files with 1,082 additions and 168 deletions.
2 changes: 2 additions & 0 deletions actionpack/lib/action_view.rb
Expand Up @@ -32,6 +32,8 @@
require 'action_view/partials'
require 'action_view/template_error'

require 'action_view/lang/en-US.rb'

ActionView::Base.class_eval do
include ActionView::Partials

Expand Down
33 changes: 23 additions & 10 deletions actionpack/lib/action_view/helpers/active_record_helper.rb
Expand Up @@ -151,12 +151,17 @@ def error_message_on(object, method, prepend_text = "", append_text = "", css_cl
# 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|
Expand All @@ -168,21 +173,29 @@ def error_messages_for(*params)
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
Expand Down
81 changes: 48 additions & 33 deletions actionpack/lib/action_view/helpers/date_helper.rb
Expand Up @@ -58,35 +58,43 @@ module DateHelper
# 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>.
#
Expand Down Expand Up @@ -498,13 +506,19 @@ def select_day(date, options = {}, html_options = {})
# 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
Expand All @@ -522,7 +536,7 @@ def select_month(date, options = {}, html_options = {})
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
Expand Down Expand Up @@ -612,15 +626,17 @@ def to_datetime_select_tag(options = {}, html_options = {})

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)
Expand All @@ -629,19 +645,19 @@ def date_or_time_select(options, html_options = {})
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
Expand All @@ -656,9 +672,8 @@ def date_or_time_select(options, html_options = {})
when :second then options[:include_seconds] ? " : " : ""
else ""
end)

end

date_or_time_select
end

Expand Down
52 changes: 13 additions & 39 deletions actionpack/lib/action_view/helpers/form_options_helper.rb
Expand Up @@ -276,16 +276,25 @@ def option_groups_from_collection_for_select(collection, group_method, group_lab
# 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
Expand Down Expand Up @@ -340,43 +349,8 @@ def option_value_selected?(value, selected)
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:
Expand Down
18 changes: 12 additions & 6 deletions actionpack/lib/action_view/helpers/number_helper.rb
Expand Up @@ -69,13 +69,19 @@ def number_to_phone(number, options = {})
# 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)
Expand Down

0 comments on commit 45d41f0

Please sign in to comment.