Next.js 的国际化 (i18n) 功能与 `react-i18next` 结合使用
前言
将 Next.js 的国际化 (i18n) 功能与 react-i18next 结合使用是一个常见的做法。您已经在项目中引入了 i18next 和 react-i18next,并且在 中配置了 Next.js 的 i18n 路由。
以下是如何将它们更好地结合起来的步骤和建议:
-
确保
i18next初始化正确:
您已经在 文件中初始化了i18n。这是一个很好的起点。请确保supportedLngs与 中的locales一致。// typescript:src/i18n.ts // ... existing code ... i18n.use(initReactI18next).init({ fallbackLng: 'en', // 确保与 next.config.ts 的 defaultLocale 一致或兼容 supportedLngs: ['en', 'zh'], // 确保与 next.config.ts 的 locales 一致 // lng: 'en', // 通常不需要在这里硬编码 lng,Next.js 的路由会处理当前语言 resources: { en: { translation: { welcome: 'Welcome', chat: 'Go to Chat', // ...更多英文翻译 }, }, zh: { translation: { welcome: '欢迎', chat: '进入聊天', // ...更多中文翻译 }, }, }, // interpolation: { // 如果需要,可以配置插值 // escapeValue: false, // }, // debug: process.env.NODE_ENV === 'development', // 开发模式下开启 debug }); // ... existing code ... -
在应用顶层提供
I18nextProvider:
为了让react-i18next的 hooks (如useTranslation) 能够在您的组件中使用,您需要在应用的根布局 () 中包裹您的children。首先,您可能需要创建一个客户端组件来包裹
I18nextProvider,因为i18n实例的传递通常在客户端进行。创建一个新的客户端组件,例如
src/components/I18nProviderWrapper.tsx:// typescript:src/components/I18nProviderWrapper.tsx 'use client' import { I18nextProvider } from 'react-i18next' import i18n from '@/i18n' // 确保路径正确 export default function I18nProviderWrapper({ children }: { children: React.ReactNode }) { return <I18nextProvider i18n={i18n}>{children}</I18nextProvider> }然后,在您的根布局 中使用它:
tsx:src/app/layout.tsx // ... existing code ... import I18nProviderWrapper from "@/components/I18nProviderWrapper"; // 导入包装器 // ... existing code ... export default function RootLayout({ children, params, // Next.js 13+ App Router 会传递 params,其中包含 locale }: Readonly<{ children: React.ReactNode params: { locale: string } // 添加 locale 到 params 类型 }>) { // 如果 i18n 实例需要根据 locale 动态改变语言,可以在这里处理 // useEffect(() => { // if (params.locale && i18n.language !== params.locale) { // i18n.changeLanguage(params.locale); // } // }, [params.locale]); // 注意:上面的 useEffect 逻辑更适合放在 I18nProviderWrapper 内部,因为它是一个客户端组件 return ( <html lang={params.locale}> {/* 使用 Next.js 提供的 locale */} <body className={`${geistSans.variable} ${geistMono.variable} antialiased `}> <I18nProviderWrapper> {children} </I18nProviderWrapper> <WebVitals /> <Toaster /> </body> </html> ) }重要: 在 App Router 中,
params.locale会自动从 URL 中获取 (例如/en/some-page或/zh/some-page)。您应该使用这个params.locale来设置<html>标签的lang属性。
i18next也可以配置为自动检测浏览器语言或从params.locale更新语言。通常,i18next-http-middleware或i18next-browser-languagedetector可以帮助处理语言检测,但与 Next.js 的内置 i18n 路由结合时,Next.js 自身会处理 URL 中的 locale。修改
src/components/I18nProviderWrapper.tsx以响应locale变化:// typescript:src/components/I18nProviderWrapper.tsx 'use client' import { I18nextProvider } from 'react-i18next' import i18n from '@/i18n' // 确保路径正确 import { useParams } from 'next/navigation' // 用于获取 locale import { useEffect } from 'react' export default function I18nProviderWrapper({ children }: { children: React.ReactNode }) { const params = useParams() const locale = params.locale as string | undefined useEffect(() => { if (locale && i18n.language !== locale) { i18n.changeLanguage(locale); } }, [locale]) return <I18nextProvider i18n={i18n}>{children}</I18nextProvider> } -
在组件中使用翻译:
现在您可以在您的客户端组件中使用useTranslationhook。例如,在 (如果它是一个客户端组件) 或者任何其他客户端组件中:
// tsx:src/components/ChatPanel.tsx 'use client' // ... other imports ... import { useTranslation } from 'react-i18next'; // ... existing code ... export default function ChatPanel({ initialConversationId, currentUser }: ChatPanelProps) { const { t } = useTranslation(); // ... existing code ... return ( <Card className="flex flex-col h-full w-full max-w-4xl mx-auto bg-card shadow-xl rounded-lg"> <CardHeader className="border-b p-4"> {/* 示例:使用 t 函数进行翻译 */} <CardTitle>{t('chat')}</CardTitle> </CardHeader> {/* ... rest of your component ... */} <CardFooter className="p-4 border-t"> <form onSubmit={handleSubmit} className="flex w-full items-center space-x-2"> <Input type="text" value={input} onChange={handleInputChange} placeholder={t('typeYourMessage')} // 示例翻译 disabled={isLoading} className="flex-1" /> <Button type="submit" disabled={isLoading || !input.trim()}> {isLoading ? t('sending') : t('send')} {/* 示例翻译 */} </Button> </form> </CardFooter> </Card> ); }确保您在 的
resources中添加了对应的翻译键,例如typeYourMessage,sending,send。 -
语言切换:
Next.js 的 i18n 路由允许通过更改 URL 路径来切换语言 (例如,从/en/about到/zh/about)。您可以使用next/link或next/router来实现语言切换链接或按钮。例如,一个简单的语言切换组件:
tsx:src/components/LanguageSwitcher.tsx 'use client' import { usePathname, useRouter } from 'next/navigation' import { useTranslation } from 'react-i18next' export default function LanguageSwitcher() { const { i18n } = useTranslation() const pathname = usePathname() const router = useRouter() const changeLanguage = (lng: string) => { // Next.js i18n routing will handle the locale prefix // We need to remove the current locale from pathname if it exists const currentLocale = i18n.language; let newPath = pathname; if (pathname.startsWith(`/${currentLocale}`)) { newPath = pathname.replace(`/${currentLocale}`, ''); } if (newPath === '') newPath = '/'; // Handle root path router.push(`/${lng}${newPath}`); } return ( <div> <button onClick={() => changeLanguage('en')} disabled={i18n.language === 'en'}> English </button> <button onClick={() => changeLanguage('zh')} disabled={i18n.language === 'zh'}> 中文 </button> </div> ) }您可以将这个 组件放置在您的导航栏或其他合适的位置。
-
服务端组件 (RSC) 中的国际化:
对于服务端组件,useTranslationhook 不可用。您需要一种不同的策略。一种常见的方法是创建一个接受locale作为 prop 的函数,并直接使用i18next实例来获取翻译。例如,创建一个
src/lib/t.ts(或类似名称):// typescript:src/lib/t.ts import i18n from '@/i18n'; // 您的 i18n 实例 export const getTranslations = async (locale: string, ns: string | string[] = 'translation') => { // 确保 i18n 实例已加载对应语言的资源 // 这可能需要您在服务器启动时或构建时加载所有语言资源 // 或者使用 i18next-fs-backend 等插件按需加载 if (i18n.language !== locale) { await i18n.changeLanguage(locale); } // 如果您有命名空间,确保它们已加载 // await i18n.loadNamespaces(ns); return { t: i18n.getFixedT(locale, ns), }; };然后在您的服务端组件中使用它:
// tsx:src/app/page.tsx // 假设这是一个服务端组件 import { getTranslations } from '@/lib/t'; export default async function HomePage({ params }: { params: { locale: string } }) { const { t } = await getTranslations(params.locale); return ( <div> <h1>{t('welcome')}</h1> <a href={`/${params.locale}/chat`}>{t('chat')}</a> </div> ); }注意:在服务端组件中使用
i18next.changeLanguage可能会有并发问题,因为它会改变全局实例的状态。更安全的方法是确保i18next实例在请求级别是隔离的,或者使用i18n.getFixedT(locale, namespace),它返回一个绑定到特定语言和命名空间的t函数,而不会改变全局实例的语言。
对于 Next.js App Router,推荐的做法是利用params.locale并传递给获取翻译的函数。
通过这些步骤,您可以有效地将 Next.js 的 i18n 路由与 react-i18next 结合起来,实现客户端和(通过一些调整)服务端组件的国际化。
这些是核心的集成步骤。根据您的具体需求,可能还需要进一步的配置,例如处理更复杂的翻译加载策略 (如代码分割命名空间) 或更高级的 i18next 功能。
注意app router 与 page route Next.config.ts 的使用问题:


更多推荐



所有评论(0)