Developers
This guide covers implementing internationalization (i18n) with Agility CMS, including locale configuration, routing, and content management.
This guide covers implementing internationalization (i18n) with Agility CMS, including locale configuration, routing, and content management.
Agility CMS supports multiple locales, allowing you to manage content in different languages and regions.
Configure locales in your environment:
AGILITY_LOCALES=en-us,fr-ca,es-mx
The first locale in the list is the default locale:
const locales = process.env.AGILITY_LOCALES?.split(',') || ['en-us']
const defaultLocale = locales[0]
Default Locale (no prefix):
/ # English (default)
/blog
/about-us
Other Locales (with prefix):
/fr # French
/fr/blog
/fr/about-us
Handle locale routing in middleware:
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const pathname = request.nextUrl.pathname
const locale = getLocaleFromPathname(pathname)
// Rewrite to locale-prefixed path
const newUrl = new URL(`/${locale}${pathname}`, request.url)
return NextResponse.rewrite(newUrl)
}
Always specify locale when fetching content:
const { fields } = await getContentItem<IPost>({
contentID: 204,
languageCode: "en-us" // or "fr-ca", "es-mx"
})
Detect locale from request:
import { headers } from 'next/headers'
export default async function Page({ params }) {
const locale = params.locale || 'en-us'
const { fields } = await getContentItem<IPost>({
contentID: 204,
languageCode: locale
})
return <div>{fields.heading}</div>
}
Each locale has its own content instances:
Implement fallback to default locale:
async function getContentWithFallback<T>(
contentID: number,
locale: string,
defaultLocale: string = 'en-us'
) {
try {
return await getContentItem<T>({
contentID,
languageCode: locale
})
} catch (error) {
if (locale !== defaultLocale) {
// Fallback to default locale
return await getContentItem<T>({
contentID,
languageCode: defaultLocale
})
}
throw error
}
}
Fetch sitemap for specific locale:
const sitemap = await getSitemapFlat({
channelName: "website",
languageCode: "en-us"
})
Generate static params for all locales:
export async function generateStaticParams() {
const locales = process.env.AGILITY_LOCALES?.split(',') || ['en-us']
const params = []
for (const locale of locales) {
const sitemap = await getSitemapFlat({
channelName: "website",
languageCode: locale
})
for (const page of sitemap) {
params.push({
locale,
slug: page.path.split('/').filter(Boolean),
})
}
}
return params
}
Create utility functions:
// lib/i18n/utils.ts
export function isValidLocale(locale: string, locales: string[]): boolean {
return locales.includes(locale)
}
export function getLocaleFromPathname(pathname: string): string {
const segments = pathname.split('/').filter(Boolean)
const firstSegment = segments[0]
const locales = process.env.AGILITY_LOCALES?.split(',') || ['en-us']
return isValidLocale(firstSegment, locales) ? firstSegment : locales[0]
}
export function removeLocaleFromPathname(pathname: string): string {
const locale = getLocaleFromPathname(pathname)
return pathname.replace(`/${locale}`, '') || '/'
}
Next: Best Practices - Development best practices