mirror of
https://gh-proxy.org/https://github.com/klinsmaya/multica.git
synced 2026-11-10 10:26:46 +08:00
* fix(runtimes): spell out Qoder Cloud Agents instead of QCA The UI, docs, landing copy and server messages called the product "QCA" in labels such as "QCA Agent", "QCA runtime" and API errors like "QCA token is required". Use the full name Qoder Cloud Agents everywhere a person reads it, and add it to the brand list in the naming conventions so the abbreviation does not come back. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix(runtimes): refine Qoder Cloud Agents copy (MUL-8282) Co-authored-by: multica-agent <[email protected]> --------- Co-authored-by: 安辰 <[email protected]> Co-authored-by: Claude Opus 5.5 <[email protected]> Co-authored-by: Sol-Boy <[email protected]> Co-authored-by: multica-agent <[email protected]>
341 lines
16 KiB
Plaintext
341 lines
16 KiB
Plaintext
---
|
||
title: 开发规范
|
||
description: 代码命名规范、i18n 翻译术语表、中文风格指南的唯一权威来源。
|
||
---
|
||
|
||
写 Multica 代码、改翻译、写中文产品文案,都从这一页查。
|
||
|
||
---
|
||
|
||
## 1. 代码命名
|
||
|
||
### 路由
|
||
|
||
工作区前置路由(用户进入工作区之前能访问的路由)必须用单个单词,或者 `/{noun}/{verb}` 格式。
|
||
|
||
- ✅ `/login`、`/inbox`、`/workspaces/new`
|
||
- ❌ `/new-workspace`、`/create-team`、`/accept-invite`
|
||
|
||
根目录的连字符词组会跟用户自选 workspace slug 冲突,逼着团队不停审保留字列表。把名词(`workspaces`)保留下来,整个 `/workspaces/*` 子树自动受保护。
|
||
|
||
### 工作区路由
|
||
|
||
永远用 `/{slug}/{section}` —— `/{slug}/issues`、`/{slug}/agents`、`/{slug}/settings`。共享代码不要复制路由逻辑,统一走 `useNavigation().push()`,不要直接用框架的 link API。
|
||
|
||
### 包与模块
|
||
|
||
monorepo 的包边界是硬约束:
|
||
|
||
| 包 | 可依赖 | 不能依赖 |
|
||
| --- | --- | --- |
|
||
| `packages/core` | 仅平台无关基础库 | `react-dom`、`localStorage`、`process.env`、`next/*`、UI 库 |
|
||
| `packages/ui` | 无业务依赖 | `@multica/core`、业务逻辑 |
|
||
| `packages/views` | `core/`、`ui/` | `next/*`、`react-router-dom`、stores |
|
||
| `apps/web/platform/` | `next/*` | 其他 app |
|
||
| `apps/desktop/.../platform/` | `react-router-dom`、electron | 其他 app |
|
||
| `apps/mobile/` | `@multica/core` 的类型和纯函数 | Web/Desktop 的 React 页面、store 和平台实现 |
|
||
|
||
Web 和 Desktop 都有的逻辑,**必须**抽到共享包。"小段重复"也不算例外。Mobile 拥有独立的 UI、数据层和发布流程,只共享类型与纯函数。
|
||
|
||
### 文件与组件
|
||
|
||
- 文件名:`kebab-case.tsx` / `kebab-case.ts`(如 `agent-row-actions.tsx`)
|
||
- 组件:`PascalCase`(如 `AgentRowActions`)
|
||
- Hook:`useCamelCase`(如 `useWorkspaceId`)
|
||
- 测试:与源文件同目录,命名 `<file>.test.ts(x)`
|
||
- Zustand store:`<feature>-store.ts`,导出名 `use<Feature>Store`
|
||
|
||
### 数据库(Go + sqlc)
|
||
|
||
- 表名:`snake_case` 单数(`user`、`workspace`、`agent_runtime`)
|
||
- 字段:`snake_case`(`workspace_id`、`created_at`、`last_seen_at`)
|
||
- 关联字段:`<table>_id`
|
||
- 布尔:`is_<state>` 或者 `<state>_at`(状态变化优先用时间戳形式)
|
||
- 迁移文件:`NNN_descriptive_name.up.sql` + `.down.sql`,**永远写双向**
|
||
- 不创建数据库 foreign key,也不使用级联删除或级联更新;关系校验和清理由应用层完成
|
||
- 所有索引都使用 `CREATE INDEX CONCURRENTLY` 或 `CREATE UNIQUE INDEX CONCURRENTLY`,每条 concurrent index 单独占一个 migration 文件
|
||
|
||
### Go
|
||
|
||
- 标准 `gofmt` + `go vet`,无例外
|
||
- Handler 文件按域命名:`agent.go`、`auth.go`、`runtime.go`
|
||
- 测试:`<file>_test.go` 同目录
|
||
- handler 里 UUID 解析遵守根 `AGENTS.md` 的规则:边界输入用 `parseUUIDOrBadRequest`,可信回环用 `parseUUID`(panic 版),永远不要直接用 `util.ParseUUID` 不查 error
|
||
|
||
### TypeScript
|
||
|
||
- 网络上 API 响应是 `snake_case`,api client 在边界处转成 `camelCase`。**TS 代码内部一律 camelCase**
|
||
- 类型:`PascalCase`(`Issue`、`AgentRuntime`),不加 `IPrefix`,不加 `_t` 后缀
|
||
- 枚举:优先用 string literal union,需要 runtime 迭代时才用 `enum`
|
||
- TanStack Query key:用 `<feature>/queries.ts` 里的工厂函数,例如 `issueKeys.detail(id)`
|
||
|
||
### API 边界
|
||
|
||
- 网络响应必须用 `packages/core/api/schema.ts` 中的 `parseWithFallback` 和 zod schema 解析,不能直接 `as T`
|
||
- 新增或修改 endpoint 时,同步更新 schema,并覆盖字段缺失或格式错误的测试
|
||
- 下游 UI 对可选字段提供默认值;服务端枚举的 `switch` 必须有 `default` 分支
|
||
- 已安装的 Desktop 可能连接更新的 backend,不能假设前后端永远同版本
|
||
|
||
### Runtime 显示名
|
||
|
||
`AgentRuntime.name` 是 daemon 的原始技术名(例如 `Codex (host)`),用户别名在 `custom_name`。用户可见文案不得直接渲染 `runtime.name`,要用共享 helper,保证别名和 provider 一致(MUL-5248、#5260):
|
||
|
||
- 独立展示 runtime(列表、标签、确认弹窗、窗口标题):`runtimeDisplayLabel(runtime)` → 别名 + provider,无别名时回退 daemon 名。
|
||
- 旁边已经单独显示 provider 图标/文字时:`runtimeDisplayName(runtime)` → 只显示别名,避免重复 provider。
|
||
- 在机器分组内:机器标题用 `machine.title`,子行用 `runtimeRowLabel(runtime, machine.title)`。
|
||
- runtime 选择器用 `buildRuntimeMachines` 按机器分组,不要自己拼扁平的原始名列表。
|
||
|
||
原始 `runtime.name` 只允许用于内部识别——hostname 解析、分组、搜索 haystack、协议 payload——绝不能进入 JSX 文本、i18n 参数、`<Select>` label 或窗口标题。
|
||
|
||
### Issue 编号
|
||
|
||
每个 issue 有人类可读的编号,比如 `MUL-123`:工作区 `issue_prefix`(大写字母和数字,通常 3 个字符,最长 10 个)+ 流水号。工作区管理员可以在**设置 → 常规**中修改前缀;修改会让所有现有 issue 重新编号,外部引用——PR 标题、分支名、文档与聊天里的链接——里的旧前缀会失效。
|
||
|
||
### 代码注释
|
||
|
||
**只允许英文**。Go 和 TypeScript 都强制。如果在代码里看到中文注释,那就是 bug,替换掉。
|
||
|
||
### Commit message
|
||
|
||
Conventional 格式:`feat(scope)`、`fix(scope)`、`refactor(scope)`、`docs`、`test(scope)`、`chore(scope)`。按意图原子化分组。
|
||
|
||
---
|
||
|
||
## 2. i18n 翻译术语表
|
||
|
||
这是每个翻译 PR 都必须遵守的术语表。原本在 `packages/views/locales/glossary.md`,那个文件已删除,由这一页取代。
|
||
|
||
### 核心区分:日常词 vs Multica 专有词
|
||
|
||
Multica 的产品名词分两类:
|
||
|
||
- **日常词** —— 用户会直接说出口的词。**完整翻译成中文**,是不是数据库实体都一样:`issue` → 任务、`workspace` → 工作区、`project` → 项目。
|
||
- **Multica 专有词** —— 中文里没有对应词的概念(`skill`),或用户可能要照着敲、照着比对的 schema 标识符(`todo`、`in_progress`、`task_id`)。**用小写英文**呈现,读起来像类型名。
|
||
|
||
其余规则以 `apps/docs/content/docs/*.zh.mdx` 为准 —— docs 是已经实战 20+ 篇的 CN voice 标准。`*.zh.mdx`、`*.ja.mdx`、`*.ko.mdx` 的正文现在也一律按下面的表格来。
|
||
|
||
### `issue` 就是产品里的「任务」,必须翻译
|
||
|
||
`issue` 是这个「用户提出、智能体去做的事」的英文产品名。在英文之外的每种语言里,它就是当地最日常的那个「任务」词:
|
||
|
||
| 实体 | en | zh-Hans | ja | ko | fr |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| 提交出来的一件事(`issue`) | Issue | **任务** | **タスク** | **태스크** | **Tâche** |
|
||
| 智能体的一次执行记录(API / DB 中为 `task`) | **Run** | **运行** | **実行** | **실행** | **Exécution** |
|
||
|
||
这两个概念用户都看得到,而且**不是一回事** —— 一个任务下面可以有多次运行。任何一种语言都不能把两者写成同一个词。`Task` 不再是智能体单次运行的用户侧产品名,只保留为已经稳定的内部标识符。
|
||
|
||
不跟着改的部分:
|
||
|
||
- **API / DB 字段**永远是 `issue` / `task` / `skill`:`issue_status`、`task_id`、`skill_uuid`。开发者正文称产品对象为 Run;需要对照协议时可写成「Run(API 中为 `task_id`)」。
|
||
- **代码引用和字面命令**保持英文:`multica issue ...`、Slack 与飞书的 `/issue` 斜杠命令。
|
||
- **`skill`** 在中文里仍用小写英文 —— Multica 特有概念,没有公认中文译法;标题可大写为 `Skills`。
|
||
- **表示「问题」的 issue** 不是这个实体:机器卡片上的 `{{count}} issues` 是 `{{count}} 个异常` / `問題 {{count}} 件` / `문제 {{count}}개`,不要用实体那个词。
|
||
|
||
**为什么 `issue` 要译,而 `skill` 不译**:用户每天都在提任务、看任务,而 "issue" 这个词在中文、日文、韩文里除了开发圈黑话之外没有含义,当地人本来就用「任务」在说这件事。`skill` 则是 Multica 特有概念,没有哪个中文词能承载它的意思。
|
||
|
||
其它产品名词同样按「有没有稳定的本地日常词」来判断:
|
||
|
||
- **`project` 翻成"项目"**:中文里早就稳定的日常词。飞书 / Tower / Teambition / PingCode / GitHub Projects 中文版 0 例外都翻译成"项目",没有产品保留 `project`。
|
||
- **`autopilot` 翻成"自动化"**:autopilot 在中文里联想到特斯拉的"自动驾驶",跟产品功能(按周期启动智能体运行)对应不上。Notion / 飞书都用"自动化",是行业共识。
|
||
|
||
### 完整翻译 —— 概念词
|
||
|
||
| 英 | 中 |
|
||
| --- | --- |
|
||
| Workspace | **工作区** |
|
||
| Agent | **智能体** |
|
||
| Project | **项目** |
|
||
| Autopilot | **自动化** |
|
||
| Daemon | **守护进程** |
|
||
| Runtime | **运行时** |
|
||
| Inbox | **收件箱** |
|
||
| Comment | **评论** |
|
||
| Reply | **回复** |
|
||
| Notifications | **通知** |
|
||
| Member | **成员** |
|
||
| Label | **标签** |
|
||
| Settings | **设置** |
|
||
| Onboarding | **上手引导** |
|
||
|
||
### 不翻 —— 品牌名 + 通用缩写
|
||
|
||
| 类别 | 词 |
|
||
| --- | --- |
|
||
| 品牌 | **Multica**、GitHub、Slack、Google、Anthropic、OpenAI、Claude、Codex、Cursor、Linear、Jira、Qoder、Qoder Cloud Agents |
|
||
| 缩写 | API、CLI、URL、SDK、OAuth、JWT、SSO、WebSocket、HTTP、JSON、YAML、SQL |
|
||
|
||
用户可见文案明确提及该产品时,使用 **Qoder Cloud Agents**。入口及可脱离页面展示的提示应能独立识别服务。上下文已明确服务时,字段可用**远端智能体**等通用名称,与 Multica 智能体区分。品牌拼写保持一致,周边文案按各语言自然表达。内部标识符和外部技术名称保持原样,包括 **QCA Assistant**。
|
||
|
||
首次说明凭据时写 **Qoder 个人访问令牌(PAT)**,后文统一为 **Qoder PAT**,并与 GitHub 仓库令牌区分。
|
||
|
||
### 完整翻译 —— 通用 UI 词
|
||
|
||
| 英 | 中 |
|
||
| --- | --- |
|
||
| Invite / Invitation | 邀请 |
|
||
| Search | 搜索 |
|
||
| Email | 邮箱(label)/ 邮件(action) |
|
||
| Password | 密码 |
|
||
| Sign in / Log in | 登录 |
|
||
| Sign up | 注册 |
|
||
| Sign out / Log out | 退出登录 |
|
||
| Save / Cancel / Delete | 保存 / 取消 / 删除 |
|
||
| Confirm / Continue / Back | 确认 / 继续 / 返回 |
|
||
| Edit / New / Create / Add | 编辑 / 新建 / 创建 / 添加 |
|
||
| Remove / Send / Open / Close | 移除 / 发送 / 打开 / 关闭 |
|
||
| Preview / Download / Upload | 预览 / 下载 / 上传 |
|
||
| Done / Loading... | 完成 / 加载中... |
|
||
| Profile / Account / Appearance | 个人资料 / 账号 / 外观 |
|
||
| Theme / Language | 主题 / 语言 |
|
||
| Light / Dark / System | 浅色 / 深色 / 跟随系统 |
|
||
| Active / Archived | 活跃(或 启用)/ 已归档 |
|
||
| Status / Priority | 状态 / 优先级 |
|
||
| Assignee / Reporter | 负责人 / 报告人 |
|
||
| Description / Title | 描述 / 标题 |
|
||
| Date / Time | 日期 / 时间 |
|
||
| Today / Yesterday / Tomorrow | 今天 / 昨天 / 明天 |
|
||
| Empty / Failed / Success | 空 / 失败 / 成功 |
|
||
| Error / Warning | 错误 / 警告 |
|
||
|
||
### 角色名 + 状态名(小写英文,不翻)
|
||
|
||
这些是 schema-level 标识符,中文环境也保持小写英文:
|
||
|
||
- 角色:`owner` / `admin` / `member`
|
||
- Issue 状态:`backlog` / `todo` / `in_progress` / `in_review` / `done` / `blocked` / `cancelled`
|
||
- Issue 状态分类:`unstarted` / `started` / `done` / `closed`
|
||
|
||
UI 里展示这些值时保持英文(必要时用 code-style 包起来):
|
||
|
||
- "你需要 owner 权限"
|
||
- "已切换到 in_progress"
|
||
|
||
### 词组组合规则
|
||
|
||
英文词(实体名 + 品牌名 + 缩写)与中文之间**加单空格**:
|
||
|
||
- "Create new issue" → "新建任务"(`任务` 是中文,不加空格)
|
||
- "Assign to agent" → "分配给智能体"
|
||
- "Configure runtime" → "配置运行时"
|
||
- "Stop daemon" → "停止守护进程"
|
||
|
||
### 复数与计数
|
||
|
||
i18next 用 `_one` / `_other`;中文不区分语法单复数,只填 `_other`。
|
||
|
||
```json
|
||
// en/issues.json
|
||
{
|
||
"issue_count_one": "{{count}} issue",
|
||
"issue_count_other": "{{count}} issues"
|
||
}
|
||
|
||
// zh-Hans/issues.json
|
||
{
|
||
"issue_count_other": "{{count}} 个任务"
|
||
}
|
||
```
|
||
|
||
常见计数格式:
|
||
|
||
- `{{count}} issues` → `{{count}} 个任务`
|
||
- `{{count}} agents` → `{{count}} 个智能体`
|
||
- `{{count}} workspaces` → `{{count}} 个工作区`
|
||
- `{{count}} comments` → `{{count}} 条评论`
|
||
- `{{count}} members` → `{{count}} 位成员`
|
||
- `{{count}} skills` → `{{count}} 个 skill`
|
||
|
||
### 插值
|
||
|
||
用 `{{var}}` 形式。中文翻译可以调整位置以符合中文语序。
|
||
|
||
```json
|
||
// en
|
||
{ "welcome_message": "Welcome back, {{name}}!" }
|
||
|
||
// zh-Hans
|
||
{ "welcome_message": "欢迎回来,{{name}}!" }
|
||
```
|
||
|
||
### Key 命名约定
|
||
|
||
3 层嵌套:`feature.component.action`。
|
||
|
||
```json
|
||
{
|
||
"feature_or_component": {
|
||
"subcomponent_or_section": {
|
||
"action_or_label": "..."
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
实例:
|
||
|
||
- `issues.toolbar.batch_update_success`
|
||
- `issues.detail.comment_form.placeholder`
|
||
- `inbox.empty.title`
|
||
- `settings.preferences.language.title`
|
||
|
||
### Web-only / Desktop-only 文案位置
|
||
|
||
- 共享文案:放 namespace JSON 顶层
|
||
- Web-only:放 `web` 段
|
||
- Desktop-only:放 `desktop` 段
|
||
|
||
参考 `auth.json`(`web` 段含 `prefer_desktop` / `desktop_handoff.*`)。
|
||
|
||
---
|
||
|
||
## 3. 中文风格
|
||
|
||
### 标点
|
||
|
||
- 中文用全角标点:`,。:;!?`
|
||
- 引号:用 `"..."`(直引号),与英文 source 保持一致。**不要**用 `「」` 或弯引号
|
||
- 省略号:用 `...`(三点)而非 `…`(单字符),与英文 source 保持一致
|
||
- 中英混排:英文词左右各加 1 个空格(详见词组组合规则)
|
||
|
||
### 风格原则
|
||
|
||
- **简洁直白**:避免翻译腔,"对于 X 来说"、"作为 X"、"我们的"
|
||
- **错误信息**:温和但明确,"无法保存修改" 优于 "保存修改失败了!"
|
||
- **按钮**:动词开头,2-4 字最佳。"取消"、"保存修改"、"立即同步"
|
||
- **Tooltip**:完整短句。"复制链接到剪贴板"
|
||
- **placeholder**:示例性提示。"输入任务标题..."
|
||
|
||
### UI 描述性文案
|
||
|
||
description 默认省略。添加前先问:**没有这句话,用户会误解什么或做错什么?** 如果标题、标签、控件、当前值或按钮已经表达清楚,就不添加。
|
||
|
||
- 同一事实只说一次,放在最相关的控件旁,不在页头、分组、字段、空状态和弹窗中反复解释。
|
||
- 优先用准确的标签或具体示例,避免用一段话讲解显然的操作。除非能消除实际歧义,不写“创建一个开始使用”“点击下方”“之后可以修改”等通用提示。
|
||
- 权限、费用、不可撤销后果、运行前提、输入限制和错误恢复信息应在相关状态下直接可见,不藏进只能悬停查看的帮助中。
|
||
- 首次使用说明只在需要的位置展示;高级用法与诊断细节放入可明确打开、支持键盘操作的帮助中。
|
||
- 保留输入标签、无障碍名称和必要的描述关联。不要把删掉的视觉废话全部转成屏幕阅读器专用文本。
|
||
- 同时检查英文、各语言翻译和移动端独立文案。PR 评审检查新增信息、同屏重复、显示条件和保留的约束;字数只是复查信号,不是自动删除标准。
|
||
|
||
共享设置组件已经支持可选 description。示例与新增调用默认省略,不增加强制填写描述的组件属性,也不另建一份文案规范。
|
||
|
||
### 拿不准的时候去哪查
|
||
|
||
术语表没覆盖的词,按这个顺序查:
|
||
|
||
1. `apps/docs/content/docs/*.zh.mdx` —— CN voice 事实标准,20+ 篇高度一致
|
||
2. `packages/views/locales/zh-Hans/auth.json` 和 `editor.json` —— JSON 结构 + selector API 用法参考
|
||
3. `packages/views/auth/login-page.tsx` —— 组件层 selector API 调用参考
|
||
4. `packages/views/settings/components/preferences-tab.tsx` —— 语言切换器参考
|
||
|
||
---
|
||
|
||
## 修改这一页时
|
||
|
||
改本页规则的同时还要:
|
||
|
||
1. 把规则在相关 locale JSON / AGENTS.md / docs 页面里同步落地
|
||
2. PR 描述里写明改了什么,方便 reviewer 检查下游是否跟着改了
|
||
|
||
本页是契约,其他文档不能 override。
|