Plane 开源贡献实战指南:本地开发环境搭建、Monorepo 架构与 i18n 翻译贡献全流程
发布时间:2026/9/7 3:07:52 锦皓数字建站

Plane 开源贡献实战指南本地开发环境搭建、Monorepo 架构与 i18n 翻译贡献全流程【免费下载链接】plane Open-source Jira, Linear, Monday, and ClickUp alternative. Plane is a modern project management platform to manage tasks, sprints, docs, and triage.项目地址: https://gitcode.com/GitHub_Trending/pl/plane本篇技术指南基于 Plane 仓库的官方贡献文档 CONTRIBUTING.md系统讲解如何从零搭建 Plane 的本地开发环境Docker Compose pnpm/Turborepo、遵循项目 Issue 规范与代码质量标准以及如何按仓库实际结构完成国际化i18n翻译与新增语言贡献。读完后你可以独立完成本地起一套可开发的 Plane 实例、通过 lint/format 检查提交代码、并按仓库现有 i18next ICU 体系安全地修改或新增翻译。提交 Issue 与命名规范在动手写代码之前贡献的第一步是规范地报告问题。官方文档给出的流程是先检索已有 Issue。提交新 Issue 前先搜索仓库的 Issue 列表确认是否已有人报告或讨论过可能直接获得 workaround。提供最小可复现场景。修复 Bug 的前提是能够复现。请提供使用仓库或 Gist 的最小复现场景——一个可运行的现场能让维护者直接掌握关键信息而无需反复追问第三方库版本、失败的具体用例等细节。缺少最小复现的 Issue 可能无法被调查甚至无法解决。遵循标题命名约定。打开新 Issue 时使用清晰简洁、带类型前缀的标题Bug Bug: [short description]功能 Feature: [short description]改进️ Improvement: [short description]文档 Docs: [short description]官方给出的示例 Bug: API token expiry time not saving correctly Docs: Clarify RAM requirement for local setup Feature: Allow custom time selection for token expiration这一约定能帮助维护者更高效地分流triage和管理 Issue。功能缺失时的处理路径如果缺少某个功能可以直接以「 Feature」模板提交功能请求如果你打算亲自实现文档明确要求必须先提交一个描述提案的 Issue与社区确认方向后再动手避免开发完却不能合并。本地开发环境需求清单与初始化步骤环境与硬件要求贡献文档列出的环境要求如下表依赖版本要求文档仓库实际使用的版本以配置文件为准Docker Engine已安装并运行Docker Compose 构建多个服务容器Node.js20LTS.node-version固定为22.22.0根 package.json 的engines要求22.22.0包管理器锁定pnpm11.3.0Python3.8用于apps/api的 Django 后端构建PostgreSQLv14docker-compose-local.yml 中实际使用postgres:15.7-alpineRedisv6.2.7开发编排中实际使用valkey/valkey:7.2.11-alpineValkey 为 Redis 的兼容实现内存最低建议 12 GB RAM8 GB 机器在容器构建/依赖安装阶段可能内存崩溃文档建议使用云端环境如 GitHub Codespaces或升级内存可以看出文档中的版本是最低基线而本地开发编排文件实际拉取了更新的镜像PostgreSQL 15.7、Valkey 7.2.11、RabbitMQ 3.13.6。以当前仓库配置为准即可无需自行降级。项目结构单仓 MonorepoPlane 是一个 monorepo后端 API 与多个前端应用同仓维护apps/apiDjango 后端含数据库模型、视图、Celery 后台任务bgtasks等apps/web主站前端dev脚本运行在3000端口apps/web/package.jsonreact-router dev --port 3000apps/admin实例管理端运行在3001端口首次部署时需在此页面完成实例初始化apps/space独立部署形态的前端运行在3002端口apps/live基于 Hocuspocus 的实时协作服务Yjs WebSocket 服务端packages/*共享库包括i18n国际化、editorTipTap 编辑器、propel设计系统组件、types、services等。工作区由 pnpm-workspace.yaml 定义apps/*packages/*排除apps/api与apps/proxy并配合 Turbo 管理任务依赖。三步初始化流程官方给出的完整操作步骤如下1. 克隆仓库并准备 setup 脚本git clone https://github.com/makeplane/plane.git [folder-name] cd [folder-name] chmod x setup.sh2. 运行 setup.sh./setup.sh结合 setup.sh 源码可以看到这一步实际完成了四件事将各服务的.env.example复制为.env覆盖根目录以及web、api、space、admin、live五个服务目录setup.sh#L47-L60为 Django 生成随机的 50 位SECRET_KEY并追加写入apps/api/.envsetup.sh#L62-L78通过corepack enable pnpm激活package.json中锁定的 pnpm 版本执行pnpm install安装全部 Node 依赖setup.sh#L80-L83。若中途任一步骤失败脚本会以非零状态退出并提示检查上方报错。3. 启动基础设施容器docker compose -f docker-compose-local.yml updocker-compose-local.yml 定义了完整的一套本地依赖全部位于dev_envbridge 网络内服务镜像端口/说明plane-redisvalkey/valkey:7.2.11-alpine6379数据卷redisdataplane-mqrabbitmq:3.13.6-management-alpine用户/密码/VHOST 来自根.env的RABBITMQ_*变量plane-miniominio/minio9000S3 API 9090控制台启动时自动创建AWS_S3_BUCKET_NAME桶plane-dbpostgres:15.7-alpine5432max_connections1000api由 apps/api/Dockerfile.dev 构建8000挂载./apps/api源码入口bin/docker-entrypoint-api-local.shworker/beat-worker同上Celery worker 与 beat 定时任务migrator同上一次性容器restart: no执行docker-entrypoint-migrator.sh --settingsplane.settings.local完成数据库迁移数据库、Redis、RabbitMQ 的连接参数示例见 apps/api/.env.example其中CORS_ALLOWED_ORIGINS已预置http://localhost:3000~3002等前端地址POSTGRES_*、REDIS_*、RABBITMQ_*与容器服务名一一对应。4. 启动前端应用pnpm dev根 package.json 中该脚本实际是turbo run dev --concurrency18会按依赖图并行拉起 web/admin/space/live 等应用的 dev server。5. 完成首次访问打开http://localhost:3001/god-mode/将你自己注册为实例管理员instance admin。god-mode是 admin 应用在 Caddy 中配置的 SPA 前缀见 apps/admin/caddy/Caddyfile路由定义见 apps/admin/app/routes.ts包含 general、workspace、email、authentication、ai、image 等实例管理页面再打开http://localhost:3000用上一步的同一账号登录主站。至此本地开发环境就绪。文档还提示如果改动没有自动热更新记得手动刷新浏览器。编码规范测试与 Lint/格式化贡献文档明确了两条代码质量红线所有功能或 Bug 修复必须附带一个或多个测试用例unit test统一使用 OxLint 检查、oxfmt 格式化共享配置文件为仓库根目录的.oxlintrc.json与.oxfmtrc.json。从源码结构看这套规范被接到了工程化工具链上turbo.json 将.oxlintrc.json、.oxfmtrc.json列为globalDependencies并提供check、check:lint、check:format、check:types、fix、fix:lint、fix:format等任务可按包增量执行根 package.json 通过lint-staged配置在提交钩子中对*.{js,jsx,ts,tsx,...,css,md}执行oxfmt、对 TS/JS 系文件执行oxlint --fix --deny-warnings并启用 husky 保证钩子生效prepare: husky。即提交前本地会自动格式化并做严格 lint警告即失败合入前还需通过 CI 的同类检查。贡献方式全景除写代码外文档列举的贡献途径包括试用 Plane Cloud 与自托管平台并反馈问题添加新的集成integrations添加或更新翻译帮助解决开放 Issue 或创建自己的 Issue分享想法与建议协助编写教程与博客文章以提案方式请求新功能报告 Bug改进文档——修复不完整或缺失的文档、措辞、示例或解释。i18n 翻译贡献实战贡献文档中专设了一章讲解如何添加或更新翻译。这一部分与仓库当前实现高度对应可以直接按下面的结构落地操作。翻译文件的实际组织方式文档描述的目录约定是按语言分文件夹每个语言文件夹内放翻译 JSONpackages/i18n/src/locales/ ├── en/ │ ├── core.json # Critical translations │ └── translations.json ├── fr/ │ └── translations.json └── [language]/ └── translations.json对照仓库当前实际结构从源码结构看packages/i18n/src/locales/下每个语言目录已演进为按功能域拆分的 28 个命名空间文件accessibility.json、auth.json、common.json、work-item.json、workspace-settings.json等与 packages/i18n/src/constants/namespaces.ts 中定义的NAMESPACES数组一一对应默认命名空间为common。贡献时请以目标语言目录下现有文件清单为准逐文件补齐不要按旧文档的translations.json单文件假设操作。键的嵌套结构与 ICU 消息格式为便于管理键采用嵌套结构组织{ issue: { label: Work item, title: { label: Work item title } } }动态内容变量、复数使用 IntlMessageFormat 的 ICU 语法简单变量{ greeting: Hello, {name}! }复数化{ items: {count, plural, one {Work item} other {Work items}} }这些能力由运行时真实支撑packages/i18n/src/core/instance.ts 中 i18next 实例通过.use(ICU)挂接i18next-icu处理 ICU 消息并用resourcesToBackend按../locales/${language}/${namespace}.json动态加载对应语言与命名空间文件依赖版本见 pnpm-workspace.yamli18next 25.10.9、i18next-icu 2.4.3、react-i18next 16.6.6。初始化时从localStorage的userLanguage键读取用户语言回退到英文FALLBACK_LANGUAGE见 packages/i18n/src/constants/language.ts并主动预加载全部命名空间以避免并发异步加载引发的重渲染级联instance.ts#L26-L52。更新现有翻译定位locales/language/下对应命名空间文件中的键修改值保持键的嵌套结构不变保留其中已有的 ICU 格式变量、复数原样不破坏。新增翻译键新键必须同时添加到所有语言文件中——即便暂无人翻译也要先用英文占位所有语言的嵌套结构保持一致若键含动态内容变量/复数ICU 格式需在所有语言中统一应用。新增一种语言的完整步骤文档给出的四步流程结合当前源码实现如下1. 更新类型定义——把新语言加入TLanguage联合类型packages/i18n/src/types/language.tsexport type TLanguage en | fr | your-lang;2. 添加语言配置——在支持语言列表中登记标签与值packages/i18n/src/constants/language.ts#L11-L32当前已内置 20 种语言export const SUPPORTED_LANGUAGES: ILanguageOption[] [ { label: English, value: en }, { label: Your Language, value: your-lang }, ];3. 创建翻译文件——在locales/下新建locales/your-lang/目录复制现有语言建议复制en/的 28 个命名空间 JSON 并逐键翻译。4. 更新导入逻辑——文档以早期「按语言写switch分支」为例private importLanguageFile(language: TLanguage): Promiseany { switch (language) { case your-lang: return import(../locales/your-lang/translations.json); // ... } }需要说明的是从当前源码结构看运行时已改为resourcesToBackend的动态路径导入import(\../locales/${language}/${namespace}.json)见 instance.ts#L18-L21因此新增语言无需再手改 import 分支只要完成前三步并保证文件命名合规即可被动态加载。质量检查清单提交前自查所有翻译键存在于每一种语言文件中各语言文件的嵌套结构完全一致ICU 消息格式实现正确所有语言在应用内可无错加载动态变量与复数化按预期工作不存在缺失或未翻译的键。实操建议文档 Pro tips 部分拿不准时以英文翻译作为上下文参照用不同数量值验证复数化分支确认动态值如{name}能正确插值复核嵌套键的访问路径是否准确。仓库提供的 i18n 校验工具除人工自查外仓库内置了两个可运行脚本辅助把关见 packages/i18n/scripts/sync-check.ts扫描各语言文件的一致性报告缺失键等问题--ci模式下发现问题会以非零码退出适合在本地模拟 CI 检查tsx packages/i18n/scripts/sync-check.ts tsx packages/i18n/scripts/sync-check.ts --cigenerate-types.ts读取src/locales/en/*.json把嵌套结构展平为点号键并生成src/types/keys.generated.ts为翻译键提供类型层约束npx tsx packages/i18n/scripts/generate-types.ts此外组件侧统一通过 packages/i18n/src/hooks/use-translation.ts 的useTranslation钩子取值其内部对t()返回值做了字符串强制转换的崩溃防护——当误取到命名空间节点键返回对象时会回退为键名并在开发态打印告警。这提醒贡献者翻译值必须始终是字符串否则会触发该防护路径。需要帮助对文档或流程有疑问、有建议或想法时官方鼓励直接参与讨论——贡献文档结尾指引通过 Plane 官方社区论坛交流。结合仓库内其他协作文档行为准则见 CODE_OF_CONDUCT.md代码归属与许可见 LICENSE.txt 与 COPYRIGHT.txt安全相关问题则按 SECURITY.md 的渠道报告。小结Plane 的贡献路径可以概括为一条清晰主线规范提 Issue →setup.shdocker compose -f docker-compose-local.yml uppnpm dev拉起本地全栈环境3000/3001/3002 三端 8000 API→ 以 OxLint/oxfmt 与单测约束代码质量 → 按 i18next 命名空间 ICU 体系做翻译贡献并用sync-check工具自检。只要遵循 CONTRIBUTING.md 中的约定并对照本文给出的实际配置文件路径setup.sh、docker-compose-local.yml、packages/i18n/*逐一核验任何方向的第一个贡献都能平滑落地。【免费下载链接】plane Open-source Jira, Linear, Monday, and ClickUp alternative. Plane is a modern project management platform to manage tasks, sprints, docs, and triage.项目地址: https://gitcode.com/GitHub_Trending/pl/plane创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。