Reputation: 13486
What is the recommended approach to maintaining multi-language values within an ActiveRecord model.
I am looking into upgrading our database schema and Object Models to allow for widespread internationalisation of many of the values, and I am weighing up various ways to do this.
The standard rails-i18n system is largely silent on this, although it offers powerful tools for internationalising field and model names, in addition to the text within views.
The R18n gem allows you to overload your database with columns that store the localised strings, and which present the correct value depending on the locale. This presents a couple of problems.
Say we are talking about a model Sport
— database table sports
. We need to be able to search for Sport.where(name: 'soccer')
even though in the UK they call it 'football', so the query becomes scope :with_name ->(n){ where("name_en_GB = ? OR name_en_AU = ?", n, n) }
.
If we want to add another locale we need to both update the schema, and update any such queries on that schema. A rather brittle solution.
Another solution I've seen is to maintain a separate SportLocale
model and associated sport_locales
table, that holds the name and locale.
Assuming
class Sport < ActiveRecord::Base
has_many :locales
end
class SportLocale < ActiveRecord::Base
belongs_to :sport
end
Then to find the right sport you'd do something like
class Sport < ActiveRecord::Base
has_many :locales, class_name: "SportLocale"
self.with_name(n)
SportLocale.where(name: n, locale: I18n.locale).first.try(:sport)
end
end
This is fine if Sport
is your only localised model but when you start adding all the other models it becomes a bit crazy, with each of them needing an associated *Locale model. Not the DRY
est of solutions either.
I'd like a solution that allows
class Sport < ActiveRecord::Base
include Localised
localised_field :name
end
and magically Sport.where(name: 'football')
will find the right sport.
Is there any such system out there already, or would I have to build it myself? How are other projects dealing with this sort of problem?
Upvotes: 4
Views: 132
Reputation: 296
The i18n
Ruby gem (which is used by Rails) is mostly useful for static translations, i.e. translations which can be considered part of the code (just like you'd consider static, hardcoded strings in your views part of the code). These are, most of the time, stored in static YAML files, so they'd change at deploy time.
I don't know about the current version of R18n
. When I once looked at it years ago it provided an alternative way to do similar things (with a different syntax and slightly different features).
Translating model data is a different task. Globalize is maybe the most widely used solution for it, but there are lots of other solutions. Unless you're feeling adventurous I'd recommend to use a mature solution, translating data (and integrating with ActiveRecord) can be hairy when it comes to more complicated usecases.
Upvotes: 3
Reputation: 167
If I understand the problem you are trying to solve, you may get something out of the Globalize gem.
It hides away the translation tables you need, but it can provide a standard for mapping of 'soccer' [en-au] to 'football' [en-uk] that you might be able to interrogate for the translated attribute values you're looking for.
Upvotes: 1
Reputation: 3347
Why don't you just store the I18n localization key associated to your sport and search for it?
To display the name to the user, just use that key against the user's current locale.
Upvotes: 0