Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

前端国际化(二): 平台旧国际化方案改造 #4

Open
csu-feizao opened this issue Dec 15, 2023 · 0 comments
Open

前端国际化(二): 平台旧国际化方案改造 #4

csu-feizao opened this issue Dec 15, 2023 · 0 comments

Comments

@csu-feizao
Copy link
Owner

[前端国际化(二): 平台旧国际化方案改造

背景

之前公司打算挖掘海外客户,需要将现有以及未来的功能都支持国际化,因此便有了本次的国际化改造项目。公司的项目架构大致可以总结为一个平台基座应用 + 几十个微应用,通过 qiankun 连接。平台已经支持国际化,但是平时都没怎么测试英文版,有各种细小的问题。而微应用则未支持国际化。下面会拆成两篇文章分别介绍平台项目和微应用项目的国际化实践。

解决方案

平台项目与微应用不一样,原先就实现了一套国际化方案,但存在几个比较大的痛点,影响大家的开发效率。趁着本次国际化项目的机会,也进行了一些改造。

支持变量替换

原先不支持在语言包中使用占位变量,在遇到需要嵌入变量场景时,往往是拆成几个部分拼接的方式。这种方式有两个明显的缺点,一个是原本定义一个 key 值能解决的事情,现在需要拆分成 key1、key2、key3,增加了代码量,不利于维护,另一个是在多语言下可能语序不一样,拼接的几个部分的翻译可能是完全不对称的,降低了自动化翻译的准确度,需要人工调整这些部分。

优化前:

// zhCN.ts
export const base_zh: IBaseLocale = {
  ...
  delete: {
    confirm_desc_1: '你确认要删除',
    confirm_desc_2: '吗?'
  }
  ...
}

// 组件
<p>
  {`${formatString(BaseLocale.table.delete.confirm_desc_1)}${
    record.name
  }${formatString(BaseLocale.table.delete.confirm_desc_2)}`}
</p>

优化后:

// zhCN.ts
export const base_zh: IBaseLocale = {
  ...
  delete: {
    confirm_desc: '你确认要删除「{name}」吗?',
  }
  ...
}

// 组件
<p>
  {formatString(BaseLocale.table.delete.confirm_desc, { name: record.name })}
</p>

这里参考了 vue-18n 的语法

减少冗余的类型定义代码

原先定义语言包的写法十分冗余且麻烦,增加一个文案,需要要先到类型文件定义好 key 值,然后再分别到中英文件中填写对应的文案,单单一个文案就得写 3 遍。

// type.ts
export interface IDocsLocale {
  home: {
    title: string;
    search: string;
    placeholder: string;
    history: string;
  };
}

// en.ts
import { IDocsLocale } from "./type";

export const docs_en: IDocsLocale = {
  home: {
    title: "Document",
    search: "Search",
    placeholder: "Please enter the keyword",
    history: "Historical Record",
  },
};

// zh.ts
import { IDocsLocale } from "./type";

export const docs_zh: IDocsLocale = {
  home: {
    title: "产品文档",
    search: "搜索",
    placeholder: "请输入关键字",
    history: "历史记录",
  },
};

对于中文开发人员而言,最符合直觉的顺序应该是增加中文文案,完成需求开发,最后再将中文文案批量翻译成英文。因此类型定义完全是多余的,不过我们依然需要一种方法保证中英文是同步更新的,这就可以利用 ts 的自动推导。最后再用自动化脚本批量 diff 中英文文件,调用 google api 进行翻译,便能完成国际化。下面是优化后的结果,可以看到我们减少了三分之一的冗余代码:

// zh.ts
export const docs_zh = {
  home: {
    title: "产品文档",
    search: "搜索",
    placeholder: "请输入关键字",
    history: "历史记录",
  },
};

export type TDocsLocale = typeof docs_zh;

// en.ts
import { TDocsLocale } from "./zh";

export const docs_en: TDocsLocale = {
  home: {
    title: "Document",
    search: "Search",
    placeholder: "Please enter the keyword",
    history: "Historical Record",
  },
};

去掉繁琐的导入

原先开发时,按功能拆分了很多翻译文件,导致在使用时,可能会出现引用四五个语言文件的情况,例如:

import { formatString } from 'services/base/language'
import { BaseLocale } from 'constants/language/base/type'
import { TimeLocale } from 'constants/language/time/type'
import { AlertLocale } from 'constants/language/alert/type'
import { AggregateRuleLocale } from 'constants/language/alert/aggregate_rule/type'

function App() {
  ...
  const xxx = formatString(AlertLocale.status.title)
  ...
}

我们可以将这些模块聚合起来,通过路径前缀进行访问,并将 formatString 方法和 Locale 语言包合到同一个文件中,方便导入:

// 新增 i18n/index.ts,
export { formatString } from 'services/base/language'
export { RootLocale as Locale } from 'constants/language'

// 使用
import { formatString, Locale } from 'i18n'

function App() {
  ...
  const xxx = formatString(Locale.alert.status.title)
  ...
}

总结

这次对国际化方案的改造解决了长期困扰我们的问题,明显提高了开发效率。在技术领域,我们很容易陷入思维的舒适区,习惯于项目原有的状态。但实际上,解决痛点很多时候并不需要花费很大的精力,可能几个小时几十行代码就能解决,而忽视痛点反而会让自己处于长期的痛苦,并且可能会在未来带来更多的麻烦。花费一些时间打破惯性,解决问题,不仅为团队省去了大量开发时间,同时也能让自己的技术得到成长,何乐而不为呢?

前文

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant