Best internationalization for Gatsby

Gatsby Localization made easy with this step-by-step guide using i18next ✅

You know Gatsby, right? — If not, stop reading this article and make something else.

Yes, Gatsby the an open-source framework that combines functionality from React, GraphQL and Webpack into a single tool for building static websites and apps.

But how does internationalization (i18n) looks like in Gatsby?

There are some plugins/libraries that may help instrumenting the Gatsby code for internationalization. In this article we will use a plugin based on the famous i18n framework i18next, respectively its great extension for React.jsreact-i18next.
The Gatsby plugin we’re using is gatsby-plugin-react-i18next created by Dmitriy Nevzorov.

So first of all: “Why i18next?”

When it comes to React localization. One of the most popular i18n framework is i18next with it’s react extension react-i18next, and for good reasons:

i18next was created in late 2011. It’s older than most of the libraries you will use nowadays, including your main frontend technology (react, vue, …).
➡️ sustainable

Based on how long i18next already is available open source, there is no real i18n case that could not be solved with i18next.
➡️ mature

i18next can be used in any javascript (and a few non-javascript — .net, elm, iOS, android, ruby, …) environment, with any UI framework, with any i18n format, … the possibilities are endless.
➡️ extensible

There is a plenty of features and possibilities you’ll get with i18next compared to other regular i18n frameworks.
➡️ rich

Here you can find more information about why i18next is special and how it works.

Let’s get into it…


Make sure you have Node.js and npm installed. It’s best, if you have some experience with simple HTML, JavaScript, React.js and basic Gatsby, before jumping to gatsby-plugin-react-i18next. This Gatsby localization example is not intended to be a Gatsby or React beginner tutorial.

Getting started

Take your own Gatsby project or create a new one, i.e. with the gatsby-cli.

npx gatsby-cli new

We will create a language switcher to make the content change between different languages.

Let’s install some i18next dependencies:

npm install gatsby-plugin-react-i18next i18next react-i18next

Create a locales directory and add a subfolder for your default/reference language (i.e. en for English).
There we will then add our namespace files, like:

Let’s add a languages.js file:

Import the languages.js file in the gatsby-config.js file and configure some plugins:

Now let’s start to instrument our first internationalized text.
Since gatsby-plugin-react-i18next is exporting all methods and components of react-i18next, we can do this:
In a page file:

Now also define an locales/en/index.json namespace file, like this:

And maybe also another one for German?


Language Switcher

To be able to switch between different languages, we need a language switcher:

You should now see something like this:

By default, on first load, gatsby-plugin-react-i18next will fallback to the defaultLanguage if the browser's detected language is not included in the array of languages.

If you want to fallback to a different language in the languages array, you can set the fallbackLanguage option.

Now switching to de (German) should also work:

🥳 Awesome, you’ve just created your first language switcher!

Internationalized links

Let’s create a second page…

A new namespace:


…and link to that page from the first one:

A new translation key for locales/en/index.json:


The Link component exported from gatsby-plugin-react-i18nextautomatically links to the correct language.
The Link component is identical to Gatsby Link component except that you can provide additional language prop to create a link to a page with different language.

Interpolation and Pluralization

i18next goes beyond just providing the standard i18n features. But for sure it’s able to handle plurals and interpolation.

Let’s count each time a button gets clicked:

…and extending the translation resources:


Based on the count value i18next will choose the correct plural form.

i18next provides also the ability to have special translation for {count: 0}, so that a more natural language can be used. If the count is 0, and a _zero entry is present, then it will be used instead of the regular language plural suffix (_other).

Read more about pluralization and interpolation in the official i18next documentation.

💡 i18next is also able to handle languages with multiple plural forms, like arabic:

Why are my plural keys not working?

Are you seeing this warning in the development console (debug: true)?

i18next::pluralResolver: Your environment seems not to be Intl API compatible, use an Intl.PluralRules polyfill. Will fallback to the compatibilityJSON v3 format handling.

With v21 i18next streamlined the suffix with the one used in the Intl API. In environments where the Intl.PluralRules API is not available (like older Android devices), you may need to polyfill the Intl.PluralRules API. In case it is not available it will fallback to the i18next JSON format v3 plural handling. And if your json is already using the new suffixes, your plural keys will probably not be shown.


npm install intl-pluralrules


Now, let’s check out how we can use different date formats with the help of i18next and Luxon to handle date and time.

npm install luxon

We like to have a footer displaying the current date:

Import luxon and define a format function, like documented in the documentation and add the new translation key:



😎 Cool, now we have a language specific date formatting!




What about a specific greeting message based on the current day time? i.e. morning, evening, etc. This is possible thanks to the context feature of i18next.

Let’s create a getGreetingTime function and use the result as context information for our footer translation:

And add some context specific translations keys:



😁 Yeah, It works!

Key extraction

Thanks to the babel-plugin-i18next-extract you can automatically extract translations inside the t function and Trans component from your pages and save them in the namespace files.

It works like this:
First install the required dependencies:

npm install @babel/cli @babel/plugin-transform-typescript babel-plugin-i18next-extract

Create or update the babel-extract.config.js file (do NOT name it babel.config.js, or it will be used by gatsby):

Add a script to your package.json:

If you want to extract translations per page for a specific namespace, you can add a special comment at the beginning of the page:

fyi: There are also other comment hints you can use.

Prepared all your pages? Nice, so let’s try that:

Running npm run extract will now add that new cta key to the namespace file:

Extra power

This is all already great, but we can do even more!

It would be nice, to have an overview showing which translations are missing and which files are completely translated…
And think about when having extracted new keys, they would automatically be translated?
To make this true we need a translation management

By sending the translations to some translators or translator agency you have more control and a direct contact with them. But this also means more work for you. This is the traditional way. But be aware, sending files around creates always an overhead.

Does a better option exist?

For sure!

i18next helps to get the application translated, and this is great — but there is more to it.

  • How do you integrate any translation services / agency?
  • How do you keep track of new or removed content?
  • How you handle proper versioning?
  • and a lot more…

Looking for something like this❓

How does this look like?

First you need to signup at locize and login. Then create a new project in locize and add all required languages. And finally you can add your translations either by using the cli or by importing the individual json files or via API.

Now let’s install the locize-cli:

npm install -g locize-cli

We’ll prepare a new script that will synchronize our local changes with locize. And also an optional second script that will just download the newest translations from locize. Make sure you use your project-id and api-key:

Use the npm run syncLocales script to synchronize your local repository with what is published on locize.

Alternatively, you can also use the npm run downloadLocales script to always download the published locize translations to your local repository before bundling your app.

If we now add a new translation key, like this:

and run npm run export and then npm run syncLocales, we get this:



Thanks to the optionally enabled automatic machine translation option, new keys not only gets added to locize, while developing the app, but are also automatically translated into the target languages using machine translation.

👀 but there’s more… (InContext Editor)

With the help of the locize plugin, you’ll be able to use your app within the locize InContext Editor.

Want to see how this looks like?

Ok, first install the locize dependency:

npm install locize

Then in the code (we choose our layout.js file) add this:

And in the gatsby-config.js add some new react options:

Then go to your locize project and define your in-context editor urls, like described here.

The result will look like this:

Isn’t this great?

🧑‍💻 The complete code can be found here.

If you want to learn more basics about i18next, there’s also an i18next crash course video.

🎉🥳 Congratulations 🎊🎁

I hope you’ve learned a few new things about gatsby-plugin-react-i18next, i18next, React.js localization and modern localization workflows.

So if you want to take your i18n topic to the next level, it’s worth to try the localization management platform — locize.

The founders of locize are also the creators of i18next. So with using locize you directly support the future of i18next.




Founder, CTO, Software Architect, Bachelor in Computer Science #serverless #nodejs #javascript Always in search for #innovative and #disruptive stuff

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
Adriano Raiano

Founder, CTO, Software Architect, Bachelor in Computer Science #serverless #nodejs #javascript Always in search for #innovative and #disruptive stuff