Software localization

Lessons Learned: Naming and Managing Rails I18n Keys

We've been localizing our user interface for several years now. But there are several steps to managing rails i18n keys that Phrase cannot solve (yet!).
Software localization blog category featured image | Phrase

Phrase Strings is built on Ruby on Rails and we’ve been using the excellent i18n gem to manage our localization since day one. Needless to say, we’re using our own product to manage and extend our translations, which is a huge timesaver. But there are several steps to managing rails i18n keys.

One of these issues is the naming of the new keys that you, the user, introduce into your project. As we all know, naming can be really difficult and poor naming will cause problems along the way. Hopefully, this post will help you name your keys a little better so you can focus more on what you love and less on managing i18n keys.

For Developers

I’ve got a few general tips concerning the workflow for developers when introducing new key names that I find ends up saving a lot of time:

Be Explicit

Use explicit key names over the inflected names provided by Rails (starting with a dot). It is much easier to find a key if you don’t have to check the name of the view or controller. This is a huge timesaver when refactoring code (for instance; when you rename a controller).

Also, avoid interpolated keys that include variables (e.g. "foo.#{some_variable}.bar"). You will most likely never find all used combinations again!

Keep It DRY

Before introducing a key, always check if another key under that resource or in thegeneral namespace (continue reading to learn more) already exists, which expresses what should be displayed. Treat translations and keys like methods and avoid duplication.

Don’t Localize Too Early

While developing a feature, it is very likely that you will remove or restructure your code along the way. If you then already have entered translations, it is much more difficult to find and rename or delete these keys.

Instead, localize your feature when you’re positive that you won’t have to do any larger changes on the code.

Stay Clean

When removing code, make sure you always remove translations (and keys) as well. A clean i18n database is the key to fast localization cycles. Try to keep your translations as clean as your codebase.

Naming

Naming your keys carefully will pay off in the long term. We found these general rules for naming keys to be very useful:

The General Namespace

We introduced a general. prefix to store translations that are likely to be used throughout your app. This prevents having duplicate keys all over your app (which makes maintaining them really hard).

When introducing this namespace for common terms, try to avoid deep nesting. Keep it simple and thus manageable.

Bad:

  • general.users.hobbies.surfing

Good:

  • general.save (Save)
  • general.and (and)
  • general.learn_more (Learn more)

Avoid Complexity

Although i18n supports nested keys, in our experience deeply nested keys are harder to manage. We recommend to not use more than two levels (some Rails helpers might be the exception). Keep your key names as flat as possible.

Be Predictable

If you name your keys too abstract you will have trouble knowing what it actually says. If you name it too close to the actual content, changing text and keeping the key name in sync will be painful.

Once again, it’s about finding a happy medium.

Bad:

  • home.paragraph_1
  • home.su_lbl

Good:

  • home.user_welcome_text
  • home.sign_up_free_trial_button_label

Style

Stick to one writing style: snake_case and CamelCase are both fine, Just make sure to stay consistent.

Content Matters

It usually doesn’t matter if the key in question is part of the footer navigation used in a controller or within a special layout.

Instead, give it a clear prefix that indicates the domain to which the key belongs and let the reader know about what might be the purpose of the key.

Inside Your Rails App

Let’s have a look at the different parts of your app where localized strings can occur and how to deal with them:

Views (Including Mailer Views)

Most of your localized strings will live in your views. You will likely reorganize your views at one point, e.g. you will extract partials or rename the whole resource. That’s why we recommend using full, descriptive names instead of implicit ones (starting with a dot).

Pro tip: Use the excellent mailer preview that comes with Rails to preview your emails in different locales.

Extra pro tip: Use Phrase's in-context editor to edit translations directly on your site. This speeds up your translation process and also boosts quality while preventing layout issues due to text that does not fit.

Models

If you paid attention to coding best practices up front, there shouldn’t be too many translatable strings present inside your models.

For validation error messages (probably the most common use case for localization inside of a Rails model), we recommend the symbol-based naming and moving error message translations to the errors.messages.* namespace (which is used byActiveModel and ActiveRecord models).

en:

  errors:

  	messages:

  	  invalid_email_format: is not a valid e-mail

In my opinion, this facilitates the making of validation methods reusable, too.

Learn more about i18n of ActiveRecord models in the Rails guides.

Forms

Localizing form elements is a great example of i18n keys that are best organized when using framework defaults since the framework will give you a lot of i18n-functionality out of the box when following its rules.

The recommended structure varies depending on which form builder you’re using. Take a look at the simple form gem which requires the following naming convention:

en:

  simple_form:

    labels:

      user:

        username: 'Username'

        ...

    hints:

      user:

        username: 'Your Username'

        ...

    placeholders:

      user:

        username: 'Enter a username'

        ...

You don’t really benefit from naming your form elements explicitly. Instead, you would just fight the framework which is usually not a good idea.

You can learn more about i18n in simple form in the documentation.

Controllers

Usually, your controllers should not contain many localizable strings anyway, besides maybe some flash messages. We recommend treating those like elements in a view template and using the resource or section as a prefix. Just like everywhere else, avoid using the dot shortcut method to make refactoring controllers easier.

Bad:

  • .headline
  • users_controller.headline
  • users.create_action.headlines.success.message

Good:

  • users.create.success_message
  • projects.create.general_error_occurred

Helpers

Helpers, too, should usually not contain a lot of text. For the (ideally) few texts you’re localizing in a helper, we recommend not to reference the actual helper in the name:

Bad:

  • projects_helper.nicer_project_title.project_name_label

Good:

  • projects.project_name

Finding Orphaned And Missing Keys

Despite all of your efforts, you will probably come to the point where you want to remove unused keys (that are not used anywhere in your app but still live inside your locale files) and also find missing translations in your app.

This is a job for the awesome i18n-tasks gem. It provides great features to check for unused or missing i18n keys, and you can also add these checks to your test suite.

By the way: Once you have cleaned your locale files from unused keys, you can re-upload them into your Phrase project and use the Delete unmentioned keys feature to reflect these changes in Phrase, too.

Find Missing Keys

Use the missing command to find missing keys throughout your app:

$ i18n-tasks missing

This will return a list of translations that are obviously missing.

Find Unused Keys

Use the unused command to find unused keys throughout your app:

$ i18n-tasks unused

You can use different formats, e.g. to only list the actual keys:

$ i18n-tasks unused --format keys

This will return a list of translations that might no longer be used in your app.

While this is a tremendous help, i18n-tasks is not always 100% correct and you should check the results manually before deleting keys that are actually still in use.*

Summary

i18n is a powerful library and works seamlessly with Rails. However, if your app and team reach a certain size, you might not only want to use localization software but also think about how to structure and name your keys.

The most important lessons might be to avoid duplication and to name keys with explicit names.

We hope our findings and best practices will help you with keeping a well-organized i18n key structure in your Rails app.