LunariaJS + Git:基于版本控制的本地化工作流
讲解 LunariaJS 如何利用 Git 追踪本地化变更,学习通过 Git 提交历史识别翻译更新、检测过时内容,实现与团队协作无缝集成的本地化工作流。
LunariaJS + Git:基于版本控制的本地化工作流
在前面几篇文章中,我们介绍了 LunariaJS 的安装、配置和仪表板使用。你可能已经注意到,LunariaJS 的一个核心特性是基于 Git 的工作流。今天,让我们深入探讨 LunariaJS 如何利用 Git 来追踪本地化变更,以及如何设计高效的团队协作工作流。
💡 官方文档:LunariaJS 中文文档 - Git 工作流
为什么需要 Git 集成?
传统本地化管理的困境
在没有 Git 集成的情况下,管理翻译状态通常需要:
方式一:手动维护表格
| 文件 | 中文 | 日文 | 韩文 |
|---|---|---|---|
| index.md | ✅ | ✅ | ❌ |
| getting-started.md | ✅ | ⚠️ | ⚠️ |
| configuration.md | ❌ | ❌ | ❌ |
问题:
- 表格容易与实际文件不同步
- 不知道”⚠️”具体落后多少
- 更新表格是额外的维护负担
方式二:依赖翻译平台的版本控制
一些在线翻译平台(如 Crowdin)有自己的版本控制系统。
问题:
- 与代码仓库分离
- 需要配置同步机制
- 可能出现版本不一致
方式三:在文件中添加标记
<!-- TODO: Translate to Chinese -->
<!-- LAST_UPDATED: 2026-02-20 -->
<!-- STATUS: OUTDATED -->
问题:
- 污染文件内容
- 容易忘记更新标记
- 难以批量分析
LunariaJS 的 Git 集成优势
LunariaJS 选择了一条不同的路:直接使用 Git 提交历史来判断翻译状态。
核心优势:
| 优势 | 说明 |
|---|---|
| 无需额外标记 | 文件本身就是数据源 |
| 自动同步 | Git 历史与代码完全同步 |
| 精确追踪 | 知道每次变更的时间和作者 |
| 团队友好 | 融入现有的 Git 工作流 |
Git 追踪机制详解
基本原理
LunariaJS 通过以下步骤判断翻译状态:
1. 获取文件最后修改时间
使用 git log 命令获取每个文件的最后修改提交:
git log -1 --format="%H %ct" -- path/to/file.md
2. 对比源文件和翻译文件的时间戳
源文件 (en/getting-started.md): 2026-02-28 14:30
翻译文件 (zh-cn/getting-started.md): 2026-02-20 10:15
时间差: 8 天
状态: 过时 (Outdated)
3. 生成状态报告
根据时间戳对比,为每个翻译文件生成状态。
文件变更检测算法
LunariaJS 使用以下算法检测文件变更:
// 简化的算法逻辑
function getTranslationStatus(sourceFile: File, translationFile: File): Status {
// 情况 1: 翻译文件不存在
if (!translationFile.exists()) {
return 'missing';
}
// 获取最后修改时间
const sourceLastModified = getLastCommitTime(sourceFile);
const translationLastModified = getLastCommitTime(translationFile);
// 情况 2: 翻译比源文件新或同步
if (translationLastModified >= sourceLastModified) {
return 'done';
}
// 情况 3: 源文件比翻译新
return 'outdated';
}
Git 提交时间戳解析
# 获取文件的最后修改提交
$ git log -1 --format="%H %ct %s" -- docs/en/getting-started.md
abc1234567 1709123400 "Update getting-started documentation"
输出解析:
%H:完整提交哈希%ct:Unix 时间戳%s:提交消息
过时翻译检测原理
时间戳对比策略
LunariaJS 使用”最后修改时间”策略来判断翻译是否过时:
时间线示例:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━▶
│ │ │
2月20日 2月25日 2月28日
│ │ │
中文翻译更新 英文源文件更新 当前时间
(commit: def5678) (commit: abc1234)
│ │
└──────────────────────┘
时间差 8 天
↓
状态: 过时 🟡
为什么不用内容对比?
你可能会问:为什么不用 git diff 直接对比内容?
内容对比的问题:
- 计算成本高(需要读取和解析每个文件)
- 无法处理结构相同但内容不同的情况
- 对大型项目性能影响大
时间戳对比的优势:
- 计算成本低(只需读取 Git 元数据)
- 性能稳定,不受文件大小影响
- 语义清晰:源文件更新后翻译就是”过时”
特殊情况处理
情况 1:源文件和翻译同时更新
# 同一次提交中更新了源文件和翻译
$ git log --oneline -- docs/en/guide.md docs/zh-cn/guide.md
abc1234 (HEAD) Update guide documentation
结果:状态为 done ✅
情况 2:只更新了翻译文件
# 只更新了翻译,源文件未变
$ git log -1 -- docs/zh-cn/guide.md
abc1234 (HEAD) Update Chinese translation
$ git log -1 -- docs/en/guide.md
def5678 (HEAD~1) Original guide
结果:状态为 done ✅
情况 3:格式调整但不影响内容
# 源文件只是格式调整
$ git show abc1234 --stat
docs/en/guide.md | 2 +-
# 只是调整空格或换行
结果:状态为 outdated ⚠️(保守策略)
💡 这是 LunariaJS 的保守设计选择。如果你确定翻译仍然有效,可以在提交消息中添加
[skip lunaria]标记。
分支策略与本地化
主分支翻译管理
大多数项目在主分支(main 或 master)上管理翻译:
main
│
├── docs/en/ # 源语言(英语)
│ ├── index.md
│ └── guide.md
│
├── docs/zh-cn/ # 中文翻译
│ ├── index.md
│ └── guide.md
│
└── docs/ja/ # 日文翻译
├── index.md
└── guide.md
LunariaJS 配置:
{
"sourceLanguage": "en",
"languages": ["en", "zh-cn", "ja"],
"files": [
{
"sourcePath": "docs/en/{slug}.md",
"localizationPath": "docs/{lang}/{slug}.md"
}
]
}
功能分支的翻译处理
当开发新功能时,通常会创建功能分支:
main
│
└── feature/new-api-docs
│
└── docs/en/api/new-endpoint.md # 新增源文件
问题:新功能分支的翻译如何处理?
策略一:功能分支不翻译
- 源文件先在功能分支完成
- 合并到主分支后再开始翻译
- 优点:避免翻译冲突
- 缺点:用户看到缺失翻译
策略二:同步翻译
feature/new-api-docs
│
├── docs/en/api/new-endpoint.md
├── docs/zh-cn/api/new-endpoint.md
└── docs/ja/api/new-endpoint.md
- 优点:功能上线时翻译同步完成
- 缺点:需要协调翻译时间
策略三:使用草稿标记
---
title: New API Endpoint
draft: true # 标记为草稿,不显示在公开站点
---
- 源文件完成后移除草稿标记
- 翻译文件也可以使用草稿标记
合并时的翻译冲突解决
当源文件更新与翻译更新发生冲突:
# 场景:主分支更新了源文件,PR 分支更新了翻译
$ git merge feature/update-zh-translation
CONFLICT (content): Merge conflict in docs/zh-cn/guide.md
解决步骤:
- 识别冲突内容
<<<<<<< HEAD
这是主分支的更新内容
=======
这是翻译分支的内容
>>>>>>> feature/update-zh-translation
-
评估冲突性质
- 是否是翻译相关的内容?
- 源文件有什么变更?
-
解决冲突
- 如果是翻译更新:保留翻译分支的内容
- 如果源文件有新内容:合并后重新翻译
-
验证翻译一致性
# 构建仪表板检查状态
npx lunaria build --verbose
团队协作工作流
翻译贡献者工作流
场景:社区贡献者想要帮助翻译
步骤 1:查看仪表板
访问项目的 LunariaJS 仪表板,找到需要翻译的文件。
步骤 2:Fork 并创建分支
# Fork 项目后
git clone https://github.com/your-username/project-name.git
cd project-name
git checkout -b translate/zh-cn-guide
步骤 3:翻译文件
# 创建或更新翻译文件
# docs/zh-cn/guide.md
步骤 4:提交并创建 PR
git add docs/zh-cn/guide.md
git commit -m "Translate guide to Chinese"
git push origin translate/zh-cn-guide
步骤 5:PR 审查
维护者审查翻译质量和准确性。
代码审查中的翻译检查
在 PR 审查时,可以添加翻译状态检查:
# .github/workflows/translation-check.yml
name: Translation Check
on: [pull_request]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # 获取完整历史
- name: Build Lunaria Dashboard
run: |
npm ci
npx lunaria build
- name: Check Translation Status
run: |
# 检查是否有新增的缺失翻译
node scripts/check-new-missing.js
翻译更新 PR 流程
自动化流程:
源文件更新
│
▼
CI 检测到过时翻译
│
▼
创建翻译更新 Issue
│
▼
翻译贡献者认领
│
▼
提交翻译更新 PR
│
▼
审查合并
│
▼
仪表板更新 ✅
Issue 自动创建示例
当检测到大量过时翻译时,可以自动创建 Issue:
## 🌙 翻译同步提醒
### 概要
- 过时翻译数量: 12
- 影响语言: 中文 (5), 日文 (4), 韩文 (3)
### 需要更新的文件
| 文件 | 语言 | 落后天数 |
|------|------|----------|
| getting-started.md | 中文 | 8 |
| configuration.md | 日文 | 5 |
| api/overview.md | 韩文 | 3 |
### 行动
请各位翻译贡献者认领并更新相关翻译。
---
*此 Issue 由 LunariaJS 自动生成*
Git 集成最佳实践
1. 保持提交粒度适中
推荐做法:
# 每个翻译文件单独提交
git add docs/zh-cn/guide.md
git commit -m "Translate guide to Chinese"
# 或相关文件一起提交
git add docs/zh-cn/
git commit -m "Update Chinese translations for v2.0"
不推荐:
# 混合源代码和翻译的提交
git add .
git commit -m "Various updates"
2. 使用有意义的提交消息
推荐格式:
[i18n/zh-cn] Translate guide.md
- Translate introduction section
- Update code examples
- Fix terminology consistency
Related: #123
3. 利用 Git Blame 追踪翻译历史
# 查看翻译文件的修改历史
git blame docs/zh-cn/guide.md
# 查看特定行的最后修改
git blame -L 10,20 docs/zh-cn/guide.md
4. 使用 Git Hooks 自动化
# pre-commit hook
#!/bin/bash
# 检查是否有源文件更新但翻译未更新
npm run lunaria:check-outdated
if [ $? -ne 0 ]; then
echo "Warning: Some translations are outdated!"
echo "Run 'npx lunaria build' to see details."
fi
5. 配置 .gitattributes
# .gitattributes
# 标记翻译文件的语言
docs/zh-cn/*.md linguist-language=Markdown
docs/ja/*.md linguist-language=Markdown
# 在 git diff 中更好地显示变更
*.md text eol=lf
高级 Git 集成技巧
1. 使用 Git 别名简化操作
# ~/.gitconfig
[alias]
lunaria = "!f() { npx lunaria \"$@\"; }; f"
i18n-status = "!f() { npx lunaria build && npx lunaria preview; }; f"
使用:
git lunaria build
git i18n-status
2. 多仓库翻译管理
对于 Monorepo 项目:
{
"files": [
{
"sourcePath": "packages/core/docs/{slug}.md",
"localizationPath": "packages/core/i18n/{lang}/{slug}.md"
},
{
"sourcePath": "packages/cli/docs/{slug}.md",
"localizationPath": "packages/cli/i18n/{lang}/{slug}.md"
}
]
}
3. 使用子模块管理翻译
# 添加翻译子模块
git submodule add https://github.com/org/translations.git i18n
# 更新翻译
git submodule update --remote i18n
4. 翻译分支策略
main
│
├── i18n/zh-cn # 中文翻译分支
│
├── i18n/ja # 日文翻译分支
│
└── i18n/ko # 韩文翻译分支
每个翻译分支由对应的语言维护者管理,定期合并回主分支。
常见问题与解决方案
Q1:Git 历史不完整导致状态错误
问题:浅克隆(shallow clone)没有完整历史。
解决方案:
# 获取完整历史
git fetch --unshallow
# 或在 CI 中配置
- uses: actions/checkout@v4
with:
fetch-depth: 0 # 完整历史
Q2:大文件翻译追踪性能问题
问题:项目文件过多导致构建缓慢。
解决方案:
{
"files": [
{
"sourcePath": "docs/{slug}.md",
"localizationPath": "i18n/{lang}/docs/{slug}.md",
"include": ["**/*.md"],
"exclude": ["**/draft/**", "**/internal/**"]
}
]
}
Q3:重命名文件后状态丢失
问题:文件重命名后 Git 历史追踪断开。
解决方案:
# 使用 git mv 保留历史
git mv docs/old-name.md docs/new-name.md
总结
LunariaJS 与 Git 的深度集成带来了强大的本地化管理能力:
| 特性 | 价值 |
|---|---|
| 时间戳对比 | 自动检测过时翻译 |
| 无额外标记 | 保持文件干净 |
| 团队协作 | 融入现有工作流 |
| 历史追踪 | 可追溯每次变更 |
| CI/CD 集成 | 自动化翻译检查 |
关键要点:
- Git 提交时间是判断翻译状态的核心依据
- 使用有意义的工作流处理分支和合并
- 利用 CI/CD 自动化翻译状态检查
- 保持良好的提交习惯便于追踪
下一步
下一篇文章,我们将探讨 LunariaJS 与 Astro Starlight 的完美集成,学习如何:
- 安装和配置 @lunariajs/starlight
- 将仪表板嵌入文档站点
- 构建三语言文档站点实战
- 解决常见集成问题
敬请期待!
💡 推荐阅读: