Learn how to generate multi-language images in seconds with Bannerly!See Bannerly.io

How to create a multi-language website in GatsbyJS?

How to create a multi-language website in GatsbyJS?

Background

In this article, I will show you how to create multi-language landing page in GatsbyJS. I assume you already set up a Gatsby project, and we will start right from adding multi-language pages.

Check our template repository on GitHub.

Install dependencies

I will use FormatJS library as it's one of the most popular React library for internationalization, and it plays nice with Gatsby plugin system.

# Npm users
npm install --save react-intl

# Yarn users
yarn add react react-intl

Create i18n configuration file

Create a i18n.js file in your src directory to keep all i18n configuration in one place.

const languages = ['en', 'pl', 'es'];
const defaultLanguage = 'en';

exports.defaultLanguage = defaultLanguage;
exports.languages = languages;

Add utility functions

Create a new file with utility functions. I named it linkUtils.js and I put this next to i18n.js file in the src directory.

import {defaultLanguage, languages} from "./i18n";

const getTranslatedPath = (pathname, to) => {
  const currentPageLanguage = getCurrentPageLanguage(pathname);

  let languagePath = '';
  const isDefaultLanguage = defaultLanguage === currentPageLanguage;
  if (!isDefaultLanguage) {
    languagePath = '/' + currentPageLanguage
  }


  let outputPath = `${languagePath}${to}`;

  const hasTrailingSlash = outputPath.endsWith("/");
  if (!hasTrailingSlash) {
    outputPath += "/";
  }

  return outputPath;
}

const getCurrentPageLanguage = (pathname) => {
  const pathElements = pathname.split("/");
  for (let element of pathElements) {
    for (let language of languages) {
      if (element === language) {
        return language;
      }
    }
  }
  return defaultLanguage;
};

export {getTranslatedPath, getCurrentPageLanguage};
  • getTranslatedPath Function returns a route to a page with in the same language as current page.
  • getCurrentPageLanguage Function returns language from current page path.

Create custom link component

In order to give a user to navigate through our website and keep the page language we need to create a custom <a/> element.

import React from "react";
import {Location} from '@reach/router';
import {getCurrentPageLanguage, getTranslatedPath} from "./linkUtils";

const LinkTranslated = ({children = [], className = "", href = "/"}) => {
  return (
    <Location>
      {locationProps => {
        const {pathname = ""} = locationProps.location;
        return <a className={className}
                  href={getTranslatedPath(pathname, href)}
                  hrefLang={getCurrentPageLanguage(pathname)}
        >
          {children}
        </a>;
      }}
    </Location>
  );
};

export default LinkTranslated;

Now we can use LinkTranslated same as a regular <a/> tag from HTML. We can pass a href property with base link to some page, and it will be converted into a translated link.

Learn more about hrefLang attribute.

I used Location component from @reach/router, to get access to the location object.

Add a wrapper for IntlProvider

import React from "react";
import {IntlProvider} from "react-intl";

function SimpleLocalize(props) {
  const language = props.pageContext.language;
  const messages = props.pageContext.messages;
  return (
    <IntlProvider
      locale={language}
      messages={messages}>
      {props.children}
    </IntlProvider>
  );
}

export default SimpleLocalize;

The main role of this component is to simplify a usage of <IntlProvider/> on every page.

Add translations

Create a i18n-translations.json file with translations for all languages.

{
  "en" : {
    "welcome-on-our-website" : "Welcome on our multi-language website",
    "hello-world" : "Hello World!",
    "about-us" : "About us",
    "learn-more-about-us" : "Learn more about us",
    "homepage" : "Homepage"
  },
  "pl" : {
    "welcome-on-our-website" : "Witamy na naszej wielojęzycznej stronie internetowej",
    "hello-world" : "Witaj Świecie!",
    "about-us" : "O nas",
    "learn-more-about-us" : "Dowiedz się więcej o nas",
    "homepage" : "Strona główna"
  },
  "es" : {
    "welcome-on-our-website" : "Bienvenido a nuestro sitio web multilingüe",
    "hello-world" : "Hola, mundo.",
    "about-us" : "Sobre nosotros",
    "learn-more-about-us" : "Más información sobre nosotros",
    "homepage" : "Página web"
  }
}

Managing a big JSON file like this might be hard and done only by a software team. This is the reason why we created SimpleLocalize where you can manage JSON files like this with ease, automatically upload and download them and use Google Translate or DeepL to auto translate the texts. Try it for free for 7 days!

Configure multi-language page generation

Now, edit your gatsby-node.js configuration file and override onCreatePage function like below.

const messages = require("./i18n-translations.json")
const {languages, defaultLanguage} = require("./src/i18n");

exports.onCreatePage = async ({page, actions}) => {
  const {createPage, deletePage} = actions;
  return new Promise((resolve) => {
    let path = page.path;
    deletePage(page);

    for (let language of languages) {
      const isDefaultLanguage = language === defaultLanguage;
      if (!isDefaultLanguage) {
        path = '/' + language + page.path;
      }

      const pageForLanguage = Object.assign({}, page, {
        originalPath: page.path,
        path: path,
        context: {
          language,
          messages: messages[language]
        }
      });
      createPage(pageForLanguage)
    }
    resolve()
  })
};

A lot of things are happening here, right? Let start from the beginning.

  • First of all, import translations.json file from root directory
  • Use deletePage to remove default page created by Gatsby
  • Iterate over all languages from i18n.js
  • Add /{language} to path if the language is not the default one
  • Get translations for given language from messages object
  • Add language and messages to a page context
  • Use createPage to recreate a page with a new path and translations

Create a first multi-language page

Create index.js in /src/pages directory and paste code below:

import React from "react";
import {FormattedMessage} from "react-intl";
import LinkTranslated from "../LinkTranslated";
import SimpleLocalize from "../SimpleLocalize";

function IndexPage(props) {
  return (
    <SimpleLocalize {...props}>
      <h1>
        <FormattedMessage
          id="hello-world"
          defaultMessage="Hello World!"
        />
      </h1>

      <p>
        <FormattedMessage
          id="welcome-on-our-website"
          defaultMessage="Welcome on our multi-language website"
        />
      </p>

      <LinkTranslated
        className="btn btn-link"
        href="/about"
      >
        <FormattedMessage
          id="learn-more-about-us"
          defaultMessage="Learn more about us"
        />
      </LinkTranslated>
      <ul>
        <li><a href="/">English (Default)</a></li>
        <li><a href="/pl/">Polish</a></li>
        <li><a href="/es/">Spanish</a></li>
      </ul>

    </SimpleLocalize>
  );
}
export default IndexPage

SimpleLocalize Component will provide a <IntlProvider/> and intl object for <FormattedMessage/> components.

Create second multi-language page

Create file about.js in /src/pages directory and paste code like below:

import React from "react";
import SimpleLocalize from "../SimpleLocalize";
import {FormattedMessage} from "react-intl";
import LinkTranslated from "../LinkTranslated";

function AboutPage(props) {
  return (
    <SimpleLocalize {...props}>
      <h1>
        <FormattedMessage
          id="about-us"
          defaultMessage="About us"
        />
      </h1>

      <LinkTranslated
        className="btn btn-link"
        href="/"
      >
        <FormattedMessage
          id="homepage"
          defaultMessage="Homepage"
        />
      </LinkTranslated>
    </SimpleLocalize>
  );
}
export default AboutPage;

Result

Now, start your project with npm run develop and you should see

Multi-language Gatsby project example

Code repository

Full code can be found on GitHub.

https://github.com/simplelocalize/multi-language-gatsby-example

Message extraction

Uploading extracted translation keys to translation editor

In the repository you will also find additional scripts in package.json.

I installed @formatjs/cli as a devDependency to extract all translations and ids from <FormattedMessage/> components.

## npm
npm install --save-dev @formatjs/cli

## yarn
yarn add -D @formatjs/cli

I used simplelocalize-cli to upload found ids and download ready to use translations.

Scripts explanation:

  • npm run extract script will extract translations to i18n-extracted.json
  • npm run sync script will upload found translation keys from i18n-extracted.json and download the latest translations from the server to i18n-translations.json

Once you change a translation in JSON file, you need to restart GatsbyJS to see the effect. Sometimes you might not see a changed translation, then you need to run npm run clean before npm run develop.

Editing translations in SimpleLocalize

Below you see a screenshot from example project which I pushed on GitHub. Now, I can manage all translations from one place, add more languages and use DeepL or Google Translate to automatically translate them and use in my Gatsby page.

Multi-language Gatsby project in SimpleLocalize Multi-language content with properly used hrefLang attributes will score much higher in SEO results.

Did you notice the small gray icons next to translated texts? I used DeepL integration to auto-translate those texts. 😄


Share article
See all articles
Try SimpleLocalize i18n editor and hosting
localization workflow process

Relevant posts

GitHub Actions is available!

GitHub Actions is available!

Jakub PomykałabyJakubNovember 28, 2021

GitHub Actions integration for Continuous Localization is available on GitHub Market! Connect your GitHub repository to SimpleLocalize i18n editor for free!

Read more
Number formatting in JavaScript

Number formatting in JavaScript

Jakub PomykałabyJakubNovember 28, 2021

Discover power of 'toLocaleString' functions in JavaScript. Format numbers, currencies, and units without any 3rd party localization library.

Read more
Localization: Tips & Tricks

Localization: Tips & Tricks

Jakub PomykałabyJakubNovember 27, 2021

Avoid common problems with localization by following these simple tips. These resources will help you save time and effort with internationalization and localization.

Read more
How to use code splitting with JSON files in React application

How to use code splitting with JSON files in React application

Jakub PomykałabyJakubAugust 06, 2021

Lazy load JSON resource with language translations to speed up your React application. Use built-in code-splitting feature to load JSON files.

Read more
List of i18n libraries for React, React Native, and NextJS

List of i18n libraries for React, React Native, and NextJS

Jakub PomykałabyJakubFebruary 12, 2021

Best i18n libraries for React web, React Native, Expo and all other React apps. Check how to react localization should look like.

Read more
FormatJS and React application localization

FormatJS and React application localization

Jakub PomykałabyJakubOctober 07, 2020

Localize your React app using FormatJS and react-intl. Manage translations using SimpleLocalize.io

Read more