1. 首页

几分钟优化你的国际化

前言

本文针对国际化翻译数据多,并存放在服务器的情况,对优化进行了思考,并写了了一个插件github.com/jmx16449196…,供大家参考或使用。抛砖引玉,如果有需要改进的地方,希望大家指正。

需求背景

我司单页面应用中的国际化功能存在两个可优化的点:

  • 国际化翻译数据存在了数据库中。每次切换语种或重新加载页面,都需要请求一次接口,接口大概会耽误1s,十分影响用户体验,特别是首屏加载。

  • 由于所有数据都存放在数据库,所以首屏加载时,请求接口前都没有翻译数据可用。

Js中文网 – 前端进阶资源教程 www.javascriptC.com,typescript 中文文档
一个帮助开发者成长的社区,你想要的,在这里都能找到

优化方案

针对第一个问题,使用缓存

针对第二个问题,我把翻译数据分为了两份:

静态翻译数据:写死在js中,用于存在一些基础的翻译数据,即使断网了,用户也可以看到正常的页面。

动态翻译数据:从接口获得,这部分数据可以让用户通过相关配置页面去修改。

优化后的页面在进入时,可以分为以下阶段:

image

关键代码


// 创建实例并调用 const translateManager = new TranslateManager({/*传参*/}) translateManager.update('en', (res) => { // 触发相应的更新视图的逻辑 // 例如在vue中,使用了vue-i18n,你可以 i18n.setLocaleMessage(res.data); });//Js中文网 - 前端进阶资源教程 https://www.javascriptc.com/ class TranslateManager { STORAGE_KEY: string expireTime: number requestFn: Function | null staticTranslateData: object /** * 构造函数 * @param params */ constructor(params: constructorParams) { this.expireTime = params.expireTime || Infinity; // 前端缓存有效时间 this.STORAGE_KEY = params.storageKey || 'TranslateManager'; this.requestFn = params.requestFn; this.staticTranslateData = params.staticTranslateData || {}; } setRequestFn(fn: Function) { this.requestFn = fn; } /** * 设置缓存 * @param {String} language */ setCache(language: string, data: object) { // 请求完成后缓存 const storageData = jsonParse(localStorage.getItem(this.STORAGE_KEY)) || {}; storageData[language] = data; storageData['time'] = new Date().getTime(); localStorage.setItem(this.STORAGE_KEY, JSON.stringify(storageData)); } /** * 从缓存中读取 * @param language 语种 */ getCache(language: string) { const storageData = jsonParse(localStorage.getItem(this.STORAGE_KEY)) || {}; if (storageData && storageData['time'] && storageData[language]) { const time = storageData['time']; const now = new Date().getTime(); // 缓存只有两小时 if (now - time <= this.expireTime) { return storageData[language] || null; } } return null; } /** * 获取后端的静态国际化数据 */ getDynamicTranslateData(language: string) { if (!this.requestFn) { console.error('请先执行setRequestFn!'); return Promise.reject(); } return this.requestFn({language}).then((res: object) => { this.setCache(language, res); return res; }); } /** * 获取前后端交集后的国际化数据 * @param {*} language */ getMergeTranslateData(language: string) { // 没缓存就发起请求 return this.getDynamicTranslateData(language).then((res: any) => { const data = this.staticTranslateData[language] || {}; // 部分国际化写在了前端,把前端的国际化文件合并到后端返回的数据中 merge(res, data) if (isEmptyResult(res)) { return Promise.reject(new Error('locale empty !!')) } return res; }) } /** * 主方法 * //Js中文网 - 前端进阶资源教程 https://www.javascriptc.com/ * @param locale 语种 * @param callback 回调函数,用于订制自己触发的渲染逻辑 */ update(locale: string, callback: Function) { let staticData = this.staticTranslateData[locale]; const cacheData = this.getCache(locale) || {}; // 使用静态数据和缓存数据的并集,触发第一次视图更新 merge(cacheData, staticData); callback(cacheData, 'first'); // 返回静态和动态数据的合集 return this.getMergeTranslateData(locale).then((res: object) => { // 获取数据是否和动态数据不一致 if (res && !isEqual(res, cacheData)) { callback(res, 'second') } }) } }

延伸

使用了上面的做法,已经很好的达到了预期效果。就在写这篇文章的时候,突然发现还有继续深入优化的方向:可以把动态数据划分不同的模块,分步加载。根据自身业务的逻辑,比如可以根据用户权限。当我用户权限低只可以看主页时,我只加载主页模块的翻译数据即可;当我用户权限高,并进入了相应页面,此时再去下载对应的模块数据。

总结

本次提供的优化方案思路并不难,只是实现起来需要些时间,我根据本次优化的思路造了个轮子,使用十分方便,内含使用demo和注释,欢迎star:github.com/jmx16449196…。如果觉得本文对你有所帮助,求点赞一下,谢谢~

作者:墨工
链接:https://juejin.im/post/5e008b2d518825126d5a37cd

看完两件小事

如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:

  1. 关注我们的 GitHub 博客,让我们成为长期关系
  2. 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
  3. 关注公众号 「画漫画的程序员」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程

JS中文网是中国领先的新一代开发者社区和专业的技术媒体,一个帮助开发者成长的社区,目前已经覆盖和服务了超过 300 万开发者,你每天都可以在这里找到技术世界的头条内容。欢迎热爱技术的你一起加入交流与学习,JS中文网的使命是帮助开发者用代码改变世界

本文著作权归作者所有,如若转载,请注明出处

转载请注明:文章转载自「 Js中文网 · 前端进阶资源教程 」https://www.javascriptc.com

标题:几分钟优化你的国际化

链接:https://www.javascriptc.com/3179.html

« 高频-React面试题
分享这半年的 Electron 应用开发和优化经验»
Flutter 中文教程资源

相关推荐

QR code