Internationalization With Gatsby
By: David Dal Busco
Tags: Accessibility, Programming, Web Development, React, JavaScript

Hands-On Coding

Enough installation and configuration — let’s code. The major modification we have to apply occurs in layout.js , which, by the way, I moved into a subfolder called src/components/layout/ for no other reason than the fact I like clean structure.

“What happens here?” you may ask. Summarized, we’re adding two new required properties, location and messages . The first one is used to guess the locale that should be applied, and the second one contains the list of translations. As you can see, we import React Intl. We also import a function called getCurrentLangKey from ptz-i18n , which is actually a utility of the above plugin.

I’m also using the <FormattedMessage/> component to print out Hello to ensure our implementation works out.

import React from "react"

import PropTypes from "prop-types"

import { useStaticQuery, graphql } from "gatsby"



import Header from "../header"

import "./layout.css"



import { FormattedMessage, IntlProvider } from "react-intl"

import "@formatjs/intl-pluralrules/polyfill"



import { getCurrentLangKey } from 'ptz-i18n';



const Layout = ({ children, location, messages }) => {

const data = useStaticQuery(graphql`

query SiteTitleQuery {

site {

siteMetadata {

title

languages {

defaultLangKey

langs

}

}

}

}

`)



const { langs, defaultLangKey } =

data.site.siteMetadata.languages;

const langKey =

getCurrentLangKey(langs, defaultLangKey, location.pathname);



return (

<IntlProvider locale={langKey} messages={messages}>

<Header siteTitle={data.site.siteMetadata.title} />



<p>

<FormattedMessage id="hello" />

</p>



</IntlProvider>

)

}



Layout.propTypes = {

children: PropTypes.node.isRequired,

location: PropTypes.any.isRequired,

messages: PropTypes.any.isRequired,

}



export default Layout

To extend the layout for each language and locale, we create a new file per each supported languages For example, in English, we create layout/en.js in which we import both our custom messages and the specific polyfill.

import React from 'react';

import Layout from "./layout"



import messages from '../../i18n/en';

import "@formatjs/intl-pluralrules/dist/locale-data/en"



export default (props) => (

<Layout

{...props}

messages={messages}

/>

);

At this point, our code won’t compile because in these languages, these messages are missing. That’s why we also create the file for these — for example, i18n/en.js .

module.exports = {

hello: "Hello world",

}

As I briefly stated in my introduction, each page is going to be duplicated. That’s why we create the corresponding index page. In case of the default, English, we rename index.js to index.en.js . Moreover, because the layout now expects a location property, we pass it for every page too.

Note also that because I’ve decided to prefix all of the routes, I also modified the link routing from /page-2/ to /en/page-2 .

import React from "react"

import { Link } from "gatsby"



import Layout from "../components/layout/en"

import SEO from "../components/seo/seo"



const IndexPage = (props) => (

<Layout location={props.location}>

<SEO />

<h1>Hi people</h1>



<Link to="/en/page-2/">Go to page 2</Link>

</Layout>

)



export default IndexPage

The same modifications that we’ve implemented for index should be propagated to every page — in this example, I also rename page-2.js in page-2.en.js and apply the same modifications as above.

import React from "react"

import { Link } from "gatsby"



import Layout from "../components/layout/en"

import SEO from "../components/seo/seo"



const SecondPage = (props) => (

<Layout location={props.location}>

<SEO title="Page two" />

<p>Welcome to page 2</p>

<Link to="/en/">Go back to the homepage</Link>

</Layout>

)



export default SecondPage

Identically, the usage of the <Layout/> component has to be enhanced with the location object in our 404.js page.

import React from "react"



import Layout from "../components/layout/layout"

import SEO from "../components/seo/seo"



const NotFoundPage = (props) => (

<Layout location={props.location}>

<SEO />

<h1>NOT FOUND</h1>

</Layout>

)



export default NotFoundPage

And voilà, that’s it — our Gastby site is internationalized. Of course, you might want to add some other languages. To do so, repeat the steps above for English, and, again, duplicate the pages.