Next.js 插件 (createNextIntlPlugin)
在为 App Router 设置 next-intl 时,您需要将 next-intl/plugin 添加到您的 Next.js 配置中。
最简单的配置示例如下:
import {NextConfig} from 'next';
import createNextIntlPlugin from 'next-intl/plugin';
const nextConfig: NextConfig = {};
const withNextIntl = createNextIntlPlugin();
export default withNextIntl(nextConfig);若要自定义,您可以向插件传递选项。
requestConfig
默认情况下,next-intl 会查找一个名为 i18n/request.ts 的文件,该文件返回请求特定的配置。此文件会在 src 文件夹和项目根目录中以 .ts、.tsx、.js 和 .jsx 扩展名进行查找。
如果您想把此文件移动到其他地方,可以向插件提供路径:
const withNextIntl = createNextIntlPlugin(
// 在此指定自定义路径
'./somewhere/else/request.ts'
);或者,如果您同时使用其他选项,可以使用 requestConfig 选项:
const withNextIntl = createNextIntlPlugin({
requestConfig: './somewhere/else/request.ts'
});experimental
对于早期使用者,Next.js 插件提供了各种实验性选项,让您能在新功能发布为稳定版本前尝试它们。
createMessagesDeclaration
要启用类型安全的消息参数,您可以将 createMessagesDeclaration 选项指向一个示例消息文件,以生成严格的声明文件。
const withNextIntl = createNextIntlPlugin({
experimental: {
// 提供您在 `AppConfig` 中使用的消息路径
createMessagesDeclaration: './messages/en.json'
}
// ...
});有关详情,请参见 TypeScript 增强。
注意: 当使用 useExtracted 时,无需此步骤。
extract
此选项启用使用 useExtracted,可自动从源文件中提取消息。
const withNextIntl = createNextIntlPlugin({
experimental: {
extract: {
// 定义要提取的源语言环境
sourceLocale: 'en'
}
// ...
}
});注意: extract 选项应与 messages 和 srcPath 一起使用。
messages
此选项定义了消息文件的存储位置以及加载方式。
const withNextIntl = createNextIntlPlugin({
experimental: {
messages: {
format: 'json',
locales: 'infer',
path: './messages',
// 可选
precompile: true
}
}
});配置 experimental.messages 时,会设置一个 Turbo- 或 Webpack 加载器,可将消息导入为普通的 JavaScript 对象(详见 format)。
path
消息目录的相对路径:
// ...
path: './messages';locales
当使用 useExtracted 时,定义了要与 extract.sourceLocale 保持同步的语言环境消息。
您可以自动检测 messages.path 目录下的所有语言环境:
// ...
locales: 'infer';或者显式指定(例如使用一个子集):
// ...
locales: ['en', 'de', 'fr'];format
定义消息目录的存储格式(如 'json'、'po' 或自定义格式)。
JSON 格式
若使用此选项,您的消息文件可能如下所示:
{
"greeting": "Hello"
}或者在使用 useExtracted 时,使用自动生成的键:
{
"NhX4DJ": "Hello"
}您可以使用诸如 VSCode 集成(比如 i18n Ally)进行 JSON 消息的本地编辑。
注意,JSON 文件只能存储键值对。如果需要为消息提供更多上下文信息(如文件引用和描述),可使用 PO 文件 或创建一个包含附加元数据的 自定义格式。
PO 格式
若使用此选项,您的消息文件示例如下:
#. Advance to the next slide
#: src/components/Carousel.tsx:13
msgid "carousel.next"
msgstr "Right"或者在使用 useExtracted 时,使用自动生成的键:
#. Advance to the next slide
#: src/components/Carousel.tsx:13
msgid "5VpL9Z"
msgstr "Right"除了消息键和文本之外,该格式还支持可选的描述和对所有使用此消息模块的文件的引用。
您可以使用例如 Poedit 等工具来本地编辑 .po 文件。
自定义格式
要配置自定义格式,需要指定一个 codec 及其对应的扩展名。
codec 可通过 next-intl/extractor 的 defineCodec 创建:
import {defineCodec} from 'next-intl/extractor';
export default defineCodec(() => ({
decode(content, context) {
// ...
},
encode(messages, context) {
// ...
},
toJSONString(content, context) {
// ...
}
}));随后,在配置中引用该 codec 和一个扩展名:
const withNextIntl = createNextIntlPlugin({
experimental: {
messages: {
format: {
codec: './CustomCodec.ts',
extension: '.json'
}
// ...
}
}
});另外可参考内置的 codecs 以获取灵感,以及提供的类型和 JSDoc 说明。
Node.js 从 v22.18 开始原生支持 TypeScript 执行,如上示例所需。如果您的版本较旧,建议将 codec 定义为 JavaScript 文件。
precompile
作为性能优化,您可以在构建时提前预编译消息,从而获得更小的包体积和更快的运行时消息格式化:
const withNextIntl = createNextIntlPlugin({
experimental: {
messages: {
path: './messages',
locales: 'infer',
format: 'json',
precompile: true
}
// ...
}
});根据所提供的选项,导入消息时将自动进行预编译:
// ✅ 会被 Turbo- 或 Webpack 加载器预处理
const messages = (await import(`../../messages/en.json`)).default;注意: 预编译的消息不支持 t.raw(详见权衡)
如何手动预编译消息?
对于未通过 import 导入消息(例如运行时动态获取消息)的情况,您可以使用 icu-minify/compile 手动预编译它们:
import compile from 'icu-minify/compile';
import {getRequestConfig} from 'next-intl/server';
type Messages = Record<string, unknown>;
function compileMessages(messages: Messages): Messages {
return Object.fromEntries(
Object.entries(messages).map(([key, value]) => {
if (value && typeof value === 'object') {
return [key, compileMessages(value as Messages)];
}
if (typeof value === 'string') {
return [key, compile(value)];
}
throw new Error(`Unexpected message: ${typeof value}`);
})
);
}
export default getRequestConfig(async () => {
const response = await fetch('https://cdn.example.com/messages/en.json');
const messages = (await response.json()) as Messages;
const compiled = compileMessages(messages);
return {
messages: compiled
// ...
};
});如果使用此方式,确保 icu-minify 版本与您所使用的 next-intl 版本依赖的版本一致,以保证兼容性。
srcPath
此选项定义消息应从哪个源路径提取。
const withNextIntl = createNextIntlPlugin({
experimental: {
srcPath: './src'
// ...
}
});如果项目划分在多个文件夹中,您可以提供一个路径数组:
// 不使用 `src` 文件夹
srcPath: './',// Monorepo 多包结构
srcPath: ['./src', '../ui'],// 依赖于外部包
srcPath: ['./src', './node_modules/@acme/components'],注意,node_modules、.next 和 .git 目录会自动被排除提取,除非它们被显式列在 srcPath 数组中。
如果您希望随包提供消息,也可以手动提取。