Knowledge Base/Integrating Advanced Localization in Next.js: From Built-In CSK Localization to next-intl
Integrating Advanced Localization in Next.js: From Built-In CSK Localization to next-intl
how-toDeveloperCSKLocalizationNextJS app router
Introduction
As businesses and applications increasingly reach global audiences, effective localization becomes essential for ensuring a seamless, user-friendly experience in multiple languages. Our Component Starter Kit (CSK) is designed with basic localization support, offering an out-of-the-box solution for uniform localization that avoids additional dependencies. This simplified approach enables quick setup and testing, ideal for early development stages when localization needs are minimal.
However, as projects progress and require more advanced features—such as URL-based routing for locale selection—this built-in localization can benefit from the added power and flexibility of next-intl. Officially recommended by Next.js, next-intl offers a robust approach to handling multilingual content. By adopting next-intl, you gain access to advanced localization features like language-based routing, centralized locale configurations, and support for custom middleware to handle requests based on locale.
In this guide, we’ll walk through a step-by-step process for integrating next-intl into your Next.js app, building on the basic localization in CSK. We’ll cover the necessary configurations, routing, middleware setup, and some final adjustments to seamlessly transition your app to next-intl. By following these steps, you’ll have a fully localized app that can scale easily as you add more languages or region-specific content.
The end result? A Next.js application that is optimized for global reach, with a flexible foundation for managing multiple locales and region-specific variations.
Step-by-Step Implementation of next-intl
Step 1: Installing next-intl package
Start by installing the next-intl package, which supports locale-based routing and other advanced localization needs. Run the following command in your terminal:
npm install next-intl
Step 2: Configuring next-intl in next.config.js
To integrate next-intl with your existing configuration, we’ll wrap it with the next-intl plugin while retaining uniform configuration support. Add add additional instance of remotePatterns. Modify your next.config.js as follows:
By wrapping the configuration with withUniformConfig and withNextIntl, we enable both uniform and next-intl support, making it possible to use locale-based routing in combination with uniform localization.
Step3: Wrapping the App in NextIntlClientProvider
To activate next-intl across the application, wrap it in NextIntlClientProvider. Open app/layout.tsx and add NextIntlClientProvider to the layout structure. Your updated layout should look like this:
import { ReactNode } from 'react';
import { NextIntlClientProvider } from 'next-intl';
import { ThemeProvider as NextThemeProvider } from 'next-themes';
import { UniformContext } from '@uniformdev/canvas-next-rsc';
import '@/styles/globals.css';
export default function Layout({ children }: { children: ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<NextIntlClientProvider>
<NextThemeProvider attribute="class" defaultTheme="light" enableSystem>
<UniformContext>{children}</UniformContext>
</NextThemeProvider>
</NextIntlClientProvider>
</body>
</html>
);
}
This change enables localization across all components, giving you access to next-intl’s advanced localization features within a uniform context.
Step 4: Creating the Request Configuration (request.ts)
The request.ts file in src/i18n lets you set up request configurations for locales. This ensures that the locale is selected based on the URL or defaults to a supported locale if necessary:
import { getRequestConfig } from 'next-intl/server';
import { routing } from './routing';
export default getRequestConfig(async ({ requestLocale }) => {
let locale = (await requestLocale) as (typeof routing)['defaultLocale'];
if (!locale || !routing.locales.includes(locale)) {
locale = routing.defaultLocale;
}
return {
locale,
};
});
Why This File is Necessary
This setup validates the locale against the supported list, ensuring that only valid locales are processed and setting a default where needed. This enhances stability for users across different locales.
Step 5: Defining Routing in routing.ts
Next, create a routing.ts file in src/i18n to manage locale-specific routes based on a configuration file (locales.json). Here’s the code:
import { defineRouting } from 'next-intl/routing';
import config from './locales.json';
export const routing = defineRouting(config);
Why This is Needed
This file enables URL-based locale routing based on locales.json. It dynamically updates the language setting based on the URL structure, improving SEO and user experience for multilingual setups.
Step 6: Adding Middleware for Locale Routing
To ensure consistent locale routing across all routes, add middleware for next-intl in src/middleware.ts. This middleware intercepts requests, managing locale-based routing and ensuring compatibility with next-intl. Here’s the middleware configuration:
import createMiddleware from 'next-intl/middleware';
import { routing } from './i18n/routing';
export default createMiddleware(routing);
export const config = {
// Match all routes but exclude _next, static, and API routes
matcher: ['/((?!_next|static|api|favicon.ico|robots.txt|sitemap.xml).*)'],
};
The matcher excludes internal and static routes, ensuring that middleware only applies to relevant pages.
Step 7: Removing Custom retrieveRoute Function in page.tsx
With next-intl managing localization, we no longer need a custom retrieveRoute function. We can import retrieveRoute directly from @uniformdev/canvas-next-rsc, as shown below:
import { cookies } from 'next/headers';
import { notFound } from 'next/navigation';
import {
createServerUniformContext,
ContextUpdateTransfer,
retrieveRoute,
PageParameters,
UniformComposition,
} from '@uniformdev/canvas-next-rsc';
import { ThemePackProvider } from '@uniformdev/theme-pack/components';
import componentResolver from '@/components';
import { isRouteWithoutErrors } from '@/utils';
export default async function Home(props: PageParameters) {
const route = await retrieveRoute(props);
const serverContext = await createServerUniformContext({
searchParams: props.searchParams,
});
const theme = cookies().get('theme')?.value || 'light';
if (!isRouteWithoutErrors(route)) return notFound();
return (
<ThemePackProvider>
<ContextUpdateTransfer
serverContext={serverContext}
update={{
quirks: {
theme,
},
}}
/>
<UniformComposition
{...props}
route={route}
resolveComponent={componentResolver}
serverContext={serverContext}
mode="server"
/>
</ThemePackProvider>
);
}
export { generateMetadata } from '@/utils/generateMetadata';
Removing the custom retrieveRoute function reduces redundancy, leveraging next-intl and uniform functionality together for a simplified setup.
Conclusion
In today’s global digital landscape, localization is not just a feature; it’s a crucial element for reaching and engaging users worldwide. By transitioning from the built-in CSK localization to next-intl, you’re equipping your Next.js application with a sophisticated, flexible localization system that meets the demands of a production-ready, multilingual app. This migration empowers your application with several key benefits:
Advanced Locale Management: With next-intl, your app can seamlessly manage multiple languages through URL-based routing. This approach improves user experience, enabling visitors to easily navigate in their preferred language while adhering to best practices for SEO, as search engines can now index language-specific routes.
Enhanced Configuration and Control: The integration of next-intl brings increased customization options, allowing you to define and manage routes, request configurations, and middleware. This flexibility lets you create a finely-tuned localization setup that caters to specific business requirements, such as region-based content variations or locale-based UI adjustments.
Improved Performance and Scalability: The architecture of next-intl aligns well with Next.js, ensuring that as your application scales and your localization needs evolve, you won’t encounter performance bottlenecks. By centralizing localization in one powerful package, future updates, new language additions, and content adjustments become more efficient and manageable.
Simplified Maintenance and Uniform Compatibility: With next-intl and uniform’s uniform context support, your localization infrastructure is both efficient and maintainable. Leveraging retrieveRoute from @uniformdev/canvas-next-rsc eliminates redundant code, simplifying the codebase and reducing the likelihood of future compatibility issues.
Integrating next-intl not only future-proofs your application but also establishes a foundation for agile growth in multilingual environments. As your project continues to expand, this setup ensures that adding more languages, tailoring region-specific content, or adjusting routes for new locales can be accomplished without major refactoring.