使用 @formatjs/cli 进行国际化文案自动提取

背景 :我们的项目有国际化文案的需求,接入的国际化方案为umi提供的react-intl。(详见国际化)项目结构大致如下:

markdown 复制代码
src
  + locales
    + zh-CN.ts
    + en-US.ts
  pages
    a.tsx
    b.tsx

每次有新的页面开发,都涉及到不少手动提取文案key的工作,现希望能把这部分的功能自动化,提高开发效率。

关于@formatjs/cli

官方文档:formatjs.io/docs/toolin...

FormatJS 是一个用于国际化的 JavaScript 库的模块化集合,专注于格式化数字、日期和字符串以向人们显示。它包括一组基于 JavaScript Intl 内置函数和行业范围的 i18n 标准构建的核心库,以及一组通用模板和组件库的集成。@formatjs/cli是其官方提供的cli工具。

实现效果

javascript 复制代码
// src/pages/a.tsx
import { useIntl, SelectLang } from "@umijs/max";
import React from "react";

export default function HomePage() {
  const intl = useIntl();
  const name = "ben";
  return (
    <div>
      <h2>
        {intl.formatMessage({
          defaultMessage: "你好",
        })}
      </h2>
      <p>
        {intl.formatMessage({
          id: "existedId",
        })}
      </p>
      <p>
        {intl.formatMessage(
          {
            defaultMessage: "你好 {name}",
          },
          { name }
        )}
      </p>
    </div>
  );
}

运行 npm run i18n 后

json 复制代码
// src/locales/zh-temp.json

{
  "5ASYdK": "你好 {name}",
  "UjIYG8": "你好"
}

使用流程

  1. 安装
css 复制代码
yarn add --dev @formatjs/cli babel-plugin-formatjs
  1. 在 package.json 添加
json 复制代码
"scripts": {
  "i18n:tsc": "tsc src/utils/i18n.ts --skipLibCheck --target es2015 -module commonjs --moduleResolution node --outDir i18n-temp",
  "i18n:extract": "formatjs extract "src/**/*.{js,jsx,ts,tsx}" --ignore "src/**/*.d.{ts}" --out-file i18n-temp/locales/temp.json --id-interpolation-pattern [sha512:contenthash:base64:6]",
  "i18n:complie": "formatjs compile i18n-temp/locales/temp.json --format i18n-temp/utils/i18n.js --out-file src/locales/zh-temp.json",
  "i18n": "npm run i18n:tsc && npm run i18n:extract && npm run i18n:complie && rm -rf i18n-temp"
}

全部参数:formatjs.io/docs/toolin...

--ignore [files]:忽略某些文件,比如d.ts

--out-file:输出文件的path

--id-interpolation-pattern:哈希id生成规则,默认为sha512:contenthash:base64:6

  1. 添加 utils/i18n.ts 用于过滤已存在的msg Id
typescript 复制代码
// src/utils/i18n.ts

import _locale from "../locales/zh-CN";

const locale: Record<string, string> = _locale;

// https://github.com/formatjs/formatjs/blob/main/packages/cli-lib/src/formatters/default.ts
export function compile(msgs: Record<string, { defaultMessage?: string }>) {
  const results: Record<string, string> = {};
  for (const k in msgs) {
    if (msgs[k].defaultMessage && !locale[k]) {
      results[k] = msgs[k].defaultMessage!;
    }
  }
  return results;
}
  1. 添加 Babel 插件
arduino 复制代码
// .umirc.ts
extraBabelPlugins: [
    [
      "formatjs",
      {
        idInterpolationPattern: "[sha512:contenthash:base64:6]",
        removeDefaultMessage: true, // 编译后删除 DefaultMessage
      },
    ],
  ]

完成。

现在运行npm run i18n ,会发现新增文案已经被提取到src/locales/zh-temp.json文件中,在编译过程中,babel插件会自动注入msgId。

json 复制代码
{
  "LCPVEl": "测试文案1",
  "PRo5ml": "测试文案2",
  "f1d3UT": "测试文案3"
}

*最好在.gitignore中加一下zh-temp.json避免上传到远程仓库。

显式注入Message Id

如果需要显式注入ID,可以使用cli提供的eslint插件开启enforce-id

formatjs.io/docs/toolin...

csharp 复制代码
yarn add -D eslint-plugin-formatjs
css 复制代码
// .eslintrc.js

  plugins: ["formatjs"],
  rules: {
    "formatjs/enforce-id": [
      1,    
      {
        idInterpolationPattern: "[sha512:contenthash:base64:6]"
      },
    ],
  },

在报错信息中选择fix all

需要注意:1. 必须存在defaultMessage;2. defaultMessage与id一一对应,所以一般情况不太建议开启。

*一些遇到的问题

id为变量时报错

github.com/formatjs/fo...

看起来插件没办法处理id是变量的情况,一个hack的处理办法是把defaultMessage赋值为空数组

ini 复制代码
intl.formatMessage({ id: keyMap[key], defaultMessage:[] })

Message ID不会自动注入

相关issue:github.com/formatjs/fo...

cli通过defaultmessage生成唯一的hashID,defaultmessage变化时(e.g.拼写错误)cli会将他定义为新的待翻译文本

Yarn add 报错:Invariant Violation: expected workspace package to exist for "ts-jest"

需要降级yarn到18,原因不明。。github.com/yarnpkg/yar...

sql 复制代码
yarn policies set-version 1.18.0 && yarn workspace core-vpc-app add --dev @formatjs/cli babel-plugin-formatjs

中文直接转换为intl.formatMessage

cli只会识别intl.formatMessage 或 FormattedMessage,如果文案是中文不会被自动提取转换

相关推荐
Solis程序员11 分钟前
Stripe 幂等表:把「不确定的重试」变成「查表返回」
前端·安全·bootstrap·php·agent
李纲明24 分钟前
WordPress 站点变慢:按 TTFB → 缓存 → 查询 → 前端 分层排查(含配置注意)
前端·缓存·性能优化·wordpress·后端开发
程序人生88833 分钟前
PDF 转 Word 版式错乱、表格丢失?DocConverter Web 格式互转引擎的保真实践
前端·人工智能·opencv·机器学习·pdf·word
粥里有勺糖2 小时前
安利一下最近用的桌面“Agent” | T3 Code
前端·github·ai编程
xy34532 小时前
Axure 9.0 动态面板基本操作
前端·ui·html·axure·原型·产品设计
不停喝水2 小时前
【前端转全栈java速通课】 项目实战④7-11节 操作数据库-登录-注册-修改密码-注销-mubatis-plus简化crud-
java·前端·数据库
一水鉴天3 小时前
统一对象拓扑(UOT)设计全链定稿:从三件事分离到三继承 之1 20261010(豆包“查看聊天内容”继续)
前端·css
栖凤3 小时前
Java 的 try-catch 在 Agent 里失效了,我用了 5 个模式才兜住
java·前端·python
粥里有勺糖3 小时前
视野修炼第136期 | 前端小恐龙"Deno"被收购
前端·github·ai编程
修炼的dance3 小时前
页面塞了13.88 MB字体,导出的PDF只有71 KB
前端