13
votes

I have a multi-tenant application and I'm experimenting with using the i18n gem to allow each of our clients to customize the system to their liking, changing the text on various pages, customizing emails, and so forth. Admittedly, I'm not using i18n as it was intended to be used, since I'm not actually translating different "languages", everything is in English, but each client has a DIFFERENT English, if that makes sense.

Still, I've come across what I think is a horribly bad design decision in the i18n gem: if ever a translation does not exist, rather than simply not doing a translation and printing out whatever it normally would, it raises an error. For example,

<%= distance_of_time_in_words_to_now @press_release.submitted_at %>

comes out as

translation missing: en, datetime, distance_in_words, x_days

I mean, come on! I don't even WANT that to be translated.

I understand that the reason this is happening is because I don't have the default translations loaded, but I'm using ActiveRecord as a backend and I wanted to keep it clean. The "solution" would be to import all of the yaml translation files into my database translation store, but that doesn't seem like a good idea. What if I upgrade rails in the future? I'm going to have to worry about keeping all of these translations in sync.

Again, I cannot fathom why this is the default behavior. When would ANYBODY want that funky error message to show up instead of just using the default "3 days ago"?

Anyway, my question is, is there a way to have it automatically turn off the translation and use the untranslated message if the translation doesn't exist? Thanks!

2

2 Answers

7
votes

This seems to do the trick.

require 'i18n' # without this, the gem will be loaded in the server but not in the console, for whatever reason

# store translations in the database's translations table
I18n.backend = I18n::Backend::ActiveRecord.new

# for translations that don't exist in the database, fallback to the Simple Backend which loads the default English Rails YAML files
I18nSimpleBackend = I18n::Backend::Simple.new
I18n.exception_handler = lambda do |exception, locale, key, options|
  case exception
  when I18n::MissingTranslationData
    I18nSimpleBackend.translate(:en, key, options || {})
  else
    raise exception
  end
end
7
votes

If you are interested in handling other exceptions with the default exception handler, this modified code from Philip Brocoum's answer should do the trick (Rails 3.2.2 version):

i18n_simple_backend = I18n::Backend::Simple.new
old_handler = I18n.exception_handler
I18n.exception_handler = lambda do |exception, locale, key, options|
  case exception
  when I18n::MissingTranslation
    i18n_simple_backend.translate(:en, key, options || {})
  else
    old_handler.call(exception, locale, key, options)
  end
end

This code will allow you to capture only the exceptions that you need to handle differently.