react-i18next 进阶用法
在过去的 React 和 React Native 项目里,对于多语言处理,使用的是 react-i18next 来处理的。今天给大家分享下这个库的一些进阶用法和注意事项。
其实一开始的时候,我自己是有点困惑的,react-i18next 和 i18next 是什么关系?为什么项目要安装这2个库,而不是一个?而且为什么在代码里如何从 i18next 里导入某些变量会出现非预期的结果。所以这里也给小伙伴解释下,react-18next 是对 i18next 的 react 版本封装。换句话来说,一般情况下,大家直接使用 react-i18next 库就可以了。
安装很简单:
npm install react-i18next i18next --save
进阶一、兼容性问题
如果你的代码在运行时出现了下面的错误:
i18next::pluralResolver:
Your environment seems not to be Intl API compatible,
use an Intl.PluralRules polyfill.
Will fallback to the compatibilityJSON v3 format handling.
那么按照官方的说明(https://www.i18next.com/how-to/faq#why-are-my-plural-keys-not-working),表示当前环境不兼容 Intl API。
解决方法:
npm install intl-pluralrules --save
然后在多语言的初始化文件里导入:
import 'intl-pluralrules'
这取决于你的 项目结构,可能就在 index.js 里,我们的项目就是在 i18n.ts 文件里。
这个问题,在我们的 React Native 项目里有碰到过。
进阶二,传字段
例如有下面的 json 文件:
{
"error": {
"required": "{{field}}必填",
"invalid": "无效的{{field}}"
}
}
那么使用时,就是这样使用的:t(‘error.required’, { field: t(‘Email’) })
进阶三,自定义多语言层级分隔符
默认情况下,代码里使用 . 来表示层级,例如 error.required,当然也可以使用下面的配置来更改为使用 “/”:
i18n.use(initReactI18next).init({
// ...
keySeparator: '/'
})
那么前面的调用就成了 t(‘error/required’, { field: t(‘Email’) }),我是觉得这个一般情况下是不必无苦硬吃的,可能在特殊场合需要使用。大家看看就可以。
进阶四,自动单复数
i18next 对于自动单复数有预定的约定,只需要在 key 后面添加 “_other” 即可,当然前提是对应的语言描述有复数的用法哈。
{
"hours": "{{ count }} hour",
"hours_other": "{{ count }} hours",
}
t('hours', { count: 5 })
// 5 hours
对于 0 来说,实际来看,会使用复数的翻译,例如 0 hours。如果需要为 0 来单独定义的话,可以添加 “_zero”,例如:
"hours_zero": "Now"
需要提醒的是,如果这里内置的 _zero、_other 和你的多语言冲突了,还是有这个可能的,那么可以修改使用自定义分隔符,例如下面这样:
// i18n.ts
i18n.use(initReactI18next).init({
... // 其它配置
pluralSeparator: '__', // 双下划线
})
具体使用:
{
"days": "{{count}} day",
"days__other": "{{count}} days",
}
进阶五,Trans 组件
这里直接借用网上的一个示例,假如要显示下面的文字“你好 {userName},你有 {count} 条未读消息。点击查看。”,并且还需要支持点击操作。
在以前的写法中,我们需要将这句话单独的拆开,使用不同的组件包装起来,例如 count 希望是一个
红色的字体之类的,还要放到不同的多语言 key 里。太费劲了。
使用 Trans 组件,可以这么写,大家琢磨琢磨,是不是简单很多。
// en.json
{
"userMessagesUnread": "Hello <1>{{userName}}</1>, you have {{count}} unread message. <5>Click to view</5>.",
"userMessagesUnread_other": "Hello <1>{{userName}}</1>, you have {{count}} unread messages. <5>Click to view</5>."
}
<Trans
defaults={t('userMessagesUnread')}
values={{ count, userName }}
parent={Text}
components={{
1: <Text style={{ fontWeight: '500' }} />,
5: <Text style={{ color: '#4682A9' }} onPress={() => {}} />
}}
/>
可以看到,通过使用 components 属性,借助索引可以将指定位置的元素给替换包装起来。那么有人就问了,为什么这里是数字1和5,而不是其它的呢?
Trans 组件将上面的文本转换为下面的结构:
[
'Hello ',
{ children: [{ user_name: 'Admin' }] },
', you have ',
{ count: 10 },
' unread messages. ',
{ children: ['Click to view'] },
'.'
]
这么来看,是不是基于 0 的索引位置就出来啦。
更多内容,可以参考官方文档说明。