views:

310

answers:

1

I have a number of models that load a collection of strings, based on the user's i18n locale. In order to simplify things, each model that does so includes the following module:

module HasStrings
  def self.included(klass)
    klass.extend ClassMethods
  end

  module ClassMethods
    def strings
      @strings ||= reload_strings!
    end

    def reload_strings!
      @strings =
        begin
          File.open(RAILS_ROOT / 'config' / 'locales' / self.name.pluralize.downcase / I18n.locale.to_s + ".yml") { |f| YAML.load(f) }
        rescue Errno::ENOENT
          # Load the English strings if the current language doesn't have a strings file
          File.open(RAILS_ROOT / 'config' / 'locales' / self.name.pluralize.downcase / 'en.yml') { |f| YAML.load(f) }
        end
    end
  end
end

I am running into a problem, however, because @strings is a class variable, and thus, the strings from one person's chosen locale are "bleeding" over into another user with a different locale. Is there a way to setup the @strings variable so that it lives only within the context of the current request?

I tried replacing @strings with Thread.current["#{self.name}_strings"] (so that there's a different thread variable per class), but in that case the variable was retained over multiple requests and strings weren't reloaded when the locale was changed.

+1  A: 

I see two options. The first is to make @strings an instance variable.

But then you may be loading them more than once on a single request, so instead, you can turn @strings into a hash of locale against a string set.

module HasStrings
  def self.included(klass)
    klass.extend ClassMethods
  end

  module ClassMethods
    def strings
      @strings ||= {}
      string_locale = File.exists?(locale_filename(I18n.locale.to_s)) ? I18n.locale.to_s : 'en'
      @strings[string_locale] ||= File.open(locale_filename(string_locale)) { |f| YAML.load(f) }
    end

    def locale_filename(locale)
      "#{RAILS_ROOT}/config/locales/#{self.name.pluralize.downcase}/#{locale}.yml"
    end
  end
end
Sarah Mei
I want to stay away from instance variables because it doesn't make sense in the logical context, plus there is reuse. I like the hash idea though
Daniel Vandersluis