Module: ActiveVersion::Translations::HasTranslations

Extended by:
ActiveSupport::Concern
Defined in:
lib/active_version/translations/has_translations.rb

Overview

Concern for models that have translations

Defined Under Namespace

Modules: ClassMethods

Instance Method Summary collapse

Instance Method Details

#active_version_translation_identity_mapObject



306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/active_version/translations/has_translations.rb', line 306

def active_version_translation_identity_map
  columns = translation_identity_columns
  values = active_version_translation_identity_values

  case values
  when Hash
    values.transform_keys(&:to_s).slice(*columns)
  when Array
    columns.zip(values).to_h
  else
    {columns.first => values}
  end
end

#active_version_translation_identity_valuesObject



320
321
322
323
324
325
326
327
328
329
330
331
332
# File 'lib/active_version/translations/has_translations.rb', line 320

def active_version_translation_identity_values
  resolver = self.class.translation_options && self.class.translation_options[:identity_resolver]
  return default_translation_identity_values if resolver.nil?

  case resolver
  when Proc
    resolver.arity.zero? ? instance_exec(&resolver) : resolver.call(self)
  when Array
    resolver.map { |column| public_send(column) }
  else
    public_send(resolver)
  end
end

#default_translation_identity_valuesObject



338
339
340
341
342
343
# File 'lib/active_version/translations/has_translations.rb', line 338

def default_translation_identity_values
  columns = translation_identity_columns
  return id if columns.one?

  Array(self.class.primary_key).map { |column| self[column] }
end

#respond_to_copy_values?Boolean

Returns:

  • (Boolean)


345
346
347
# File 'lib/active_version/translations/has_translations.rb', line 345

def respond_to_copy_values?
  respond_to?(:copy_values_from_translation, true)
end

#translate(attr_name, locale: nil, presence_check: nil, fallback: true) ⇒ Object

Translate an attribute to a specific locale



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/active_version/translations/has_translations.rb', line 184

def translate(attr_name, locale: nil, presence_check: nil, fallback: true)
  locale ||= I18n.locale
  locale_column = ActiveVersion.column_mapper.column_for(self.class, :translations, :locale)
  # Ensure the column exists in the translation class, fallback to default if not
  translation_class = self.class.translation_class
  unless translation_class.column_names.include?(locale_column.to_s)
    locale_column = ActiveVersion.config.translation_locale_column
  end

  translation_records = if persisted?
    translation_class.where(active_version_translation_identity_map)
  else
    translations
  end

  # Find translation for requested locale
  translation = translation_records.find do |t|
    t.send(locale_column) == locale &&
      t.attr_present_for_locale?(locale, attr_name, presence_check)
  end

  return translation&.send(attr_name) if translation

  # Fallback chain
  if fallback
    # Try default locale
    translation = translation_records.find do |t|
      t.send(locale_column) == I18n.default_locale &&
        t.attr_present_for_locale?(I18n.default_locale, attr_name, presence_check)
    end
    if translation
      ActiveVersion::Instrumentation.instrument_translation_fallback_used(
        self,
        attr: attr_name,
        requested_locale: locale,
        resolved_locale: I18n.default_locale
      )
      return translation.send(attr_name)
    end

    # Try any translation
    translation = translation_records.first
    if translation
      ActiveVersion::Instrumentation.instrument_translation_fallback_used(
        self,
        attr: attr_name,
        requested_locale: locale,
        resolved_locale: translation.send(locale_column)
      )
      return translation.send(attr_name)
    end

    # Try source record
    if respond_to?(attr_name)
      ActiveVersion::Instrumentation.instrument_translation_fallback_used(
        self,
        attr: attr_name,
        requested_locale: locale,
        resolved_locale: :source
      )
      return send(attr_name)
    end
  end

  nil
end

#translation(locale: nil) ⇒ Object

Get translation record for a locale



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/active_version/translations/has_translations.rb', line 252

def translation(locale: nil)
  locale ||= I18n.locale
  locale_column = ActiveVersion.column_mapper.column_for(self.class, :translations, :locale)
  # Ensure the column exists in the translation class, fallback to default if not
  translation_class = self.class.translation_class
  unless translation_class.column_names.include?(locale_column.to_s)
    locale_column = ActiveVersion.config.translation_locale_column
  end
  # First try in-memory association
  result = translations.find { |t| t.send(locale_column) == locale }
  return result if result

  # If not found in memory, query database (in case translation was just created)
  return nil unless persisted?
  translation_class.where(
    active_version_translation_identity_map.merge(locale_column => locale)
  ).first
end

#translation_identity_columnsObject



334
335
336
# File 'lib/active_version/translations/has_translations.rb', line 334

def translation_identity_columns
  Array(self.class.translation_class.source_foreign_key).map(&:to_s)
end

#update_default_translationObject

Update default translation after create



272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
# File 'lib/active_version/translations/has_translations.rb', line 272

def update_default_translation
  locale_column = ActiveVersion.column_mapper.column_for(self.class, :translations, :locale)
  # Ensure the column exists in the translation class
  translation_class = self.class.translation_class
  unless translation_class.column_names.include?(locale_column.to_s)
    # Fall back to default if custom column doesn't exist
    locale_column = ActiveVersion.config.translation_locale_column
  end
  translation = translation_class.find_or_initialize_by(
    active_version_translation_identity_map.merge(locale_column => I18n.default_locale)
  )
  return if translation.persisted?

  # Copy attributes from source to default translation
  translation.assign_attributes(
    attributes.slice(
      *translation.attributes.keys.excluding(
        "id",
        "created_at",
        "updated_at",
        "locale",
        locale_column.to_s,
        *Array(translation.class.source_foreign_key).map(&:to_s)
      )
    )
  )
  translation.save
  translations.reset
end