An approach to handle translations in Ruby on Rails + React.js applications

One of the first challenges I had to face while integrating React.js into a Ruby on Rails application was handling translations.

My first (brute force) approach was to avoid using text in my React components.

First approach:

Before:

  var Name = React.createClass({

    render: function() {
      return (
        <dt>Name</dt>
        <dd>{this.props.name}</dd>
      )
    }
  });

After:

<span><%= User.human_attribute_name(:name) %></span>
<%= react_component "FinalPrice", props={ name: "John Doe" } %>

That worked, of course. The problem is that it doesn’t scale well for bigger and more complex components. I would have ended creating too many small components just to avoid translations and seriously compromising reusability.

I was having the same problem for localization of dates and currencies. There’s an excellent library developed by yahoo called react-intl but the configuration is not straight forward and support for IE is limited, so you will need to install additional libraries (shims) to support it.

I really wanted to continue using Rails’s I18n API!

TL;DR

The solution I came across with was to pass to the React component a hash property with all the necessary translations.

E.g passing the translations hash as prop to the React component:

  var Name = React.createClass({

    render: function() {
      return (
        <dt>{this.props.translations.name}</dt>
        <dd>{this.props.name}</dd>
      )
    }
  });
<%= react_component "FinalPrice", props={ name: "John Doe", translations: t('activerecord.attributes.user') } %>

Calling t('activerecord.attributes.user') will return a hash with all the translations under that key. Thanks Robert Pankowecki for pointing out this improvement.

If you are going to use this approach you will find the need to organice your translation files into the same way you are building your components. E.g: if you have a ShoppingCart component you will need a ‘views.components.shopping_cart’ key yo group all the translations keys. You may find some key repetition, which may seem inconvenient in some cases.

As @brauliobo pointed out, there’s a great library named i18n-js which allows you to access your Rails translations from JavaScript. The library in fact translates all your keys to a JavaScript file which you can then access through an API similar to Rail’s I18n.

E.g with i18n-js:

  var Name = React.createClass({

    render: function() {
      return (
        <dt>{I18n.t('activerecord.attributes.user.name')}</dt>
        <dd>{this.props.name}</dd>
      )
    }
  });

Which approach is better? I usually try to avoid using external libraries to do things I can hack myself without too much effort. Each time you add a new gem to your project you are paying hidden costs (E.g: performance) and risks (E.g: potential issues) which you should try to avoid if possible. So choose wisely which approach you are going to use in your next project!

I appreciate any comments about this approach, please feel free to send your suggestions.

And keep in touch! In the next post I’ll talk about how I implemented Flux with the react-rails gem and why we should stop naming things with fancy names.

Thanks for reading.

Comments

comments powered by Disqus