使用 @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,如果文案是中文不会被自动提取转换

相关推荐
少云清1 分钟前
【功能测试】6_Web端抓包 _Fiddler抓包工具的应用
前端·功能测试·fiddler
豐儀麟阁贵9 分钟前
8.5在方法中抛出异常
java·开发语言·前端·算法
zengyuhan50339 分钟前
Windows BLE 开发指南(Rust windows-rs)
前端·rust
醉方休42 分钟前
Webpack loader 的执行机制
前端·webpack·rust
前端老宋Running1 小时前
一次从“卡顿地狱”到“丝般顺滑”的 React 搜索优化实战
前端·react.js·掘金日报
隔壁的大叔1 小时前
如何自己构建一个Markdown增量渲染器
前端·javascript
用户4445543654261 小时前
Android的自定义View
前端
WILLF1 小时前
HTML iframe 标签
前端·javascript
枫,为落叶1 小时前
Axios使用教程(一)
前端
小章鱼学前端1 小时前
2025 年最新 Fabric.js 实战:一个完整可上线的图片选区标注组件(含全部源码).
前端·vue.js