Software localization
Lessons Learned: Naming and Managing Rails I18n Keys
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.