
Fish Shell 的中文文档翻译项目 fish-shell-docs-l10n在开源社区里不算大但它特别能代表文档本地化l10n这件事的完整运作方式。如果你跟我一样第一次在终端里敲下fish命令时既惊喜又困惑大概就能理解为什么官方文档的翻译质量直接决定了一个用户是留下来继续用还是转头回到 bash。fish 的交互体验确实舒服自动建议、语法高亮、强大的补全系统都做得比传统 shell 友好但前提是你愿意先读一读文档。而文档只有英文版时相当一部分中文用户会直接卡在第一步。这个项目做的事情很纯粹把 fish shell 官方文档翻译成简体中文并长期跟进上游版本更新。对想参与开源翻译的人它也是一个非常合适的练手对象——流程标准、范围清晰、反馈及时。下面我从项目背景、协作机制、实际操作到问题排查完整梳理一遍。如果手头刚好有正在做的开源文档翻译项目哪怕不是 fish 相关这篇文章里的很多思路也直接拿过去能用。1. 项目背景与定位为什么要给 fish shell 做中文文档1.1 fish shell 到底好在哪为什么值得翻译它的文档fish 全称 Friendly Interactive Shell从名字就能看出来它主打“友好”。我最早接触 fish 是因为受够了 bash 里各种需要背的语法细节循环要写分号、变量赋值不能有空格、条件判断的方括号里外都得留空。这些倒不是不能用但每次都要小心翼翼交互体验始终差点意思。fish 的定位完全不同它希望用户打开终端之后不用折腾配置就能获得一个高可用的交互环境。具体到功能上几个点特别打动我。第一是语法高亮你输入命令的时候合法命令是亮色不存在的命令会标红色路径变量等元素也有不同颜色错误在回车之前就能看出来。第二是自动建议根据历史记录和当前目录fish 会在输入时用灰色字给出完整命令提示按右方向键就能补全确实快。第三是补全系统fish 自带了大量命令的补全定义比如 git 的子命令、参数、远程分支tab 按下去基本都是准确的。第四是fish_config一个基于 Web 的配置界面主题、提示符、别名都能在浏览器里点着设置完全不用手写配置。这些特性叠加起来fish 对新手非常友好但对老手来说迁移成本是真实存在的——因为 fish 的语法和 bash 不兼容这不只是换一个 shell等于要重新学一套脚本语言的规则。官方文档写得已经很清晰从 tutorial 到命令参考、语言规范、FAQ覆盖很全。但对不习惯读英文文档的人来说这道门槛比想象中高很多人试用两天遇到一点小问题去搜中文资料又搜不到像样的解释最后就放弃了。fish-shell-docs-l10n 瞄准的正是这个缺口让中文用户能直接读文档而不是靠猜和试错。1.2 文档本地化到底在做什么先澄清两个经常混用的词i18n 和 l10n。i18n 是 internationalization国际化的缩写因为 i 和 n 之间有 18 个字母l10n 是 localization本地化l 和 n 之间是 10 个字母。日常讨论里国际化通常指软件在设计上支持多语言比如界面字符串抽离、编码统一用 UTF-8、日期数字格式可配置本地化则指把英文内容转换成某种具体语言是落地那一层。fish-shell-docs-l10n 这个项目名里的 l10n工作的全部内容就是本地化而且集中在文档上。文档本地化和软件界面翻译不太一样。软件界面翻译通常要处理 gettext 的 PO 文件、iOS 的 strings 文件、Web 项目的 JSON 资源字符串往往很短还要考虑运行时长度变化和占位符。文档翻译面对的是一篇篇长文章有标题层级、段落、列表、代码块、链接和表格没有运行时约束但对语言质量和结构一致性要求更高。文档里一句话翻译错了用户照着操作可能就踩坑代码块漏了个引号复制到终端就报错。所以我一直觉得文档翻译项目要做得好不能只靠“把英文换成中文”这个动作。你需要维护一套协作规范保证所有人翻出来的语气一致、术语统一、格式不错乱你还需要处理版本同步——上游 fish shell 文档每周可能都会更新你翻完的东西过一阵就又过期了。这些才是文档本地化真正的复杂度所在。2. 翻译协作机制设计一个人单干还是社区共建2.1 社区协作流程从 Fork 到 PR 的全链路一开始有人可能会想docs 仓库就那几个文件我全翻译完交上去不就行了真做起来会发现文档量很大一个人翻完可能要好几个月而且翻到后面前面已经过时。所以这类项目基本都是社区协作很多译者各自认领文件通过 pull request 提交再由维护者 review 合并。fish-shell-docs-l10n 采用的就是标准的 GitHub 协作流程。新参与者一般先在 issue 里找带help wanted或者明确标注“待翻译”的任务回复认领避免两个人同时翻同一个文件。然后 fork 仓库到自己的账号clone 到本地新建一个翻译分支开始翻译。翻译完提交 push去 GitHub 发起 pull request维护者在 PR 下面逐条 review提修改意见来回几轮之后合并。我画个简单流程给你感觉一下# 克隆自己的 fork git clone gitgithub.com:你的用户名/fish-shell-docs-l10n.git cd fish-shell-docs-l10n # 添加上游仓库方便同步最新文档 git remote add upstream gitgithub.com:fish-shell-docs-l10n/fish-shell-docs-l10n.git # 基于最新 upstream/main 分支建一个翻译分支 git fetch upstream git checkout -b translate/tutorial-zh upstream/main # ...翻译文件... git add . git commit -m translated tutorial page (zh_CN) git push origin translate/tutorial-zh推送之后在 GitHub 页面创建 PR描述里写清楚翻译了哪个文件、对应 upstream 的哪个 commit方便 reviewer 核对。这一套流程对没参与过开源协作的人来说第一次走会有些手忙脚乱但第二次基本就熟了。这个项目的门槛低就低在你不需要理解 fish 的 C 源码只要能读懂文档、能写好中文、会基本的 Git 操作就能贡献。2.2 术语表怎么定才能让几十个译者口吻一致社区协作最怕的就是十个译者十个语气。同一个 prompt有人翻译成“提示符”有人翻译成“命令提示”还有人直接写“prompt”同一个 argument有人用“参数”有人用“实参”。读者看单篇文档可能没感觉把所有文档连起来读就会觉得特别分裂。fish-shell-docs-l10n 这类文档翻译项目通常会在仓库里维护一份术语表放在类似CONTRIBUTING.md或glossary.md的位置或者以 issue 形式固定在某个置顶讨论里。术语表把高频词的译法定死比如英文原文推荐译法备注prompt提示符视觉上的命令提示区域command命令通用译法不译成“指令”argument参数命令行中传给命令的值option选项如-l这类开关completion补全动词 complete 可译为“补全”variable变量无争议function函数尽量不意译session会话一个终端会话syntax highlighting语法高亮固定搭配autosuggestion自动建议也可译“自动补全建议”统一即可working directory工作目录不译成“现行目录”bind绑定按键绑定config配置不译成“配置文件”的简称fish_config保留不译这是具体命令名除了术语表行文风格也需要约法三章。一个很常见的规定是不要过度“归化”。英文文档里大量的命令名、文件名、环境变量、路径该保留原文就保留不要强行翻译。比如~/.config/fish/config.fish这种路径翻译成“家目录下的点配置目录里的 fish 配置文件”只会增加读者的认知负担直接保留原文并稍微解释一下就够了。代词的处理也值得统一。英文文档大量使用 “you”中文里要么省略主语要么统一成“你”不要一会儿“你一会儿”您“一会儿又”我们“。很多翻译项目最终会约定面向教程类文档用“你”面向参考类文档可以省略主语尽量避免“我们”因为文档很多时候是单人操作场景用“我们”显得别扭。2.3 自动化检查翻译项目的 CI 原来这么用一开始很多人以为翻译项目不需要 CI反正就是改文字而已。实际上文档翻译项目的 CI 大有可为至少可以做三件事。第一检查 Markdown 格式。原文里列表缩进、代码块标记、标题层级、表格语法都有严格要求翻译过程中很容易手滑破坏格式。用 markdownlint 跑一遍能在 PR 合并前就暴露问题。第二检查链接有效性。文档里有大量站内相对链接和外部链接翻译标题会把锚点改掉如果别处的#anchor链接没同步改文档就会出现死链。用 lychee 这类工具扫描所有链接或者 CI 里构建一下文档站点都能发现这些问题。第三检查代码块完整性。翻译时最容易出问题的是代码块少写一个围栏反引号整个文档的渲染都会乱掉。CI 可以检查代码块 fence 数量是否偶数、语言标签是否规范。这类项目常见的是一个简单的 GitHub Actions workflow触发时机是 PR 和 push 到 mainname: docs-check on: pull_request: push: branches: [main] jobs: check: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - uses: actions/setup-nodev4 with: node-version: 20 - run: npm install -g markdownlint-cli - run: markdownlint docs/**/*.md - run: npx lychee docs/**/*.html --config .lycheeignore这个 workflow 本身不复杂但很多文档翻译项目都没有认真做。我见过几个项目翻了几百个 PR最后还是靠维护者手动看格式效率低且容易漏。fish-shell-docs-l10n 这类项目让我看到文档协作的正确姿势翻译是内容生产自动化是质量护栏两者配合项目才能长期跑下去。3. 实操过程与核心环节实现3.1 本地环境准备与仓库初始化要实际动手翻译第一步是准备本地环境。这一步不需要多高级的环境装好 Git、一个趁手的代码编辑器、一个命令行终端就够了。编辑器最好能装 Markdown 预览插件翻译时左边原文档右边译稿效率高很多。接下来克隆仓库并初始化远程地址。这里有个小技巧很多人 clone 完自己 fork 的仓库就忘了加 upstream等到要同步上游更新时还得重新配置。直接一步到位后面会省很多事。git clone gitgithub.com:你的用户名/fish-shell-docs-l10n.git cd fish-shell-docs-l10n git remote add upstream gitgithub.com:fish-shell-docs-l10n/fish-shell-docs-l10n.git git remote -v初始化完成之后建议先浏览一下仓库目录结构和CONTRIBUTING文档。通常你会在docs/下看到与 upstream fish-shell 官方文档对应的文件列表每个.md文件就是一篇文章。维护者通常会在 README 或 issue 里标注当前优先级哪些文件需要优先翻译、哪个文件正在被人认领、哪些文件已经翻译完只需要校对。先读这些再动手避免做无用功。有一个细节特别容易忽略确认你要翻译的文件在仓库里的路径和 upstream 官方文档的路径是否一致。翻译项目一般会尽量保持目录结构同步但偶尔有调整。如果你从 upstream 官网找到了文档并不意味着本地仓库里也有同名文件最好以仓库 README 或维护者指认为准。3.2 一篇文档的完整翻译流程粗译、精校、格式化认领一篇文档之后不要急着从头到尾逐句翻。先花几分钟通读一遍原文搞清楚文章讲什么、面向什么读者、有哪些带格式的元素。这一步看起来费时间实际上能避免后面返工。完整流程我一般这样走第一步粗译。把整篇文档从头到尾翻一遍速度优先不要纠结某个术语是“选项”还是“可选项”。粗译的目标是把原文意思完整落到中文不要留死角。遇到拿不准的句子用批注或 TODO 标出来不要中断。第二步精校。粗译稿放一放至少隔一两个小时再回来逐句对照原文。这一步重点检查三件事有没有漏译的句段、有没有理解偏差、中文表达是否通顺。我自己的经验是翻译容易翻错的往往是长难句英文里用从句层层修饰中文直接用几个逗号串联就会乱。正确做法是拆成短句先翻译核心语义再补充修饰信息。第三步格式化。对照原文检查 Markdown 标记是否完整比如## Introduction This is a paragraph with **bold text** and a [link](https://fishshell.com). fish echo friendly翻译后要保证加粗、斜体、链接、代码块这些标记一个不落尤其是行内代码里的反引号不要弄丢。很多新手会不小心把 fish 翻译成“鱼”这在脚注或术语说明时可以但在正文里作为命令名出现就不应该译通常直接用原文 fish 并保持代码格式。 翻译结束后自己通读一遍中文稿不需要对照英文而是假设自己是第一次看这篇文档的中文读者看细节是否清楚、步骤是否连贯。这一步能发现大量“翻译腔”。 ### 3.3 处理文档里的代码块与特殊语法元素 fish 文档里代码块占比不低而且有几种不同类型处理方式完全不同。 第一种是纯命令展示比如告诉用户“想启动 fish 请输入” fish fish代码块里这部分必须原样保留绝对不能翻译因为用户看到的是要复制到终端里的真实命令。第二种是脚本片段展示 fish 语法if test -f /etc/fish/config.fish echo exists end脚本里的注释可以翻译但关键字、变量名、文件名、路径都不能动。翻译注释时也要注意注释不要比代码还长尽量保持简洁。第三种是输出示例展示某个命令执行后的结果显示。输出内容同样原样保留通常也不需要翻译。除了代码块标题和锚点的问题比较多。英文标题如## Changing Colors翻译成## 修改颜色之后URL 锚点会从#changing-colors变成#修改颜色。如果其他文档里有链接指向这个锚点必须同步更新链接否则用户点击后无法跳转。处理办法要么是翻译后统一更新所有引用要么在 GitHub 渲染的其他链接确认是否能正确识别中文锚点——实测 GitHub 对中文锚点的支持并不稳定所以相当多的项目采取保守策略文档内链接尽量指向上游原文站内引用则用维护者约定好的方式处理。文档中还会出现键盘快捷键、菜单名、网页界面的按钮文字。比如fish_config页面里的按钮翻译时保留英文还是中文需要根据上下文判断如果是让用户去点击的实际界面元素最好保留界面真实显示的文案否则用户对照不起来会很困惑。4. 常见问题与排查技巧实录4.1 上游更新了你的翻译怎么同步这是所有文档翻译项目最头疼的问题。你翻完一篇文档没几个月上游 fish shell 新增了一个功能文档里多了三节或者某个命令的参数变了原文改了一段你的翻译还是老内容。长期不跟进翻译就和实际版本脱节项目价值会迅速缩水。fish-shell-docs-l10n 通常会在 main 分支定期执行一次上游同步把 upstream fish-shell 的 docs 目录变更合并进来。这个操作在 Git 里就是一个普通的 mergegit fetch upstream git merge upstream/main合并之后已经翻译过的文件如果有冲突需要手动解决未翻译的新文件保持英文原样被上游修改过的段落由维护者跟踪记录在 issue 里列出“需要重新翻译的文件”。很多文档项目挂在 GitHub 上后会用 GitHub Actions 定时拉取上游仓库自动生成一个“同步 PR”把变更内容高亮出来维护者只需要看 diff 就知道哪些文件需要动。对普通贡献者更相关的是另一种情况你认领翻译的文件翻译到一半发现 upstream 更新了。正确的做法是先完成当前翻译的基本内容然后合入最新的上游变更再处理冲突。不要在上游更新的基础上用旧版本硬翻这样你完成后又要重来。合并冲突的处理大多数时候是同一段英文上游改了新表述你已经翻译了旧版本。Git 会把两个版本都留在冲突标记里处理时保留上游新内容把你的翻译套用上去。核心原则是以上游语义为准不要在这种场景下坚持自己的旧翻译。4.2 术语与格式问题排查速查表翻译实践中问题大同小异。我把常见的坑整理成一张速查表PR 之前对照检查一遍能省下不少 review 往返。常见问题表现处理方式术语不统一同一概念在不同文件中出现不同译法先查术语表术语表没有就在 issue 里讨论定稿锚点失效点击目录或站内链接跳转不过去检查翻译后的标题是否改变了 anchor同步更新引用代码块被破坏Markdown 渲染成一堆纯文本检查围栏反引号数量语言标签不要改动行内代码被翻译variable_name被译成“变量名”回到原文重新用代码包裹漏翻译段落中文文档里夹杂大段英文和原文逐段对照不要只凭印象过度意译命令名、路径被翻成中文命令、文件名、路径保持原样标点不一致英文半角标点和中文全角混用中文正文用全角标点代码块和链接内用半角链接失效指向 upstream 的链接已 404用 lychee 检查或手动核对其中“行内代码被翻译”真的是高频问题。很多新手看到echo就以为是需要翻译的词实际上行内代码标记本身就说明“这里是代码或命令”一律不要动它。如果确实需要解释在外部说明用途而不是修改标记内部的文本。4.3 给新参与翻译项目的人几条实在建议最后这部分是给新人的。如果你从来没有参与过开源翻译又恰好想用 fish-shell-docs-l10n 入门我建议按这个节奏来。第一从短文件开始。历史总是惊人的相似新手容易高估自己的英文能力上去就认领一篇长文档结果半个月交不出来。选一篇 FAQ 或简短教程两三天能完成的那种先走通整个 PR 流程建立信心。第二第一遍先看懂再动笔。不是所有英文都能直接逐句翻遇到不理解的句子可以先去 fish 的官网或源码仓库里找对应语境。宁可慢一点也不要翻出“机器翻译感”。第三PR 标题和描述要写清楚。维护者每天要对着代码看很久你说清楚改了哪个文件、对应上游哪个 commit、是否补充了链接锚点更新会大幅加快 review 速度。第四被 review 打回来不要玻璃心。文档翻译项目里维护者出的 review 意见通常非常具体比如“这个链接指向的锚点已经变了”“这里的代码块格式有问题”“prompt 在术语表里统一译成提示符”。这些都是学习机会。我在第一次提交里踩过三个格式问题改完之后后面的 PR 就顺畅得多。第五也是最重要的一点参与 review 别人的 PR。你不要觉得只有自己的 PR 才有学习价值。去看看别人怎么处理一段难翻译的英文、怎么组织长句、怎么给注释做本地化比自己闷头翻十篇收获大多了。开源项目里的维护者基本都是在 review 中练出来的。我个人在实际操作中的体会是文档翻译这件事看起来没有写代码那么“硬核”但对一个开源项目的海外影响力完全是实打实的。翻译得好的文档能把一大批不会读英文的用户接进来翻译得差伤害的其实是项目在中文社区的名声。fish-shell-docs-l10n 给我的最大教训就是“保持克制”英文文档里有大量精确的术语、路径、命令示例稍微不小心就会过度加工让读者对着终端比对不上。所以我给自己的规矩一直没变——每次提交 PR 之前把译稿和原文逐段对照一遍尤其盯代码块、链接和文件名。这个习惯延伸到我自己写技术文档、写博客也一直很受用。如果你想找一个能长期参与、又能真实帮到人的开源项目从这种文档 l10n 项目开始是个非常聪明的起点。