--- title: Implement Localization category: CMS Features order: 1 status: published summary: Configure languages in React Bricks, translate pages, and fetch localized content in a Next.js project. estimatedTime: 12 min keywords: localization i18n languages translations next.js locale localized content hreflang canonical --- React Bricks stores translations as localized versions of the same page. In this how-to, you'll set up the editorial workflow in the Dashboard, translate a page, and wire your Next.js project so it fetches the right localized content for each route. Docs reference: [Localization](https://docs.reactbricks.com/common-tasks/localization/) ## Configure languages in the Dashboard Open the React Bricks Dashboard and go to **Settings**. From there you can: - add or remove languages, based on your plan limits - choose the default language The default language is important because React Bricks uses it as the source content when an editor creates a new translation. If a page has no translation in the default language, React Bricks copies content from the first available language instead. ## Translate a page Open a page in the React Bricks visual editor. When your app has more than one language, the editor shows language tabs for the page. Click the tab for the language you want to translate. If that translation does not exist yet, React Bricks asks whether you want to create it. When a translation is created: - content is copied from the default language when available - each language keeps its own content - page attributes, slug, SEO fields, meta data, and custom field values are independent for each translation This means editors can localize not only the visible text, but also language-specific metadata and page-level custom fields. ## Fetch one localized page When rendering a page, pass the current locale as the `language` argument to `fetchPage`. ```tsx import { fetchPage } from 'react-bricks/rsc' import config from '@/react-bricks/config' export async function getPage(slug: string, locale: string) { const page = await fetchPage({ slug, language: locale, config, fetchOptions: { next: { revalidate: 3 } }, }) return page } ``` If you do not pass a `language`, React Bricks returns the page in the default language. ## Fetch localized page lists Use the same idea when fetching lists of pages. For server-side or build-time lists, pass `language` in the `fetchPages` options object: ```tsx import { fetchPages } from 'react-bricks/frontend' const posts = await fetchPages(process.env.API_KEY!, { type: 'blog', language: locale, sort: '-publishedAt', }) ``` ## Build a language switcher A page returned by `fetchPage` includes a `translations` field with the available translations for that page. Each translation includes the language, slug, page name, status, edit status, lock state, and scheduled publishing date. ```ts type Page = { translations: Translation[] } type Translation = { language: string slug: string name: string status: PageStatus editStatus: EditStatus isLocked: boolean scheduledForPublishingOn: string } ``` Use `translations` to build links to the matching localized URL. ```tsx import Link from 'next/link' type Translation = { language: string slug: string name: string } export function LanguageSwitcher({ translations, }: { translations: Translation[] }) { return ( ) } ``` Adapt the `href` format to your routing strategy. For example, the home page usually needs a special case so `/en` does not become `/en/`. ## Configure Next.js App routing If your project uses the Next.js App Router, place the locale in the route, for example: ```txt app/[lang]/[[...slug]]/page.tsx ``` Then read the route parameter and pass it to `fetchPage`: ```tsx export default async function Page({ params, }: { params: Promise<{ lang: string; slug?: string[] }> }) { const { lang, slug } = await params const cleanSlug = slug?.join('/') ?? '/' const page = await fetchPage({ slug: cleanSlug, language: lang, config, fetchOptions: { next: { revalidate: 3 } }, }) return } ``` For Next.js App projects, React Bricks provides `createI18nMiddleware` to centralize locale resolution in middleware. Use it when your project has localized routes and you want middleware to resolve the correct language before the page renders. In current Next.js App starters, `middleware.ts` is already set up for both i18n and optional A/B Testing: ```ts import { NextResponse } from 'next/server' import { chain, createI18nMiddleware, createWithAbTestingMiddleware, } from 'react-bricks/rsc' import { i18n } from '@/i18n-config' import { abTestingEnabled, getConfig } from './react-bricks/getConfig' const rbConfig = getConfig() const withAbTestingMiddleware = createWithAbTestingMiddleware({ i18n, config: rbConfig, }) const withI18nMiddleware = createI18nMiddleware({ i18n, NextResponse }) const middleware = abTestingEnabled ? chain([withAbTestingMiddleware, withI18nMiddleware]) : withI18nMiddleware export default middleware export const config = { // Matcher ignoring `/_next/` and `/api/` matcher: [ '/((?!api|_next/static|_next/image|favicon.ico|admin|logo.svg|bricks-preview-images|masks|preview).*)', ], } ``` If your project only uses localization, `withI18nMiddleware` handles the request. If your project also uses A/B Testing, `chain` runs the A/B Testing middleware first and the i18n middleware after it, so the same request resolves both the active variant and the active locale. If you maintain an older Next.js Pages Router project, see the [Localization docs](https://docs.reactbricks.com/common-tasks/localization/) for the Pages Router setup. ## Manage canonical and hreflang metadata Localized pages should expose a canonical URL and `hreflang` alternates, so search engines can understand which translated URLs belong to the same page. Create an `i18n-config.ts` file in the project root: ```ts export const i18n = { siteUrl: process.env.NEXT_PUBLIC_SITE_URL, defaultLocale: 'en', locales: ['en', 'it'], } as const export type Locale = (typeof i18n)['locales'][number] ``` Then, in `app/[lang]/[[...slug]]/page.tsx`, use the page translations returned by React Bricks to create the alternate language URLs. ```tsx import type { Metadata } from 'next' import { getMetadata } from 'react-bricks/rsc' import { i18n, type Locale } from '@/i18n-config' function getLocalizedUrl(language: string, slug: string) { const normalizedSlug = slug === '/' ? '' : slug const localePrefix = language === i18n.defaultLocale ? '' : `/${language}` return `${i18n.siteUrl}${localePrefix}/${normalizedSlug}` } export async function generateMetadata(props: { params: Promise<{ lang: Locale; slug?: string[] }> }): Promise { const params = await props.params const cleanSlug = params.slug?.join('/') ?? '/' const { page } = await getData(cleanSlug, params.lang) if (!page?.meta) { return {} } const metadata = getMetadata(page) return { ...metadata, alternates: { canonical: getLocalizedUrl(params.lang, page.slug), languages: page.translations.reduce>( (acc, translation) => ({ ...acc, [translation.language]: getLocalizedUrl( translation.language, translation.slug ), }), {} ), }, } } ``` With this pattern: - the default language uses URLs without a locale prefix - translated pages use URLs with the language prefix - each translation gets its own canonical URL - `page.translations` provides the language and slug for each alternate URL ## Check the result After wiring localization: - create or translate a page in at least two languages - visit the localized routes in your app - confirm each route fetches the correct translation - check that language switcher links use the translated slugs - verify localized canonical URLs, hreflang alternates, SEO fields, and custom fields if your page type uses them ## Related docs - [Localization CMS feature](https://docs.reactbricks.com/cms-features/localization/) - [Implement Localization](https://docs.reactbricks.com/common-tasks/localization/) - [fetchPage](https://docs.reactbricks.com/api-reference/utilities/fetch-page/) - [fetchPages](https://docs.reactbricks.com/api-reference/utilities/fetch-pages/) - [createI18nMiddleware](https://docs.reactbricks.com/api-reference/utilities/create-i18n-middleware/)