动手搭建翻译协作平台

1,768 阅读2分钟

通常在项目支持国际化的开发过程中,会跑出项目中相关的语料词典,将汇总的文件发给翻译人员,翻译完成后传回研发,研发再替换到项目中。(一般给翻译人员的是 excel 或者 txt,还需要脚本进行转换至 json 之类的格式);

或者,可以将待翻译文件被上传至在线文档,多名翻译人员可以同时协同翻译;

又或者,也可以使用专门的翻译协作平台, 如 Transifex, Lokalise, Crowdin等。这些平台基本都集成了 github,gitlab 等仓库,也支持 api 访问。

然而这些平台收费都不菲(企业 5000 刀/年),今天介绍的是一款开源的翻译协作项目 “weblate”,基于它可以自行搭建翻译协作平台。

安装

  1. 安装 docker,docker-compose

  2. 下载 weblate

git clone https://github.com/WeblateOrg/docker-compose.git weblate-docker
cd weblate-docker && vi docker-compose.override.yml
version: '3'
services:
    weblate:
        ports:
        - 80:8080
        environment:
        WEBLATE_EMAIL_HOST: smtp.example.com // 发送邮件邮箱
        WEBLATE_EMAIL_HOST_USER: user // 邮箱用户名
        WEBLATE_EMAIL_HOST_PASSWORD: *** // 邮箱密码
        WEBLATE_ALLOWED_HOSTS: weblate.example.com // 必须配置才能通过weblate.example.com访问
        WEBLATE_ADMIN_PASSWORD: *** // 管理员密码
        WEBLATE_SITE_DOMAIN: weblate.example.com // 站点域名
        WEBLATE_ADMIN_EMAIL: admin@example.com // 管理员邮箱
// 启动
docker-compose up
// 停止
docker-compose down

附上官方安装步骤

集成 git

  1. 将 ssh 密钥添加至 git 仓库

weblate-ssh.png

  1. 在组件的设置里配置 git 地址

weblate-git.png

  1. 设置文件模板

weblate-file.png

官方版本控制集成文档

api 访问

如果对 weblate 的安全持有怀疑,weblate 也提供了 api 访问

  1. 上传 官方文档给了示例:
curl -X POST \
    -F file=@strings.xml \
    -H "Authorization: Token TOKEN" \
    http://example.com/api/translations/hello/android/cs/file/

但是尝试了多次都失败了,一度怀疑是配置有问题,后来发现是缺少了 method,加上method: replace就可以了

下面是用 node 实现的关键步骤

const program = require("commander");
const axios = require("axios");
const fsExtra = require("fs-extra");
const FormData = require("form-data");

// 获取相关参数
program
  .option("-p, --path <path>", "翻译文件的路径")
  .option("-o, --organization <organization>", "所属组织")
  .parse(process.argv);

// 创建axiosBase
const axiosBase = axios.create({
  baseURL: "http://xxx/api/",
  headers: {
    "Content-Disposition": "attachment",
    "Content-Type": "multipart/form-data",
    Authorization: "Token xxx",
  },
});

// 获取所有需要上传的文件
const files = fsExtra.readdirSync(uploadPath);

// 组装formdata
let formData = new FormData();
formData.append("method", "replace");
formData.append("file", file);
formData.append("filename", fileName);
const headers = formData.getHeaders();

// 上传文件
await axiosBase.post(
  `translations/${organization}/${componentName}/${fileLang}/file/`,
  formData,
  { headers }
);
  1. 下载 翻译人员在平台上翻译完成后,再通过脚本将文案拉到项目中。
// 获取目标文件夹中所有需要下载的语言
const fileList = await fsExtra.readdirSync(outputPath);

// 下载所有语言的文件
fileList.forEach(async (file) => {
  let [fileName] = file.split(".");
  const res = await axiosBase(
    `translations/${organization}/${componentName}/${fileName}/file/`
  );
});

// 将文件写入本地
await fsExtra.outputFileSync(
  `${outputPath}/${fileName}.json`,
  JSON.stringify(res.data, null, 2),
  "utf8"
);

如果国际化使用的是 kiwi,也可以支持,大致思路就是将导出的 txt 转为 json 再上传,翻译完成,下载后再转为 txt,关键包为 d3-dsv。