Localization is a common problem and there are many solutions, each with their own benefits and trade-offs. With Gatsby and Sanity.io its possible to achieve a solution that is easy to work with and extend. If you haven’t already read about why Gatsby and Sanity.io pair so well check out the blog post by Knut Melvær: Blazing fast development with Gatsby and Sanity.io.
I have completed two sites with Gatsby and Sanity that required localization. The first site needed to maintain every link from the original site without redirects: each language living in its own subdomain, es.my-web-page.com
for example. The simplest solution at the time was to use multiple builds which always bothered me. The second site I vowed to do it the right™ way.
The new setup would generate pages for every language in one build step giving urls like my-home-page.com/es/...
. This makes it easier for both the content team and our developers to use.
Setting Up Sanity to Support Translations
Sanity.io has some good documentation which has great examples to help you achieve localized text.
Create a new contentType schema called localeText
to use with the schemas in your project.
This will allow you to add localeText
as a type in your schemas and renders a nice UI for adding translations.
In your schema:
Updating Gatsby Setup
Now that you have your Sanity schemas set up for adding translations you need to set up your Gatsby project to handle them. You’re going to update the queries to handle the new shape of your data.
Which gives you a data prop that looks like the following:
Getting the Correct Language Text
At this point you could use the above as-is in your components with data.sanitySomeDataType.title.en
. You could do something like:
It is preferable to reference only the title key and get the correct text. No need to remember what locale is active.
So let’s make that work.
Once again, you can use the example from the Sanity.io documentation for a function to localize the text from a given Sanity document. I’ve modified the example below to always default to English. This suits my use case and it’s a good starting point if your use case differs. The function walks through a given document and updates any object with _type: 'locale<TEXT_TYPE>'
( for example _type: 'localeText'
, or _type: 'localeString'
) and returns only the correct translation text.
You could use render props for this but I decided on a higher-order component (HOC).
Wrap Page Components With the Localize HOC
For each page or template that needs to be localized add your HOC.
Generating Pages with the Correct Context
In the gatsby-node.js
file you need to add a function that generates pages for each supported language with a path prefix for each, such as ‘es’ for Spanish, and ‘fr’ for French. It needs to be called in onCreatePage
so that every automatically generated page from your pages
directory gets localized. It also needs to be added into the createPages
to localize all of your dynamic content. This is needed as gatsby doesn’t call onCreatePage
for pages generated by the same plugin at the moment to avoid infinite loops.
Sanity.io + Gatsby.js + Localization = Win
If you haven’t already started using Sanity.io as your content backend I encourage you to check it out. You and your content team will love it.
For a quick start with the combo, the peeps at Sanity put up a great starting point at Combo Example: Company Website
If you have any questions or want to geek out about all things React hit me up on Twitter @cpt_silverfox