一.不谈谈历史,字数是凑不够的
以前原始时代,没有三大框架的时候。做多语言设计,你能想到怎么做?无非是对页面的dom结构进行标记,然后在遍历替换。这说实话效果就很扯,体验效果很差。简直就是一闪一闪亮晶晶。当然神器jquery,有提供一些插件方案,效果也好不到哪里去。
后来前端出了几大框架,各社区也有对应的开源方案,一般是定义json,然后在应用最外层包裹一个数据层。传递key,通过改key和页面刷新实现切换。
二.首先说一下结论,我们决定自己造轮子
为什么要造轮子?
1、首先我们需要切换无刷
2、可以实时注册增减多语言
3、不想应用顶层包裹一个多语言的容器
4、可以在任意地方注册多语言并全局生效。
因为我们公司采用react框架为主。我们历史有项目用过react-intl,其实这个框架整体还是挺强大的,但是使用起来不够简单,创建,消费都需要特定方法和组件。而且包有200多kb,是我们不能接受的。同时在使用的过程,还有浏览器兼容性问题。无法支持某组件差异更新。其次还不支持hooks用法。
后来项目中我们后来改进了,定义一个全局json,采用rxjs全局监听一个多语言对象。再使用时用observer收集组件依赖,从而更轻量简化了多语言方案。并支持某一个组件多语言单独刷新。提供多语言组件TextMessage,只需要包裹一个key就能实现转化。同时提供getMessage,useMessage等多样化的消费方式,满足不同的使用场景。
总之这版多语言我们团队上下都还比较满意。
直到有一天,有人说起,每个组件都包裹着一个observer不觉得比较繁琐,且不好理解吗?,同时对forwardRef也不友好。为什么不能自动收集一下依赖?
首先我们去调研了一下开源的能实现自动收集依赖的库很多,如 recoil,valtio,zustand,jotai等。发现他们实现的原理都不复杂。
所以感觉我上我也行。
所以我们自己就编写属于我们团队自己的自动收集依赖库@focbiz/loong,同时我们也使用此库做我们的全局数据流方案。
三.基于自动收集依赖的框实现多语方案
有了loong一切都简单了。
1.首先定义多语言格式:
export const companent = {
'zh-CN': {companent: { base: '基础组件', baseform: '基础表单', }},
'en-US': {companent: { base: 'Base component', baseform: 'Base form'}},
'ja': {companent: { base: 'ベースコンポーネント', baseform: 'ベースフォーム', }}};
key可以尽量参照于国际化标准。
2.提供全局多语言对象locales生成一个可以被监听loong对象,这里loong可以用其他库替换
import { loong} from '@focbiz/loong';
const locales= {};
export const localesHander = loong(locales);
3.提供消费的hooks,根据对象路径进行查找,期间要对传入的 tokenstring做必须得校验,和查找。校验是必要的tokenstring格式验证已经存在验证等。查找是根据 tokenstring 作为对象路径查找
const useMessage=(key:tokenstring)=>{
const [data] = useLoong<typeof locales>(localesHander)
return data[nowLangKey][tokenstring]
}
4.组件不做演示,组件就是使用hooks,封装一个基础的react组件即可。
5.提供全局注册多语言的方法 mergeLocales方法就是对象的合并
export const registerLocales=(...packages: Locales[]) => {
packages.forEach((locales) => {
mergeLocales(locales, locales)}
)}
6.最后可以把这些方法挂着window上,可以实时查看以及注册调试等。
这个方案带来的使用体验以及性能体验都是相当的哇塞的。
整体思路仅作参考,如有雷同,纯属巧合。