I have worked, and am currently working on internationalization of a Rails app. The apps require translating the ActiveRecord models. I have done some googling, but haven't really found any best practices / conventions / guidelines on how to think through this and what guidelines to follow.
I decided to create this document, to give myself a start and have it possibly help others. I am not an expert at any of this, and there may be things I am thinking incorrectly, but having it documented makes it easier to see the flaws and improve upon. If you have some ideas on additions, or think that somethings should change, get in touch.
Note: I use Globalize for model translations
-
I18n.locale
controls the app wide locale. It refers to the particular localization version of the app. It defines how the app is localized to the user. It's scope is somewhat larger than the language/translation of the content in consideration. So use that parameter when the app needs to be localized to a user, not just to refer to the translation of the resource. -
When using Globalize,
Globalize.locale
controls the translation (or locale) of ActiveRecord models. It does not have to match with I18n.locale. When they both don't match, ActiveRecord returns the translation corresponding toGlobalize.locale
(unless one doesn't exist). -
Use the translation, language or
lang
query parameter parameter (in the context of resource / model translations) to describe the translation language of the resource the user has requested. For the use case in which, for a particular locale, the user requests a translation of a resource that is different from the default translation, use the translation/language/lang locale for it. -
It is fair to have the language /
lang
parameter default to locale unless the user wants language to be different from the locale. -
Set both
I18n.locale
andGlobalize locale
on every request. This currently works as a workaround for a bug, and might not be a bad practice anyway. -
Set
Globalize.locale
toI18n.locale
just afterI18n.locale
is set. It can be changed later based on the use-case to deliver the correct model translation. -
To create a translation use
ActiveRecord#update_attributes
like so:@tranlsated_object.update_attributes(:title => 'Title', :locale => :ko)
-
Do not set up a AR class around the Globalize translations table unless you are really sure you cannot do without it, for the following reasons:
- This avoids temptation to write hacky code in the translations class, once that is defined, and write complex code.
- This will force you to use Globalize3 API correctly.
- This will also force us to contributing to Globlize3 API, which is something we should be eager to do since it will help for us to have a better codebase.
-
When testing, set up a default RSpec hook to reset locale after every test. When writing every test, write it with keeping in mind that all locales are set to defaults. It might be benificial to reset locale after every test rather than before.
RSpec.configure do |config| config.after(:each) do I18n.locale = :en Globalize.locale = :en end end
-
When you work on your rails app, you will probably use
default_url_options
to use I18n.locale as the default locale parameter for your route / path helpers. However this doesn't work in tests. I picked up a solution from this github issue on rspec-rails. I monkey patchActionDispatch::Routing::RouteSet
like so:class ActionDispatch::Routing::RouteSet def url_for_with_locale_fix(options={}) url_for_without_locale_fix(options.merge(:locale => I18n.locale)) end alias_method_chain :url_for, :locale_fix end
-
Set up a translate helper 't' as a wrapper around the I18n.t method
module I18nHelper def t string, options = {} I18n.t string, options end end RSpec.configure do |config| config.include I18nHelper end
Another hack for the last item (using
t()
in tests):(You might need to read the documentation of
AbstractController::Translation#translate
for some edge cases.)