How to translate a Symfony and React project.

Florent Destremau
Feb 24 · 5 min read
Image for post
Image for post
Translating in an international world — Photo by Leonardo Toshiro Okubo on Unsplash

When starting a new web app, I tend to think that internationalization is not a first-version concern. However, as soon as your side project starts becoming a real world app, your user base grows, and when you don’t live in in an English-speaking country (such as France), you might want your application to be available in English.

Although it’s often pretty straightforward to handle internationalization in Symfony or in React on their own, handling it in both at the same time appeared to be quite the challenge for us at Windoo.

In this post I will talk about how we maintain a single translation file for both Symfony & React. I will not address the user-side of handling locale setting as it is not the challenge here.

Translating in a Symfony project

You need to have the translation component set up. You probably need only to require it and use it right away if you’re using Flex (and your probably should):

If you are using twig for your templates (pages, emails…), you will need to have your translations in a file such as messages.fr.yml and messages.en.yml and use the following syntax in your templates:

If you want to translate a message in a controller or in service, you need to inject the TranslatorInterface service:

You end up with a big yaml file such as:

This way, you can use the Yaml keys in your translation. You can handle your local with Symfony, have two files, one in English, one in French, and there you go!

Before some people comment I should be using xliff format instead, I can already address the matter: I find Yaml translations files a whole lot easier to maintain and visualize on a single-dev project. The xliff format is the official recommended by Symfony’s best practices, but the conversion is pretty easy if needed. More on that later in the article.

Translating in a React project

In react there a big standard lib called react-i18next. Once you set it up, you end up using it like this (there are several options).

And your translations’ initialization would look like this:

So you basically need to have a JSON file that can be parsed in a Javascript object.

Using React and Symfony translations together

Now this is all good when you work on a React SPA or a Symfony full-stack project. But when you start to share your translations across both projects, things become…messy.

For starters, the Symfony and React-i18n format are not exactly compatible. React-i18n doesn’t read xliff format, neither yaml…actually it only wants a javascript object in JSON-style as an input file. So this way, that’s also one of the reason we didn’t use the xliff format for storing our translations.

In order to use the same source file for both projects at Windoo, we decided to script an on-the-fly conversion of the Symfony format to be injected into the React project. To do this we used a yaml loader to convert the yaml files into a javascript object.

This way , we only need to update one type of file (and I prefer the Yaml format, it’s prettier to look at and easier to search), and both projects can use the shared translations. All good to go, right ?

Beware of pluralization and parameters !

We thought we had it all figured out because the previous works for simple strings such a button labels, titles… but then it became rapidly clear that the plural formulations were not mapped the same way, and led to broken translation in front. For the same reason too the template translations with variables did not work at all.

Here is the react-i18n syntax for pluralization in the keys dictionary:

And here is the Symfony syntax for the same thing:

And I’m not even talking about the full format for each language. We only translate French and English (as of today at least), so we kept using the simple syntax.

So the number of keys is not the same in React and this makes it way more difficult to transpose from Symfony-Yaml to i18n-JS. Ideally we would like to use the ICU Format for both, but I could find sufficient documentation for this. We might come back to it later in due time.

Parameter format

Before injecting the file, we updated all parameter syntax with a simple function handling all entries:

Then we had to split the plural keys in Symfony

And this way, we made a full transposition of our translations on-the-fly from Symfony to React. Here a complete example in one gist:

a full i18n.js service you could import in your project

After that, you simply import your new i18n.js service into your React components and voilà !

I will write a follow-up on how we improved this workflow with a translation service in the middle, using Localize.

The Startup

Medium's largest active publication, followed by +718K people. Follow to join our community.

Florent Destremau

Written by

CTO & Founder @ Windoo, a platform for happiness at work ! https://windoo.fr

The Startup

Medium's largest active publication, followed by +718K people. Follow to join our community.

Florent Destremau

Written by

CTO & Founder @ Windoo, a platform for happiness at work ! https://windoo.fr

The Startup

Medium's largest active publication, followed by +718K people. Follow to join our community.

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