When using external modules or sibling packages in a monorepo, you have two configuration strategies:
1. Extract messages into the main app
If you want your main Next.js app to own all messages, configure srcPath in createNextIntlPlugin to include the source directories of your external packages. This will extract their messages into your app's message directory.
2. Ship messages with the external package
If your shared package is used by multiple apps, follow these steps:
- Extract messages during the package build: Use
unstable_extractMessages from next-intl/extractor in your package's build process. - Configure the consuming app:
- Set
extract.path to only extract first-party messages. - Include the external package's messages in the
messages.path array. - Use Next.js
transpilePackages to ensure useExtracted is compiled to useTranslations in the external package. - Merge the messages in
getRequestConfig (e.g., in i18n/request.ts).
// Strategy 1: Include external paths in srcPath
const withNextIntl = createNextIntlPlugin({
experimental: {
extract: true,
messages: {
path: './messages',
format: 'json',
locales: 'infer',
sourceLocale: 'en'
},
srcPath: [
'./src',
'../ui/src',
'./node_modules/@acme/components'
]
}
});
// Strategy 2: Consuming app configuration
// next.config.ts
const withNextIntl = createNextIntlPlugin({
experimental: {
extract: {
path: './messages'
},
messages: {
path: [
'./messages',
'../ui/messages',
'./node_modules/@acme/components/messages'
],
format: 'po',
locales: 'infer',
sourceLocale: 'en'
},
srcPath: './src'
}
});
const nextConfig = {
transpilePackages: ['@acme/ui', '@acme/components']
};
// i18n/request.ts
const messages = {
...(await import(`@acme/ui/messages/${locale}.po`)).default,
...(await import(`@acme/components/messages/${locale}.po`)).default,
...(await import(`../../messages/${locale}.po`)).default
};