module SimpleLocalizer::ClassMethods

Public Instance Methods

translates(*columns) click to toggle source
# File lib/simple_localizer.rb, line 26
def translates *columns
  translated_attribute_names = columns.map &:to_s

  unless const_defined? :Translation
    underscore_name = name.underscore.gsub("/", "_").to_sym
    foreign_key     = "#{underscore_name}_id".to_sym

    translation_class = const_set(:Translation, Class.new(ActiveRecord::Base))

    translation_class.table_name = "#{underscore_name}_translations"
    translation_class.belongs_to(underscore_name, # WORKAROUND Rails prefers association name to be symbol
      :class_name  => self.name,
      :foreign_key => foreign_key
    )
    translation_class.validates :locale, :presence => true
    translation_class.validates underscore_name, :presence => true
    translation_class.validates :locale, :uniqueness => { :scope => foreign_key }

    has_many(:translations,
      :dependent   => :destroy,
      :autosave    => true,
      :class_name  => translation_class.name,
      :inverse_of  => underscore_name,
      :foreign_key => foreign_key
    )
  end

  translated_attribute_names.each do |attr|
    define_method attr do
      locale = SimpleLocalizer.read_locale
      send("#{attr}_#{locale}")
    end

    define_method "#{attr}=" do |value|
      locale = SimpleLocalizer.read_locale || I18n.default_locale.to_s
      send("#{attr}_#{locale}=", value)
    end

    # I use method 'detect'. This is not the fastest solution, but it is simple.
    # If you have many entries for 'translations' association and this piece of code slows down,
    # you can use the hash, but then do not forget to take care of cleaning it when call the method 'reload' for model.
    SimpleLocalizer.supported_locales.each do |locale|
      define_method "#{attr}_#{locale}" do
        translation = translations.detect { |translation|
          translation.locale == locale
        }

        if I18n.respond_to?(:fallbacks) && translation.try(attr).nil?
          fallbacks_locales = I18n.fallbacks[locale].map(&:to_s)

          translation = translations.detect { |translation|
            fallbacks_locales.include?(translation.locale) && translation.send(attr).present?
          }
        end

        translation.try(attr)
      end

      define_method "#{attr}_#{locale}=" do |value|
        translation = translations.detect { |translation|
          translation.locale == locale
        }
        translation ||= translations.build :locale => locale
        translation.send("#{attr}=", value)
      end
    end
  end
end