locale-sync-cli
v1.0.1
Published
Enterprise i18n Sync CLI (Local <-> Google Sheets)
Readme
🌐 locale-sync-cli
企业级国际化 (i18n) 同步命令行工具 — 本地语言包 ↔ Google Sheets 双向同步
📋 目录
- 核心功能
- 架构概览
- 安装与初始化
- 命令详解
- Google Sheets 双工作表架构
- 颜色语义系统
- 智能同步策略
- 冲突检测与解决
- 文件扫描与解析
- 多 Locale 文件格式支持
- 占位符一致性校验
- 安全防护
- 配置参考
- 凭证管理
- CI/CD 集成
- 本地语言包目录结构
- 技术栈
- 常见问题
🎯 核心功能
| 功能 | 描述 |
|------|------|
| 双向同步 | 本地语言包 ⇄ Google Sheets,支持 Push(上传)和 Pull(下载) |
| 智能匹配 | 基于英文锚点 (English Anchor) 的精准 key 匹配,兼容多 key 同值场景 |
| 冲突检测 | 多人协作时自动检测翻译冲突,以黄色标记提示人工确认 |
| 颜色语义 | Google Sheets 中通过单元格背景色区分翻译来源与状态 |
| 双表架构 | Common 表 + 项目表,实现共享翻译与项目级覆盖的灵活管理 |
| 多格式支持 | 支持 .js (AST)、.json (Comment JSON)、.yaml/.yml 三种文件格式 |
| Multi-Locale | 自动识别单文件多 locale 格式(如 { "en-US": {...}, "ar-SA": {...} }) |
| AST 保真 | JS 文件通过 AST 解析 + recast 回写,保留原始代码风格、注释、格式 |
| 占位符检查 | Pull 时自动校验 ${...}、{...}、%s 等占位符一致性,防止翻译遗漏 |
| 安全拦截 | 自动拦截 Google Sheets 公式注入(= 开头)及非法控制字符 |
| 防环路机制 | 可配置的 antiLoopWindow 防止 Push/Pull 在短时间内形成循环更新 |
| Dry-Run | 默认预览模式,显示变更计划后确认执行,安全可控 |
| CI/CD | 支持 --yes 参数跳过交互确认,适配自动化流水线 |
| 凭证安全 | Base64 编码存入 Shell Profile,无需在项目中暴露敏感文件 |
🏗 架构概览
┌──────────────────────────────────────────────────────────────┐
│ CLI Layer (bin/) │
│ commander + inquirer 交互 │
├──────────────────────────────────────────────────────────────┤
│ Commands (lib/cli/) │
│ init / push / pull / set-credentials / ignore │
├──────────────────────┬───────────────────────────────────────┤
│ Push Engine │ Pull Engine │
│ lib/core/engines/ │ lib/core/engines/ │
│ pushEngine.js │ pullEngine.js │
├──────────────────────┴───────────────────────────────────────┤
│ Core Utils │
│ stringNormalizer.js │ placeholderChecker.js │
├──────────────────────┬───────────────────────────────────────┤
│ IO: Google Sheets │ IO: Local FS │
│ googleSheets.js │ scanner.js / astUpdater.js │
├──────────────────────┴───────────────────────────────────────┤
│ Config Manager │
│ lib/config/manager.js │
└──────────────────────────────────────────────────────────────┘模块说明
| 模块 | 文件 | 职责 |
|------|------|------|
| CLI 入口 | bin/locale-sync.js | Commander 命令行定义、Web API polyfill |
| 项目初始化 | lib/cli/commands/init.js | 交互式创建 .locale-sync.json 配置,配置凭证 |
| Push 命令 | lib/cli/commands/push.js | 扫描本地 → 读取 Sheets → 生成推送计划 → 执行 |
| Pull 命令 | lib/cli/commands/pull.js | 读取 Sheets → 扫描本地 → 生成拉取计划 → AST 回写 |
| 凭证管理 | lib/cli/commands/set-credentials.js | 独立更新 Google 凭证 |
| 忽略规则 | lib/cli/commands/ignore.js | 管理文件/文件夹忽略规则 |
| Push 引擎 | lib/core/engines/pushEngine.js | 核心推送逻辑:增量更新、冲突检测、新增行 |
| Pull 引擎 | lib/core/engines/pullEngine.js | 核心拉取逻辑:优先级链解析、变化检测 |
| Google Sheets IO | lib/io/googleSheets.js | Google Sheets API v4 封装:认证、读写、格式化、批量操作 |
| 文件扫描器 | lib/io/localFs/scanner.js | 递归扫描 locale 目录,解析 JS/JSON/YAML 文件提取 key-value |
| AST 更新器 | lib/io/localFs/astUpdater.js | AST 解析回写,支持 ObjectProperty、数组、TemplateLiteral |
| 字符串规范化 | lib/core/utils/stringNormalizer.js | 英文锚点规范化、locale 码格式化 |
| 占位符检查 | lib/core/utils/placeholderChecker.js | 正则提取 + 一致性比较({...}, ${...}, %s, XML 标签等) |
| 配置管理 | lib/config/manager.js | 加载/合并配置文件,CI 环境检测 |
| 日志工具 | lib/cli/utils/logger.js | 统一风格的彩色日志输出 (info/success/warn/error) |
| 默认配置 | config/default.json | 默认配置值、targetLocales、formats 策略 |
📦 安装与初始化
环境要求
- Node.js >= 16.0.0
- Google Cloud 项目 + 启用了 Google Sheets API 的 Service Account
- 目标 Google Sheet 已共享给 Service Account 的邮箱(Editor 权限)
安装
npm install初始化
npx locale-sync init交互式引导:
| 提示 | 说明 | 示例 |
|------|------|------|
| Google Sheet ID | 从 Sheets URL 中提取 | 1NbUr7mtbRMZXtrOmyvcjiaMeQzzgWmYhNUke7uUSe54 |
| Locales Directory | 本地语言包根目录 | locales/lang |
| Project Name | 项目名称(用作项目表名) | my-app |
| Ignore patterns | 跳过扫描的文件/文件夹(逗号分隔) | node_modules,*.d.ts |
| Credentials source | Service Account JSON 路径或 URL | ./service-account.json |
初始化后生成 .locale-sync.json 配置文件,并将凭证 Base64 编码写入 Shell Profile(~/.zshrc / ~/.bash_profile)。
📟 命令详解
init — 项目初始化
npx locale-sync init创建 .locale-sync.json 配置,设置 Google 凭证。重复运行可重新配置。
push — 本地 → Google Sheets
npx locale-sync push [options]| 选项 | 说明 |
|------|------|
| -y, --yes | 跳过确认提示,直接执行同步 |
| -v, --verbose | 输出详细错误堆栈 |
执行流程:
- ✅ 加载配置 + 认证 Google Sheets API
- ✅ 扫描本地 locale 目录(.js / .json / .yaml)
- ✅ 读取 Google Sheets 的 Common 表和项目表
- ✅ 输出 Scan Summary(每个 locale 的 key 数量、空值数量)
- ✅ 生成推送计划并展示 Push Preview(新增行数、更新行数)
- ✅ 用户确认后执行批量写入
pull — Google Sheets → 本地
npx locale-sync pull [options]| 选项 | 说明 |
|------|------|
| -y, --yes | 跳过确认提示 |
| -v, --verbose | 输出详细错误堆栈 |
执行流程:
- ✅ 读取 Google Sheets 的 Common 表和项目表
- ✅ 扫描本地 locale 目录
- ✅ 按优先级链生成 Pull Plan
- ✅ 展示每个变更(locale/key: old → new)+ 总计 key 变更数
- ✅ 用户确认后通过 AST 回写到本地文件,结果报告实际更新的 key 数量
set-credentials — 凭证管理
npx locale-sync set-credentials独立更新 Google Service Account 凭证,支持本地文件路径或远程 URL。
ignore — 忽略规则管理
# 添加忽略规则
npx locale-sync ignore node_modules
npx locale-sync ignore *.d.ts index.js
# 查看当前规则
npx locale-sync ignore --list
# 移除规则
npx locale-sync ignore --remove node_modules忽略规则会自动转换为 glob 模式:
node_modules→**/node_modules/**,**/node_modules*.d.ts→**/*.d.tsindex.js→**/index.js- 含
/的路径(如locales/i18n.js)视为项目根目录的相对路径,自动转换为相对于扫描目录(locales)的路径后再应用 glob 规则
config — 查看当前配置
npx locale-sync
# 或直接运行无参数命令展示合并后的完整配置(Default + Local + Overrides)。
📊 Google Sheets 双工作表架构
┌─────────────────────────────────────────────────────────┐
│ Google Sheet │
├─────────────────────┬───────────────────────────────────┤
│ Common 表 (共享) │ Project 表 (项目专用) │
├─────────────────────┼───────────────────────────────────┤
│ en-US │ ar-SA │ ... │ key │ filePath │ en-US │ ar-SA │...│
├─────────────────────┼───────────────────────────────────┤
│ Hello │ مرحبا │ ... │ a.b │ path/to/ │ │ مرحبا │ │
│ World │ 世界 │ ... │ x.y │ path/to/ │ Hello │ │ │
└─────────────────────┴───────────────────────────────────┘Common 表(共享翻译层)
- 列结构:
en-US | ar-SA | pt-BR | ... | _lastSyncBy | _lastSyncAt - 锚点: 以英文(en-US / en / enus)列作为匹配锚点
- 职责: 存放跨项目共享的通用翻译,Push 时优先写入此处
- 特点: 无
key、filePath列,纯翻译内容驱动
Project 表(项目专用层)
- 列结构:
key | filePath | en-US | ar-SA | pt-BR | ... | _lastSyncBy | _lastSyncAt - 主键:
key + filePath组合唯一 - 职责:
- 项目级翻译覆盖(优先级高于 Common)
- 存放冲突翻译(黄色行)
- 存放项目独有的 key
- 灰色行: 整行标记为已废弃/忽略
元数据列
| 列名 | 说明 |
|------|------|
| _lastSyncBy | 最后同步方向:push 或 pull |
| _lastSyncAt | 最后同步时间戳 (ISO 8601) |
🎨 颜色语义系统
| 颜色 | 含义 | 触发条件 | |------|------|----------| | 🟢 绿色 | 自动同步内容 | Push 写入的新值或填充的空格 | | 🟡 黄色 | 冲突待确认 | 同一 locale 存在多个不同翻译来源 | | ⬜ 无色/白色 | 人工编辑锁定 | 译者在 Sheets 中手动输入的值,Push 不会覆盖 | | 🔴 红色 | 错误标记 | (预留) | | 🩶 灰色 | 整行废弃 | 整行标记为忽略,Push/Pull 均跳过 | | 🔵 青色(Header) | 表头标识 | 首行自动格式化为青色背景 + 粗体 |
Push 写入规则
单元格状态 │ Push 行为
──────────────────┼────────────
空 + 无色 │ ✅ 写入(绿色)
有值 + 绿色 │ ✅ 更新(绿色)
有值 + 无色 │ ❌ 跳过(视为人工编辑锁定)
有值 + 黄色 │ ❌ 跳过(保留冲突状态)
空 + 绿色/黄色 │ ❌ 跳过(视为主动清空)🧠 智能同步策略
Push 详细流程
本地文件扫描
│
▼
┌─────────────────────────────────────┐
│ 1. 构建英文锚点 (normalizeForAnchor) │
│ "Hello World" → "Hello World" │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 2. 在 Common 表按锚点匹配 │
│ 找到?→ 更新 Common 行 │
│ 未找到?→ 新增 Common 行 │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 3. 在 Project 表按 key+filePath 匹配 │
│ 找到?→ 更新 Project 行 │
│ 冲突?→ 追加黄色冲突行 │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 4. 同一批次内冲突检测 │
│ 同锚点多次出现 → 首个写入 Common │
│ 后续差异 → 追加 Project 冲突行 │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 5. 批量写入 Google Sheets │
│ • appendCells (新增行) │
│ • updateCells (更新单元格) │
│ 每批最多 400 请求 + 3 次重试 │
└─────────────────────────────────────┘Pull 详细流程
Google Sheets 数据
│
▼
┌───────────────────────────────────────┐
│ 优先级链(按列独立判定) │
│ │
│ 1. 项目表 有值 (不论颜色) ← 最高 │
│ 2. 项目表 清空 (空+有色) │
│ 3. Common 有值 (无色/绿色) │
│ 4. Common 有值 (黄色) ← 警告 │
│ 5. Common 清空 (空+有色) │
│ 6. 保留本地值 ← 最低 │
└───────────────────────────────────────┘
│
▼
┌───────────────────────────────────────┐
│ 第一轮:遍历 Project 表行 │
│ • 跳过灰色行 │
│ • 跳过 antiLoopWindow 内的行 │
│ • en 锚点 → 备用锚点(__noen__/__key__)│
│ • 按优先级链取最终值 │
│ • 若与本地不同 → 加入 Pull Plan │
└───────────────────────────────────────┘
│
▼
┌───────────────────────────────────────┐
│ 第二轮:遍历 Common 表未覆盖的行 │
│ • 跳过已在 Project 表处理过的锚点 │
│ • 同样支持备用锚点 │
│ • 相同优先级逻辑处理 │
└───────────────────────────────────────┘
│
▼
┌───────────────────────────────────────┐
│ AST 回写到本地文件 │
│ .js → recast AST 保真写入 │
│ .json → comment-json 保留注释 │
│ .yaml → js-yaml dump │
└───────────────────────────────────────┘英文锚点策略
Push 和 Pull 都使用 英文值 (en) 作为跨表匹配的锚点:
// 规范化流程
" Hello World " → normalizeForAnchor → "Hello World"- 合并连续空白为单空格
- 移除零宽字符(
\u200B-\u200D)和不间断空格(\u00A0) - 保留大小写(区分大小写匹配)
备用锚点(en 为空时,Push/Pull 均支持):
__noen__前缀 + 按表头 locale 列顺序取第一个非空翻译值__key__前缀 +key|filePath组合兜底
Locale 码多级回退匹配
Pull 时从 Sheet 行读取值与颜色,采用三级回退兼容本地短码与 Sheet 长格式:
localeKey = "ar"(来自本地目录结构)
│
├─ 1. 精确匹配: row["ar"] → ar-SA 表头归一化为 arsa,不命中
├─ 2. 基础码匹配: row["ar"] → 若 ar 存在于 Sheet 行
└─ 3. 前缀扫描: row["arsa"] → 找到以 "ar" 开头且更长的 key这确保以下场景无缝工作:
| 本地目录 | Sheet 表头 | 匹配结果 |
|---------|-----------|---------|
| locales/lang/ar/ | ar-SA | ✅ arsa |
| locales/lang/en/ | en-US | ✅ enus |
| locales/lang/pt/ | pt-BR | ✅ ptbr |
| locales/lang/arae/ | ar-SA | ✅ arsa |
⚔️ 冲突检测与解决
冲突场景
场景 1: 同一英文锚点,不同 locale 值
File A: en="Hello" → ar="مرحبا"
File B: en="Hello" → ar="أهلا"
→ Common 写入 "مرحبا",Project 追加黄色行 "أهلا"
场景 2: 同一批次 Push 内重复锚点
第 1 个 en="Welcome" → Common 写入(绿色)
第 2 个 en="Welcome" → 差异 locale 追加冲突行(黄色)
场景 3: Pull 时 Common 与 Project 不一致
Project ar = "مرحبا" (绿色)
Common ar = "أهلا" (黄色)
→ 优先取 Project 值,若为黄色则附加警告黄色冲突行的处理
- Push 阶段: 黄色冲突行保留不改,供人工审核
- Pull 阶段: 黄色值会被拉取,但附带
[待人工确认]警告 - 人工解决: 译者在 Sheets 中确认正确翻译后,可清除颜色标记锁定
📝 文件扫描与解析
扫描器 (scanner.js)
扫描目录
│
├─ .js 文件 → @babel/parser + recast (AST)
│ ├─ ObjectProperty: StringLiteral → 提取 key-value
│ ├─ ObjectProperty: TemplateLiteral → 序列化 ${...}
│ ├─ Array StringLiteral → 提取
│ └─ Array TemplateLiteral → 序列化
│
├─ .json 文件 → comment-json 解析(保留注释)
│ └─ 递归 flatten 嵌套对象
│
└─ .yaml/.yml 文件 → js-yaml 解析
└─ 递归 flatten 嵌套对象AST 更新器 (astUpdater.js)
Pull 回写策略
.js 文件:
├─ StringLiteral → 直接替换 value
├─ TemplateLiteral → 按 ${expr} 分割重组 quasis
└─ recast.print() 保真输出(保留代码风格)
.json 文件:
└─ comment-json 深度赋值 + stringify(保留注释)
.yaml 文件:
└─ js-yaml dump(保持结构)Locale 检测策略
文件路径解析优先级:
1. 文件名是合法 locale 代码 → 使用文件名
例: ar-SA.js → locale='ar', en-US.js → locale='en'
2. 任意目录层级是合法 locale 代码 → 使用该目录名
例: lang/en-US/common.js → locale='en'
3. 都不满足 → 使用文件名(后续 multi-locale 检测覆盖)🌍 多 Locale 文件格式支持
格式 1: 单文件单 Locale(推荐)
// locales/lang/en-US/common.js
export default {
hello: 'Hello',
welcome: 'Welcome'
};
// locales/lang/ar-SA/common.js
export default {
hello: 'مرحبا',
welcome: 'أهلا وسهلا'
};格式 2: 单文件多 Locale(自动识别)
// locales/oom/en-US.js
export default {
enUS: { hello: 'Hello', welcome: 'Welcome' },
arSA: { hello: 'مرحبا', welcome: 'أهلا وسهلا' },
ptPT: { hello: 'Olá', welcome: 'Bem-vindo' }
};自动识别条件: 顶层所有 key 均为合法 locale 代码 (/^[a-z]{2,3}([A-Z]{2,3}|[-_][a-zA-Z]{2,3})?$/)
格式 3: JSON / YAML 多 Locale
{
"en-US": { "hello": "Hello" },
"ar-SA": { "hello": "مرحبا" }
}同样自动拆分合并。
🔍 占位符一致性校验
Pull 回写时自动检测翻译中的占位符是否与英文源一致。
支持的占位符类型
| 类型 | 正则 | 示例 |
|------|------|------|
| 花括号 | {name} | {count} {username} |
| 美元花括号 | ${expr} | ${process.env.API} |
| printf 风格 | %s %d | %s %d |
| 命名 printf | %{name} | %{value} |
| XML 标签 | <tag/> <br/> | <br/> |
校验输出
⚠️ Pull 警告:
[arSA] 缺失占位符: {username}, %s
[ptPT] 多余占位符: {email}
[arSA] 来源为黄色单元格(待人工确认)🔒 安全防护
公式注入拦截
Google Sheets 中 = 开头的值会被解释为公式,存在安全风险。Push 时自动检测并拒绝:
// ❌ 拒绝写入
"=IMPORTXML(\"https://evil.com\")" → Error: [Formula Injection]
// ✅ 正常写入
"Hello World" → OK控制字符检测
拒绝包含 ASCII 控制字符(\x00-\x08, \x0B-\x0C, \x0E-\x1F, \x7F)的翻译值。
凭证安全
- Service Account JSON 不保留在项目文件中
- Base64 编码后存入 Shell Profile 环境变量
init完成后提示删除原始文件:rm ./service-account.json
⚙️ 配置参考
.locale-sync.json
{
"sheetId": "1NbUr7mtbRMZXtrOmyvcjiaMeQzzgWmYhNUke7uUSe54",
"locales": ["locales/lang"],
"project": "my-project",
"ignore": ["node_modules", "*.d.ts"],
"sync": {
"dryRun": false,
"pruneDeadKeys": false,
"antiLoopWindow": 0
}
}配置项说明
| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| sheetId | string | - | Google Sheets 表格 ID |
| locales | string[] | ["locales/lang"] | 本地语言包目录列表 |
| project | string | package.json.name | 项目名(Project 表名) |
| ignore | string[] | [] | 扫描时要忽略的文件/目录 |
| sync.dryRun | boolean | false | 预览模式,不真正写入 |
| sync.pruneDeadKeys | boolean | false | 是否删除过期 key(待实现) |
| sync.antiLoopWindow | number | 0 | 防环路窗口(秒),0 表示关闭 |
| sync.ciAntiLoopWindow | number | 300 | CI 环境下的防环路窗口 |
| keyFile | string | ./service-account.json | 凭证文件路径(向后兼容) |
环境变量检测
CI=true或--ci参数:自动切换为ciAntiLoopWindowLOCALE_SYNC_CREDENTIALS:Base64 编码的凭证(优先于 keyFile)
🔐 凭证管理
凭证获取
- 前往 Google Cloud Console
- 创建/选择项目,启用 Google Sheets API
- 创建 Service Account → 生成 JSON 密钥
- 将生成的文件保存为
service-account.json - 将该文件拖入项目根目录
凭证存储
方式一:环境变量(推荐,CI 友好)
LOCALE_SYNC_CREDENTIALS = "base64-encoded-json"
方式二:Shell Profile
运行 locale-sync init → 自动写入 ~/.zshrc 或 ~/.bash_profile
方式三:本地文件(向后兼容)
项目根目录/service-account.jsonGoogle Sheets 权限
将 Service Account 的邮箱(client_email,形如 [email protected])添加为 Google Sheet 的 Editor。
🤖 CI/CD 集成
GitHub Actions 示例
- name: Sync Locales to Google Sheets
env:
LOCALE_SYNC_CREDENTIALS: ${{ secrets.LOCALE_SYNC_CREDENTIALS }}
run: |
npx locale-sync push --yes注意事项
- CI 环境自动启用
ciAntiLoopWindow(默认 300 秒) - 使用
--yes跳过交互确认 - 凭证通过 CI Secrets 注入
LOCALE_SYNC_CREDENTIALS环境变量
📁 本地语言包目录结构
示例项目结构
project/
├── .locale-sync.json # 项目配置
├── locales/
│ └── lang/
│ ├── en-US/ # 以 locale 命名的目录
│ │ ├── index.js
│ │ ├── common.js
│ │ ├── home.js
│ │ └── account.js
│ ├── ar-SA/
│ │ ├── index.js
│ │ ├── common.js
│ │ └── home.js
│ ├── pt-BR/
│ │ └── ...
│ └── es-MX/
│ └── ...
│
├── locales_foota/ # 另一个 locale 目录(可配置多个)
│ └── lang/en-US/...
│
└── locales_gulf/ # 第三个 locale 目录
└── lang/en-US/...Locale 代码规范
支持多种命名风格,内部自动规范化:
| 输入格式 | 规范化 | Google Sheets 表头 |
|----------|--------|-------------------|
| en-US | enus | en-US |
| ar-SA | arsa | ar-SA |
| pt-BR | ptbr | pt-BR |
| zh_CN | zhcn | zh-CN |
| en | en | en |
| arb | arb | arb |
🛠 技术栈
| 类别 | 技术 | 用途 | |------|------|------| | 运行时 | Node.js >= 16 | JavaScript 运行环境 | | CLI 框架 | Commander.js + Inquirer.js | 命令行交互 | | AST 解析 | @babel/parser + recast | JS 文件解析与保真回写 | | AST 遍历 | @babel/traverse + @babel/types | AST 节点遍历/类型判断 | | Google API | googleapis v173+ | Google Sheets API v4 | | JSON 解析 | comment-json | 保留 JSON 注释的解析/序列化 | | YAML 解析 | js-yaml | YAML 格式支持 | | 重试机制 | p-retry | API 请求自动重试 | | 并发控制 | p-queue | 批量操作队列管理 | | 日志美化 | chalk + ora | 彩色日志 + 加载动画 | | 文件匹配 | fast-glob | 递归文件扫描 | | HTTP Polyfill | undici + node-fetch | 低版本 Node.js 兼容 |
❓ 常见问题
Q: Push 后某些翻译没有出现在 Sheets 中?
检查是否被 忽略规则 排除(locale-sync ignore --list)。含 / 的路径(如 locales/i18n.js)以项目根目录为基准解析,确认文件确实在扫描目录内。
Q: 为什么某些单元格没有被 Push 更新?
该单元格可能处于以下状态之一:
- 无色 + 有值 → 人工编辑锁定,Push 不会覆盖
- 黄色 → 冲突状态,由人工确认后清除颜色
- 灰色行 → 已废弃,整行跳过
Q: 如何处理 Push 后出现的黄色冲突行?
- 打开 Google Sheet
- 查看黄色行中的冲突 locale
- 确认正确翻译,删除错误的
- 清除黄色背景 → 下次 Push 将遵循新值
Q: Pull 后本地文件格式变了?
JS 文件的 AST 回写使用 recast 保真输出,应保留原始代码风格。如遇格式变化,请检查源文件是否有语法错误导致 AST 解析失败。
Q: 如何在多项目间共享翻译?
Common 表中的翻译对所有使用同一 Google Sheet 的项目可见。Pull 时以 Project 表优先,Common 表作为 fallback。
Q: antiLoopWindow 是什么?
防止 Push 和 Pull 在短时间内形成循环更新。例如 Pull 写入某行后,antiLoopWindow 秒内来自 Pull 的行不会被 Push 回写。CI 环境下默认 300 秒。
📄 License
ISC
