Skip to content
文档使用指南Next.js 插件

Next.js 插件 (createNextIntlPlugin)

在为 App Router 设置 next-intl 时,您需要将 next-intl/plugin 添加到您的 Next.js 配置中。

最简单的配置示例如下:

next.config.ts
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 扩展名进行查找。

如果您想把此文件移动到其他地方,可以向插件提供路径:

next.config.ts
const withNextIntl = createNextIntlPlugin(
  // 在此指定自定义路径
  './somewhere/else/request.ts'
);

或者,如果您同时使用其他选项,可以使用 requestConfig 选项:

next.config.ts
const withNextIntl = createNextIntlPlugin({
  requestConfig: './somewhere/else/request.ts'
});

experimental

对于早期使用者,Next.js 插件提供了各种实验性选项,让您能在新功能发布为稳定版本前尝试它们。

createMessagesDeclaration

要启用类型安全的消息参数,您可以将 createMessagesDeclaration 选项指向一个示例消息文件,以生成严格的声明文件。

next.config.ts
const withNextIntl = createNextIntlPlugin({
  experimental: {
    // 提供您在 `AppConfig` 中使用的消息路径
    createMessagesDeclaration: './messages/en.json'
  }
  // ...
});

有关详情,请参见 TypeScript 增强

注意: 当使用 useExtracted 时,无需此步骤。

extract

此选项启用使用 useExtracted,可自动从源文件中提取消息。

const withNextIntl = createNextIntlPlugin({
  experimental: {
    extract: {
      // 定义要提取的源语言环境
      sourceLocale: 'en'
    }
    // ...
  }
});

注意: extract 选项应与 messagessrcPath 一起使用。

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/extractordefineCodec 创建:

./CustomCodec.ts
import {defineCodec} from 'next-intl/extractor';
 
export default defineCodec(() => ({
  decode(content, context) {
    // ...
  },
 
  encode(messages, context) {
    // ...
  },
 
  toJSONString(content, context) {
    // ...
  }
}));

随后,在配置中引用该 codec 和一个扩展名:

next.config.ts
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;

另见:使用 next-intl 的预编译

注意: 预编译的消息不支持 t.raw(详见权衡

如何手动预编译消息?

对于未通过 import 导入消息(例如运行时动态获取消息)的情况,您可以使用 icu-minify/compile 手动预编译它们:

i18n/request.ts
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 数组中。

如果您希望随包提供消息,也可以手动提取

注意: srcPath 选项应与 extractmessages 共同使用。