Skip to content

Commit

Permalink
Cache I18n lookups in Formtastic::Localizer
Browse files Browse the repository at this point in the history
  • Loading branch information
Sascha Konietzke committed Jan 26, 2012
1 parent 7d62ee3 commit a6dad77
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 7 deletions.
1 change: 1 addition & 0 deletions lib/formtastic/form_builder.rb
Expand Up @@ -23,6 +23,7 @@ def self.configure(name, value = nil)
configure :file_metadata_suffixes, ['content_type', 'file_name', 'file_size']
configure :priority_countries, ["Australia", "Canada", "United Kingdom", "United States"]
configure :i18n_lookups_by_default, true
configure :i18n_cache_lookups, true
configure :i18n_localizer, Formtastic::Localizer
configure :escape_html_entities_in_hints_and_labels, true
configure :default_commit_button_accesskey
Expand Down
52 changes: 46 additions & 6 deletions lib/formtastic/localizer.rb
Expand Up @@ -24,27 +24,59 @@ module Formtastic
# 'formtastic.labels.post.title'
# 'formtastic.labels.title'
class Localizer

class Cache
def get(key)
cache[key]
end

def has_key?(key)
cache.has_key?(key)
end

def set(key, result)
cache[key] = result
end

def cache
@cache ||= {}
end

def clear!
cache.clear
end
end

attr_accessor :builder


def self.cache
@cache ||= Cache.new
end

def initialize(current_builder)
self.builder = current_builder
end

def localize(key, value, type, options = {}) #:nodoc:
key = value if value.is_a?(::Symbol)

if value.is_a?(::String)
escape_html_entities(value)
else
use_i18n = value.nil? ? i18n_lookups_by_default : (value != false)

use_cache = i18n_cache_lookups
cache = self.class.cache

if use_i18n
model_name, nested_model_name = normalize_model_name(builder.model_name.underscore)

action_name = builder.template.params[:action].to_s rescue ''
attribute_name = key.to_s


# look in the cache first
if use_cache
cache_key = [::I18n.locale, action_name, model_name, nested_model_name, attribute_name, key, value, type, options]
return cache.get(cache_key) if cache.has_key?(cache_key)
end

defaults = Formtastic::I18n::SCOPES.reject do |i18n_scope|
nested_model_name.nil? && i18n_scope.match(/nested_model/)
Expand All @@ -71,7 +103,11 @@ def localize(key, value, type, options = {}) #:nodoc:
options[:default] = defaults
i18n_value = ::I18n.t(default_key, options)
end
(i18n_value.is_a?(::String) && i18n_value.present?) ? escape_html_entities(i18n_value) : nil

# save the result to the cache
result = (i18n_value.is_a?(::String) && i18n_value.present?) ? escape_html_entities(i18n_value) : nil
cache.set(cache_key, result) if use_cache
result
end
end
end
Expand Down Expand Up @@ -105,6 +141,10 @@ def escape_html_entities(string) #:nodoc:
def i18n_lookups_by_default
builder.i18n_lookups_by_default
end

def i18n_cache_lookups
builder.i18n_cache_lookups
end

end
end
4 changes: 4 additions & 0 deletions lib/generators/templates/formtastic.rb
Expand Up @@ -68,6 +68,10 @@
# i.e. :label => true, or :hint => true (or opposite depending on initialized value)
# Formtastic::FormBuilder.i18n_lookups_by_default = false

# Specifies if I18n lookups of the default I18n Localizer should be cached to improve performance.
# Defaults to false.
# Formtastic::FormBuilder.i18n_cache_lookups = true

# Specifies the class to use for localization lookups. You can create your own
# class and use it instead by subclassing Formtastic::Localizer (which is the default).
# Formtastic::FormBuilder.i18n_localizer = MyOwnLocalizer
Expand Down
1 change: 1 addition & 0 deletions spec/actions/generic_action_spec.rb
Expand Up @@ -213,6 +213,7 @@ def to_html
}
}
}

concat(semantic_form_for(:post, :url => 'http://example.com') do |builder|
concat(builder.action(:submit, :as => :generic))
concat(builder.action(:reset, :as => :generic))
Expand Down
6 changes: 5 additions & 1 deletion spec/spec_helper.rb
Expand Up @@ -419,10 +419,14 @@ def with_config(config_method_name, value, &block)
::ActiveSupport::Deprecation.silenced = false

RSpec.configure do |config|
config.before(:each) do
Formtastic::Localizer.cache.clear!
end

config.before(:all) do
DeferredGarbageCollection.start unless ENV["DEFER_GC"] == "false"
end
config.after(:all) do
DeferredGarbageCollection.reconsider unless ENV["DEFER_GC"] == "false"
DeferredGarbageCollection.reconsider unless ENV["DEFER_GC"] == "false"
end
end

0 comments on commit a6dad77

Please sign in to comment.