前言 💬
- 实现
React
项目国际化,不得不提在业界中较受欢迎的库:react-intl
,它是雅虎的语言国际化开源项目 formatjs 的一部分,通过其提供的组件和api
可以在React
项目中实现多语言支持。 react-intl
最大的优势是它用props
的方式注入语言包,无需重新加载页面就可以直接更改显示的语言,而其缺点主要有两个:- 只能应用于视图层,仅支持在
jsx
文件的内容(即React.Component
)中使用,不支持在普通js
对象中使用 😫。 - 它用包裹组件的形式装饰
React.Component
,因此组件行为在很多方面都发生了改变,具有较强的侵入性 😱。
- 只能应用于视图层,仅支持在
- 在开发中发现,为了实现国际化,使用
react-intl
库的国际化步骤还是比较繁琐的,具体步骤不是本文的重点(传送门👉:react-intl 实现 React 国际化多语言),而且虽然这个库提供了许多组件,但是大多时候只需要使用<FormattedMessage/>
这个组件,实在是没必要为了一棵🌲,买下整个森林 🤷♀️。 - 基于以上提到的问题,本文将介绍基于
React-hook
实现的一套简易的前端国际化方案(已在React
项目中投入使用,目前没遇到什么问题)。
效果展示 🤩
开发思路 🤔
- 用过
react-intl
库的同学都知道,该库提供了<IntlProvider/>
组件用于提供国际化的上下文:当使用<IntlProvider/>
包裹住某个组件的时候,这个组件本身和组件内部包含的子组件就可以获得所有react-intl
提供的接口以及在<IntlProvider/>
中引入的locale
配置文件的内容。 - 实际上,当我们创建了不同语言版本的国际化资源文件后,只要确定了语言,对应语言版本文件就可作为
dictionary
在组件中进行查询使用。中英文的国际化资源文件大致长这个样子 👇: - 我们可以使用
React
提供的createContext
方法创建一个React
的上下文(Context
)用于存放当前的语言版本,然后将Context.Provider
作为最外层包装我们的组件(一般是<App/>
),则<App/>
组件本身和组件内部包含的子组件,只要是函数式组件,均可以使用useContext
方法获取到当前的语言版本,根据对应的dictionary
对文案进行翻译。 - 前面提到,
react-intl
库只能在组件中实现国际化,不支持在普通js
对象中使用。为了解决这个问题,我们可以在全局存放当前的语言版本currentLang
,当切换语言版本时,对该全局变量进行更新,对 js 文件提供的 api 只需要根据当前currentLang
值选取相关的语言版本dictionary
,并通过传入的key
进行文案翻译(取value
)即可。
- 听不懂的同学不要慌,这里先介绍整个方案实现的思路,具体怎么实现,再往下看看吧 🚶,看完代码回头看看思路,可能会更加清晰。
获取/切换当前语言版本
-
提供
getLang
方法用于获取当前语言版本(主要是 js 文件使用),用于和setLang
方法用于切换当前语言版本,相关代码如下: -
细心的同学发现代码中也有
updaterList
这个变量,在调用setLang
方法时,会依次遍历updaterList
里面的方法并执行相关的方法。下面将提到的<IntlProvider/>
组件将涉及到updaterList
值的修改。
实现 IntlProvider 组件
- 使用
React
提供的createContext
方法创建一个React
的上下文(Context
)用于存放当前的语言版本,相关代码如下: - 将
Context.Provider
作为最外层包装我们的组件:
实现 FormattedMessage 组件
<FormattedMessage/>
组件支持传入id
(必填)和参数args
(可选),相关代码如下:- 从
<FormattedMessage/>
组件的实现代码可以看到,核心代码是调用了自定义hook
(即useFormatMessage
方法),该方法利用了字符串的split
方法能使用正则来分割使结果中包含分隔块的特性(传送门 👉: MDN文档),并使用useContext
方法获取到<IntlProvider/>
组件存放的语言版本。 - 在组件中使用:
实现支持普通 js 对象的 api
-
为了让普通 js 对象也能使用国际化的功能,我们提供了两种方法用于处理不带参数(
getRawText
方法)和带参数(getFormattedText
方法,不传参数时等价于getRawText
方法)的情况: -
如需在接口报错时对错误信息进行国际化:
-
以上就是整套前端国际化方案的完整实现,看到这里,还不明白的同学可以结合前面的开发思路再缕缕。
总结 👀
- 针对目前较为热门的国际化开源库
react-intl
在项目中使用起来存在配置繁琐、只能应用于视图层、有较强的侵入性等缺点,本文介绍了基于React-hook
实现的简易前端国际化方案,即实现了常用的组件和api
,并在项目中投入使用。 - 题外话:针对
react-intl
库的缺陷,阿里推出了react-intl-universal
库,这个库使用起来也挺方便的,提供了更多丰富的功能,至于为啥要自己写一套方案,这就见仁见智了,因为项目中仅使用到少量的组件和api
,通过理解原理,在项目中自己实现一套国际化方案也是可以的。
以上内容如有遗漏错误,欢迎留言 ✍️指出,一起进步💪💪💪
如果觉得本文对你有帮助,🏀🏀留下你宝贵的 👍