i18n icon indicating copy to clipboard operation
i18n copied to clipboard

I18n.localize ignores cache for time objects

Open the8472 opened this issue 11 years ago • 2 comments

When localizing times in an "most recently updated" index list then those Time objects obviously change all the time.

the .localize method passes in the object in question to the options of the translate method despite only looking for the format string for strftime.

Which means this gets passed through to any caching layer and since options are part of the cache key it prevents caching of such highly volatile values.

Running the index page through a profiler repeatedly yields this result, which is about 10% of the overall runtime:

           |       # Acts the same as +strftime+, but uses a localized version of the
           |       # format string. Takes a key from the date/time formats translations as
           |       # a format argument (<em>e.g.</em>, <tt>:short</tt> in <tt>:'date.formats'</tt>).
           |       def localize(locale, object, format = :default, options = {})
    35.5ms |          raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime)
           | 
     3.8ms |          if Symbol === format
           |           key  = format
    23.5ms |            type = object.respond_to?(:sec) ? 'time' : 'date'
   108.8ms |            options = options.merge(:raise => true, :object => object, :locale => locale)
  9663.2ms |            format  = I18n.t(:"#{type}.formats.#{key}", options)
           |         end
           | 
           |         # format = resolve(locale, object, format, options)
    32.7ms |          format = format.to_s.gsub(/%[aAbBp]/) do |match|
           |           case match
           |           when '%a' then I18n.t(:"date.abbr_day_names",                  :locale => locale, :format => format)[object.wday]
           |           when '%A' then I18n.t(:"date.day_names",                       :locale => locale, :format => format)[object.wday]
           |           when '%b' then I18n.t(:"date.abbr_month_names",                :locale => locale, :format => format)[object.mon]
           |           when '%B' then I18n.t(:"date.month_names",                     :locale => locale, :format => format)[object.mon]
           |           when '%p' then I18n.t(:"time.#{object.hour < 12 ? :am : :pm}", :locale => locale, :format => format) if object.respond_to? :hour
           |           end
           |         end
           | 
  1031.5ms |          object.strftime(format)
           |       end

My workaround is to monkeypatch the cache backend to strip the :object key from the options if its value is a time-like object.

the8472 avatar May 06 '13 15:05 the8472

Good point where I18n could be optimized.

dmitry avatar Nov 17 '16 09:11 dmitry

twitter/twitter-cldr-rb (https://github.com/twitter/twitter-cldr-rb) has some pretty advanced localization code already, based on the Unicode CLDR library. Perhaps some collaboration/sharing with that project would be good.

(not immediately related to this performance issue, but if we could avoid duplication across that project and this one it could be a good thing)

sandstrom avatar Dec 04 '16 14:12 sandstrom