Internationalization
This article collects all the resources you need to take advantage of Prismic's multi-language and localization feature when building a Next.js website.
You will be using Next.js’ built-in internationalization features to add fully-featured support for multiple locales in your app.
Configure Route Resolver
The Route Resolver is an API option that resolves the URL for a page. In this example of an internationalized website, the Route Resolver will localize the content using a locale code in the URL. If the URL does not contain a locale code, the default locale is used.
Here’s how that might look:
/hello-world
(English, the default locale)/fr-fr/bonjour-le-monde
(French)
You can include locale codes in your app’s Route Resolver paths using the :lang?
symbol.
const routes = [
{
type: "homepage",
path: "/:lang?",
},
{
type: "page",
path: "/lang?/:uid",
},
];
The ?
in lang?
configures the Route Resolver to exclude the locale if it is the Prismic repository’s default locale.
Configure Next.js
To enable Next.js’ built-in internationalization support, add an i18n
property to your project’s next.config.js
file pointing to a list of your Prismic repository’s locale codes.
You can query your Prismic repository using @prismicio/client
to automatically retrieve a list of your content’s locale codes. Note that the configuration object is wrapped in an async function.
const prismic = require("@prismicio/client");
const sm = require("./slicemachine.config.json");
/** @returns {Promise<import('next').NextConfig>} */
module.exports = async () => {
const client = prismic.createClient(sm.repositoryName);
const repository = await client.getRepository();
const locales = repository.languages.map(
(lang) => lang.id,
);
return {
i18n: {
locales,
// This is the default locale. It will not be included in URLs.
defaultLocale: locales[0],
},
};
};
Your app now supports routes prefixed with locale codes, like /en-us/hello
and /fr-fr/bonjour
.
Query by locale
You’ll need to query content by the route’s locale. Next.js provides the route’s locale code to getStaticProps()
through the locale
parameter.
Pass the locale parameter to your query’s lang
parameter.
export async function getStaticProps({
params,
locale,
previewData,
}) {
const client = createClient({ previewData });
const page = await client.getByUID("page", params.uid, {
lang: locale,
});
return {
props: {
page,
},
};
}
Define paths for all locales
If you have a dynamic route with getStaticPaths()
, such as in a src/pages/[uid].js
file, update your Prismic query in getStaticPaths()
to fetch documents from all languages.
Add a lang: '*'
parameter to your query.
export async function getStaticPaths() {
const client = createClient();
const pages = await client.getAllByType("page", {
lang: "*",
});
return {
paths: pages.map((page) => page.url),
fallback: false,
};
}
Create a locale switcher
Now that routes are configured to support locales, your project needs a way to switch between locales.
In this example, you’ll see how to render a simple list of links linking to a page’s available locales. Feel free to customize it to fit your app.
Add the getLocales()
helper
You’ll need a helper function to fetch a list of all the locales available for a specific document. This function will be used in your pages’ getStaticProps()
function.
Create a file at src/lib/getLocales.js
(you may need to create a lib directory) with the following contents.
/**
* Returns an array of document metadata containing each locale a document has
* been translated into.
*
* A `lang_name` property is included in each document containing the document's
* locale name as it is configured in the Prismic repository.
*
* @param {import("@prismicio/types").PrismicDocument} doc
* @param {import("@prismicio/client").Client} client
*
* @returns {Promise<(import("@prismicio/types").PrismicDocument & { lang_name: string })[]>}
*/
export async function getLocales(doc, client) {
const [repository, altDocs] = await Promise.all([
client.getRepository(),
doc.alternate_languages.length > 0
? client.getAllByIDs(
doc.alternate_languages.map(
(altLang) => altLang.id,
),
{
lang: "*",
// Exclude all fields to speed up the query.
fetch: `${doc.type}.__nonexistent-field__`,
},
)
: Promise.resolve([]),
]);
return [doc, ...altDocs].map((doc) => {
return {
...doc,
lang_name: repository.languages.find(
(lang) => lang.id === doc.lang,
).name,
};
});
}
Query a document’s available locales
In your pages’ getStaticProps()
function, use the getLocales()
helper to fetch a list of all the available locales for the page.
Return the result as a prop called locales
.
+ import { getLocales } from "@/lib/getLocales"
export async function getStaticProps({ params, locale, previewData }) {
const client = createClient({ previewData })
const page = await client.getByUID('page', params.uid, { lang: locale })
+ const locales = await getLocales(page, client)
return {
props: {
page,
+ locales,
},
}
}
Display a list of locale links
The locales
prop is an array of metadata for each of the page’s available languages.
You can turn that array into a list of links like this:
import { PrismicNextLink } from "@prismicio/next";
const Page = ({ page, locales }) => {
return (
<ul>
{locales.map((locale) => (
<li key={locale.id}>
<PrismicNextLink href={locale.url}>
{locale.lang_name}
</PrismicNextLink>
</li>
))}
</ul>
);
};
We recommend adding the locale switcher somewhere in your app’s header or footer in an easily discoverable location.