Reputation: 54882
We are having a dilemna about a feature we need to implement. We want to support n
languages in our app (0 < n < +infinity
).
We decided to go with the solution below:
module TranslatedAttributes
def use_translated_attributes
has_many :translated_attributes, as: :owner
accepts_nested_attributes_for :translated_attributes
define_method :translate_attribute do |attribute, locale = I18n.locale|
TranslatedAttribute.where(attribute_name: attribute.to_s, owner_type: self.class.model_name, owner_id: self.id, locale: locale.to_s).first.try(:translation)
end
end
end
The User should be able to define X translation(s) for an instance of the Product model for example. Also, depending on the user's locale set in his profile, he will see the translated version of the attribute.
Example:
Product
id: 12
TranslatedAttribute
attribute_name: 'name'
owner_id: 12
owner_type: 'Product'
locale: 'en'
translation: 'Magnificent shiny shoes'
TranslatedAttribute
attribute_name: 'name'
owner_id: 12
owner_type: 'Product'
locale: 'fr'
translation: 'Magnifiques chaussures brillantes'
In the view, it would be called like this:
product.translate_attribute(:name)
# or we will eventually define_method for each attribute to be translated
# so we could use the following
# product.name
This works, already tested.
The problem is when we will try to load tons of records, each one needing to query the DB to know the proper translation to display.
My question is: How would you handle a CACHE about this?
Another question I have is: is there another problem you see that I might not see so far? Also, I thought about accepts_nested_attributes_for :translated_attributes
to build the translation's form with fields_for
. Do you think it is a bad idea to handle it like this?
Thanks you!
Upvotes: 0
Views: 47
Reputation: 2118
A first optimization could be to fetch all the translations in the desired locale[1] for a Product instance at the first call to translate_attribute
, and cache them in an instance variable.
This way, the number of requests for translations would be reduced to just one by Product instance.
Quick example:
define_method :translate_attribute do |attribute, locale = I18n.locale|
locale = locale.to_s
@attributes_translations_cache ||= {}
@attributes_translations_cache[locale] ||= Hash[
self.translated_attributes
.where(locale: locale)
.map do |translated_attribute|
[translated_attribute.name, translated_attribute.translation]
end
]
@attributes_translations_cache[locale][attribute]
end
I think that it should also be possible to join
or at least include
the translation to the Products in some way, but I haven't given much thought to this idea yet. I'll try to update this answer.
[1] This assumes that you only use a single locale in a given page, but you could also fetch all the locales at the same time, or any combination of locale and attributes.
Upvotes: 1
Reputation: 107708
You could use something such as the globalize3 gem to implement this feature.
Upvotes: 2