Docs
/
Next.js 13
/
Server Components (preview)

Usage in Server Components (preview)

Next.js 13 introduces support for React Server Components in the app directory. next-intl is adopting the new capabilities and is currently offering a preview to early adopters, who are already building apps with the app directory.

💡

The app directory is currently in beta, patterns are still emerging and APIs may change. Please use this at your own risk, knowing that you might have to face a migration effort when the app directory becomes stable. next-intl tries to stay up to date with the latest developments on the Next.js side, but during this period there can be unexpected issues.

Current preview version

npm install next-intl@2.11.0-alpha.4

This preview version was tested with next@13.0.6.

Getting started

If you haven't done so already, create a Next.js 13 app that uses the app directory. The goal is to prefix all routes with the locale, so we can retrieve it as a dynamic segment and use it to configure next-intl.

Start by creating the following file structure:

├── i18n.tsx (1)
├── tsconfig.json (2)
├── middleware.tsx (3)
├── messages (4)
│   ├── en.json
│   └── ...
└── app
    ├── [locale]
    │   ├── layout.tsx (5)
    │   └── page.tsx (6)
    └── ...

Now, set up these files as follows:

  1. Define your configuration in i18n.tsx:
import {NextIntlConfig} from 'next-intl';

const config: NextIntlConfig = {
  locales: ['en', 'de'],
  defaultLocale: 'en',
  async getMessages({locale}) {
    return (await import(`../messages/${locale}.json`)).default;
  }
};

export default config;
  1. Link to your configuration in tsconfig.json:
{
  "compilerOptions": {
    "paths": {
      "next-intl/config": ["./i18n"]
    },
    ...
  }
}
  1. Create a middleware that handles redirects in middleware.tsx:
import {createIntlMiddleware} from 'next-intl/server';

// This middleware intercepts requests to `/` and will redirect
// to one of the configured locales instead (e.g. `/en`). A cookie
// is set in the background, so if the user switches to a new
// language, this language will take precedence from now on.
export default createIntlMiddleware();
  1. Set up messages for a language, e.g. in messages/en.json:
{
  "Index": {
    "title": "Hello world!"
  }
}
  1. Pass your received locale to NextIntlServerProvider in app/[locale]/layout.tsx:
import {NextIntlServerProvider} from 'next-intl/server';

export default async function LocaleLayout({children, params: {locale}}) {
  return (
    <NextIntlServerProvider locale={locale}>{children}</NextIntlServerProvider>
  );
}
  1. Use translations in your page component in app/[locale]/page.tsx or anywhere else!
import {useTranslations} from 'next-intl';

export default function Index() {
  const t = useTranslations('Index');
  return <h1>{t('title')}</h1>;
}

That's all it takes! Now you can internationalize your apps without adding i18n features to your client bundle.

If you've encountered an issue, you can explore the code for a working example (demo).

If you're in a transitioning phase, either from the pages directory to the app directory, or from Client Components the the Server Components preview, you can apply NextIntlClientProvider additionally.

Switching to Client Components

If you need to use translations in Client Components, the best approach is to pass the generated labels as props.

// app/[locale]/page.tsx
import {useTranslations} from 'next-intl';
import Counter from './Counter';

export default function Index() {
  const t = useTranslations('Index');
  return <Counter title={t('counterTitle')} />;
}
// app/[locale]/Counter.tsx
'use client';

import {useState} from 'react';

function Counter({title}) {
  const [count, setCount] = useState(0);

  function onIncrement() {
    setCount(count + 1);
  }

  return (
    <p>
      {title}: {count} <button onClick={onIncrement}>+</button>
    </p>
  );
}

This way your messages never leave the server and the client only needs to load the code that is necessary for initializing your interactive components.

If you absolutely need to use functionality from next-intl on the client side, you can wrap the respective components with NextIntlClientProvider (example code). Note however that this will increase your client bundle size.

Providing feedback

If you have feedback about using next-intl in the app directory, feel free to leave feedback in the PR which implements the React Server Components support.