---
title: Foolproof I18n Setup in Rails
teaser:
tags: web,rails
author: Gabe Berke-Williams
published_on: 2014-06-17
---

Let's make I18n on Rails better, quickly and easily. These tips have helped us
here at thoughtbot and caught some easy-to-fix but hard-to-track-down mistakes.

## Raise an exception on missing translations

When a translation is missing, Rails will fall back to a default translation.
For example the code `t(:hello)` will output `"hello"` if there is no provided
translation for `:hello`. This is almost certainly not what you want, especially
for more complicated I18n keys like `t('users.sign_in')`.

Most versions of Rails include a way to raise exceptions when a translation is
missing. Raising an exception ensures that all of your calls to `t()` are using
your copy, instead of using a default string. I recommend raising exceptions in
the `test` and `development` environments, so that you can find missing
translations by running tests and by browsing around on localhost.

To raise exceptions on missing translations in [Rails 4.1.0 and higher]:

```ruby
# config/environments/test.rb
# and
# config/environments/development.rb
Rails.application.configure do |config|
  config.action_view.raise_on_missing_translations = true
end
```

And in Rails 3:

```ruby
# config/initializers/i18n.rb
if Rails.env.development? || Rails.env.test?
  I18n.exception_handler = lambda do |exception, locale, key, options|
    raise "Missing translation: #{key}"
  end
end
```

If you're using a version of Rails 4 between 4.0.0 and 4.1.0, it requires a
monkey patch, from [Henrik Nyh]:

```ruby
# config/initializers/i18n.rb
if Rails.env.test? || Rails.env.development?
  module ActionView::Helpers::TranslationHelper
    def t_with_raise(*args)
      value = t_without_raise(*args)

      if value.to_s.match(/title="translation missing: (.+)"/)
        raise "Translation missing: #{$1}"
      else
        value
      end
    end
    alias_method :translate_with_raise, :t_with_raise

    alias_method_chain :t, :raise
    alias_method_chain :translate, :raise
  end
end
```

[Rails 4.1.0 and higher]: https://github.com/rails/rails/blob/4-1-stable/actionview/CHANGELOG.md#rails-410-april-8-2014
[Henrik Nyh]: https://gist.github.com/henrik/8729516

## Time's a-Wasting

Using `I18n.t` in tests is more typing than you really need. Here's how you can
use `t()` instead of `I18n.t()` in all of your tests:

```ruby
RSpec.configure do |config|
  config.include AbstractController::Translation
end
```

Excellent.

## What's next

Read about [better tests through internationalization]. You can also use the
[i18n-tasks gem] to find and manage missing and unused translations in your
application.

[better tests through internationalization]: https://thoughtbot.com/blog/better-tests-through-internationalization
[i18n-tasks gem]: https://github.com/glebm/i18n-tasks
