Translate your React app with ease using Facebook’s own framework (FBT)

Adam Ramberg
7 min readAug 28, 2019

Checkout this demo app using the concepts from this blog post.

This spring (2019) I went to React Europe, a really great conference dedicated to React development. John Watson had a talk there where he introduced an internationalization (i18n) framework called FBT, which is used over at Facebook. I only had prior experience using react-intl, so when the time came to translate my companies’ website I wanted to give FBT a go. This article is going to go through my findings using FBT for the first time and will be show casing examples that you can follow in order to add FBT to your own React application.

🤔 Why should I use FBT?

FBT has a couple of features that stands out compared to other similar frameworks (for example react-intl):

  • Translatable text resides inline with the rest of your JSX. This means that you can search for English text strings in your text editor and directly find the React component where it’s used.
  • It supports plural variations out of the box.
  • It supports enums!
  • Adjust translations based on pronouns.

🍖 The meat

Note: the steps below assumes your is using Babel, Webpack and yarn. It also assumes that you are developing in an UNIX environment. If you don’t have an existing app and instead want to start a new one, you can use the template app created in my other blog post Setting up a React app from scratch.

Install Dependencies

Start by installing fbt and fbt-easy-setup to your project. Open your terminal, navigate to the root of your project (where your package.json resides) and type the following:

yarn add fbt fbt-easy-setup --save

fbt-easy-setup is a package that I have created to make life easier adding fbt to a React app. It provides you with an init function, a LocaleProvider and a LocaleConsumer (see React’s documentation on Context). Check out the docs for fbt-easy-setup here.

Continue by installing the following dev dependencies:

yarn add babel-plugin-fbt babel-plugin-fbt-runtime @babel/node @babel/core fbt-generate-translations --dev

babel-plugin-fbt and babel-plugin-fbt-runtime are two Babel plugins that are required in order to run FBT. See more info here regarding those two plugins. Both @babel/node @babel/core are needed in order for the plugins to run properly. fbt-generate-translations is a script that I have made in order to generate translations from the output from FBT’s collect script and consumed by FBT’s translate script. This step would otherwise be manual (ugh!). More on the different scripts and steps later in this post.

Configure Babel

Add the babel plugins installed above to your babel config file. If you are going to use enums the babel-plugin-fbt should be fed a path to the generated enums manifest (more on what this is later in the post). You also might need to add sourceType to be unambiguous (at least I did) in order for the mix between commonjs modules and ES modules to transpile correctly. Here is an example of what to you need to add to your Babel config:

Add locales

Let’s add the locales that you want your app to support! Start by creating a file defining the locales and add it to a folder called i18n:

mkdir i18n && touch ./i18n/locales.js

Open up locales.js in your favourite text editor and add your locales of choice using the following format:

An example of how 2 of the most widely used locales, English (US) and Swedish, could be added to your project.

Add scripts

When first getting into the FBT demo, the scripts was the most confusing part to me. There are 3 scripts in the FBT demo app, and I have added another one in order to reduce the manual work needed:

  • manifest-fbts — Creates two json files, the first one (.src_manifest.json) keeps track of every file that imports FBT (and therefore might contain translations) and the other one (.enum_manifest.json) keeps track of all FBT enums used in the project.
  • collect-fbts — Given the output from the last step, it collects all the texts to translate and generate corresponding hashes. See this for more info.
  • fbt-generate-translations / fbt-generate-translations-single-file — Given the output from collect-fbts, it generates translation files (could also just be a single file) that could be consumed by translate-fbts (see below). The file / files generated are then supposed to be manually edited with translations for each locale.
  • translate-fbts / translate-fbts-single-file — Takes the output from the step above and creates the translation object that should be passed to FBT’s init function at runtime.

It is also useful to add scripts to clean the generated files (see clean-fbts below) and to do all the steps of above in one go (see prepare-fbts below). If you got scripts to build and start the app it might also be useful to add pre-scripts that runs all the steps above one go (see prestart and prebuild below). My scripts ended up like this:

In the above example the source code is located in a folder called src, there is a folder called translations and locales are located under src/i18n/locales.js.

As a side note: FBT supports having all translations in one file (using the *-single-file script above) or dividing the translations by locale into several files.

Initialize FBT

In order for FBT to work you need to provide translations. This needs to happen before any of the React components containing translations load. You also need to pass your locales and default locale to the this function. Mine ended up like this:

Since initialization needs to be done before the translations are used in any React component, add it to your Webpack config’s entry:

Add the Provider and the Consumer

The next step is to add the LocaleProvider and theLocaleConsumer to your app. Start by wrapping your app with the LocaleProvider:

Now you can use the LocaleConsumer where applicable. For example you can create a component that toggles between English and Swedish like this:

Add your text

You are now all setup to add translations to you app! Hurray!

You can now for example add a fancy translatable paragraph component:

FBT’s docs for how to add translatable text to your JSX is actually really good. Check it out here!

Git ignore

All git users out there should also add the following to.gitgnore:

Workflow

When you have added all the translatable text you want to your JSX you should run yarn prepare-fbts. After that you can add the translations for each locale to the generated file(s) (either in translations_input.json or in the files located in the translations folder). The typical workflow for translations (using the setup from this blog post) will look like this:

  • Add FBT JSX to your app.
  • Run your scripts to generate translation files.
  • Add and modify translations in the generated files from the above step.
  • Build and run your app that now contains the new translations.

However, there are endless possibilities on how to improve this process. For example it is possible (with the help of some custom scripts) to fetch translations from a remote location (eg. a translations API) and merge them with your translation file(s). This process could for example be a part of your build pipe. This is actually how Facebook is using it:

Architectural image posted by John Watson in this issue.

Some notes on shared enumerations

Something that is not documented when it comes to shared enums is that you need to add the suffix $FbtEnum.js to the filename of the module that defines it.

Another thing to note is that due to some issues regarding the babel plugin (eg. see this issue for example), you need to use require and not ES imports when using the module that defines the shared enum:

const SharedEnum = require('Shared$FbtEnum');

You also might notice that the shared enum above is required using an absolute path. Due to a bug in the babel plugin this is required, otherwise it throws. In order for the absolute path to work you will need to add a resolve entry to your Webpack config:

😝 Still stuck?

If you have followed this post you should have a working app with translations. However, if you for some reason is stuck you can check out the source on Github of this demo app.

🌦️ Conclussions

FBT promises some really awesome features like inlining translatable JSX text (which makes the text searchable in your text editor), support for plural variations, enums and pronouns. For the most part this works really well (after the initial setup has been made). However, the problems with enums shines light on some FBT’s rough edges. It feels like FBT needs some more users and maintainers in order to get some of these issues discovered and fixed. So if you are not afraid to dig in to some open source work, I definitely think that FBT is great candidate for managing i18n in your next React app.

Let me know what you think about this post in the comments below and hit that 👏 button if you liked what you read. You can also find me on Twitter if you got any further questions or comments on what you just read.

--

--

Adam Ramberg

Independent web & game developer based in Gothenburg, Sweden. GitHub: https://github.com/AdamRamberg