gp-rest-api/docs/api-reference.md
wenpai 414c5c7c46 docs: add CLAUDE.md, update API reference and multisite support
- CLAUDE.md: 项目定位与治理规则
- API reference: 补充 multisite 参数文档
- Multisite blog_id 参数支持

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 19:14:44 +08:00

290 lines
7.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# GlotPress REST API 文档
## 概述
`gp-rest-api` 是部署在 `wpfanyi.com` 的 WordPress mu-plugin为 GlotPress 翻译平台提供 REST API 端点,支持通过 Application Password 认证进行程序化翻译管理。
- 部署位置:`/www/wwwroot/wpfanyi.com/wp-content/mu-plugins/gp-rest-api.php`
- 服务器feicode-prod (45.117.8.70)
- 源码仓库:`~/Projects/gp-rest-api/`(待推送 feicode
- 版本1.0.0
- GlotPress 版本4.0.3
## 认证
使用 WordPress Application PasswordBasic Auth
### 创建 Application Password
1. 登录 wpfanyi.com 后台
2. 用户 → 个人资料 → Application Passwords
3. 输入名称(如 `ai-translate-pipeline`),点击"添加新的应用程序密码"
4. 记录生成的密码(只显示一次)
### 请求认证
```bash
curl -u "用户名:应用密码" "https://wpfanyi.com/wp-json/gp/v1/..."
```
或使用 Authorization header
```
Authorization: Basic base64(用户名:应用密码)
```
## 多站点说明
wpfanyi.com 是 WordPress 多站点架构67 个子站各自运行独立的 GlotPress 实例。所有端点需要传 `blog_id` 参数指定目标子站。
### 子站 blog_id 对照表Top 15
| blog_id | 路径 | 产品 |
|---------|------|------|
| 2 | /woocommerce/ | WooCommerce |
| 3 | /buddypress/ | BuddyPress |
| 4 | /bbpress/ | bbPress |
| 5 | /mainwp/ | MainWP |
| 8 | /elementor/ | Elementor |
| 9 | /learndash/ | LearnDash |
| 10 | /gravityforms/ | GravityForms |
完整列表可通过 WP 网络管理后台查看。
## 端点
### 1. GET /wp-json/gp/v1/projects/{path}
获取项目信息、翻译集列表和翻译进度统计。
**参数**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| path | string | 是 | URL 路径参数GP 项目路径 |
| blog_id | integer | 否 | 子站 ID默认 0当前站 |
**示例**
```bash
curl -u "user:pass" \
"https://wpfanyi.com/wp-json/gp/v1/projects/woocommerce?blog_id=2"
```
**响应**
```json
{
"id": 1,
"name": "WooCommerce",
"slug": "woocommerce",
"path": "woocommerce",
"description": "...",
"parent_project_id": 0,
"translation_sets": [
{
"id": 2,
"locale": "zh-cn",
"slug": "default",
"name": "Chinese (China)",
"stats": {
"all": 8378,
"current": 8378,
"waiting": 0,
"fuzzy": 0,
"untranslated": 0
},
"percent": 100
}
],
"sub_projects": [
{
"id": 2,
"name": "WooCommerce - Stable",
"slug": "stable",
"path": "woocommerce/stable"
}
]
}
```
### 2. GET /wp-json/gp/v1/originals
查询项目原文及其翻译状态,支持按状态过滤和分页。
**参数**
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| project_path | string | 是 | - | GP 项目路径 |
| locale | string | 是 | - | 语言代码,如 `zh-cn` |
| blog_id | integer | 否 | 0 | 子站 ID |
| slug | string | 否 | `default` | 翻译集 slug |
| status | string | 否 | `untranslated` | 过滤状态:`untranslated`/`current`/`fuzzy`/`waiting`/`all` |
| per_page | integer | 否 | 50 | 每页数量1-200 |
| page | integer | 否 | 1 | 页码 |
**示例**
```bash
# 获取 WooCommerce 未翻译的原文
curl -u "user:pass" \
"https://wpfanyi.com/wp-json/gp/v1/originals?project_path=woocommerce&locale=zh-cn&blog_id=2&status=untranslated&per_page=10"
# 获取已翻译的原文
curl -u "user:pass" \
"https://wpfanyi.com/wp-json/gp/v1/originals?project_path=woocommerce&locale=zh-cn&blog_id=2&status=current&per_page=5"
```
**响应**
```json
{
"project": "woocommerce",
"locale": "zh-cn",
"slug": "default",
"total": 8378,
"page": 1,
"per_page": 5,
"items": [
{
"original_id": 1,
"singular": "Nuevo León",
"plural": null,
"context": null,
"references": ["i18n/states.php:943"],
"translation_id": 1,
"translation_0": "新莱昂",
"gp_status": "current"
}
]
}
```
### 3. POST /wp-json/gp/v1/translations
批量提交翻译。单次最多 100 条。
**权限要求**:用户必须拥有目标翻译集的 GP `edit` 权限。
**状态逻辑**
- 用户有 `approve` 权限 → 翻译直接设为 `current`(已批准)
- 用户无 `approve` 权限 → 翻译设为 `waiting`(待审核)
**请求体JSON**
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| project_path | string | 是 | GP 项目路径 |
| locale | string | 是 | 语言代码 |
| blog_id | integer | 否 | 子站 ID |
| slug | string | 否 | 翻译集 slug默认 `default` |
| translations | array | 是 | 翻译数组(最多 100 条) |
**translations 数组项**
| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| original_id | integer | 是 | 原文 ID |
| translation_0 | string | 是 | 单数翻译 |
| translation_1~5 | string | 否 | 复数形式翻译 |
**示例**
```bash
curl -X POST -u "user:pass" \
"https://wpfanyi.com/wp-json/gp/v1/translations" \
-H "Content-Type: application/json" \
-d '{
"blog_id": 4,
"project_path": "bbpress",
"locale": "zh-cn",
"translations": [
{"original_id": 100, "translation_0": "论坛"},
{"original_id": 101, "translation_0": "主题"}
]
}'
```
**响应**
```json
{
"summary": {
"submitted": 1,
"skipped": 1,
"errors": 0
},
"results": [
{
"original_id": 100,
"status": "created",
"translation_id": 5678,
"gp_status": "current",
"warnings": false
},
{
"original_id": 101,
"status": "skipped",
"translation_id": 1234,
"message": "Identical current translation exists."
}
]
}
```
**结果状态说明**
| status | 含义 |
|--------|------|
| `created` | 翻译已创建 |
| `skipped` | 已存在相同的 current 翻译,跳过 |
| `error` | 创建失败(附 message 说明原因) |
## 内部机制
### 翻译提交流程
1. 通过 `GP::$project->by_path()` 定位项目
2. 通过 `GP::$translation_set->by_project_id_slug_and_locale()` 定位翻译集
3. 检查 GP 权限(`edit` on `translation-set`
4. 对每条翻译:
- 验证 `original_id` 存在且属于目标项目
- 重复检测比较所有复数字段translation_0~5相同则跳过
- 运行 `GP::$translation_warnings->check()` 质量检查
- 调用 `GP::$translation->create()` 创建翻译
- 调用 `$translation->set_status()` 设置状态(处理 old/current 状态机)
### 安全特性
- Application Password 认证WP 5.6+ 内置)
- GP 权限层自动继承(基于 `wp_get_current_user()`
- 隐藏优先级原文priority -2对非项目管理员不可见
- 翻译质量警告自动检查
- 单次请求上限 100 条
### 多站点处理
使用 `switch_to_blog()` / `restore_current_blog()` 切换子站上下文,并重新初始化 GP 表名前缀(`wp_N_gp_projects` 等)。
## 环境配置
### nginx
`/www/server/nginx/conf/fastcgi.conf` 需包含:
```
fastcgi_param HTTP_AUTHORIZATION $http_authorization;
```
### Application Password over HTTP
插件只在 `local``development` 环境覆盖 `wp_is_application_passwords_available`,用于反向代理终止 SSL 但 PHP 仍看到 HTTP 的开发环境。生产环境继续使用 WordPress 默认的 HTTPS 检查。
## 错误码
| code | HTTP | 说明 |
|------|------|------|
| `rest_forbidden` | 401 | 未认证或无权限 |
| `gp_project_not_found` | 404 | 项目路径不存在 |
| `gp_set_not_found` | 404 | 翻译集不存在 |
| `gp_too_many` | 400 | 超过 100 条限制 |
| `rest_missing_callback_param` | 400 | 缺少必填参数 |