feat(notification): 通知标题和正文支持多语言

- 通知静态配置支持 title/body i18n
- 前端通知列表和详情页展示本地化内容
- 新增数据库迁移脚本
- 更新通知协议文档
This commit is contained in:
ZL-Q
2026-04-28 17:20:17 +08:00
parent b9617ae152
commit a940f2ea47
16 changed files with 601 additions and 213 deletions
@@ -27,6 +27,7 @@ List notifications for the current user.
- `limit` (optional, integer, default 20, max 50): number of items per page
- `cursor` (optional, string): pagination cursor (ISO 8601 timestamp of last item's `created_at`)
- `locale` (optional, string): requested locale for title/body resolution. Supported values: `zh` (default), `zh_Hant`, `en`. If the requested locale is not available in the notification's i18n dict, falls back to `zh`.
**Response (200)**:
@@ -61,6 +62,7 @@ Field rules:
- `payload`: discriminated union (see Payload section below)
- `isRead`: boolean
- `readAt`: ISO 8601 timestamp or `null`
- `title` and `body`: resolved plain strings based on the `locale` parameter. The database stores these as i18n JSONB objects (`{"zh": "...", "zh_Hant": "...", "en": "..."}`); the API resolves the best match before returning.
- Results are filtered: `notifications.status = 'published'` and `notifications.deleted_at IS NULL`
### GET /api/v1/notifications/unread-count
@@ -92,6 +94,10 @@ Mark a single notification as read. Idempotent.
- `notification_id`: UUID of the `user_notifications` record
**Query parameters**:
- `locale` (optional, string): requested locale for title/body resolution (same rules as list endpoint)
**Response (200)**:
```json
@@ -41,8 +41,14 @@ notification:
type: system
status: published
published_at: 2026-04-10T08:00:00Z
title: 新用户欢迎通知
body: 你已获得注册奖励,可前往积分中心查看。
title:
zh: 新用户欢迎通知
zh_Hant: 新用戶歡迎通知
en: Welcome
body:
zh: 你已获得注册奖励,可前往积分中心查看。
zh_Hant: 你已獲得註冊獎勵,可前往積分中心查看。
en: You have received a registration reward. Check your points.
payload:
action: open_route
route: /points
@@ -60,8 +66,8 @@ targets:
- `status`: required, one of `draft`, `published`, `revoked`
- `deleted`: optional, boolean, default `false`, soft-delete this notification
- `published_at`: optional ISO 8601 timestamp
- `title`: required, non-empty string
- `body`: required, non-empty string
- `title`: required, non-empty dict mapping locale codes to translated strings. Must include at least `zh`. Supported keys: `zh`, `zh_Hant`, `en`.
- `body`: required, non-empty dict mapping locale codes to translated strings. Must include at least `zh`. Supported keys: `zh`, `zh_Hant`, `en`.
- `payload`: required, must follow the notification payload protocol
### targets