number_helper.rb 24.4 KB
Newer Older
1
require 'active_support/core_ext/big_decimal/conversions'
J
Jeremy Kemper 已提交
2
require 'active_support/core_ext/float/rounding'
3
require 'active_support/core_ext/object/blank'
S
Santiago Pastorino 已提交
4
require 'active_support/core_ext/string/output_safety'
J
Jeremy Kemper 已提交
5

6
module ActionView
R
Rizwan Reza 已提交
7
  # = Action View Number Helpers
8
  module Helpers #:nodoc:
9

10
    # Provides methods for converting numbers into formatted strings.
11
    # Methods are provided for phone numbers, currency, percentage,
12 13 14 15
    # precision, positional notation, file size and pretty printing.
    #
    # Most methods expect a +number+ argument, and will return it
    # unchanged if can't be converted into a valid number.
16
    module NumberHelper
17

18 19 20
      DEFAULT_CURRENCY_VALUES = { :format => "%u%n", :unit => "$", :separator => ".", :delimiter => ",",
                                  :precision => 2, :significant => false, :strip_insignificant_zeros => false }

21 22 23 24 25 26 27 28 29
      # Raised when argument +number+ param given to the helpers is invalid and
      # the option :raise is set to  +true+.
      class InvalidNumberError < StandardError
        attr_accessor :number
        def initialize(number)
          @number = number
        end
      end

30
      # Formats a +number+ into a US phone number (e.g., (555) 123-9876). You can customize the format
31
      # in the +options+ hash.
32 33
      #
      # ==== Options
34
      # * <tt>:area_code</tt>  - Adds parentheses around the area code.
35
      # * <tt>:delimiter</tt>  - Specifies the delimiter to use (defaults to "-").
36
      # * <tt>:extension</tt>  - Specifies an extension to add to the end of the
37
      #   generated number.
38 39
      # * <tt>:country_code</tt>  - Sets the country code for the phone number.
      #
40
      # ==== Examples
41
      #  number_to_phone(5551234)                                           # => 555-1234
42 43 44 45 46 47
      #  number_to_phone(1235551234)                                        # => 123-555-1234
      #  number_to_phone(1235551234, :area_code => true)                    # => (123) 555-1234
      #  number_to_phone(1235551234, :delimiter => " ")                     # => 123 555 1234
      #  number_to_phone(1235551234, :area_code => true, :extension => 555) # => (123) 555-1234 x 555
      #  number_to_phone(1235551234, :country_code => 1)                    # => +1-123-555-1234
      #
48
      #  number_to_phone(1235551234, :country_code => 1, :extension => 1343, :delimiter => ".")
49
      #  => +1.123.555.1234 x 1343
50
      def number_to_phone(number, options = {})
S
Santiago Pastorino 已提交
51
        return nil unless number
52

53 54 55
        begin
          Float(number)
        rescue ArgumentError, TypeError
56 57
          raise InvalidNumberError, number
        end if options[:raise]
58

59
        number       = number.to_s.strip
60
        options      = options.symbolize_keys
61
        area_code    = options[:area_code]
62
        delimiter    = options[:delimiter] || "-"
63 64
        extension    = options[:extension].to_s.strip
        country_code = options[:country_code]
65

66 67 68 69 70 71 72
        str = ""
        str << "+#{country_code}#{delimiter}" unless country_code.blank?
        str << if area_code
          number.gsub!(/([0-9]{1,3})([0-9]{3})([0-9]{4}$)/,"(\\1) \\2#{delimiter}\\3")
        else
          number.gsub!(/([0-9]{0,3})([0-9]{3})([0-9]{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
          number.starts_with?('-') ? number.slice!(1..-1) : number
73
        end
74
        str << " x #{extension}" unless extension.blank?
75
        html_escape(str)
76 77
      end

78
      # Formats a +number+ into a currency string (e.g., $13.65). You can customize the format
79 80
      # in the +options+ hash.
      #
81
      # ==== Options
82
      # * <tt>:locale</tt>     -  Sets the locale to be used for formatting (defaults to current locale).
83
      # * <tt>:precision</tt>  -  Sets the level of precision (defaults to 2).
84
      # * <tt>:unit</tt>       - Sets the denomination of the currency (defaults to "$").
85 86
      # * <tt>:separator</tt>  - Sets the separator between the units (defaults to ".").
      # * <tt>:delimiter</tt>  - Sets the thousands delimiter (defaults to ",").
87
      # * <tt>:format</tt>     - Sets the format of the output string (defaults to "%u%n"). The field types are:
88 89 90
      #
      #     %u  The currency unit
      #     %n  The number
91 92 93 94 95
      #
      # ==== Examples
      #  number_to_currency(1234567890.50)                    # => $1,234,567,890.50
      #  number_to_currency(1234567890.506)                   # => $1,234,567,890.51
      #  number_to_currency(1234567890.506, :precision => 3)  # => $1,234,567,890.506
96
      #  number_to_currency(1234567890.506, :locale => :fr)   # => 1 234 567 890,506 €
97
      #
98
      #  number_to_currency(1234567890.50, :unit => "&pound;", :separator => ",", :delimiter => "")
99
      #  # => &pound;1234567890,50
100 101
      #  number_to_currency(1234567890.50, :unit => "&pound;", :separator => ",", :delimiter => "", :format => "%n %u")
      #  # => 1234567890,50 &pound;
102
      def number_to_currency(number, options = {})
103 104
        return nil if number.nil?

105 106
        options.symbolize_keys!

107 108
        defaults  = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
        currency  = I18n.translate(:'number.currency.format', :locale => options[:locale], :default => {})
109

110 111
        defaults  = DEFAULT_CURRENCY_VALUES.merge(defaults).merge!(currency)
        options   = defaults.merge!(options)
112

113 114 115
        unit      = options.delete(:unit)
        format    = options.delete(:format)

116 117
        begin
          value = number_with_precision(number, options.merge(:raise => true))
118
          format.gsub(/%n/, value).gsub(/%u/, unit).html_safe
119 120 121 122 123 124 125
        rescue InvalidNumberError => e
          if options[:raise]
            raise
          else
            formatted_number = format.gsub(/%n/, e.number).gsub(/%u/, unit)
            e.number.to_s.html_safe? ? formatted_number.html_safe : formatted_number
          end
126
        end
127

128 129
      end

130
      # Formats a +number+ as a percentage string (e.g., 65%). You can customize the
131 132
      # format in the +options+ hash.
      #
133
      # ==== Options
134
      # * <tt>:locale</tt>     - Sets the locale to be used for formatting (defaults to current locale).
135 136 137
      # * <tt>:precision</tt>  - Sets the precision of the number (defaults to 3).
      # * <tt>:significant</tt>  - If +true+, precision will be the # of significant_digits. If +false+, the # of fractional digits (defaults to +false+)
      # * <tt>:separator</tt>  - Sets the separator between the fractional and integer digits (defaults to ".").
138
      # * <tt>:delimiter</tt>  - Sets the thousands delimiter (defaults to "").
139
      # * <tt>:strip_insignificant_zeros</tt>  - If +true+ removes insignificant zeros after the decimal separator (defaults to +false+)
140 141
      #
      # ==== Examples
142 143 144 145
      #  number_to_percentage(100)                                        # => 100.000%
      #  number_to_percentage(100, :precision => 0)                       # => 100%
      #  number_to_percentage(1000, :delimiter => '.', :separator => ',') # => 1.000,000%
      #  number_to_percentage(302.24398923423, :precision => 5)           # => 302.24399%
146
      #  number_to_percentage(1000, :locale => :fr)                       # => 1 000,000%
147
      def number_to_percentage(number, options = {})
148 149
        return nil if number.nil?

150 151
        options.symbolize_keys!

152 153
        defaults   = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
        percentage = I18n.translate(:'number.percentage.format', :locale => options[:locale], :default => {})
154
        defaults  = defaults.merge(percentage)
155

156
        options = options.reverse_merge(defaults)
157

158 159 160 161 162 163 164 165 166
        begin
          "#{number_with_precision(number, options.merge(:raise => true))}%".html_safe
        rescue InvalidNumberError => e
          if options[:raise]
            raise
          else
            e.number.to_s.html_safe? ? "#{e.number}%".html_safe : "#{e.number}%"
          end
        end
167 168
      end

169 170
      # Formats a +number+ with grouped thousands using +delimiter+ (e.g., 12,324). You can
      # customize the format in the +options+ hash.
171
      #
172
      # ==== Options
173
      # * <tt>:locale</tt>     - Sets the locale to be used for formatting (defaults to current locale).
174
      # * <tt>:delimiter</tt>  - Sets the thousands delimiter (defaults to ",").
175
      # * <tt>:separator</tt>  - Sets the separator between the fractional and integer digits (defaults to ".").
176 177
      #
      # ==== Examples
178 179 180
      #  number_with_delimiter(12345678)                        # => 12,345,678
      #  number_with_delimiter(12345678.05)                     # => 12,345,678.05
      #  number_with_delimiter(12345678, :delimiter => ".")     # => 12.345.678
P
Pratik Naik 已提交
181
      #  number_with_delimiter(12345678, :separator => ",")     # => 12,345,678
182
      #  number_with_delimiter(12345678.05, :locale => :fr)     # => 12 345 678,05
183
      #  number_with_delimiter(98765432.98, :delimiter => " ", :separator => ",")
184
      #  # => 98 765 432,98
185
      def number_with_delimiter(number, options = {})
186 187
        options.symbolize_keys!

188 189 190 191 192 193 194 195 196 197
        begin
          Float(number)
        rescue ArgumentError, TypeError
          if options[:raise]
            raise InvalidNumberError, number
          else
            return number
          end
        end

198 199
        defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
        options = options.reverse_merge(defaults)
200

201
        parts = number.to_s.split('.')
202 203
        parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
        parts.join(options[:separator]).html_safe
204

205
      end
206

207 208
      # Formats a +number+ with the specified level of <tt>:precision</tt> (e.g., 112.32 has a precision
      # of 2 if +:significant+ is +false+, and 5 if +:significant+ is +true+).
209 210 211
      # You can customize the format in the +options+ hash.
      #
      # ==== Options
212
      # * <tt>:locale</tt>     - Sets the locale to be used for formatting (defaults to current locale).
213 214 215
      # * <tt>:precision</tt>  - Sets the precision of the number (defaults to 3).
      # * <tt>:significant</tt>  - If +true+, precision will be the # of significant_digits. If +false+, the # of fractional digits (defaults to +false+)
      # * <tt>:separator</tt>  - Sets the separator between the fractional and integer digits (defaults to ".").
216
      # * <tt>:delimiter</tt>  - Sets the thousands delimiter (defaults to "").
217
      # * <tt>:strip_insignificant_zeros</tt>  - If +true+ removes insignificant zeros after the decimal separator (defaults to +false+)
218
      #
219
      # ==== Examples
220 221 222 223 224 225 226
      #  number_with_precision(111.2345)                                            # => 111.235
      #  number_with_precision(111.2345, :precision => 2)                           # => 111.23
      #  number_with_precision(13, :precision => 5)                                 # => 13.00000
      #  number_with_precision(389.32314, :precision => 0)                          # => 389
      #  number_with_precision(111.2345, :significant => true)                      # => 111
      #  number_with_precision(111.2345, :precision => 1, :significant => true)     # => 100
      #  number_with_precision(13, :precision => 5, :significant => true)           # => 13.000
227
      #  number_with_precision(111.234, :locale => :fr)                             # => 111,234
228
      #  number_with_precision(13, :precision => 5, :significant => true, strip_insignificant_zeros => true)
229 230
      #  # => 13
      #  number_with_precision(389.32314, :precision => 4, :significant => true)    # => 389.3
231 232
      #  number_with_precision(1111.2345, :precision => 2, :separator => ',', :delimiter => '.')
      #  # => 1.111,23
233
      def number_with_precision(number, options = {})
234 235
        options.symbolize_keys!

236 237 238
        number = begin
          Float(number)
        rescue ArgumentError, TypeError
239 240 241 242 243
          if options[:raise]
            raise InvalidNumberError, number
          else
            return number
          end
244 245 246 247
        end

        defaults           = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
        precision_defaults = I18n.translate(:'number.precision.format', :locale => options[:locale], :default => {})
248
        defaults           = defaults.merge(precision_defaults)
249

250 251 252
        options = options.reverse_merge(defaults)  # Allow the user to unset default values: Eg.: :significant => false
        precision = options.delete :precision
        significant = options.delete :significant
253
        strip_insignificant_zeros = options.delete :strip_insignificant_zeros
254

255
        if significant and precision > 0
256 257 258
          if number == 0
            digits, rounded_number = 1, 0
          else
259
            digits = (Math.log10(number.abs) + 1).floor
260 261
            rounded_number = BigDecimal.new((number / 10 ** (digits - precision)).to_s).round.to_f * 10 ** (digits - precision)
          end
262 263 264 265
          precision = precision - digits
          precision = precision > 0 ? precision : 0  #don't let it be negative
        else
          rounded_number = BigDecimal.new((number * (10 ** precision)).to_s).round.to_f / 10 ** precision
266
        end
267
        formatted_number = number_with_delimiter("%01.#{precision}f" % rounded_number, options)
268
        if strip_insignificant_zeros
269
          escaped_separator = Regexp.escape(options[:separator])
270
          formatted_number.sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '').html_safe
271
        else
272
          formatted_number
273
        end
274

275
      end
276

277 278
      STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb].freeze

279
      # Formats the bytes in +number+ into a more understandable representation
280
      # (e.g., giving it 1500 yields 1.5 KB). This method is useful for
281
      # reporting file sizes to users. You can customize the
282 283
      # format in the +options+ hash.
      #
284 285
      # See <tt>number_to_human</tt> if you want to pretty-print a generic number.
      #
286
      # ==== Options
287
      # * <tt>:locale</tt>     - Sets the locale to be used for formatting (defaults to current locale).
288 289 290
      # * <tt>:precision</tt>  - Sets the precision of the number (defaults to 3).
      # * <tt>:significant</tt>  - If +true+, precision will be the # of significant_digits. If +false+, the # of fractional digits (defaults to +true+)
      # * <tt>:separator</tt>  - Sets the separator between the fractional and integer digits (defaults to ".").
291
      # * <tt>:delimiter</tt>  - Sets the thousands delimiter (defaults to "").
292
      # * <tt>:strip_insignificant_zeros</tt>  - If +true+ removes insignificant zeros after the decimal separator (defaults to +true+)
293
      # ==== Examples
294
      #  number_to_human_size(123)                                          # => 123 Bytes
295
      #  number_to_human_size(1234)                                         # => 1.21 KB
296
      #  number_to_human_size(12345)                                        # => 12.1 KB
297 298 299 300 301 302
      #  number_to_human_size(1234567)                                      # => 1.18 MB
      #  number_to_human_size(1234567890)                                   # => 1.15 GB
      #  number_to_human_size(1234567890123)                                # => 1.12 TB
      #  number_to_human_size(1234567, :precision => 2)                     # => 1.2 MB
      #  number_to_human_size(483989, :precision => 2)                      # => 470 KB
      #  number_to_human_size(1234567, :precision => 2, :separator => ',')  # => 1,2 MB
303
      #
304
      # Non-significant zeros after the fractional separator are stripped out by default (set
305
      # <tt>:strip_insignificant_zeros</tt> to +false+ to change that):
306 307
      #  number_to_human_size(1234567890123, :precision => 5)        # => "1.1229 TB"
      #  number_to_human_size(524288000, :precision=>5)              # => "500 MB"
308
      def number_to_human_size(number, options = {})
309 310
        options.symbolize_keys!

311 312 313
        number = begin
          Float(number)
        rescue ArgumentError, TypeError
314 315 316 317 318
          if options[:raise]
            raise InvalidNumberError, number
          else
            return number
          end
319
        end
320

321 322
        defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
        human    = I18n.translate(:'number.human.format', :locale => options[:locale], :default => {})
323
        defaults = defaults.merge(human)
324

325
        options = options.reverse_merge(defaults)
326 327
        #for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
        options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros)
328

329
        storage_units_format = I18n.translate(:'number.human.storage_units.format', :locale => options[:locale], :raise => true)
330

331 332
        if number.to_i < 1024
          unit = I18n.translate(:'number.human.storage_units.units.byte', :locale => options[:locale], :count => number.to_i, :raise => true)
333
          storage_units_format.gsub(/%n/, number.to_i.to_s).gsub(/%u/, unit).html_safe
334 335 336 337 338 339 340 341 342
        else
          max_exp  = STORAGE_UNITS.size - 1
          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 = I18n.translate(:"number.human.storage_units.units.#{unit_key}", :locale => options[:locale], :count => number, :raise => true)

343
          formatted_number = number_with_precision(number, options)
344
          storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit).html_safe
345
        end
346
      end
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361

      DECIMAL_UNITS = {0 => :unit, 1 => :ten, 2 => :hundred, 3 => :thousand, 6 => :million, 9 => :billion, 12 => :trillion, 15 => :quadrillion,
        -1 => :deci, -2 => :centi, -3 => :mili, -6 => :micro, -9 => :nano, -12 => :pico, -15 => :femto}.freeze

      # Pretty prints (formats and approximates) a number in a way it is more readable by humans
      # (eg.: 1200000000 becomes "1.2 Billion"). This is useful for numbers that
      # can get very large (and too hard to read).
      #
      # See <tt>number_to_human_size</tt> if you want to print a file size.
      #
      # You can also define you own unit-quantifier names if you want to use other decimal units
      # (eg.: 1500 becomes "1.5 kilometers", 0.150 becomes "150 mililiters", etc). You may define
      # a wide range of unit quantifiers, even fractional ones (centi, deci, mili, etc).
      #
      # ==== Options
362
      # * <tt>:locale</tt>     - Sets the locale to be used for formatting (defaults to current locale).
363 364 365 366
      # * <tt>:precision</tt>  - Sets the precision of the number (defaults to 3).
      # * <tt>:significant</tt>  - If +true+, precision will be the # of significant_digits. If +false+, the # of fractional digits (defaults to +true+)
      # * <tt>:separator</tt>  - Sets the separator between the fractional and integer digits (defaults to ".").
      # * <tt>:delimiter</tt>  - Sets the thousands delimiter (defaults to "").
367
      # * <tt>:strip_insignificant_zeros</tt>  - If +true+ removes insignificant zeros after the decimal separator (defaults to +true+)
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
      # * <tt>:units</tt> - A Hash of unit quantifier names. Or a string containing an i18n scope where to find this hash. It might have the following keys:
      #   * *integers*: <tt>:unit</tt>, <tt>:ten</tt>, <tt>:hundred</tt>, <tt>:thousand</tt>,  <tt>:million</tt>,  <tt>:billion</tt>, <tt>:trillion</tt>, <tt>:quadrillion</tt>
      #   * *fractionals*: <tt>:deci</tt>, <tt>:centi</tt>, <tt>:mili</tt>, <tt>:micro</tt>, <tt>:nano</tt>, <tt>:pico</tt>, <tt>:femto</tt>
      # * <tt>:format</tt> - Sets the format of the output string (defaults to "%n %u"). The field types are:
      #
      #     %u  The quantifier (ex.: 'thousand')
      #     %n  The number
      #
      # ==== Examples
      #  number_to_human(123)                                          # => "123"
      #  number_to_human(1234)                                         # => "1.23 Thousand"
      #  number_to_human(12345)                                        # => "12.3 Thousand"
      #  number_to_human(1234567)                                      # => "1.23 Million"
      #  number_to_human(1234567890)                                   # => "1.23 Billion"
      #  number_to_human(1234567890123)                                # => "1.23 Trillion"
      #  number_to_human(1234567890123456)                             # => "1.23 Quadrillion"
      #  number_to_human(1234567890123456789)                          # => "1230 Quadrillion"
      #  number_to_human(489939, :precision => 2)                      # => "490 Thousand"
      #  number_to_human(489939, :precision => 4)                      # => "489.9 Thousand"
      #  number_to_human(1234567, :precision => 4,
      #                           :significant => false)               # => "1.2346 Million"
      #  number_to_human(1234567, :precision => 1,
      #                           :separator => ',',
      #                           :significant => false)               # => "1,2 Million"
      #
      # Unsignificant zeros after the decimal separator are stripped out by default (set
394
      # <tt>:strip_insignificant_zeros</tt> to +false+ to change that):
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
      #  number_to_human(12345012345, :significant_digits => 6)       # => "12.345 Billion"
      #  number_to_human(500000000, :precision=>5)                    # => "500 Million"
      #
      # ==== Custom Unit Quantifiers
      #
      # You can also use your own custom unit quantifiers:
      #  number_to_human(500000, :units => {:unit => "ml", :thousand => "lt"})  # => "500 lt"
      #
      # If in your I18n locale you have:
      #   distance:
      #     centi:
      #       one: "centimeter"
      #       other: "centimeters"
      #     unit:
      #       one: "meter"
      #       other: "meters"
      #     thousand:
      #       one: "kilometer"
      #       other: "kilometers"
      #     billion: "gazilion-distance"
      #
      # Then you could do:
      #
      #  number_to_human(543934, :units => :distance)                              # => "544 kilometers"
      #  number_to_human(54393498, :units => :distance)                            # => "54400 kilometers"
      #  number_to_human(54393498000, :units => :distance)                         # => "54.4 gazilion-distance"
      #  number_to_human(343, :units => :distance, :precision => 1)                # => "300 meters"
      #  number_to_human(1, :units => :distance)                                   # => "1 meter"
      #  number_to_human(0.34, :units => :distance)                                # => "34 centimeters"
      #
      def number_to_human(number, options = {})
426 427
        options.symbolize_keys!

428 429 430
        number = begin
          Float(number)
        rescue ArgumentError, TypeError
431 432 433 434 435
          if options[:raise]
            raise InvalidNumberError, number
          else
            return number
          end
436 437 438 439 440 441 442
        end

        defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
        human    = I18n.translate(:'number.human.format', :locale => options[:locale], :default => {})
        defaults = defaults.merge(human)

        options = options.reverse_merge(defaults)
443 444
        #for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
        options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros)
445 446 447 448 449 450 451 452 453 454 455 456 457

        units = options.delete :units
        unit_exponents = case units
        when Hash
          units
        when String, Symbol
          I18n.translate(:"#{units}", :locale => options[:locale], :raise => true)
        when nil
          I18n.translate(:"number.human.decimal_units.units", :locale => options[:locale], :raise => true)
        else
          raise ArgumentError, ":units must be a Hash or String translation scope."
        end.keys.map{|e_name| DECIMAL_UNITS.invert[e_name] }.sort_by{|e| -e}

458
        number_exponent = number != 0 ? Math.log10(number.abs).floor : 0
459 460 461 462 463 464 465 466 467 468 469 470 471 472
        display_exponent = unit_exponents.find{|e| number_exponent >= e }
        number  /= 10 ** display_exponent

        unit = case units
        when Hash
          units[DECIMAL_UNITS[display_exponent]]
        when String, Symbol
          I18n.translate(:"#{units}.#{DECIMAL_UNITS[display_exponent]}", :locale => options[:locale], :count => number.to_i)
        else
          I18n.translate(:"number.human.decimal_units.units.#{DECIMAL_UNITS[display_exponent]}", :locale => options[:locale], :count => number.to_i)
        end

        decimal_format = options[:format] || I18n.translate(:'number.human.decimal_units.format', :locale => options[:locale], :default => "%n %u")
        formatted_number = number_with_precision(number, options)
473
        decimal_format.gsub(/%n/, formatted_number).gsub(/%u/, unit).strip.html_safe
474 475
      end

476 477
    end
  end
478
end