最近VoerkaI18n
新出了3.0
版本,功能更加强大易用,针对NextJs
提供了全方面的适配,这可能是最好的NextJs国际化方案,没有之一。
VoerkaI18n
为Nextjs
应用的国际化解决方案提供了一个全新的解决方案!
在Nextjs
应用引入国际化需要引入以下插件:
-
@voerkai18n/nextjs
Nextjs插件 ,提供访问
当前语言
、切换语言
、自动更新
等功能。
使用方法
第1步:安装依赖
首先安装@voerkai18n/cli
到全局.
::: code-group
bash
npm install -g @voerkai18n/cli
bash
yarn global add @voerkai18n/cli
bash
pnpm add -g @voerkai18n/cli
:::
第2步:初始化
接着VoerkaI18n init
初始化工程。
bash
> voerkai18n init
初始化完成后,会创建一个语言工作目录,默认位置是src/languages
。文件夹结构如下:
myapp //i src //i languages messages/ paragraphs/ translates/ // 提取需要翻译的内容 messages/ // 提取的需要翻译的内容 paragraphs/ // 提取的需要翻译的段落 prompts/ // 执行AI翻译的相关提示词 api.json // API接口 component.tsx // 翻译组件 server.ts //! 服务端入口 client.ts //! 客户端入口 index.ts //! 客户端入口文件 settings.json // 配置文件 storage.ts // 存储管理 loader.ts // 加载器 transform.ts // 翻译变换 formatters.json // 格式化器配置 package.json //i index.ts //i
与React
应用不同的是,Nextjs
应用需要提供服务端入口
和客户端入口
。
第3步:启用Nextjs
支持
接下需要voerkai18n apply
来启用Nextjs
支持。
bash
> voerkai18n apply
执行voerkai18n apply
命令后,选择Nextjs
后,会执行以下操作:
- 安装
@voerkai18n/nextjs
- 更新
languages
的相关文件,主要是server.ts
和client.ts
。
:::warning 提示 也可以手动安装@voerkai18n/nextjs
,并更新languages
的相关文件。见下文手工配置。 :::
第4步:配置应用
不同于其他Nextjs
国际化方案,VoerkaI18n
不需配置相应的中间件配置,只需要客户端配置相应的组件即可。
修改app/layout.tsx
文件,引入VoerkaI18nNextjsProvider
。
tsx
import { VoerkaI18nNextjsProvider } from "@/languages/client";
// .....
export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
return (
<html lang="en">
<body >
<VoerkaI18nNextjsProvider fallback={<div>loading language...</div>}>
{children}
</VoerkaI18nNextjsProvider>
</body>
</html>
);
}
第5步:翻译内容
Nextjs
应用组件包括服务端组件
和客户端组件
两部分,需要导入不同的组件。
- 服务端组件
tsx
import { Translate } from "@/languages/server";
export default async function Server() {
return (<div>
<Translate message="服务端组件"/>
</div>)
}
- 客户端组件
tsx
import { Translate } from "@/languages/client";
export default async function Client() {
return (<div>
<Translate message="客户端组件"/>
</div>)
}
第6步:切换语言
引入useVoerkaI18n
来实现切换语言的功能。
tsx
'use client'
import React from 'react';
import { useVoerkaI18n } from "@voerkai18n/nextjs/client";
import classNames from 'classnames'
const LanguageBar: React.FC = () => {
const { activeLanguage, changeLanguage, languages } = useVoerkaI18n();
return (
<div className="flex md:order-2 flex-row justify-items-center align-middle">
{ languages.map((lang) => {
return (<button
key={lang.name}
onClick={() => changeLanguage(lang.name) }
className={ lang.name === activeLanguage ? 'active' : ''}
>{lang.name}</button>)
})}
</div>
)
}
useVoerkaI18n
返回值:
ts
{
scope : VoerkaI18nScope
manager : VoerkaI18nManager
activeLanguage : string
defaultLanguage: string
languages : VoerkaI18nLanguage
changeLanguage : (language:string)=>Promise<string>,
t : VoerkaI18nTranslate
};
:::warning 提示 useVoerkaI18n
运行在客户端。 :::
指南
手动配置
voerkai18n apply
负责自动配置Nextjs
应用支持,也可以手动配置.
- 编辑
languages/client.{ts|js}
文件
ts
'use client'
import {
createClientTranslateComponent,
ReactTranslateComponentType
} from "@voerkai18n/nextjs/client"
import { VoerkaI18nScope, VoerkaI18nTranslateProps } from '@voerkai18n/runtime';
import formatters from "@voerkai18n/formatters"
import storage from "./storage"
import idMap from "./messages/idMap.json"
import paragraphs from "./paragraphs"
import settings from "./settings.json"
import defaultMessages from "./messages/zh-CN"
const component = createClientTranslateComponent()
const messages = {
'zh-CN' : defaultMessages,
'en-US' : ()=>import("./messages/en-US"),
'ja-JP' : ()=>import("./messages/ja-JP"),
}
export const i18nScope = new VoerkaI18nScope<ReactTranslateComponentType>({
id: "nextjs_client", // 当前作用域的id
idMap, // 消息id映射列表
injectLangAttr:false, // 不注入lang属性
formatters, // 格式化器
storage, // 语言配置存储器
messages, // 语言包
paragraphs, // 段落
component, // 翻译组件
...settings
})
export const t = i18nScope.t
export const Translate = i18nScope.Translate as React.FC<VoerkaI18nTranslateProps>
export { VoerkaI18nNextjsProvider } from "@voerkai18n/nextjs/client"
- 编辑
languages/server.{ts|js}
文件
ts
import {
createServerTranslateComponent,
ReactServerTranslateComponentType
} from "@voerkai18n/nextjs/server"
import { VoerkaI18nScope, VoerkaI18nTranslateProps } from '@voerkai18n/runtime';
import formatters from "@voerkai18n/formatters"
import storage from "./storage"
import idMap from "./messages/idMap.json"
import paragraphs from "./paragraphs"
import settings from "./settings.json"
import zhCNMessages from "./messages/zh-CN"
import enUSMessages from "./messages/en-US";
import jaJPMessages from "./messages/ja-JP";
const component = createServerTranslateComponent()
const messages = {
'zh-CN' : zhCNMessages,
'en-US' : enUSMessages,
'ja-JP' : jaJPMessages
}
export const i18nScope = new VoerkaI18nScope<ReactServerTranslateComponentType>({
id: "nextjs_server", // 当前作用域的id
injectLangAttr:false, // 不注入lang属性
idMap, // 消息id映射列表
formatters, // 格式化器
storage, // 语言配置存储器
messages, // 语言包
paragraphs,
component, // 翻译组件
...settings
})
export const t = i18nScope.t
export const Translate = i18nScope.Translate as React.FC<VoerkaI18nTranslateProps>
React
@voerkai18n/nextjs
依赖于@voerkai18n/react
,并且导出了@voerkai18n/react
的所有API。
详见@voerkai18n/react文档。
常见问题
- 如何处理hydration错误问题?
Nextjs
应用经常出现以下错误:
shell
A tree hydrated but some attributes of the server rendered
HTML didn't match the client properties. This won't be patched up.
This can happen if a SSR-ed Client Component used:
- A server/client branch `if (typeof window !== 'undefined')`.
- Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
- Date formatting in a user's locale which doesn't match the server.
- External changing data without sending a snapshot of it along with the HTML.
- Invalid HTML tag nesting.
这是Nextjs
的常见的问题,开发者需要充分了解Nextjs
的hydration
机制。
:::warning 提示
- 有时
chrome
相关插件也会导致hydration
错误,因为某些插件可能会在DOM中注入内容而导致hydrated
错误。 VoerkaI18n
默认会在body
注入lang
属性,可能会导致hydration error
,因此需要在settings.json
中设置injectLangAttr
为true
。 :::
示例
- 完整的示例请见这里