I18n Dynamic Ruby Translations with Lambdas

Sebastian Suttner
May 24, 2019 · 3 min read
Image for post
Image for post

YAML files are the number one place to define translations with I18n. But, did you know that ruby (rb) files can be another option? Even a more powerful one…

I found out about this while working on a project that uses it, and when I tried to find more about it online I realized it was not a straightforward thing to search for. I hope that with this post, developers can find this more easily and leverage it sooner in their codebase if needed. Please note that this post is based on i18n v1.6.0–I didn’t try earlier versions.

How to store your translations

As stated in the Rails Guides, translations can be stored in both ruby and YAML file formats. Please note that this is also true for any ruby application using i18n. Just make sure all the translation files are part of the I18n.load_path.

# config/locales/en.rb{
en: {
foo: 'bar'
}
}

Which is equivalent to:

# config/locales/en.ymlen:
foo: 'bar'

If both translation files are loaded, the union of the two would make up the set of translations our application will use.

These are still static translation examples we are talking about. Let’s take a look at a more complex scenario next.

Add logic to translations

We know we can pass variables into translations, obviously supported by translations stored in YAML files. But, what if we need something more complex that cannot be handled by interpolation? Then, the only option left is to embed ruby logic into our translations. This is where ruby translations come in handy.

Translations stored in ruby files support the use of lambdas. Documentation about this can be found in the code of i18n itself.

# config/locales/en.rb{
en: {
salutation: lambda do |key, options|
if options[:formal]
"Welcome #{options[:name]}."
else
"Hi #{options[:name]}!"
end
end
}
}

Actually, the string returned by lambda will go through string interpolation too.

# config/locales/en.rb{
en: {
salutation: lambda do |key, options|
if options[:formal]
"Welcome %{name}."
else
"Hi %{name}!"
end
end
}
}

Both of the examples above would behave in the following way:

I18n.t(:salutation, formal: true, name: 'Foo') => 'Welcome Foo.'
I18n.t(:salutation, formal: false, name: 'Foo') => 'Hi Foo!'

Powerful! Isn’t it? A lot of complex translations can be solved with this technique. A quick glance at the use of lambdas for pluralization in Rails can be found in the Rails Guides as well.

A small caveat that the i18n gem recommends taking into account:

It is recommended to use/implement lambdas in an “idempotent” way. E.g. when a cache layer is put in front of I18n.translate it will generate a cache key from the argument values passed to #translate. Therefor your lambdas should always return the same translations/values per unique combination of argument values.

Conclusion

Both YAML and ruby translation files are great to use on a project. While ruby files are more powerful, YAML files are more dry and maintainable.

I’ve seen them work together perfectly. They can even team up and interact with each other, letting developers unleash their full potential.

Last, but not least, check out the following example!

# config/locales/en.rb{
en: {
salutation: lambda do |key, options|
if options[:formal]
I18n.t('salutations.formal', name: options[:name])
else
I18n.t('salutations.informal', name: options[:name])
end
end
}
}
# config/locales/en.ymlen:
salutations:
formal: 'Welcome %{name}.'
informal: 'Hi %{name}!'

Cedarcode

Adding value from day one.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store