Advanced techniques, tips and tricks - Get on Rails with Globalize! Part 5 of 8
Bridge Globalize and TZInfo
Timezones are something that are able to scare the #%@! out of a programmer. Some of the best informed folks even drew the conclusion that timezones must have been specifically designed to do so. ;-)
Lourens Naudé describes how you can get these work with Globalize and get "DRY timezones indexed by country, with daylight savings time covered.". To read more about this head over to his blog: Bridge Globalize and TZInfo
Preload View Translations in Production
After you're done with your Globlized application, extracted and translated everything and are now preparing stuff for production you might want to consider pre-loading your view translations in one go during the application startup process.
Lourens Naudé has a snippet that does right this. It hooks into the Dispatcher#to_prepare application startup stage and adds all view translations for all supported languages to the translations cache.
Go and grab the code right here: Preloading Globalize view translations in production
Please note that you might need to adjust how that code loops through your supported languages in case that you don't use Globalize's SupportedLanguage class.
Clear Globalize's translations runtime cache
When you're devoloping your Globalized application you might find it useful to know about the fact that Globalize caches ViewTranslations in memory ... and how to clear this cache.
# clear the viewtranslations cache Locale.translator.cache_reset
Note the fact that this method belongs to the
translator. Don't confuse it with the
Locale#clear_cache method which resets the locale cache, not the translations cache.
Use nice predicated block helpers in your views
Sometimes you want to show or hide stuff depending on whether the current locale is your
base_language or not (or similar conditions). For example you might want to allow creating new items only for the
Here's a nice piece of code from Jeremy Voorhis’ Canada on Rails slides that also shows a typical Ruby'ish pattern (Jeremy calls it "predicated blocks") for purposes like this:
# in your app/helpers/application_helper.rb def base_language_only yield if Locale.base? end def not_base_language yield unless Locale.base? end <!-- in your template --> <% base_language_only do -%> <%= link_to 'New product', :action => 'new' %> <% end -%>
Organize your translations through Globalize's namespaces
Multilingual URLs are a great example for a situation where you might want to namcespace your translations.
Imagine an application that contains "sections" which are available at
http://example.com/section. The following funny dialog from Saimons blog (who originally invented that feature in Globalize) demonstrates nicely why you might want to namespace your translations:
Your boss phones you up and bellows: “None of the site’s links are working in Spanish?”
Oops! You start to investigate and find that the stupid translators, went ahead and translated
'section' => 'sección' (in Spanish)
... which you were using to translate the url:
http://example.com/section => http://example.com/seccion
You: “Jeez, don’t translators know you can’t use non-ascii characters in URLs?”
Boss: “Umm, well no. They’re translators. That’s your job.”
You: “Ah, well, ok I’ll just give them a list of words that are urls and should be translated without accents.”
Boss: “But we use the word ‘section’ in the view as well …”
You: “ummm … Let me think …” (time passes)
You: “Well, what we need is to be able to have two sorts of translation of the word ‘section’, one for the front end and one for the urls.”
... and that’s what namespaced translations are all about. You find a pretty complete writeup about how to use this Globalize feature on Saimons blog.
Alternative Storage Mechanism for Model Translations
Globalize stores all translations in one big database table and transparently JOINs this table into SQL queries as needed.
This is cool and nifty but it comes with some costs. For example you're restricted from using the ActiveRecord :select and :include feature because these would get in conflict with the internal JOIN usage. This in turn leads to incompatibility with Rails plugins that rely on this functionality. Also, sometimes you'd rather want to spare your datbase to do all these joins for performance reasons.
In those cases you might want to consider switching to the alternative storage mechanism for model translations that Globalize comes with since the for-1.2 release.
class Product <ActiveRecord::Base self.keep_translations_in_model = true translates :name end
Basically, what this does is that the translations for the field
name will be kept in extra columns in the
products table, one per language:
Disable Globalize::ViewTranslation's SQL logging
Sometimes you just want less noise in your log files, especially when your Globalize setup runs fine and you don't need it to tell you about every single move it makes. Globalize can be just too noisy then.
Joost Hietbrink thought this, too, and sent me this code so you don't need to suffer from Globalize's chattiness any more.
module Globalize # :nodoc: class DbViewTranslator alias_method :orig_fetch_view_translation, :fetch_view_translation def fetch_view_translation(key, language, idx, namespace = nil) ActiveRecord::Base.silence do orig_fetch_view_translation(key, language, idx, namespace = nil) end end end end
Obviously, this wraps around the fetch_view_translation method and uses ActiveRecord::Base#silence to prevent ActiveRecord from logging the query.
That's handy. Thanks, Joost!
Of course a list like this can't ever really be complete. Please drop me a note if you have any corrections or additions to this list.