You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 13 App Router集成react-intl的替代方案咨询

Next.js 13 App Router 集成 react-intl 的替代方案

App Router 不再支持 next/router 的 useRouter 钩子,但可以通过服务器组件API、客户端专用钩子及配置复用的方式获取国际化信息,核心是拿到当前locale、支持的locales列表、默认defaultLocale三个关键值,再结合翻译messages初始化IntlProvider。


方案1:服务器组件中获取(推荐,适合根布局)

服务器组件可直接访问路由参数和项目配置,适合在根layout.tsx中处理,避免客户端额外请求:

步骤1:抽离国际化配置

把next.config.mjs中的i18n配置抽成单独可导入的文件(如src/config/i18n.ts),方便组件复用:

// src/config/i18n.ts
export const i18nConfig = {
  locales: ["en", "es"],
  defaultLocale: "en",
};

步骤2:更新next.config.mjs

导入抽离的配置,保持配置统一:

// next.config.mjs
import { i18nConfig } from './src/config/i18n.js';

const nextConfig = {
  reactStrictMode: true,
  i18n: i18nConfig,
};

export default nextConfig;

步骤3:根布局中传递国际化参数

在app/[locale]/layout.tsx(服务器组件)中,从路由参数获取当前locale,再传递给客户端的IntlProvider包装组件:

// app/[locale]/layout.tsx
import { i18nConfig } from '@/config/i18n';
import IntlProviderWrapper from './IntlProviderWrapper';
import type { Metadata } from 'next';

export const metadata: Metadata = {
  title: 'My App',
  description: 'Next.js 13 + react-intl',
};

export default function RootLayout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: { locale: string };
}) {
  const currentLocale = params.locale;
  const { locales, defaultLocale } = i18nConfig;

  return (
    <html lang={currentLocale}>
      <body>
        <IntlProviderWrapper
          locale={currentLocale}
          defaultLocale={defaultLocale}
          locales={locales}
        >
          {children}
        </IntlProviderWrapper>
      </body>
    </html>
  );
}

步骤4:客户端组件初始化IntlProvider

创建客户端组件IntlProviderWrapper.tsx,加载对应locale的翻译文件并初始化IntlProvider:

// app/[locale]/IntlProviderWrapper.tsx
'use client';

import { IntlProvider } from 'react-intl';
import { useEffect, useState } from 'react';

type Props = {
  locale: string;
  defaultLocale: string;
  locales: string[];
  children: React.ReactNode;
};

// 动态加载翻译文件(假设文件放在public/locales/[locale].json)
const loadMessages = async (locale: string) => {
  const response = await fetch(`/locales/${locale}.json`);
  return response.json();
};

export default function IntlProviderWrapper({ locale, defaultLocale, children }: Props) {
  const [messages, setMessages] = useState<Record<string, string>>({});

  useEffect(() => {
    loadMessages(locale).then(setMessages);
  }, [locale]);

  if (Object.keys(messages).length === 0) return <div>Loading...</div>;

  return (
    <IntlProvider
      locale={locale}
      messages={messages}
      defaultLocale={defaultLocale}
    >
      {children}
    </IntlProvider>
  );
}

方案2:客户端组件使用useLocale钩子

如果需要在客户端组件中直接获取当前locale,可使用App Router提供的useLocale钩子,结合抽离的配置获取其他国际化参数:

'use client';

import { IntlProvider } from 'react-intl';
import { useLocale } from 'next/navigation';
import { i18nConfig } from '@/config/i18n';
import { useEffect, useState } from 'react';

const loadMessages = async (locale: string) => {
  const response = await fetch(`/locales/${locale}.json`);
  return response.json();
};

export default function ClientIntlWrapper({ children }: { children: React.ReactNode }) {
  const locale = useLocale();
  const { defaultLocale } = i18nConfig;
  const [messages, setMessages] = useState<Record<string, string>>({});

  useEffect(() => {
    loadMessages(locale).then(setMessages);
  }, [locale]);

  if (Object.keys(messages).length === 0) return <div>Loading...</div>;

  return (
    <IntlProvider
      locale={locale}
      messages={messages}
      defaultLocale={defaultLocale}
    >
      {children}
    </IntlProvider>
  );
}

方案3:静态导入所有翻译文件(小型项目适用)

如果项目locale数量少,可直接静态导入所有翻译文件,避免动态请求:

'use client';

import { IntlProvider } from 'react-intl';
import { useLocale } from 'next/navigation';
import { i18nConfig } from '@/config/i18n';
import enMessages from '@/locales/en.json';
import esMessages from '@/locales/es.json';

const messagesMap = {
  en: enMessages,
  es: esMessages,
};

export default function StaticIntlWrapper({ children }: { children: React.ReactNode }) {
  const locale = useLocale();
  const { defaultLocale } = i18nConfig;
  const messages = messagesMap[locale as keyof typeof messagesMap] || enMessages;

  return (
    <IntlProvider
      locale={locale}
      messages={messages}
      defaultLocale={defaultLocale}
    >
      {children}
    </IntlProvider>
  );
}

注意事项

  • 确保路由结构为app/[locale]/的动态路由,Next.js会自动匹配对应locale;
  • 翻译文件路径可根据项目结构调整(如src/locales或public/locales);
  • 服务器组件中不能使用客户端钩子(如useLocale),根布局推荐用服务器组件获取locale后传递给客户端包装组件。

内容的提问来源于stack exchange,提问作者Richie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 18:05:35