1 # This module allows you to easily cache all responses from the backend - thus
2 # speeding up the I18n aspects of your application quite a bit.
4 # To enable caching you can simply include the Cache module to the Simple
5 # backend - or whatever other backend you are using:
7 # I18n::Backend::Simple.send(:include, I18n::Backend::Cache)
9 # You will also need to set a cache store implementation that you want to use:
11 # I18n.cache_store = ActiveSupport::Cache.lookup_store(:memory_store)
13 # You can use any cache implementation you want that provides the same API as
14 # ActiveSupport::Cache (only the methods #fetch and #write are being used).
16 # The cache_key implementation assumes that you only pass values to
17 # I18n.translate that return a valid key from #hash (see
18 # http://www.ruby-doc.org/core/classes/Object.html#M000337).
20 # If you use a lambda as a default value in your translation like this:
22 # I18n.t(:"date.order", :default => lambda {[:month, :day, :year]})
24 # Then you will always have a cache miss, because each time this method
25 # is called the lambda will have a different hash value. If you know
26 # the result of the lambda is a constant as in the example above, then
27 # to cache this you can make the lambda a constant, like this:
29 # DEFAULT_DATE_ORDER = lambda {[:month, :day, :year]}
31 # I18n.t(:"date.order", :default => DEFAULT_DATE_ORDER)
33 # If the lambda may result in different values for each call then consider
34 # also using the Memoize backend.
39 @@cache_namespace = nil
45 def cache_store=(store)
53 def cache_namespace=(namespace)
54 @@cache_namespace = namespace
63 # TODO Should the cache be cleared if new translations are stored?
65 def translate(locale, key, options = {})
66 I18n.perform_caching? ? fetch(cache_key(locale, key, options)) { super } : super
71 def fetch(cache_key, &block)
72 result = _fetch(cache_key, &block)
73 throw(:exception, result) if result.is_a?(MissingTranslation)
74 result = result.dup if result.frozen? rescue result
78 def _fetch(cache_key, &block)
79 result = I18n.cache_store.read(cache_key) and return result
80 result = catch(:exception, &block)
81 I18n.cache_store.write(cache_key, result) unless result.is_a?(Proc)
85 def cache_key(locale, key, options)
86 # This assumes that only simple, native Ruby values are passed to I18n.translate.
87 "i18n/#{I18n.cache_namespace}/#{locale}/#{key.hash}/#{USE_INSPECT_HASH ? options.inspect.hash : options.hash}"
91 # In Ruby < 1.9 the following is true: { :foo => 1, :bar => 2 }.hash == { :foo => 2, :bar => 1 }.hash
92 # Therefore we must use the hash of the inspect string instead to avoid cache key colisions.
93 USE_INSPECT_HASH = RUBY_VERSION <= "1.9"