news 2026/9/7 3:07:49

Plane 开源贡献实战指南:本地开发环境搭建、Monorepo 架构与 i18n 翻译贡献全流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Plane 开源贡献实战指南:本地开发环境搭建、Monorepo 架构与 i18n 翻译贡献全流程

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 与命名规范

在动手写代码之前,贡献的第一步是规范地报告问题。官方文档给出的流程是:

  1. 先检索已有 Issue。提交新 Issue 前先搜索仓库的 Issue 列表,确认是否已有人报告或讨论过,可能直接获得 workaround。

  2. 提供最小可复现场景。修复 Bug 的前提是能够复现。请提供使用仓库或 Gist 的最小复现场景——一个可运行的现场能让维护者直接掌握关键信息,而无需反复追问第三方库版本、失败的具体用例等细节。缺少最小复现的 Issue 可能无法被调查,甚至无法解决。

  3. 遵循标题命名约定。打开新 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.js20+(LTS).node-version固定为22.22.0,根 package.json 的engines要求>=22.22.0,包管理器锁定pnpm@11.3.0
Python3.8+用于apps/api的 Django 后端构建
PostgreSQLv14docker-compose-local.yml 中实际使用postgres:15.7-alpine
Redisv6.2.7开发编排中实际使用valkey/valkey:7.2.11-alpine(Valkey 为 Redis 的兼容实现)
内存最低建议 12 GB RAM8 GB 机器在容器构建/依赖安装阶段可能内存崩溃,文档建议使用云端环境(如 GitHub Codespaces)或升级内存

可以看出,文档中的版本是最低基线,而本地开发编排文件实际拉取了更新的镜像(PostgreSQL 15.7、Valkey 7.2.11、RabbitMQ 3.13.6)。以当前仓库配置为准即可,无需自行降级。

项目结构:单仓 Monorepo

Plane 是一个 monorepo,后端 API 与多个前端应用同仓维护:

  • apps/api:Django 后端(含数据库模型、视图、Celery 后台任务bgtasks等);
  • apps/web:主站前端,dev脚本运行在3000端口(apps/web/package.json:react-router dev --port 3000);
  • apps/admin:实例管理端,运行在3001端口,首次部署时需在此页面完成实例初始化;
  • apps/space:独立部署形态的前端,运行在3002端口;
  • apps/live:基于 Hocuspocus 的实时协作服务(Yjs WebSocket 服务端);
  • packages/*:共享库,包括i18n(国际化)、editor(TipTap 编辑器)、propel(设计系统组件)、typesservices等。

工作区由 pnpm-workspace.yaml 定义(apps/*+packages/*,排除apps/apiapps/proxy),并配合 Turbo 管理任务依赖。

三步初始化流程

官方给出的完整操作步骤如下:

1. 克隆仓库并准备 setup 脚本

git clone https://github.com/makeplane/plane.git [folder-name] cd [folder-name] chmod +x setup.sh

2. 运行 setup.sh

./setup.sh

结合 setup.sh 源码可以看到,这一步实际完成了四件事:

  • 将各服务的.env.example复制为.env,覆盖根目录以及webapispaceadminlive五个服务目录(setup.sh#L47-L60);
  • 为 Django 生成随机的 50 位SECRET_KEY并追加写入apps/api/.env(setup.sh#L62-L78);
  • 通过corepack enable pnpm激活package.json中锁定的 pnpm 版本;
  • 执行pnpm install安装全部 Node 依赖(setup.sh#L80-L83)。

若中途任一步骤失败,脚本会以非零状态退出并提示检查上方报错。

3. 启动基础设施容器

docker compose -f docker-compose-local.yml up

docker-compose-local.yml 定义了完整的一套本地依赖,全部位于dev_envbridge 网络内:

服务镜像端口/说明
plane-redisvalkey/valkey:7.2.11-alpine6379,数据卷redisdata
plane-mqrabbitmq:3.13.6-management-alpine用户/密码/VHOST 来自根.envRABBITMQ_*变量
plane-miniominio/minio9000(S3 API)+ 9090(控制台),启动时自动创建AWS_S3_BUCKET_NAME
plane-dbpostgres:15.7-alpine5432,max_connections=1000
api由 apps/api/Dockerfile.dev 构建8000,挂载./apps/api源码,入口bin/docker-entrypoint-api-local.sh
worker/beat-worker同上Celery worker 与 beat 定时任务
migrator同上一次性容器(restart: "no"),执行docker-entrypoint-migrator.sh --settings=plane.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 --concurrency=18,会按依赖图并行拉起 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/格式化

贡献文档明确了两条代码质量红线:

  1. 所有功能或 Bug 修复必须附带一个或多个测试用例(unit test);
  2. 统一使用 OxLint 检查、oxfmt 格式化,共享配置文件为仓库根目录的.oxlintrc.json.oxfmtrc.json

从源码结构看,这套规范被接到了工程化工具链上:

  • turbo.json 将.oxlintrc.json.oxfmtrc.json列为globalDependencies,并提供checkcheck:lintcheck:formatcheck:typesfixfix:lintfix: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 翻译贡献实战

贡献文档中专设了一章讲解如何添加或更新翻译。这一部分与仓库当前实现高度对应,可以直接按下面的结构落地操作。

翻译文件的实际组织方式

文档描述的目录约定是按语言分文件夹,每个语言文件夹内放翻译 JSON:

packages/i18n/src/locales/ ├── en/ │ ├── core.json # Critical translations │ └── translations.json ├── fr/ │ └── translations.json └── [language]/ └── translations.json

对照仓库当前实际结构(从源码结构看),packages/i18n/src/locales/下每个语言目录已演进为按功能域拆分的 28 个命名空间文件accessibility.jsonauth.jsoncommon.jsonwork-item.jsonworkspace-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.yaml:i18next 25.10.9i18next-icu 2.4.3react-i18next 16.6.6)。初始化时从localStorageuserLanguage键读取用户语言,回退到英文(FALLBACK_LANGUAGE,见 packages/i18n/src/constants/language.ts),并主动预加载全部命名空间以避免并发异步加载引发的重渲染级联(instance.ts#L26-L52)。

更新现有翻译

  1. 定位locales/<language>/下对应命名空间文件中的键;
  2. 修改值,保持键的嵌套结构不变
  3. 保留其中已有的 ICU 格式(变量、复数)原样不破坏。

新增翻译键

  1. 新键必须同时添加到所有语言文件中——即便暂无人翻译,也要先用英文占位;
  2. 所有语言的嵌套结构保持一致;
  3. 若键含动态内容(变量/复数),ICU 格式需在所有语言中统一应用。

新增一种语言的完整步骤

文档给出的四步流程,结合当前源码实现如下:

1. 更新类型定义——把新语言加入TLanguage联合类型(packages/i18n/src/types/language.ts):

export 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): Promise<any> { 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 --ci
  • generate-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.sh+docker compose -f docker-compose-local.yml up+pnpm dev拉起本地全栈环境(3000/3001/3002 三端 + 8000 API)→ 以 OxLint/oxfmt 与单测约束代码质量 → 按 i18next 命名空间 + ICU 体系做翻译贡献并用sync-check工具自检。只要遵循 CONTRIBUTING.md 中的约定,并对照本文给出的实际配置文件路径(setup.shdocker-compose-local.ymlpackages/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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 3:06:28

Codex CLI 安装实战:/rewind 回滚功能与常见报错排查

这次我们来看一个终端 AI 编程工具&#xff1a;Codex CLI。它最值得关注的地方不只是自动写代码&#xff0c;而是自带了文件回滚命令/rewind&#xff0c;可以让对话历史和代码文件状态一起退回去。简单理解&#xff0c;就是 AI 改崩了代码之后&#xff0c;不用手动去 git 里翻 …

作者头像 李华
网站建设 2026/9/7 3:06:15

Qt静态编译部署指南:从gcc485到libc217,解决工业Linux依赖地狱

简介&#xff1a;面向 Linux 下需要发布免安装 Qt 图形界面程序的开发者&#xff0c;提供 Qt 5.9.9 静态编译库&#xff0c;编译环境为 CentOS 7.6 x64、GCC 4.8.5、glibc 2.17&#xff0c;并已开启 qt-xcb&#xff0c;支持 X11 窗口系统。使用该库编译后的程序通过 ldd 检查不…

作者头像 李华
网站建设 2026/9/7 3:05:48

YT8521S千兆PHY硬件设计:从RGMII到RJ45的完整指南

简介&#xff1a;面向嵌入式系统与网络硬件设计工程师的裕太微YT8521S PHY芯片电路设计参考图&#xff0c;聚焦RGMII转UTP接口方案&#xff0c;解决FT2000-4主控与PHY芯片之间的物理层连接、网络变压器隔离及复位控制等关键设计问题&#xff0c;适用于飞腾平台网络模块开发及RG…

作者头像 李华