大家好,我是前端西瓜哥。
我给网站加上按需加载语言功能有一段时间后,测试给我找到了这么一个的 bug。
可能还是因为支持的语言太少,国外用户也太少的原因,所以这个问题这么晚才被发现。
那我们来看看这个问题。
场景
用户设置网站语言为中文,但浏览器设置语言为英文。
用户打开网站,跳转到登录界面。因用户未登录,前端读取到浏览器为英语语言,所以动态加载英语语言。
输入用户名和密码,跳转到首页。因为用的是单页面应用(SPA),没有刷新页面,所以文案仍然是英文文案。
用户需要刷新一下页面,才能拿到他设置的中文语言的文案。
方案 1:重新加载页面
最简单的方案,是丢弃 SPA 的不刷新页面的 “假跳转”,换成真跳转。
也就是说,不要使用原来底层为 history.pushState()
的 React Router 或 Vue Router 库的 API,直接使用 window.location.href = homeUrl
。
登录请求成功后,前端拿到了用户 Token。接着跳到首页并做一个重新加载语言的操作,因为有用户凭证,我们就能正确加载用户设置的语言。
虽然 SPA 打包后的文件通常很大,但我们有缓存,重新加载一遍的速度还是挺快的。
这里有一个可选的优化点:如果用户设置的语言和浏览器语言相同,可以仍旧使用 “假跳转”。这点需要后端配合,让登录接口额外返回当前用户语言字段。
方案 2:加载用户语言,覆盖掉浏览器语言
请求登录接口,拿到用户 Token 后,需要额外拿到用户设置的语言。
根据这个语言标识,动态获取对应的语言包 JS 文件,语言包下载完毕并覆盖掉原来的语言包,然后再 “假跳转” 到主页。
同样,如果用户语言和浏览器语言相同,直接“假跳转”到主页即可。
看起来好像不是很复杂的样子,但其实里面有很多坑。
要使用这种方案,你必须保证你的代码对语言包对象是响应式的。也就是说语言包对象一改变,你的组件你的方法都得自动跟着变化。
这意味着在某些情况下你不能使用缓存,对一些涉及到国际化文案的逻辑,要写成函数的形式。组件不能使用外部的静态内容,需要依赖 Context 或 Redux 这些会触发组件重渲染的方案。
当然如果你这样做了,也有好处,就是你切换语言时,不需要重新加载页面,组件会重新渲染应用新的语言文案。
结尾
我更倾向于使用方案 1,因为它简单,适用于任何场景。此外从不登录到登录,里面会发生非常多的状态变化,不太好维护。
另外,退出登录同样也要做重新加载页面的操作,因为用户语言和浏览器语言可能并不同。
我是前端西瓜哥,一名喜欢思考的前端开发,欢迎关注我。