Texterify——开源的本地化资源管理系统

前言

在调研管理本地化资源文件这条路上我一直摸索,之前团队内部也尝试过 Weblate,但是没有推行起来,主要是学习成本太高,并且对于非技术出生的翻译人员来说交互不够友好!

最近在逛 Github 时偶然发现一个 Star 数才三位数的开源项目 Texterify,官网提供 SaaS 服务,体验了以后觉得各方面都还不错,真是深得我心!

介绍

Texterify 的后端是采用 Ruby on Rails 框架开发的,支持的语言文件类型如下:

  • iOS: .strings 文件
  • JSON: .json 文件
  • JSON POEditor: .json 文件
  • JSON FormatJS: .json 文件
  • Chrome JSON: .json 文件
  • go-i18n: .toml 文件
  • TOML: .toml 文件
  • Java: .properties 文件
  • gettext: .po 文件
  • Django: .po 文件
  • Flutter: .arb 文件
  • XLIFF: .xlf, .xliff 文件
  • Rails: .yml, .yaml 文件
  • YAML: .yml, .yaml 文件

虽然是开源的但是 Self-Hosted 版依然需要付费购买 License,否则很多功能用不了,而它的 License 认证使用的是 Gitlab-License 库,所以可以从技术上解决授权的问题。

部署

参考官方文档,使用 Docker Compose 进行 Demo 部署,一路比较顺利,但是如果要自定义一些配置,给项目还有一些待优化的地方,我已经在 Github 上提交了 Issue 和 PR。

# Clone the docker-compose configuration.
git clone https://github.com/texterify/texterify-docker-compose-setup.git
cd texterify-docker-compose-setup
# Generate a secret key for the app.
# Make sure to keep this private.
echo SECRET_KEY_BASE=`openssl rand -hex 64` > secrets.env
# Open the .env file and replace "example.com" with your host (if you
# are trying to run Texterify locally just use "localhost" as host).
# Also make sure to check out the other configuration options (see below).
# Start the service.

docker volume create --name=texterify-database
docker volume create --name=texterify-assets
docker compose up --always-recreate-deps
# After everything has started create the database in another terminal.
docker compose exec app bin/rails db:create db:migrate db:seed

目前遇到的坑如下:

  • 第一个坑是 sidekiq 服务中无法获取到 REDIS_URL 环境变量,我提了 Issue
  • 第二个坑是 SMTP 配置中的 FORM,无法高度自定义,我提了 PR

付费模式

我在本地跑起来 Demo 以后,发现很多功能需要 Upgrade Plan,这个模式类似于 Gitlab CE 那种,具体 Plan 可以参考官网

于是我分析了 Texterify 的源码,发现 License 的许可主要使用的是 Gitlab::License 这个包。

瞟了一眼,发现这中授权模式是通过非对称加密,来加密 License 信息,然后通过公钥来进行解密,获取 License 的信息!

免费使用

知道了 License 的授权原理,那么接下来就好办了。于是乎我想到了,只要替换 Docker Image 中的 license_key.pub 文件就可以实现对自己生成的 License 进行验证。

然后登录 Texterify 的管理后台,上传 License 就可以了,具体操作步骤可以移步至我的博客

这里因为我没有录入 active_users_count 的信息,所以这里没有展示!

该授权方式仅用作技术交流,有能力的请订阅 Texterify 的 SaaS 服务,毕竟开源不易!

最佳实践

为了团队协作方便,这里需要约定了如下配置:

默认语言

默认语言是相对于开发者说的,也就是说,作为开发者我们只需要维护一个语言下的组件和对应的语言包。例如 zh_CN 这个语言,我们在编写代码时,将这个语言下的所有语言包对应的简体中文都完善,然后使用 CLI 将默认语言下的语言包 Push 到 Texterify,等待其他翻译人员对其他语言进行翻译,完成翻译后再由开发者使用 CLI 将其他语言包 Pull 到项目中,大致流程如下:

Texterify——开源的本地化资源管理系统

请记住每个项目只能设置一个默认语言!!!

语言名称

在 Texterify 的后台创建语言的时候,需要选择语言和国家,然后输入名称,这里建议将名称定义为如下格式lang_COUNTRY,例如:

Texterify——开源的本地化资源管理系统

在导出到项目时,CLI 会按照这个名称创建语言的目录,所以务必要按照这个约定创建语言名称!

项目组件

Laravel 项目下的语言包结构如下:

laravel tree lang               
lang
├── en_US
│   ├── auth.php
│   ├── pagination.php
│   └── passwords.php
├── zh_CN
│   ├── auth.php
│   ├── pagination.php
│   └── passwords.php
└── zh_TW
    ├── auth.php
    ├── pagination.php
    └── passwords.php

4 directories, 9 files

我们将每个 php 文件视为一个 component,并使用文件名称作为 component 的名称,也作为 Texterify 上的 keys 前缀。所有语言文件不要出现多级结构,例如 lang/en_US/estate/auth.php 这种方式在管理起来会有一定的麻烦!

例如 lang/zh_CN/auth.php 文件:

<?php

return [
    'failed' => '这些凭据与我们的记录不符。',
    'password' => '提供的密码不正确。',
    'throttle' => '登录尝试次数过多。请在 :seconds 秒后重试。',
];

使用 CLI 导入到 Texterify 后,会生成三个 keys,分别是:

  • auth.failed
  • auth.password
  • auth.throttle

这样对于 Laravel 开发者来说没有任何的学习成本,因为在项目中也是使用文件名加数组中的索引 Key 作为翻译的 Key。

管理组件

目前 CLI 未提供同步本地删除的 Key,因为这对于调用 Texterify 来说是非常麻烦的!所以只能在本地删除之后再到 Texterify 管理后台搜索 Key 再删除!

Key 名称

在定义翻译内容的 Key 时尤其是数据模型字段枚举值,尽量不要用数字,而是用语义化的字符串,这样便于翻译人员理解!例如:

# 尽量不要定义这样的 Key
estate.status.01

# 而是采用这种语义化的定义
estate.status.displaying

CLI

截止到写本文档为止,Texterify 尚未支持 PHP 文件的导入和导出,为此我在项目上提了 Issue,但是并未得到回应,于是只能按照已有的 API 来实现一个适配 PHP 项目的开源的 CLI

安装

composer global require betterde/texterify
or
composer require betterde/texterify --dev

配置

在项目目录下面使用如下命令生成项目的配置文件:

texterify auth https://texterify.sjmsdev.cn <project-id> <email> <token>

执行后会在项目目录下创建一个.texterify.json 文件,结构如下:

{
    "endpoint": "https:\/\/texterify.sjmsdev.cn\/api\/v1",
    "project": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "email": "developer@example.com",
    "token": "XXXXXXXXXXXXXXXXXXXXX"
}

常用命令

# 列出项目下所有的语言包
texterify component list

# 将本地的默认语言下的语言包推送到 Texterify
texterify component push

# 如果只需要推送单个语言包可以使用如下命令,这里的 COMPONENT_NAME 就是 texterify component list 命令列出的。
texterify component push COMPONENT_NAME

# 将 Texterify 上的语言包拉取到项目中
texterify component pull

# 将 Texterify 上的指定语言包拉取到项目中,会拉取除了默认语言外的其他语言
texterify component pull COMPONENT_NAME

# 将 Texterify 上的指定语言包拉取到项目中,仅拉取指定语言的语言包
texterify component pull COMPONENT_NAME --language en_US

代码美化

在使用 CLI 将翻译 Pull 到项目中时,使用的是 var_export 函数将数组转为代码的,所以最终生成的格式如下:

<?php

return array (
  'failed' => 'These credentials do not match our records.',
  'password' => 'The provided password is incorrect.',
  'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
);

可以看到使用的还是 array() 这种方式定义的数组,所以在项目中需要使用 laravel/pint 这个包,将这部分代码风格进行标准化!具体使用方法可以参考官方文档

我的博客:george.betterde.com
Github: github.com/jinrenjie or github.com/betterde

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!