Internationalization of a Static Website with GatsbyJS
Do you use React? Do you need an internationalized static website? We have a brand new GatsbyJS starter supporting you out-of-box! Check out our Github.
In Ackee, we use React as the main front-end technology. Most of the time we create SPAs, but sometimes we need to create a static website with just a few pages, and an internationalization is compulsory every time. There is a lot of static site builders but if you want something easy to use with React, you should go with GatsbyJS and its huge starter ecosystem.
GatsbyJS
Don't you know GatsbyJS? Well, it is a static site builder powered by React ecosystem. It uses React, SSR, Webpack, NodeJS and others. You write the whole website in React and let GatsbyJS generate static pages. Where is the magic? The idea is to use SSR to generate the pages. But instead of generating them on demand using a server, the pages are pre-generated and served as static HTML, JS, CSS. The JS code is a small React app specific for the page. This concept is really powerful and it allows you to hook into every stage of the page generation and modify it.
On the other side, if you just want to code your pages and not to care about the rest, you can use a huge library of GatsbyJS starters, code skeletons to build on. And we created one of the starters for you! But before you start with the starter, go through GatsbyJS tutorials to understand what it is all about.
gatsby-starter-internationalized
It started with a few requirements:
- use React,
- has to be internationalized
- has to have internationalized routes (ie. /en/home and /cs/domu ).
So we used GatsbyJS for the site generation and tried to find some appropriate starter. There are some starters supporting internationalization in the library but if you take a closer look, none of them supports internationalized routes. The only way was to write our own code to generate internationalized routes. Because we used gatsby-starter-intl, we had something to build on and to learn from.
Route internationalization
First, you have to specify the name of the routes for the specific language and then, based on them, generate the final pages. The language configuration can look something like:
[
locale: "cs",
label: "Čeština",
routes: {
"/": "/",
"/page1": "/stranka1",
"/subpage/page1": "/podstranka/stranka1",
},
default: true,
locale: "en",
label: "English",
routes: {
"/": "/",
"/page1": "/page1",
"/subpage/page1": "/subpage/page1",
];
Second, GatsbyJS has a lot of options of how to hook into the generation of pages. It is set in the gatsby-node.js file. Here, you can override the default page generation behavior and support your own. The code is really simple:
const languages = require("./src/i18n/languages");
const getLocalizedPath = require("./src/i18n/getLocalizedPath");
exports.onCreatePage = ({ page, actions }) => {
const { createPage, deletePage } = actions;
if (page.internalComponentName === "ComponentDev404Page") {
return;
return new Promise(resolve => {
deletePage(page);
languages.forEach(lang => {
const localizedPath = getLocalizedPath(page.path, lang.locale);
const localePage = {
...page,
path: localizedPath,
context: {
locale: lang.locale,
originalPath: page.path
};
createPage(localePage);
});
resolve();
});
};
Page content internationalization
By now, we have got generated pages with correct internationalized names. The next step is to inject locale into the pages using react-intl provider. It is not so complicated, because the context object that you can see in the code above is passed as a prop into every page you create. Our starter has a HOC to help you out:
const withPageContext = PageComponent => props => {
const { locale } = props.pageContext;
return (
<IntlProvider locale={locale} messages={translations[locale]}>
<PageContext.Provider value={props.pageContext}>
<PageComponent {...props} />
</PageContext.Provider>
</IntlProvider>
);
};
Creating web pages
In the end, the only thing a developer using our GatsbyJS starter has to care about are the pages to create. Along with withPageContext HOC, there are two built-in components to support the internationalization:
- LocalizedLink creates a correct link based on the current language of the page,
- LanguageSwitcher allows to switch to an equivalent page of other supported languages.
With the support of the starter, writing any internationalized website is fun! Take a look at the code you will likely write with our starter.
import Link from '../components/LocalizedLink';
import LanguageSwitcher from '../components/LanguageSwitcher';
const IndexPage = () => (
<>
<header>
<FormattedMessage id="index.title" />
<nav>
<Link to="/about/contact">
<FormattedMessage id="nav.about">
</Link>
<LanguageSwitcher />
</nav>
</header>
<main>
<FormattedMessage id="index.main"/>
</main>
<footer>
<FormattedMessage id="index.footer" />
</footer>
</>
);
export default withPageContext(IndexPage);
Just try it out!
We used the starter many times internally in the company and decided to share it with the community because it saves us a huge amount of time. If you are interested in how it all works, there is no easier way than to take a look at the codebase or the live demo! If you are having any issue with the starter, just submit one into the repo. We're glad to help anytime we can.
If you like the article or the starter, clap as many times as you want! Sending ❤ from Ackee.