Skip to content

Nextjs

VoerkaI18nNextjs应用的国际化解决方案提供了一个全新的解决方案!

Nextjs应用引入国际化需要引入以下插件:

  • @voerkai18n/nextjs

    Nextjs插件,提供访问当前语言切换语言自动更新等功能。

使用方法

第1步:安装依赖

首先安装@voerkai18n/cli到全局.

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
    • src
      • 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
    • index.ts

React应用不同的是,Nextjs应用需要提供服务端入口客户端入口

第3步:启用Nextjs支持

接下需要voerkai18n apply来启用Nextjs支持。

bash
> voerkai18n apply

执行voerkai18n apply命令后,选择Nextjs后,会执行以下操作:

  • 安装@voerkai18n/nextjs
  • 更新languages的相关文件,主要是server.tsclient.ts

提示

也可以手动安装@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
};

提示

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的常见的问题,开发者需要充分了解Nextjshydration机制。

相关问题可以参考Nextjs文档以及这里

提示

  • 有时chrome相关插件也会导致hydration错误,因为某些插件可能会在DOM中注入内容而导致hydrated错误。
  • VoerkaI18n默认会在body注入lang属性,可能会导致hydration error,因此需要在settings.json中设置injectLangAttrtrue

示例