前端多语言加载优化

背景:站点具有多语言需求,用户访问站点期间需要加载相应的多语言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,上传到多语言平台,释放开发者录入词条的时间
相关推荐
Anlici1 小时前
跨域解决方案还有优劣!?
前端·面试
庸俗今天不摸鱼1 小时前
【万字总结】构建现代Web应用的全方位性能优化体系学习指南(二)
前端·性能优化·webp
追寻光1 小时前
Java 绘制图形验证码
java·前端
前端snow1 小时前
爬取数据利用node也行,你知道吗?
前端·javascript·后端
村头一颗草1 小时前
高德爬取瓦片和vue2使用
前端·javascript·vue.js
远山无期1 小时前
vue3+vite项目接入qiankun微前端关键点
前端·vue.js
陈随易1 小时前
告别Node.js:2025年,我为何全面拥抱Bun
前端·后端·程序员
还是鼠鼠2 小时前
Node.js--exports 对象详解:用法、示例与最佳实践
前端·javascript·vscode·node.js·web
CQU_JIAKE2 小时前
2.5[frontEnd]
前端
Moment2 小时前
前端性能指标 —— FMP
前端·javascript·面试