前端多语言加载优化

背景:站点具有多语言需求,用户访问站点期间需要加载相应的多语言json 文件。

  1. 如何更快响应产品变更词条需求。
  2. 如何更快让用户加载多语言文件是需要考虑的点。
痛点:
  1. 随着多语言JSON文件的词条不断增加,文件体积的增大会导致加载时间延长,进而影响用户体验。因此,优化文件加载效率对于提升用户满意度至关重要。

  2. 以前的多语言文件维护在项目中,每次产品词条更新都需经过CI/CD流程发布,这不仅耗时较长,还难以实现快速响应变更需求。

如何解决:
  1. 基于以上两点问题,全球站多语言需要解决2个问题

  2. 多语言 json文件需要热更新,即产品改动词条之后直接发布,前端不需要CI/CD,用户即可加载最新的多语言文件

  3. 分片加载: 当用户访问特定模块(如KYC页面)时,我们只会加载 kyc 相关的多语言json 文件。其余模块多语言文件并不会被加载 (比如: 用户访问kyc模块,assets 模块多语言就不会被加载)。分片加载带来的好处是: 按需加载,且请求的词条量较小,用户体验更好

项目如何接入:
  1. 初始化拿到所有的 多语言josn文件 在S3的绝对地址,形成一个[国家]+[语言模块]结构。 (类似以下结构)
ruby 复制代码
// 这里的 data 是后端返回的 多语言文件在 S3 绝对地址,只会请求一次
 const data = {
    en_US_asset: 'https://xxx/public/abc.json',    // 英文模式  资产模块    多语言json 文件
    en_US_common: 'https://xxx/public/abcd1.json', // 英文模式  common模块 多语言json 文件
    en_US_kyc: 'https://xxx/public/acb31.json',    // 英文模式  kyc模块    多语言json 文件
    
    zh_CN_asset: 'https://xxx/public/asd1.json',   // 中文简体模式  资产模块     多语言json 文件
    zh_CN_common: 'https://xxx/public/231.json',   // 中文简体模式  common模块  多语言json 文件
    zh_CN_kyc: 'https://xxx/public/12321das.json', // 中文简体模式  kyc模块     多语言json 文件
    
    zh_TW_asset: 'https://xxx/public/1fsa1dsa.json', // 中文繁体模式  资产模块    多语言json 文件
    zh_TW_common: 'https://xxx/public/asds213.json', // 中文繁体模式  common模块 多语言json 文件
    zh_TW_kyc: 'https://xxx/public/sdadasd1.json',   // 中文繁体模式  kyc模块    多语言json 文件
  };
  1. 当用户访问具体某个业务模块的时候,只加载对应模块的多语言json 文件
javascript 复制代码
import i18n from 'i18next';
import HTTPApi from 'i18next-http-backend';
import { awaitWrap } from 'cus-utils';

import {
  getLocalLang,
  EN,
  ZHCN,
  ZHHK,
  LangMapVal,
  NameSpace,
} from '@/utils/utils';
import { getS3LangUrl } from '@/service/common';
import formatS3RemoteLang, {
  type TypeFormatS3RemoteLangUnion,
} from './utils/formatS3RemoteLang';

async function getRemoteS3Url() {
  const [err, s3data] = await awaitWrap(getS3LangUrl());

  const formatS3Data = formatS3RemoteLang(
    s3data?.updateLanguageParameters ?? [],
  );
  // 后续看需要不要加统一错误处理
  if (err) {
    console.error(err, '远端多语言加载失败');
  }

  i18n.use(HTTPApi).init({
    lng: getLocalLang(),
    fallbackLng: {
      zh_CN: [ZHCN],
      zh_HK: [ZHHK],
      en_US: [EN],
      default: [EN],
    },
    ns: 'common',
    fallbackNS: ['default'],
    backend: {
      loadPath: async ([lngs]: LangMapVal[], [namespaces]: NameSpace[]) => {
        const key = (lngs +
          '_' +
          namespaces) as keyof TypeFormatS3RemoteLangUnion;

        // 本地开发模式多语言 json 文件名map
        if (import.meta.env.MODE === 'development') {
          // mock json 文件
          const data = {
            en_US_asset: 'abc',
            en_US_common: 'abcd1',
            en_US_kyc: 'acb31',
            zh_CN_asset: 'asd1',
            zh_CN_common: '231',
            zh_CN_kyc: '12321das',
            zh_TW_asset: '1fsa1dsa',
            zh_TW_common: 'asds213',
            zh_TW_kyc: 'sdadasd1',
          };
          const devModeFilename = data[key];

          return `${import.meta.env.VITE_STATIC_PUBLICPATH}locales/${devModeFilename}.json?hash=${import.meta.env.LANG_HASH}`;
        }

        // 这里控制 多语言按需加载
        const filename = formatS3Data[key].downloadUrl;
        return filename;
      },
      overrideMimeType: 'application/json',
    },
    load: 'currentOnly',
  });
}

getRemoteS3Url();

export default i18n;
  1. 业务代码如何控制多个模块多语言json文件

    1. 方式一:通过 useTranslation 自定义声明 namespace
    javascript 复制代码
    export default function Page() {
      
      const { t } = useTranslation('kyc');       // 加载 kyc 模块多语言文件
      const { t: t1 } = useTranslation('asset'); // 加载 asset 模块多语言文件
      const { t: t2 } = useTranslation('common');// 加载 common 模块多语言文件
    
      return (
        <>
          <div>kyc词条--- {t('common.overview')}</div>
          <div>asset词条 --- {t1('common.overview')}</div>
          <div>common词条 --- {t2('common.overview')}</div>
        </>
      );
    }
    1. 方式二:通过 withTranslation 高阶组件进行 提前注入 namespace
javascript 复制代码
function Page(props) {
  return (
    <>
      <div>kyc词条--- {props.t('common.overview')}</div>
      <div>asset词条 --- {props.t('common.overview', { ns: 'asset' })}</div>
      <div>common词条 --- {props.t('common.overview', { ns: 'common' })}</div>
    </>
  );
}

export default withTranslation(['kyc', 'asset', 'common'])(Page);
效果:
  1. 通过以上配置 i18n文件, 我们可以做到词条维护在 远端S3,实现词条热更新

  2. 用户按需加载多语言词条,用户体验更好

未来优化:
  1. 多语言加载一次之后,缓存在本地,当多语言文件内容 MD5 值明确发生变更之后,再次请求多语言json 文件。即用户请求一次,文件内容没发生变更,直接使用缓存过的多语言文件,避免用户每次刷新都请求多语言文件
  2. 使用 namespace 之后,开发者每次导出组件 都需要引入至少1个namespace,后续考虑使用 AST 进行动态注入每个 组件,尽可能少写 引入 namespace
  3. 目前词条是一个一个录入的,后续考虑在打包编译阶段自动识别到多语言 key,上传到多语言平台,释放开发者录入词条的时间
相关推荐
小样还想跑10 分钟前
axios无感刷新token
前端·javascript·vue.js
Java水解19 分钟前
一文了解Blob文件格式,前端必备技能之一
前端
用户38022585982440 分钟前
vue3源码解析:响应式机制
前端·vue.js
bo5210042 分钟前
浏览器渲染机制详解(包含渲染流程、树结构、异步js)
前端·面试·浏览器
普通程序员1 小时前
Gemini CLI 新手安装与使用指南
前端·人工智能·后端
山有木兮木有枝_1 小时前
react受控模式和非受控模式(日历的实现)
前端·javascript·react.js
流口水的兔子1 小时前
作为一个新手,如果让你去用【微信小程序通过BLE实现与设备通讯】,你会怎么做,
前端·物联网·微信小程序
多啦C梦a1 小时前
🪄 用 React 玩转「图片识词 + 语音 TTS」:月影大佬的 AI 英语私教是怎么炼成的?
前端·react.js
呆呆的心1 小时前
大厂面试官都在问的 WEUI Uploader,源码里藏了多少干货?🤔
前端·微信·面试
heartmoonq1 小时前
深入理解 Vue 3 响应式系统原理:Proxy、Track 与 Trigger 的协奏曲
前端