背景
随着京东国际团队的加入,多语言能力已是必然,而且还可以加速 nutui-react 组件库在公司内部项目中的落地,更加及时的发现 nutui-react 存在的问题,从而不断的进行打磨。
NutUI-React 国际化版本示例
1.安装 nutui-react
css
npm i @nutui/nutui-react
2.通过 ConfigProvider 组件配置多语言
javascript
// 引入多语言包
import en from "@nutui/nutui-react/dist/locales/en-US"
// 引入 ConfigProvider 组件
import {ConfigProvider} from "@nutui/nutui-react";
// 通过 ConfigProvider 包裹应用
ReactDOM.render(<ConfigProvider locale={en}>
<App/>
</ConfigProvider>, querySelector('#root'))
NutUI-React 如何实现国际化
nutui-react 多语言能力设计主要分为两个方面:对外( nutui-react 用户)提供具有国际化能力的组件和机制,目前 nutui-react 组件库提供 ConfigProvider 组件用于配制多语言。目前 nutui-react 组件库提供了中文简体、中文繁体、英文三个语言包,未来可能会增加泰语、印尼语、俄语、西班牙语等;对内(nutui-react 的贡献者)需要提供多语言基础能力支持,例如:本地预览多语言版本、多语言包规范、多语言文档翻译规范等。

NutUI-React 国际化实现
对于 nutui-react 的用户而言,ConfigProvider 组件是一大重点,其次便是 nutui-react 包中提供的多语言文件,文件路径为 @nutui/nutui-react/dist/locales 下。在此目录下除多语言文件外,还提供了对应的 typescript 类型文件。

nutui-react 用户除了可以使用 locales 文件夹下的多语言文件,也可以开发特有的多语言文件,只需按照 nutui-react 提供的多语言文件格式,创建新的文件即可。
csharp
{
save: '保存',
confirm: '确认',
cancel: '取消',
done: '完成',
noData: '暂无数据',
placeholder: '请输入内容',
select: '请选择',
video: {
errorTip: '视频加载失败',
clickRetry: '点击重试',
},
// 非完整版本,完整版本参考 nutui-react 代码库
...
}
上面代码是组件库中的 zh-CN 文案结构,实际使用以安装的 nutui-react 包中的结构为准。
假设在我的项目中,增加 nutui-react 未提供的泰文文案,只需在项目中创建相应的 js 文件,将上述代码进行翻译。
arduino
const TH = {
save: 'บันทึก',
confirm: 'ยืนยัน',
cancel: 'ยกเลิก',
done: 'เสร็จสิ้น',
noData: 'ยังไม่มีข้อมูล',
placeholder: 'โปรดป้อน',
select: 'โปรดเลือก',
video: {
errorTip: 'โหลดวิดีโอไม่สําเร็จ',
clickRetry: 'คลิกเพื่อลองอีกครั้ง',
},
// 非完整版本,完整版本参考 nutui-react 代码库
...
}
export default TH
之后将 ConfigProvider 组件的 locale 属性设置为 TH。ConfigProvider 组件的实现依赖 React 中的 Context,ConfigProvider 组件创建 Context 的 Provider,并提供 useConfig 方法,useConfig 方法在 nutui-react 的各个组件中引入,从而实现多语言文案的支持。
javascript
export const useConfig = () => {
return useContext(ConfigContext) ?? getDefaultConfig()
}
// 创建一个 Context 对象
const ConfigContext = createContext<ConfigProviderProps | null>(null)
export const ConfigProvider: FunctionComponent<
Partial<ConfigProviderProps> & React.HTMLAttributes<HTMLDivElement>
> = (props) => {
const { children, ...config } = { ...defaultProps, ...props }
const parentConfig = useConfig()
return (
<ConfigContext.Provider
value={{
...parentConfig,
...config,
}}
>
{children}
</ConfigContext.Provider>
)
}
对于 nutui-react 的贡献者而言,组件库需要提供给他们开发多语言组件的能力,其中主要的部分有文档和 Demo 的多语言支持、组件文案多语言替换。
文档和 Demo 最初只有中文,多语言需要对文档和 Demo 进行扩展。文档主要采用的方案是多份语言文档,例如 button 组件同时提供了 doc.md、doc.zh-TW.md、doc.en-US.md 文件。Demo 文件需要提取原有的文案,转成对应的语言包。

在文档的加载过程中,需要创建 docs.ts 文件来集合各个组件中的 *.md 文件,这里主要借助 vite 的 import raw 特性:
javascript
import CountDown from '@/packages/countdown/doc.md?raw';
通过 ?raw 我们将 doc.md 倒入为字符串,用于之后的 react-markdown 的处理。由于要支持多语言,也就意味着要解析不同语言的 doc.md 文件所以需要一种机制来匹配加载哪种语言文件。如上图所示,我们在流程中增加了多语言路由支持,并借助 useLocale hook 实现。
Demo 文件对于组件库来讲就是一个普通的 React 组件,Vite 支持使用特殊的 import.meta.glob
函数从文件系统导入多个模块:
arduino
const modulesPage = import.meta.glob('/src/packages/**/demo.tsx')
我们可以将所有的 Demo 组件导入,并通过遍历的形式处理路由映射关系。
ini
{routes.map((item: any, index: number) => {
const C = loadable(item.component)
return (
<Route
key={Math.random()}
path={`${locale ? `/${locale}` : ''}${item.path}`}
component={WithNavRouter(C)}
/>
)
})
由于 Demo 预览功能是一个 React 应用,而且组件内部实现已经处理过多语言,所以我们在这里对多语言的处理和普通的业务应用处理方式一致,通过 ConfigProvider 组件实现多语言切换。
ini
<Configprovider locale={languages[locale]}>
<Switch>
{routes.map((item: any, index: number) => {
const C = loadable(item.component)
return (
<Route
key={Math.random()}
path={`${locale ? `/${locale}` : ''}${item.path}`}
component={WithNavRouter(C)}
/>
)
})}
</Switch>
</Configprovider>
组件内部的多语言工作
组件内部文案的多语言支持主要以提取多语言包为主,并替换组件内部的对应的固定文案。组件所使用多语言包文件目前存放在 src/locales 目录中,在目前的代码仓库中有三个中语言的文件,分别是:en-US.ts、zh-CN.ts、zh-TW.ts 文件。多语言包的引入和使用主要借助于 configProvider 中提供的 useConfig 来处理。useConfig 会返回对应语言的 key-value 数据。

Demo 文件内的文案提取
Demo 文件的多语言实现要借助 useTranslate hook,并按照语言包的形式提供对应的 key-value 结构,然而自己逐条文案提取对应的 key-value 结构枯燥而低效,所以对于 Demo 内部的文案,我们开发了提取文案的脚本,方便 Demo 文案的翻译工作。

例如 Radio 组件中,我们将用到的文案通过 node scripts/extract-language.js 提取出 key-value 的结构,这一结构的实施依赖我们提供的 useTranslate hook。这样便将 Demo 翻译最繁琐的一步给简化了。
extract-language.js 中主要通过正则进行文案的提取和替换,这主要得利于 Demo 文件的标准化。 useTranslate 通过对监听 popstate 事件,从而选择当前的语言方案。
总结
本次主要介绍了 NutUI-React 组件库对于多语言支持的实现思路,目前已经有部分组件实现了对多语言的支持,在未来逐步的迭代中全部组件都将实现对多语言的支持。
加入我们
期待您早日成为我们共建大军中的一员!
微信群:hanyuxinting(暗号:NutUI-React)
官网GitHub: 点击进入
欢迎共建、使用!