Welcome to the exciting world of internationalization! In this guide, we will explore how to seamlessly integrate multiple languages into your applications using Payload CMS for the backend and Next.js for the frontend. This tutorial will equip you with the knowledge to create a multilingual website, enabling you to offer content in both German and English, with the flexibility to add more languages as needed. Let's dive into the process of setting up internationalization with Payload and Next.js.
This article provides a comprehensive written tutorial complementing our detailed video guide available on YouTube at https://www.youtube.com/watch?v=w58O_E0La3M. If you're a visual learner or prefer to follow along with demonstrations, we recommend checking out the video, which offers the same content enriched with additional context and real-time implementation of each step in the internationalization process.
In this project, we will build a simple Next.js frontend that allows users to select between different languages. The frontend will communicate with a Payload backend that contains a pages collection with localized content. Users will be able to switch languages dynamically, and changes will reflect immediately across the website.
To get started, you will need to set up a basic Payload backend. If you follow the tutorial series by Sandro, you’ll find it quite straightforward to implement. The backend will consist of a media collection and a users collection, while the pages collection will house our multilingual content.

Once your Payload backend is running, you will notice that there’s nothing in the collections yet. We need to extend the Payload configuration to support multiple languages. This involves adding a localization object to the configuration.
To enable localization, go to your Payload config file and add the following code snippet:
localization: {
locales: [
{ label: 'English', code: 'en' },
{ label: 'Deutsch', code: 'de' }
],
defaultLocale: 'en',
fallback: true
}
This configuration allows us to define the languages we want to support. In this case, we have English and German. The default locale is set to English, and the fallback option ensures that if a translation is not available, it will revert to English.
Next, we will create a pages collection that will enable us to manage our multilingual content. Each page will have a layout containing different blocks, which can be localized individually. Here’s how to set up the pages collection:
export default {
slug: 'pages',
labels: {
singular: 'Page',
plural: 'Pages'
},
versions: {
drafts: true
},
fields: [
{
name: 'name',
type: 'text',
label: 'Name',
required: true
},
{
name: 'slug',
type: 'text',
label: 'Slug',
unique: true,
required: true
},
{
name: 'layout',
type: 'blocks',
label: 'Layout',
initCollapsed: true
}
]
}In this collection, we define fields such as name, slug, and layout. The layout will allow us to create different blocks, which we will define next.
We will create two types of blocks: a navigation block and a rich text block. The navigation block will allow us to customize the title for each language, while the rich text block will allow us to add dynamic content.
export const navbarBlock = {
slug: 'navbar',
fields: [
{
name: 'title',
type: 'text',
label: 'Title',
required: true,
localized: true
}
]
}By setting the localized property to true, we ensure that this field can store multiple language variants. Next, let's define the rich text block:
export const richTextBlock = {
slug: 'richText',
fields: [
{
name: 'content',
type: 'richText',
label: 'Content'
}
]
}Now that we have our blocks defined, we can create pages and assign content for both English and German. In the Payload admin panel, we can create a new page and fill in the localized fields for each language.
When creating content, ensure you switch between languages to add the appropriate titles and content for each variant. Once you save your changes, you will see both versions of the page available in your backend.
Now that our backend is ready, let’s turn to the frontend. In your Next.js application, you will need to install the next-i18next package, which simplifies the internationalization process.
npm install next-i18next
Next, configure the Next.js application to recognize the supported locales:
i18n: {
locales: ['en', 'de'],
defaultLocale: 'en'
}Next, we will create a dynamic page that fetches the localized content based on the user's language preference. Create a new file named [slug].js in the pages directory:
export const getStaticPaths = async () => {
const response = await axios.get('/api/pages');
const pages = response.data.docs;
const paths = pages.flatMap(page => {
return [
{ params: { slug: page.slug }, locale: 'en' },
{ params: { slug: page.slug }, locale: 'de' }
];
});
return { paths, fallback: false };
}This code fetches all the pages from the backend and generates paths for each language. Now, let’s implement the getStaticProps function to fetch the specific page data based on the slug and locale:
export const getStaticProps = async ({ params, locale }) => {
const response = await axios.get(`/api/pages?slug=${params.slug}&locale=${locale}`);
const pageData = response.data.docs[0];
return { props: { page: pageData } };
}
To render the blocks in the frontend, we will create a RenderBlocks component. This component will take the layout from our backend and map it to the frontend:
const RenderBlocks = ({ layout }) => {
return (
{layout.map((block, index) => { if (block.blockType === 'navbar') { return ; } else if (block.blockType === 'richText') { return ; } return null; })}
);
}This component checks the block type and renders the appropriate component for each block in the layout.
To allow users to switch between languages, we will implement a language toggle component. This component will dynamically change the URL to reflect the selected language:
const LanguageToggle = () => {
const router = useRouter();
const { locale } = router;
return (
English Deutsch
);
}This component utilizes the Next.js router to switch locales while preserving the current path.
Congratulations! You have successfully implemented internationalization using Payload and Next.js. This guide has walked you through setting up a backend that supports multiple languages, creating a frontend that dynamically fetches and displays localized content, and implementing a user-friendly language switching feature.
As you continue to develop your application, remember that internationalization is an ongoing process. You can always add more languages and expand the content to cater to a broader audience.
Payload CMS is a headless content management system that allows developers to manage and deliver content through APIs, making it easy to integrate with various frontend frameworks.
Next.js provides built-in support for internationalization through its next-i18next package, allowing developers to easily manage multiple locales and dynamic content.
Yes, you can easily add more languages to your Payload backend and configure your Next.js frontend to support them.
If you have any feedback or suggestions, please feel free to drop your questions in the comments below. Your insights are incredibly important to us!