Update translations
This commit is contained in:
parent
4af1379d1e
commit
1030e735c0
96 changed files with 13449 additions and 0 deletions
165
locales/zh-Hans/client-server-api/modules/receipts.md
Normal file
165
locales/zh-Hans/client-server-api/modules/receipts.md
Normal file
|
@ -0,0 +1,165 @@
|
|||
### 回执
|
||||
|
||||
{{% changed-in v="1.4" %}} 新增了私有已读回执。
|
||||
|
||||
本模块增加了对回执的支持。回执是一种对事件的确认方式。该模块定义了用于表示用户已读至某一事件的 `m.read` 回执,以及用于相同目的但不会被其他用户察觉的 `m.read.private` 回执。主要来说,`m.read.private` 旨在清除[通知](#receiving-notifications),而不向他人公开已读状态。
|
||||
|
||||
为每个事件发送回执可能导致向主服务器发送大量流量。为了防止这一问题,回执采用“已读至”标记的方式实现。此标记表示确认适用于“至(含)”指定事件的所有事件。例如,将某事件标记为“已读”就意味着用户已经阅读了*至此*的所有事件。关于已读回执如何影响通知计数,请参见[接收通知](#receiving-notifications)章节。
|
||||
|
||||
{{% added-in v="1.4" %}} 已读回执主要有三种形式:
|
||||
* 非线程化:表示已读至某事件的回执,与线程无关。这等同于线程功能引入前的已读回执。
|
||||
* 线程化,主时间线:表示对非特定线程事件的已读回执。用线程 ID `main` 标识。
|
||||
* 线程化,特定线程:表示在指定线程内的已读回执。用线程根事件的事件 ID 标识。
|
||||
|
||||
有关线程化回执的更多详细信息,请参阅[下文](#threaded-read-receipts)。
|
||||
|
||||
#### 事件
|
||||
|
||||
{{% changed-in v="1.4" %}} 每个 `user_id`、`receipt_type` 和类别(非线程化,或 `thread_id`)三元组必须只关联一个 `event_id`。
|
||||
|
||||
{{% event event="m.receipt" %}}
|
||||
|
||||
#### 客户端行为
|
||||
|
||||
{{% changed-in v="1.4" %}} 修订以支持线程化已读回执。
|
||||
|
||||
在 [`/sync`](#get_matrixclientv3sync) 接口中,回执列在指定房间的 `ephemeral` 事件数组下。新收到的回执是增量信息,用于更新已有的映射。客户端应依据 `user_id`、`receipt_type` 和(如有)`thread_id` 替换旧的已读回执。例如:
|
||||
|
||||
客户端收到 m.receipt:
|
||||
user = @alice:example.com
|
||||
receipt_type = m.read
|
||||
event_id = $aaa:example.com
|
||||
thread_id = undefined
|
||||
|
||||
客户端收到另一个 m.receipt:
|
||||
user = @alice:example.com
|
||||
receipt_type = m.read
|
||||
event_id = $bbb:example.com
|
||||
thread_id = main
|
||||
|
||||
此时客户端尚未替换任何确认。
|
||||
|
||||
客户端再次收到 m.receipt:
|
||||
user = @alice:example.com
|
||||
receipt_type = m.read
|
||||
event_id = $ccc:example.com
|
||||
thread_id = undefined
|
||||
|
||||
客户端用新回执 $ccc:example.com 替换之前 $aaa:example.com 的确认,但不会替换 $bbb:example.com,因为它属于线程。
|
||||
|
||||
客户端再次收到 m.receipt:
|
||||
user = @alice:example.com
|
||||
receipt_type = m.read
|
||||
event_id = $ddd:example.com
|
||||
thread_id = main
|
||||
|
||||
现在客户端用新 $ddd:example.com 的确认替换旧的 $bbb:example.com。客户端不会替换 $ccc:example.com 的旧回执,因为它是未线程化的。
|
||||
|
||||
客户端应在确定事件**已显示**给用户时才发送已读回执。仅仅收到事件并不能确保用户已经看到。用户应当*执行某些操作*,如查看事件所处房间或关闭通知,事件方可计为“已读”。客户端**不应**为自己的用户发送已读回执。
|
||||
|
||||
与发送回执的规则类似,线程化回执应出现在线程上下文中。如果线程被折叠,客户端尚未向用户展示该事件(或任何相关已读回执)。一旦用户展开线程,就应发送线程化已读回执,并显示来自其他用户的每线程回执。
|
||||
|
||||
客户端可通过以下 HTTP API 与其用户相关的回执状态进行更新。
|
||||
|
||||
{{% http-api spec="client-server" api="receipts" %}}
|
||||
|
||||
##### 私有已读回执
|
||||
|
||||
{{% added-in v="1.4" %}}
|
||||
|
||||
部分用户希望标记房间为已读,以清除其[通知计数](#receiving-notifications),但又不希望暴露自己已经阅读了特定消息。为此,客户端可以发送 `m.read.private` 回执,作用同 `m.read`,但不会向其他用户广播回执,从而实现只清除通知不公开已读状态。
|
||||
|
||||
服务器**不得**将 `m.read.private` 回执发送给除最初发送用户外的任何其他用户。
|
||||
|
||||
在 `m.read` 和 `m.read.private` 两者间,决定最高已读至标记时会采用“更靠前”或“更近期”的回执。关于这对通知计数影响的更多信息,请参见[通知](#receiving-notifications)章节。
|
||||
|
||||
如果客户端发送的 `m.read` 回执“落后”于 `m.read.private` 回执,其他用户会看到该变化,但发送用户的通知计数不会回退到那一时间点。尽管不常见,出现 `m.read`(公开)回执比 `m.read.private` 回执滞后几条消息的情况也是合法的。
|
||||
|
||||
##### 线程化已读回执
|
||||
|
||||
{{% added-in v="1.4" %}}
|
||||
|
||||
如果客户端未使用[线程](#threading)功能,则只会发送“非线程化”已读回执,无论线程如何都影响整个房间。
|
||||
|
||||
线程化回执指的是带有 `thread_id` 的回执,其目标为线程根事件的事件 ID 或主时间线用 `main`。
|
||||
|
||||
线程化引入了在同一房间中进行多次独立会话的概念,因此也对应有独立的已读回执和通知计数。某事件被认为“属于线程”,需满足以下任一条件:
|
||||
|
||||
* 其 `rel_type` 为 `m.thread`,或
|
||||
* 在事件关系链上,其父事件通过 `rel_type` 为 `m.thread` 的方式被关联到线程根。实现时不应无限级递归,建议最多递归 3 级以覆盖间接关系。
|
||||
|
||||
房间内未归属于某线程的事件视为主时间线中的事件。当用作线程引用(如回执和通知计数中),主时间线采用特殊线程 ID `main`。
|
||||
|
||||
线程根本身被视作主时间线事件,通过非线程关系与线程根相关的事件也被视为主时间线事件。
|
||||
|
||||
以下是一个房间的 DAG 示例,虚线表示事件间关系,实线表示拓扑排序。
|
||||
|
||||
{{% diagram name="threaded-dag" alt="呈现包含线程关系的单一时间线的DAG图" %}}
|
||||
|
||||
该 DAG 可分解为 3 条线程化时间线,其中 `A` 和 `B` 为线程根:
|
||||
|
||||
{{% diagram name="threaded-dag-threads" alt="呈现包含3条相关线程化时间线的 DAG 图" %}}
|
||||
|
||||
据此可说明:
|
||||
* 在 `I` 上的线程化已读回执会标记 `A`、`B` 和 `I` 为已读。
|
||||
* 在 `E` 上的线程化已读回执会标记 `C` 和 `E` 为已读。
|
||||
* 在 `D` 上的非线程化已读回执会标记 `A`、`B`、`C` 和 `D` 为已读。
|
||||
|
||||
注意,仅用线程化回执将 `A` 标记为已读,并不会让 `C`、`E`、`G` 或 `H` 也被标记为已读。线程 A 的时间线需在 `H` 上设置属于该线程的线程化回执才能做到。
|
||||
|
||||
上述 3 个例子的回执示例如下:
|
||||
|
||||
```json
|
||||
{
|
||||
"$I": {
|
||||
"m.read": {
|
||||
"@user:example.org": {
|
||||
"ts": 1661384801651,
|
||||
"thread_id": "main" // 因为 `I` 不在任何线程中,但回执为线程化回执
|
||||
}
|
||||
}
|
||||
},
|
||||
"$E": {
|
||||
"m.read": {
|
||||
"@user:example.org": {
|
||||
"ts": 1661384801651,
|
||||
"thread_id": "$A" // 因为 `E` 属于线程 `A`
|
||||
}
|
||||
}
|
||||
},
|
||||
"$D": {
|
||||
"m.read": {
|
||||
"@user:example.org": {
|
||||
"ts": 1661384801651
|
||||
// 无 `thread_id`,因为这是*非线程化*回执
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
发送已读回执的条件在线程化与非线程化场景下适用方式一致。例如,当用户展开某线程时,客户端可能会为该线程事件发送私有已读回执。
|
||||
|
||||
#### 服务器行为
|
||||
|
||||
出于高效性考虑,应将回执合并打包为按房间和线程分组的事件后再发送给客户端。
|
||||
|
||||
部分回执会作为类型为 `m.receipt` 的 EDU 跨联邦发送。该 EDU 格式为:
|
||||
|
||||
```
|
||||
{
|
||||
<room_id>: {
|
||||
<receipt_type>: {
|
||||
<user_id>: { <内容(ts & thread_id, 当前支持)> }
|
||||
},
|
||||
...
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
这些均以增量方式相较此前已发送的回执推送。目前仅应使用一个 `<receipt_type>` :`m.read`。`m.read.private` **不得**出现在联邦 `m.receipt` EDU 内。
|
||||
|
||||
#### 安全性注意事项
|
||||
|
||||
回执是在事件图之外发送的,因此 `m.receipt` 事件内容不会进行完整性校验。
|
Loading…
Add table
Add a link
Reference in a new issue