I’m building a multilang application that has two essential models Category and Product, where a Category has many Products..
So I want the ability to display the same categories with more than a language, for example, consider a category called Cars, it should be presented as Vehicules for a user using the french version of the application.
How could I do that? Should I store them in different models? or should I add a lang column in the Category model ?
What I thought of doing is adding a lang column in the Category model and add a default_scope call to scope it to search for only the desired language, I have two questions though:
- How can I get the used language from inside a model, an I18n call ? Which method should I call on it ?
- A problem arises from using this technique, a product which references a category in french wouldn’t show up in a search under the category in english, how can I resolve this issue ?
Thank you
Frankie Roberto gave you a good answer. I will just add some additional info.
First the easy part: getting current locale in a model.
If you set the language in a controller as
I18n.locale = something, then you may read it in a model the same way. TheI18nis a global constant, after all.Now about searching:
I generally prefer the designs where you have one category, but the name of the category is translated to many languages. The design where one car belongs to category “Cars” and another one belongs to “Vehicules” is flawed IMHO. In the later case there is no sense of making it a single site – you could create a one-language application, and install it in multiple instances, where every one is translated to a single language.
If you have a short, static list of supported languages, you may add a column for every language:
name_en,name_fr,name_pl.If your list of languages will be large or unknown at the moment of designing your application, it would be easier to store the “name” (given as an example) as a serialized hash. So, you could get the intended translation as
name["fr"],name["de"]and so on.I have already learned (the hard way 🙂 ) that users usually are too lazy to provide all the translations (or they just do not know all the languages), so you should be prepared that some of your models will not have the data in a language you are trying to display or search.
For every ‘translated’ attribute you may want to prepare a method which will supply you with the most appropriate translation in case the required one is missing.
This method may work in a way similar to:
Of course, you do not need to use I18n.locale, and you should define
other_languagesin a way which would (ideally) match user language preferences, possibly by analyzing the “Accept-Language” header.I sometimes use the method name
name_for(lang)orname_in(lang), if I have to support more languages for data than for interface (which I shall translate and put in I18n config files).Ah, yes – searching. 🙂
If you have defined the “names” as separate attributes, you may just search the appropriate column.
If you have the “names” as a single, serialized hash, you may search the column as a simple text (however I am not sure whether YAML will not mangle the non-ASCII characters) or create another column with searchable data, and then (at the model-level, not at the SQL level) partition the models into groups: “The search string has been found in your language”, “The search string has been found in some other language”. I believe the user of multi-lang service will be happy with search results presented in this way.