Hello everybody!
Why is "number_to_human_size" method dependent on locales and
translations? Why this method doesnt provide always some reasonable
output? Im using 'de_DE' locale for my application, but Im surprised
that this method actually doesnt work out of the box. I have to search
somewhere for locales etc, thats a shame from my point of view,
especially when size units are quite international. Why are you
leaving poor developer in the dark? Why there is not any note in
documentation etc.
There was also attempts of others to provide some default fallback
(
http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/
1448-add-i18n-for-number_to_human_size-storage-units) but it was
denied. I would say that it is mistake to take defaults from yaml
file. Yaml should be used just for override, even if you want to use
default english.
However, here is my proposal for solution:
def number_to_human_size(number, *args)
return nil if number.nil?
options = args.extract_options!
options.symbolize_keys!
defaults = translate_with_default_fallback
(:'number.format', :locale => options[:locale])
human = translate_with_default_fallback
(:'number.human.format', :locale => options[:locale])
defaults = defaults.merge(human)
unless args.empty?
ActiveSupport::Deprecation.warn('number_to_human_size takes
an option hash ' +
'instead of a separate precision argument.', caller)
precision = args[0] || defaults[:precision]
end
precision ||= (options[:precision] || defaults[:precision])
separator ||= (options[:separator] || defaults[:separator])
delimiter ||= (options[:delimiter] || defaults[:delimiter])
storage_units_format = translate_with_default_fallback
(:'number.human.storage_units.format', :locale => options[:locale])
if number.to_i < 1024
unit = translate_with_default_fallback
(:'number.human.storage_units.units.byte', :locale => options
[:locale], :count => number.to_i)
storage_units_format.gsub(/%n/, number.to_i.to_s).gsub(/%u/,
unit)
else
max_exp = STORAGE_UNITS.size - 1
number = Float(number)
exponent = (Math.log(number) / Math.log(1024)).to_i #
Convert to base 1024
exponent = max_exp if exponent > max_exp # we need this to
avoid overflow for the highest unit
number /= 1024 ** exponent
unit_key = STORAGE_UNITS[exponent]
unit = translate_with_default_fallback
(:"number.human.storage_units.units.#{unit_key}", :locale => options
[:locale], :count => number)
begin
escaped_separator = Regexp.escape(separator)
formatted_number = number_with_precision(number,
:precision => precision,
:separator => separator,
:delimiter => delimiter
).sub(/(\d)(#{escaped_separator}[1-9]*)?0+\z/, '\1\2').sub
(/#{escaped_separator}\z/, '')
storage_units_format.gsub(/%n/, formatted_number).gsub(/
%u/, unit)
rescue
number
end
end
end
private
def translate_with_default_fallback(key, options)
options[:raise] = true
begin
I18n.translate(key, options)
rescue
options[:locale] = :en
I18n.translate(key, options)
end
end
I also created Rails ticket
http://rails.lighthouseapp.com/projects/8994/tickets/2029
for this issue