hooktstudios-globalize3 0.2.0.beta8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +4 -0
 - data/LICENSE +21 -0
 - data/README.textile +205 -0
 - data/Rakefile +22 -0
 - data/lib/globalize.rb +52 -0
 - data/lib/globalize/active_record.rb +12 -0
 - data/lib/globalize/active_record/act_macro.rb +56 -0
 - data/lib/globalize/active_record/adapter.rb +101 -0
 - data/lib/globalize/active_record/attributes.rb +27 -0
 - data/lib/globalize/active_record/class_methods.rb +156 -0
 - data/lib/globalize/active_record/exceptions.rb +19 -0
 - data/lib/globalize/active_record/instance_methods.rb +175 -0
 - data/lib/globalize/active_record/migration.rb +161 -0
 - data/lib/globalize/active_record/translation.rb +41 -0
 - data/lib/globalize/versioning.rb +5 -0
 - data/lib/globalize/versioning/paper_trail.rb +41 -0
 - data/lib/globalize3.rb +1 -0
 - data/lib/globalize3/version.rb +3 -0
 - data/lib/i18n/missing_translations_log_handler.rb +41 -0
 - data/lib/i18n/missing_translations_raise_handler.rb +25 -0
 - data/lib/patches/active_record/query_method.rb +35 -0
 - data/lib/patches/active_record/xml_attribute_serializer.rb +13 -0
 - metadata +160 -0
 
| 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Helper class for storing values per locale. Used by Globalize::Adapter
         
     | 
| 
      
 2 
     | 
    
         
            +
            # to stash and cache attribute values.
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Globalize
         
     | 
| 
      
 5 
     | 
    
         
            +
              module ActiveRecord
         
     | 
| 
      
 6 
     | 
    
         
            +
                class Attributes < Hash # TODO: Think about using HashWithIndifferentAccess ?
         
     | 
| 
      
 7 
     | 
    
         
            +
                  def [](locale)
         
     | 
| 
      
 8 
     | 
    
         
            +
                    locale = locale.to_sym
         
     | 
| 
      
 9 
     | 
    
         
            +
                    self[locale] = {} unless has_key?(locale)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    self.fetch(locale)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  def contains?(locale, name)
         
     | 
| 
      
 14 
     | 
    
         
            +
                    self[locale].has_key?(name.to_s)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  def read(locale, name)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    self[locale][name.to_s]
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  def write(locale, name, value)
         
     | 
| 
      
 22 
     | 
    
         
            +
                    #raise 'z' if value.nil? # TODO
         
     | 
| 
      
 23 
     | 
    
         
            +
                    self[locale][name.to_s] = value
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,156 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Globalize
         
     | 
| 
      
 2 
     | 
    
         
            +
              module ActiveRecord
         
     | 
| 
      
 3 
     | 
    
         
            +
                module ClassMethods
         
     | 
| 
      
 4 
     | 
    
         
            +
                  delegate :translated_locales, :set_translations_table_name, :to => :translation_class
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  def with_locales(*locales)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    scoped.merge(translation_class.with_locales(*locales))
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def with_translations(*locales)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    locales = translated_locales if locales.empty?
         
     | 
| 
      
 12 
     | 
    
         
            +
                    includes(:translations).with_locales(locales).with_required_attributes
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  def with_required_attributes
         
     | 
| 
      
 16 
     | 
    
         
            +
                    required_translated_attributes.inject(scoped) do |scope, name|
         
     | 
| 
      
 17 
     | 
    
         
            +
                      scope.where("#{translated_column_name(name)} IS NOT NULL")
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  def with_translated_attribute(name, value, locales = nil)
         
     | 
| 
      
 22 
     | 
    
         
            +
                    locales ||= Globalize.fallbacks
         
     | 
| 
      
 23 
     | 
    
         
            +
                    with_translations.where(
         
     | 
| 
      
 24 
     | 
    
         
            +
                      translated_column_name(name)    => value,
         
     | 
| 
      
 25 
     | 
    
         
            +
                      translated_column_name(:locale) => Array(locales).map(&:to_s)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    )
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  def translated?(name)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    translated_attribute_names.include?(name.to_sym)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  def required_attributes
         
     | 
| 
      
 34 
     | 
    
         
            +
                    validators.map { |v| v.attributes if v.is_a?(ActiveModel::Validations::PresenceValidator) }.flatten
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  def required_translated_attributes
         
     | 
| 
      
 38 
     | 
    
         
            +
                    translated_attribute_names & required_attributes
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  def translation_class
         
     | 
| 
      
 42 
     | 
    
         
            +
                    @translation_class ||= begin
         
     | 
| 
      
 43 
     | 
    
         
            +
                      klass = self.const_get(:Translation) rescue nil
         
     | 
| 
      
 44 
     | 
    
         
            +
                      if klass.nil? || klass.class_name != (self.class_name + "Translation")
         
     | 
| 
      
 45 
     | 
    
         
            +
                        klass = self.const_set(:Translation, Class.new(Globalize::ActiveRecord::Translation))
         
     | 
| 
      
 46 
     | 
    
         
            +
                      end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                      klass.belongs_to name.underscore.gsub('/', '_')
         
     | 
| 
      
 49 
     | 
    
         
            +
                      klass
         
     | 
| 
      
 50 
     | 
    
         
            +
                    end
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                  def translations_table_name
         
     | 
| 
      
 54 
     | 
    
         
            +
                    translation_class.table_name
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  def translated_column_name(name)
         
     | 
| 
      
 58 
     | 
    
         
            +
                    "#{translation_class.table_name}.#{name}"
         
     | 
| 
      
 59 
     | 
    
         
            +
                  end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                  if RUBY_VERSION < '1.9'
         
     | 
| 
      
 62 
     | 
    
         
            +
                    def respond_to?(method_id, *args, &block)
         
     | 
| 
      
 63 
     | 
    
         
            +
                      supported_on_missing?(method_id) || super
         
     | 
| 
      
 64 
     | 
    
         
            +
                    end
         
     | 
| 
      
 65 
     | 
    
         
            +
                  else
         
     | 
| 
      
 66 
     | 
    
         
            +
                    def respond_to_missing?(method_id, include_private = false)
         
     | 
| 
      
 67 
     | 
    
         
            +
                      supported_on_missing?(method_id) || super
         
     | 
| 
      
 68 
     | 
    
         
            +
                    end
         
     | 
| 
      
 69 
     | 
    
         
            +
                  end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                  def supported_on_missing?(method_id)
         
     | 
| 
      
 72 
     | 
    
         
            +
                    return super unless RUBY_VERSION < '1.9' || respond_to?(:translated_attribute_names)
         
     | 
| 
      
 73 
     | 
    
         
            +
                    match = ::ActiveRecord::DynamicFinderMatch.match(method_id) || ::ActiveRecord::DynamicScopeMatch.match(method_id)
         
     | 
| 
      
 74 
     | 
    
         
            +
                    return false if match.nil?
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                    attribute_names = match.attribute_names.map(&:to_sym)
         
     | 
| 
      
 77 
     | 
    
         
            +
                    translated_attributes = attribute_names & translated_attribute_names
         
     | 
| 
      
 78 
     | 
    
         
            +
                    return false if translated_attributes.empty?
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                    untranslated_attributes = attribute_names - translated_attributes
         
     | 
| 
      
 81 
     | 
    
         
            +
                    return false if untranslated_attributes.any?{|unt| ! respond_to?(:"scoped_by_#{unt}")}
         
     | 
| 
      
 82 
     | 
    
         
            +
                    return [match, attribute_names, translated_attributes, untranslated_attributes]
         
     | 
| 
      
 83 
     | 
    
         
            +
                  end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                  def method_missing(method_id, *arguments, &block)
         
     | 
| 
      
 86 
     | 
    
         
            +
                    match, attribute_names, translated_attributes, untranslated_attributes = supported_on_missing?(method_id)
         
     | 
| 
      
 87 
     | 
    
         
            +
                    return super unless match
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                    scope = scoped
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                    translated_attributes.each do |attr|
         
     | 
| 
      
 92 
     | 
    
         
            +
                      scope = scope.with_translated_attribute(attr, arguments[attribute_names.index(attr)])
         
     | 
| 
      
 93 
     | 
    
         
            +
                    end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                    untranslated_attributes.each do |unt|
         
     | 
| 
      
 96 
     | 
    
         
            +
                      index = attribute_names.index(unt)
         
     | 
| 
      
 97 
     | 
    
         
            +
                      raise StandarError unless index
         
     | 
| 
      
 98 
     | 
    
         
            +
                      scope = scope.send(:"scoped_by_#{unt}", arguments[index])
         
     | 
| 
      
 99 
     | 
    
         
            +
                    end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                    if match.is_a?(::ActiveRecord::DynamicFinderMatch)
         
     | 
| 
      
 102 
     | 
    
         
            +
                      if match.instantiator? and scope.blank?
         
     | 
| 
      
 103 
     | 
    
         
            +
                        return scope.find_or_instantiator_by_attributes match, attribute_names, *arguments, &block
         
     | 
| 
      
 104 
     | 
    
         
            +
                      end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                      return scope.send(match.finder).tap do |found|
         
     | 
| 
      
 107 
     | 
    
         
            +
                        found.is_a?(Array) ? found.map { |f| f.translations.reload } : found.translations.reload unless found.nil?
         
     | 
| 
      
 108 
     | 
    
         
            +
                      end
         
     | 
| 
      
 109 
     | 
    
         
            +
                    end
         
     | 
| 
      
 110 
     | 
    
         
            +
                    return scope
         
     | 
| 
      
 111 
     | 
    
         
            +
                  end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                  def find_or_instantiator_by_attributes(match, attributes, *args)
         
     | 
| 
      
 114 
     | 
    
         
            +
                    options = args.size > 1 && args.last(2).all?{ |a| a.is_a?(Hash) } ? args.extract_options! : {}
         
     | 
| 
      
 115 
     | 
    
         
            +
                    protected_attributes_for_create, unprotected_attributes_for_create = {}, {}
         
     | 
| 
      
 116 
     | 
    
         
            +
                    args.each_with_index do |arg, i|
         
     | 
| 
      
 117 
     | 
    
         
            +
                      if arg.is_a?(Hash)
         
     | 
| 
      
 118 
     | 
    
         
            +
                        protected_attributes_for_create = args[i].with_indifferent_access
         
     | 
| 
      
 119 
     | 
    
         
            +
                      else
         
     | 
| 
      
 120 
     | 
    
         
            +
                        unprotected_attributes_for_create[attributes[i]] = args[i]
         
     | 
| 
      
 121 
     | 
    
         
            +
                      end
         
     | 
| 
      
 122 
     | 
    
         
            +
                    end
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
                    record = if ::ActiveRecord::VERSION::STRING < "3.1.0"
         
     | 
| 
      
 125 
     | 
    
         
            +
                      class_name.constantize.new do |r|
         
     | 
| 
      
 126 
     | 
    
         
            +
                        r.send(:attributes=, protected_attributes_for_create, true) unless protected_attributes_for_create.empty?
         
     | 
| 
      
 127 
     | 
    
         
            +
                        r.send(:attributes=, unprotected_attributes_for_create, false) unless unprotected_attributes_for_create.empty?
         
     | 
| 
      
 128 
     | 
    
         
            +
                      end
         
     | 
| 
      
 129 
     | 
    
         
            +
                    else
         
     | 
| 
      
 130 
     | 
    
         
            +
                      class_name.constantize.new(protected_attributes_for_create, options) do |r|
         
     | 
| 
      
 131 
     | 
    
         
            +
                        r.assign_attributes(unprotected_attributes_for_create, :without_protection => true)
         
     | 
| 
      
 132 
     | 
    
         
            +
                      end
         
     | 
| 
      
 133 
     | 
    
         
            +
                    end
         
     | 
| 
      
 134 
     | 
    
         
            +
                    yield(record) if block_given?
         
     | 
| 
      
 135 
     | 
    
         
            +
                    record.send(match.bang? ? :save! : :save) if match.instantiator.eql?(:create)
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
                    record
         
     | 
| 
      
 138 
     | 
    
         
            +
                  end
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
                protected
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                  def translated_attr_accessor(name)
         
     | 
| 
      
 143 
     | 
    
         
            +
                    define_method(:"#{name}=") do |value|
         
     | 
| 
      
 144 
     | 
    
         
            +
                      write_attribute(name, value)
         
     | 
| 
      
 145 
     | 
    
         
            +
                    end
         
     | 
| 
      
 146 
     | 
    
         
            +
                    define_method(name) do |*args|
         
     | 
| 
      
 147 
     | 
    
         
            +
                      read_attribute(name, {:locale => args.first})
         
     | 
| 
      
 148 
     | 
    
         
            +
                    end
         
     | 
| 
      
 149 
     | 
    
         
            +
                    alias_method :"#{name}_before_type_cast", name
         
     | 
| 
      
 150 
     | 
    
         
            +
                  end
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                end
         
     | 
| 
      
 153 
     | 
    
         
            +
             
     | 
| 
      
 154 
     | 
    
         
            +
              end
         
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
      
 156 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,19 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Globalize
         
     | 
| 
      
 2 
     | 
    
         
            +
              module ActiveRecord
         
     | 
| 
      
 3 
     | 
    
         
            +
                module Exceptions
         
     | 
| 
      
 4 
     | 
    
         
            +
                  class MigrationError < StandardError; end
         
     | 
| 
      
 5 
     | 
    
         
            +
              
         
     | 
| 
      
 6 
     | 
    
         
            +
                  class BadFieldName < MigrationError
         
     | 
| 
      
 7 
     | 
    
         
            +
                    def initialize(field)
         
     | 
| 
      
 8 
     | 
    
         
            +
                      super("Missing translated field #{field.inspect}")
         
     | 
| 
      
 9 
     | 
    
         
            +
                    end
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
              
         
     | 
| 
      
 12 
     | 
    
         
            +
                  class BadFieldType < MigrationError
         
     | 
| 
      
 13 
     | 
    
         
            +
                    def initialize(name, type)
         
     | 
| 
      
 14 
     | 
    
         
            +
                      super("Bad field type for field #{name.inspect} (#{type.inspect}), should be :string or :text")
         
     | 
| 
      
 15 
     | 
    
         
            +
                    end
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,175 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Globalize
         
     | 
| 
      
 2 
     | 
    
         
            +
              module ActiveRecord
         
     | 
| 
      
 3 
     | 
    
         
            +
                module InstanceMethods
         
     | 
| 
      
 4 
     | 
    
         
            +
                  delegate :translated_locales, :to => :translations
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  def globalize
         
     | 
| 
      
 7 
     | 
    
         
            +
                    @globalize ||= Adapter.new(self)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def attributes
         
     | 
| 
      
 11 
     | 
    
         
            +
                    super.merge(translated_attributes)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def self.included(base)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    # Maintain Rails 3.0.x compatibility while adding Rails 3.1.x compatibility
         
     | 
| 
      
 16 
     | 
    
         
            +
                    if base.method_defined?(:assign_attributes)
         
     | 
| 
      
 17 
     | 
    
         
            +
                      base.class_eval %{
         
     | 
| 
      
 18 
     | 
    
         
            +
                        def assign_attributes(attributes, options = {})
         
     | 
| 
      
 19 
     | 
    
         
            +
                          with_given_locale(attributes) { super }
         
     | 
| 
      
 20 
     | 
    
         
            +
                        end
         
     | 
| 
      
 21 
     | 
    
         
            +
                      }
         
     | 
| 
      
 22 
     | 
    
         
            +
                    else
         
     | 
| 
      
 23 
     | 
    
         
            +
                      base.class_eval %{
         
     | 
| 
      
 24 
     | 
    
         
            +
                        def attributes=(attributes, *args)
         
     | 
| 
      
 25 
     | 
    
         
            +
                          with_given_locale(attributes) { super }
         
     | 
| 
      
 26 
     | 
    
         
            +
                        end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                        def update_attributes!(attributes, *args)
         
     | 
| 
      
 29 
     | 
    
         
            +
                          with_given_locale(attributes) { super }
         
     | 
| 
      
 30 
     | 
    
         
            +
                        end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                        def update_attributes(attributes, *args)
         
     | 
| 
      
 33 
     | 
    
         
            +
                          with_given_locale(attributes) { super }
         
     | 
| 
      
 34 
     | 
    
         
            +
                        end
         
     | 
| 
      
 35 
     | 
    
         
            +
                      }
         
     | 
| 
      
 36 
     | 
    
         
            +
                    end
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  def write_attribute(name, value, options = {})
         
     | 
| 
      
 40 
     | 
    
         
            +
                    # raise 'y' if value.nil? # TODO.
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                    if translated?(name)
         
     | 
| 
      
 43 
     | 
    
         
            +
                      # Deprecate old use of locale
         
     | 
| 
      
 44 
     | 
    
         
            +
                      unless options.is_a?(Hash)
         
     | 
| 
      
 45 
     | 
    
         
            +
                        warn "[DEPRECATION] passing 'locale' as #{options.inspect} is deprecated. Please use {:locale => #{options.inspect}} instead."
         
     | 
| 
      
 46 
     | 
    
         
            +
                        options = {:locale => options}
         
     | 
| 
      
 47 
     | 
    
         
            +
                      end
         
     | 
| 
      
 48 
     | 
    
         
            +
                      options = {:locale => nil}.merge(options)
         
     | 
| 
      
 49 
     | 
    
         
            +
                      attribute_will_change! name.to_s
         
     | 
| 
      
 50 
     | 
    
         
            +
                      the_locale = options[:locale] || Globalize.locale
         
     | 
| 
      
 51 
     | 
    
         
            +
                      self.translations.reject!{|t| t.new_record? && t.locale != the_locale}
         
     | 
| 
      
 52 
     | 
    
         
            +
                      globalize.write(the_locale, name, value)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    else
         
     | 
| 
      
 54 
     | 
    
         
            +
                      super(name, value)
         
     | 
| 
      
 55 
     | 
    
         
            +
                    end
         
     | 
| 
      
 56 
     | 
    
         
            +
                  end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                  def read_attribute(name, options = {})
         
     | 
| 
      
 59 
     | 
    
         
            +
                    # Deprecate old use of locale
         
     | 
| 
      
 60 
     | 
    
         
            +
                    unless options.is_a?(Hash)
         
     | 
| 
      
 61 
     | 
    
         
            +
                      warn "[DEPRECATION] passing 'locale' as #{options.inspect} is deprecated. Please use {:locale => #{options.inspect}} instead."
         
     | 
| 
      
 62 
     | 
    
         
            +
                      options = {:locale => options}
         
     | 
| 
      
 63 
     | 
    
         
            +
                    end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                    options = {:translated => true, :locale => nil}.merge(options)
         
     | 
| 
      
 66 
     | 
    
         
            +
                    if self.class.translated?(name) and options[:translated]
         
     | 
| 
      
 67 
     | 
    
         
            +
                      globalize.fetch(options[:locale] || Globalize.locale, name)
         
     | 
| 
      
 68 
     | 
    
         
            +
                    else
         
     | 
| 
      
 69 
     | 
    
         
            +
                      super(name)
         
     | 
| 
      
 70 
     | 
    
         
            +
                    end
         
     | 
| 
      
 71 
     | 
    
         
            +
                  end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                  def attribute_names
         
     | 
| 
      
 74 
     | 
    
         
            +
                    translated_attribute_names.map(&:to_s) + super
         
     | 
| 
      
 75 
     | 
    
         
            +
                  end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                  def translated?(name)
         
     | 
| 
      
 78 
     | 
    
         
            +
                    self.class.translated?(name)
         
     | 
| 
      
 79 
     | 
    
         
            +
                  end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                  def translated_attributes
         
     | 
| 
      
 82 
     | 
    
         
            +
                    translated_attribute_names.inject({}) do |attributes, name|
         
     | 
| 
      
 83 
     | 
    
         
            +
                      attributes.merge(name.to_s => translation.send(name))
         
     | 
| 
      
 84 
     | 
    
         
            +
                    end
         
     | 
| 
      
 85 
     | 
    
         
            +
                  end
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                  # This method is basically the method built into Rails
         
     | 
| 
      
 88 
     | 
    
         
            +
                  # but we have to pass {:translated => false}
         
     | 
| 
      
 89 
     | 
    
         
            +
                  def untranslated_attributes
         
     | 
| 
      
 90 
     | 
    
         
            +
                    attrs = {}
         
     | 
| 
      
 91 
     | 
    
         
            +
                    attribute_names.each do |name|
         
     | 
| 
      
 92 
     | 
    
         
            +
                      attrs[name] = read_attribute(name, {:translated => false})
         
     | 
| 
      
 93 
     | 
    
         
            +
                    end
         
     | 
| 
      
 94 
     | 
    
         
            +
                    attrs
         
     | 
| 
      
 95 
     | 
    
         
            +
                  end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                  def set_translations(options)
         
     | 
| 
      
 98 
     | 
    
         
            +
                    options.keys.each do |locale|
         
     | 
| 
      
 99 
     | 
    
         
            +
                      translation = translation_for(locale) ||
         
     | 
| 
      
 100 
     | 
    
         
            +
                        translations.build(:locale => locale.to_s)
         
     | 
| 
      
 101 
     | 
    
         
            +
                      translation.update_attributes!(options[locale])
         
     | 
| 
      
 102 
     | 
    
         
            +
                    end
         
     | 
| 
      
 103 
     | 
    
         
            +
                  end
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                  def reload(options = nil)
         
     | 
| 
      
 106 
     | 
    
         
            +
                    translated_attribute_names.each { |name| @attributes.delete(name.to_s) }
         
     | 
| 
      
 107 
     | 
    
         
            +
                    globalize.reset
         
     | 
| 
      
 108 
     | 
    
         
            +
                    super(options)
         
     | 
| 
      
 109 
     | 
    
         
            +
                  end
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                  def clone
         
     | 
| 
      
 112 
     | 
    
         
            +
                    obj = super
         
     | 
| 
      
 113 
     | 
    
         
            +
                    return obj unless respond_to?(:translated_attribute_names)
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                    obj.instance_variable_set(:@translations, nil) if new_record? # Reset the collection because of rails bug: http://pastie.org/1521874
         
     | 
| 
      
 116 
     | 
    
         
            +
                    obj.instance_variable_set(:@globalize, nil )
         
     | 
| 
      
 117 
     | 
    
         
            +
                    each_locale_and_translated_attribute do |locale, name|
         
     | 
| 
      
 118 
     | 
    
         
            +
                      obj.globalize.write(locale, name, globalize.fetch(locale, name) )
         
     | 
| 
      
 119 
     | 
    
         
            +
                    end
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                    return obj
         
     | 
| 
      
 122 
     | 
    
         
            +
                  end
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
                  def translation
         
     | 
| 
      
 125 
     | 
    
         
            +
                    translation_for(::Globalize.locale)
         
     | 
| 
      
 126 
     | 
    
         
            +
                  end
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
                  def translation_for(locale)
         
     | 
| 
      
 129 
     | 
    
         
            +
                    @translation_caches ||= {}
         
     | 
| 
      
 130 
     | 
    
         
            +
                    unless @translation_caches[locale]
         
     | 
| 
      
 131 
     | 
    
         
            +
                      # Fetch translations from database as those in the translation collection may be incomplete
         
     | 
| 
      
 132 
     | 
    
         
            +
                      _translation = translations.detect{|t| t.locale.to_s == locale.to_s}
         
     | 
| 
      
 133 
     | 
    
         
            +
                      _translation ||= translations.with_locale(locale).first
         
     | 
| 
      
 134 
     | 
    
         
            +
                      _translation ||= translations.build(:locale => locale)
         
     | 
| 
      
 135 
     | 
    
         
            +
                      @translation_caches[locale] = _translation
         
     | 
| 
      
 136 
     | 
    
         
            +
                    end
         
     | 
| 
      
 137 
     | 
    
         
            +
                    @translation_caches[locale]
         
     | 
| 
      
 138 
     | 
    
         
            +
                  end
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
                  def rollback
         
     | 
| 
      
 141 
     | 
    
         
            +
                    @translation_caches[::Globalize.locale] = translation.previous_version
         
     | 
| 
      
 142 
     | 
    
         
            +
                  end
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
                protected
         
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
                  def each_locale_and_translated_attribute
         
     | 
| 
      
 147 
     | 
    
         
            +
                    used_locales.each do |locale|
         
     | 
| 
      
 148 
     | 
    
         
            +
                      translated_attribute_names.each do |name|
         
     | 
| 
      
 149 
     | 
    
         
            +
                        yield locale, name
         
     | 
| 
      
 150 
     | 
    
         
            +
                      end
         
     | 
| 
      
 151 
     | 
    
         
            +
                    end
         
     | 
| 
      
 152 
     | 
    
         
            +
                  end
         
     | 
| 
      
 153 
     | 
    
         
            +
             
     | 
| 
      
 154 
     | 
    
         
            +
                  def used_locales
         
     | 
| 
      
 155 
     | 
    
         
            +
                    locales = globalize.stash.keys.concat(globalize.stash.keys).concat(translations.translated_locales)
         
     | 
| 
      
 156 
     | 
    
         
            +
                    locales.uniq!
         
     | 
| 
      
 157 
     | 
    
         
            +
                    locales
         
     | 
| 
      
 158 
     | 
    
         
            +
                  end
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
                  def save_translations!
         
     | 
| 
      
 161 
     | 
    
         
            +
                    globalize.save_translations!
         
     | 
| 
      
 162 
     | 
    
         
            +
                    @translation_caches = {}
         
     | 
| 
      
 163 
     | 
    
         
            +
                  end
         
     | 
| 
      
 164 
     | 
    
         
            +
             
     | 
| 
      
 165 
     | 
    
         
            +
                  def with_given_locale(attributes, &block)
         
     | 
| 
      
 166 
     | 
    
         
            +
                    attributes.symbolize_keys! if attributes.respond_to?(:symbolize_keys!)
         
     | 
| 
      
 167 
     | 
    
         
            +
                    if locale = attributes.try(:delete, :locale)
         
     | 
| 
      
 168 
     | 
    
         
            +
                      Globalize.with_locale(locale, &block)
         
     | 
| 
      
 169 
     | 
    
         
            +
                    else
         
     | 
| 
      
 170 
     | 
    
         
            +
                      yield
         
     | 
| 
      
 171 
     | 
    
         
            +
                    end
         
     | 
| 
      
 172 
     | 
    
         
            +
                  end
         
     | 
| 
      
 173 
     | 
    
         
            +
                end
         
     | 
| 
      
 174 
     | 
    
         
            +
              end
         
     | 
| 
      
 175 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,161 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'digest/sha1'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Globalize
         
     | 
| 
      
 4 
     | 
    
         
            +
              module ActiveRecord
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Migration
         
     | 
| 
      
 6 
     | 
    
         
            +
                  attr_reader :globalize_migrator
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def globalize_migrator
         
     | 
| 
      
 9 
     | 
    
         
            +
                    @globalize_migrator ||= Migrator.new(self)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  delegate :create_translation_table!, :drop_translation_table!,
         
     | 
| 
      
 13 
     | 
    
         
            +
                    :translation_index_name, :to => :globalize_migrator
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  class Migrator
         
     | 
| 
      
 16 
     | 
    
         
            +
                    include Globalize::ActiveRecord::Exceptions
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    attr_reader :model, :fields
         
     | 
| 
      
 19 
     | 
    
         
            +
                    delegate :translated_attribute_names, :connection, :table_name,
         
     | 
| 
      
 20 
     | 
    
         
            +
                      :table_name_prefix, :translations_table_name, :columns, :to => :model
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    def initialize(model)
         
     | 
| 
      
 23 
     | 
    
         
            +
                      @model = model
         
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                    def create_translation_table!(fields = {}, options = {})
         
     | 
| 
      
 27 
     | 
    
         
            +
                      @fields = fields
         
     | 
| 
      
 28 
     | 
    
         
            +
                      complete_translated_fields
         
     | 
| 
      
 29 
     | 
    
         
            +
                      validate_translated_fields
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                      create_translation_table
         
     | 
| 
      
 32 
     | 
    
         
            +
                      move_data_to_translation_table if options[:migrate_data]
         
     | 
| 
      
 33 
     | 
    
         
            +
                      remove_source_columns if options[:remove_source_columns]
         
     | 
| 
      
 34 
     | 
    
         
            +
                      create_translations_index
         
     | 
| 
      
 35 
     | 
    
         
            +
                    end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                    def remove_source_columns
         
     | 
| 
      
 38 
     | 
    
         
            +
                      translated_attribute_names.each do |attribute|
         
     | 
| 
      
 39 
     | 
    
         
            +
                        connection.remove_column(table_name, attribute)
         
     | 
| 
      
 40 
     | 
    
         
            +
                      end
         
     | 
| 
      
 41 
     | 
    
         
            +
                    end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                    def drop_translation_table!(options = {})
         
     | 
| 
      
 44 
     | 
    
         
            +
                      move_data_to_model_table if options[:migrate_data]
         
     | 
| 
      
 45 
     | 
    
         
            +
                      drop_translations_index
         
     | 
| 
      
 46 
     | 
    
         
            +
                      drop_translation_table
         
     | 
| 
      
 47 
     | 
    
         
            +
                    end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                    def complete_translated_fields
         
     | 
| 
      
 50 
     | 
    
         
            +
                      translated_attribute_names.each do |name|
         
     | 
| 
      
 51 
     | 
    
         
            +
                        fields[name] = column_type(name) unless fields[name]
         
     | 
| 
      
 52 
     | 
    
         
            +
                      end
         
     | 
| 
      
 53 
     | 
    
         
            +
                    end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                    def create_translation_table
         
     | 
| 
      
 56 
     | 
    
         
            +
                      connection.create_table(translations_table_name) do |t|
         
     | 
| 
      
 57 
     | 
    
         
            +
                        t.references table_name.sub(/^#{table_name_prefix}/, '').singularize
         
     | 
| 
      
 58 
     | 
    
         
            +
                        t.string :locale
         
     | 
| 
      
 59 
     | 
    
         
            +
                        fields.each { |name, type| t.column name, type }
         
     | 
| 
      
 60 
     | 
    
         
            +
                        t.timestamps
         
     | 
| 
      
 61 
     | 
    
         
            +
                      end
         
     | 
| 
      
 62 
     | 
    
         
            +
                    end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                    def create_translations_index
         
     | 
| 
      
 65 
     | 
    
         
            +
                      connection.add_index(
         
     | 
| 
      
 66 
     | 
    
         
            +
                        translations_table_name,
         
     | 
| 
      
 67 
     | 
    
         
            +
                        "#{table_name.sub(/^#{table_name_prefix}/, "").singularize}_id",
         
     | 
| 
      
 68 
     | 
    
         
            +
                        :name => translation_index_name
         
     | 
| 
      
 69 
     | 
    
         
            +
                      )
         
     | 
| 
      
 70 
     | 
    
         
            +
                      # index for select('DISTINCT locale') call in translation.rb
         
     | 
| 
      
 71 
     | 
    
         
            +
                      connection.add_index(
         
     | 
| 
      
 72 
     | 
    
         
            +
                        translations_table_name,
         
     | 
| 
      
 73 
     | 
    
         
            +
                        :locale
         
     | 
| 
      
 74 
     | 
    
         
            +
                      )
         
     | 
| 
      
 75 
     | 
    
         
            +
                    end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                    def drop_translation_table
         
     | 
| 
      
 78 
     | 
    
         
            +
                      connection.drop_table(translations_table_name)
         
     | 
| 
      
 79 
     | 
    
         
            +
                    end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                    def drop_translations_index
         
     | 
| 
      
 82 
     | 
    
         
            +
                      connection.remove_index(translations_table_name, :name => translation_index_name)
         
     | 
| 
      
 83 
     | 
    
         
            +
                    end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                    def move_data_to_translation_table
         
     | 
| 
      
 86 
     | 
    
         
            +
                    # this refactored version might be a good idea,
         
     | 
| 
      
 87 
     | 
    
         
            +
                    #  but only if made into a code that doesn't break tests
         
     | 
| 
      
 88 
     | 
    
         
            +
                    # model.find_each do |record|
         
     | 
| 
      
 89 
     | 
    
         
            +
                    #   translation = record.translations.build(:locale => I18n.default_locale)
         
     | 
| 
      
 90 
     | 
    
         
            +
                    #    translated_attribute_names.each do |attribute|
         
     | 
| 
      
 91 
     | 
    
         
            +
                    #      translation[attribute] = record[attribute]
         
     | 
| 
      
 92 
     | 
    
         
            +
                    #    end
         
     | 
| 
      
 93 
     | 
    
         
            +
                    #    translation.save!
         
     | 
| 
      
 94 
     | 
    
         
            +
                    # end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                      # Find all of the existing untranslated attributes for this model.
         
     | 
| 
      
 97 
     | 
    
         
            +
                      all_model_fields = @model.all
         
     | 
| 
      
 98 
     | 
    
         
            +
                      model_attributes = all_model_fields.map(&:untranslated_attributes)
         
     | 
| 
      
 99 
     | 
    
         
            +
                      all_model_fields.each do |model_record|
         
     | 
| 
      
 100 
     | 
    
         
            +
                        # Assign the attributes back to the model which will enable globalize3 to translate them.
         
     | 
| 
      
 101 
     | 
    
         
            +
                        model_record.attributes = model_attributes.detect{|a| a['id'] == model_record.id}
         
     | 
| 
      
 102 
     | 
    
         
            +
                        model_record.save!
         
     | 
| 
      
 103 
     | 
    
         
            +
                      end
         
     | 
| 
      
 104 
     | 
    
         
            +
                    end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                    def move_data_to_model_table
         
     | 
| 
      
 107 
     | 
    
         
            +
                      add_missing_columns
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                      # Find all of the translated attributes for all records in the model.
         
     | 
| 
      
 110 
     | 
    
         
            +
                      all_translated_attributes = @model.all.collect{|m| m.attributes}
         
     | 
| 
      
 111 
     | 
    
         
            +
                      all_translated_attributes.each do |translated_record|
         
     | 
| 
      
 112 
     | 
    
         
            +
                        # Create a hash containing the translated column names and their values.
         
     | 
| 
      
 113 
     | 
    
         
            +
                        translated_attribute_names.inject(fields_to_update={}) do |f, name|
         
     | 
| 
      
 114 
     | 
    
         
            +
                          f.update({name.to_sym => translated_record[name.to_s]})
         
     | 
| 
      
 115 
     | 
    
         
            +
                        end
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                        # Now, update the actual model's record with the hash.
         
     | 
| 
      
 118 
     | 
    
         
            +
                        @model.update_all(fields_to_update, {:id => translated_record['id']})
         
     | 
| 
      
 119 
     | 
    
         
            +
                      end
         
     | 
| 
      
 120 
     | 
    
         
            +
                    end
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
                    def validate_translated_fields
         
     | 
| 
      
 123 
     | 
    
         
            +
                      fields.each do |name, type|
         
     | 
| 
      
 124 
     | 
    
         
            +
                        raise BadFieldName.new(name) unless valid_field_name?(name)
         
     | 
| 
      
 125 
     | 
    
         
            +
                        raise BadFieldType.new(name, type) unless valid_field_type?(name, type)
         
     | 
| 
      
 126 
     | 
    
         
            +
                      end
         
     | 
| 
      
 127 
     | 
    
         
            +
                    end
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                    def column_type(name)
         
     | 
| 
      
 130 
     | 
    
         
            +
                      columns.detect { |c| c.name == name.to_s }.try(:type)
         
     | 
| 
      
 131 
     | 
    
         
            +
                    end
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                    def valid_field_name?(name)
         
     | 
| 
      
 134 
     | 
    
         
            +
                      translated_attribute_names.include?(name)
         
     | 
| 
      
 135 
     | 
    
         
            +
                    end
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
                    def valid_field_type?(name, type)
         
     | 
| 
      
 138 
     | 
    
         
            +
                      !translated_attribute_names.include?(name) || [:string, :text].include?(type)
         
     | 
| 
      
 139 
     | 
    
         
            +
                    end
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                    def translation_index_name
         
     | 
| 
      
 142 
     | 
    
         
            +
                      # FIXME what's the max size of an index name?
         
     | 
| 
      
 143 
     | 
    
         
            +
                      index_name = "index_#{translations_table_name}_on_#{table_name.singularize}_id"
         
     | 
| 
      
 144 
     | 
    
         
            +
                      index_name.size < 50 ? index_name : "index_#{Digest::SHA1.hexdigest(index_name)}"
         
     | 
| 
      
 145 
     | 
    
         
            +
                    end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
                    private
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
                    def add_missing_columns
         
     | 
| 
      
 151 
     | 
    
         
            +
                      translated_attribute_names.map(&:to_s).each do |attribute|
         
     | 
| 
      
 152 
     | 
    
         
            +
                        unless model.column_names.include?(attribute)
         
     | 
| 
      
 153 
     | 
    
         
            +
                          connection.add_column(table_name, attribute, model::Translation.columns_hash[attribute].type)
         
     | 
| 
      
 154 
     | 
    
         
            +
                        end
         
     | 
| 
      
 155 
     | 
    
         
            +
                      end
         
     | 
| 
      
 156 
     | 
    
         
            +
                    end
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
                  end
         
     | 
| 
      
 159 
     | 
    
         
            +
                end
         
     | 
| 
      
 160 
     | 
    
         
            +
              end
         
     | 
| 
      
 161 
     | 
    
         
            +
            end
         
     |