Internationalization using next-intl

Version:

A Content SDK app created from the Next.js App Router template ships with built-in integration for internationalization using next-intl. The integration handles the following:

  • Locale-aware routing (including multisite support).

  • Server and client component translation access patterns.

  • Dictionary phrase retrieval from Sitecore per site (namespaced by siteName).

You declare supported locales, configure the default locale, and control prefix behavior in src/i18n/routing.ts. You provide server-only resolution of locale plus dictionary phrases in src/i18n/request.ts.

Note

Before you begin, configure languages in SitecoreAI before wiring up application-level i18n.

Configuration files

Your application directory's i18n folder contains two integration files provided by the next-intl package to support internationalization.

  1. src/i18n/routing.ts - You must use this file to configure the following:

    • All supported locales

    • Default language

    • Locale prefix setting

    See the following example of the routing.ts file:

    import { defineRouting } from "next-intl/routing";
    import sitecoreConfig from "sitecore.config";
    
    export const routing = defineRouting({
      // A list of all locales that are supported
      locales: [sitecoreConfig.defaultLanguage, "de-DE", "fr-FR"],
    
      // Used when no locale matches
      defaultLocale: sitecoreConfig.defaultLanguage,
    
      // No prefix is added for the default locale ("as-needed")
      // For other configuration options, refer to the next-intl documentation:
      // https://next-intl.dev/docs/routing/configuration
      localePrefix: "as-needed",
    });
  2. src/i18n/request.ts - This file exposes the defineRequestConfig function from next-intl and resolves, per request, the current locale and associated dictionary phrases from Sitecore. This is then used by server components that can't use hooks.

Localized routing in multisite and SSG solutions

The Content SDK Next.js App Router template contains the following to support localized routing in multisite scenarios and static site generation (SSG):

  • Two leading segments as shown below in the catch-all route to match the current site and locale.

    [site]/[locale]/[[...path]]
  • localeMiddleware runs first in src/middleware.ts, resolving the current locale from the configured list, then handing it to subsequent middlewares.

  • generateStaticParams in the catch-all route enumerates all site + locale combinations, producing static parameters for SSG builds.

Component internationalization

Because of Next.js App Router semantics, translation access differs between async server components, regular server components, and client components. All translation retrieval in this setup is ultimately backed by phrases fetched from Sitecore using the dictionary service in request.ts, namespaced by page.siteName (or equivalent context), ensuring isolation across sites. For more information, see Internationalization of Server and Client Components.

  • Async server components - primarily fetch data and cannot use hooks. To support this next-intl provides awaitable versions of the functions that you usually call as hooks from within the components. You can use them as shown:

    ...
    import { getTranslations } from 'next-intl/server';
    
    type MyComponentProps = ComponentWithContextProps & {
      fields: {
        ...
      };
    };
    
    export const Dafault = async ({ fields, page }: MyComponentProps) => {
      const t = await getTranslations(page.siteName);
    
      return (
        <div className="contentBlock">
          <h5>{t('content-block-label')}</h5>
          ...
        </div>
      );
    };
  • Non-async server components - can use the useTranslations hook as shown below:

    ...
    import { useTranslations } from 'next-intl';
    
    type MyComponentProps = ComponentWithContextProps & {
      fields: {
        ...
      };
    };
    
    export const Dafault = ({ fields, page }: MyComponentProps): JSX.Element => {
      
      const t = useTranslations(page.siteName);
    
      return (
        <div className="contentBlock">
          <h5>{t('content-block-label')}</h5>
          ...
        </div>
      );
    };
  • Client components - receive locale and messages through NextIntlClientProvider, which the template adds by default to the catch-all route, Page.tsx. Client components use the same functions as the non-async server components:

    'use client'
    
    import { useTranslations } from 'next-intl';
    ...
    
    const t = useTranslations();
Note

To retrieve the current locale, you can the appropriate API based on the component type as shown:

// Regular Server & Client Components
import { useLocale } from 'next-intl';
const locale = useLocale();

// Async Server Components
import { getLocale } from 'next-intl/server';
const locale = await getLocale();

To learn more about client components and to optimize their performance, see the official next-intl documentation.

If you have suggestions for improving this article, let us know!