Scope · 适用范围与依据
Why · 要解决什么问题
用户在跨语言社交与工作沟通中常在聊天里收到非母语文本消息,当前需跳出聊天去第三方工具翻译,链路长、上下文丢失、无法连续阅读。
Glossary · 统一术语
| 术语 | 定义 |
|---|---|
| 普通文本消息 | 用户发送的纯文本消息,是本功能唯一支持翻译的消息类型。 |
| 单条消息翻译 | 长按某条消息 → 点击「翻译」→ 半屏弹窗展示原文与译文。 |
| 翻译全部聊天记录 | 连续翻译模式,自动翻译聊天界面可视区域内的普通文本消息并随滚动增量翻译。 |
| 顶部固定翻译栏 | 连续翻译开启后位于导航栏下方的常驻控制条,用于切换展示态/目标语言/隐藏。 |
| 原文态 / 译文态 | 气泡显示原文(栏文案「翻译为 XX」)/ 气泡显示译文(栏文案「显示原文」)。 |
| 可视区域 | 当前聊天列表在屏幕内可见的消息范围,是自动翻译的触发范围。 |
| 译文缓存 | 以「消息 ID + 内容版本 + 目标语言」为键的缓存。 |
Scope · 能力矩阵与主流程
| 能力 | 个人聊天 | 群聊 | 入口 |
|---|---|---|---|
| 单条消息翻译 | 支持 | 支持 | 长按消息 →「翻译」 |
| 翻译全部聊天记录 | 支持 | 支持 | 弹窗内「翻译全部聊天记录」 |
| 可视区域自动翻译 | 支持 | 支持 | 连续翻译开启后自动 |
| 切换目标语言 | 支持 | 支持 | 弹窗「到 XX ⌄」/ 翻译栏「⋯」 |
| 隐藏翻译栏 | 支持 | 支持 | 翻译栏「⋯ → 隐藏」 |
| 全局开关与语言偏好 | 支持 | 我的 › 语言 | |
| 非文本消息翻译 | 不支持 | 见 §6.8 | |
Screens · 点击任一截图可在原型中直接打开对应页面
入口 · 长按操作菜单
Half-sheet · 结构、状态与交互
弹窗自底部升起,375×812 基准下高度 505pt(约 62% 屏高),顶部圆角。分 6 个区块:
| # | 区域 | 元素 | 说明 |
|---|---|---|---|
| 1 | 标题栏(固定) | 关闭按钮「×」· 居中标题「翻译」 | 毛玻璃背景;内容滚动时保持固定 |
| 2 | 原文区 | 「从 {源语言}」+ 原文 + 「更多 / 折叠」 | 默认收起,最多 1 行,超出以「更多」展开 |
| 3 | 分隔线 | 1px 细线 | 与内容左对齐 |
| 4 | 译文区 | 「到 {目标语言} ⌄」+ 译文 | 标签可点击切换目标语言(§6.3) |
| 5 | 操作区 | 「拷贝译文」 「翻译全部聊天记录」 | 行 = 图标 + 文案 + 右箭头,行间有分隔线 |
| 6 | 底部(固定) | 主按钮「关闭」 | 品牌紫填充 + 白字,圆角胶囊 |
| 操作 | 行为 | 备注 |
|---|---|---|
| 点击「更多」/「折叠」 | 切换原文展开 / 收起 | 默认收起原文 |
| 点击「到 XX ⌄」 | 展开目标语言下拉面板 | 见 §6.3 |
| 点击「拷贝译文」 | 译文写入剪贴板,Toast「已拷贝」 | 仅拷贝译文 |
| 点击「翻译全部聊天记录」 | 弹窗收起 → 顶部出现翻译栏 → 翻译可视区域 | 见 §6.4 |
| 点击「关闭」/「×」/ 蒙层 / 下滑 | 关闭弹窗 | 不改变已有译文状态 |
| 加载中关闭弹窗 | 取消请求或后台完成并写入缓存 | 建议写入缓存 |
| 状态 | 原文区 | 译文区 | 允许的操作 |
|---|---|---|---|
| 加载中 | 立即可见,可展开/收起 | 骨架占位 | 滚动、关闭、切换语言、点击遮罩均不被阻塞 |
| 成功 | 正常 | 展示译文 | 全部可用 |
| 失败 | 保留原文 | 失败文案 + 「重试」 | 可重试、可关闭 |
| 离线 | 保留原文 | 「当前网络不佳,请稍后重试」 | 恢复网络后可重试 |
Language picker · 下拉面板
点击 到 {目标语言} ⌄ → 在其下方展开下拉面板。
Continuous translation · 可视区域增量翻译
| 规则 | 说明 |
|---|---|
| 翻译范围 | 个人聊天与群聊均只翻译当前聊天界面的可视区域;不预翻译不可见的历史消息。 |
| 滚动增量 | 用户滑动时新进入可视区域的普通文本消息自动翻译。 |
| 缓存复用 | 已翻译过的消息复用已有译文,不重复请求。 |
| 消息筛选 | 仅处理「普通文本消息」;其他类型直接跳过,不占位、不显示加载。 |
| 请求合并 | 同一批入屏消息合并为批量请求,避免逐条串行请求造成抖动。 |
| 离开页面 | 退出聊天页后停止当前页面的可视区域翻译任务;再次进入时恢复翻译。 |
| 消息被编辑 | 原译文失效,按编辑后的新文本重新翻译。 |
连续翻译开启后,原文态气泡显示原文、栏文案「翻译为 {目标语言}」;译文态气泡显示译文、栏文案「显示原文」。切换仅改变展示内容,不触发重新翻译。
Translation bar · 状态机与菜单
| 属性 | 值 |
|---|---|
| 位置 | 导航栏下方,距导航栏 15pt;左右边距 15pt |
| 尺寸 / 圆角 | 345 × 32pt / 16pt(胶囊) |
| 背景 | 半透明毛玻璃(浅色 / 深色模式自适应) |
| 结构 | 左侧翻译图标 · 居中状态文案(可点击)· 右侧「⋯」圆形按钮 |
点击栏文案可在 原文态 与 译文态 之间切换;点击「⋯」打开菜单。
| 菜单项 | 原文态 | 译文态 | 行为 |
|---|---|---|---|
| 选择其他语言 | ✔ | ✔ | 展开语言单选列表(含「← 返回」) |
| 状态切换项 | 「翻译为中文」 | 「显示原文」 | 等价于点击翻译栏文案 |
| 隐藏 | ✔ | ✔ | 立即隐藏翻译栏,不停止自动翻译 |
切换目标语言后,当前界面消息立即按新目标语言重新翻译。
Hide bar · 隐藏与恢复
Settings · 翻译消息与界面语言
| 分组 | 条目 | 控件 | 行为 |
|---|---|---|---|
| 翻译消息 | 显示"翻译"按钮 | Switch(默认开) | 控制长按菜单中是否展示「翻译」入口 |
| 无需翻译 | 值 + 箭头 | 选择不需要翻译的语言 | |
| 说明文案:无需翻译:不要为该语言显示"翻译"按钮。 | |||
| 界面语言 | Chinese / 中文 | 单选 ✓ | 切换 App 界面语言 |
| English / English | 单选 ✓ | 切换 App 界面语言 | |
Chinese),副标题为本地名(中文)。Constraints · 哪些消息可以翻译
| 消息类型 | 可翻译 | 长按菜单 | 连续翻译 |
|---|---|---|---|
| 普通文本消息 | 支持 | 展示「翻译」 | 入屏即翻译 |
| 图片消息 | 不支持 | 隐藏「翻译」 | 跳过 |
| 语音消息 | 不支持 | 隐藏「翻译」 | 跳过 |
| 撤回消息 | 不支持 | 隐藏「翻译」 | 跳过;已翻译译文同步移除 |
| 系统通知 | 不支持 | 无长按菜单 | 跳过 |
| 纯表情消息 | 不支持 | 隐藏「翻译」 | 跳过 |
| 其他富媒体 | 不支持 | 隐藏「翻译」 | 跳过 |
Edge cases · 需求说明逐条落地
| # | 场景 | 预期行为 |
|---|---|---|
| 1 | 网络断开 | 保留原文,并提示「当前网络不佳,请稍后重试」 |
| 2 | 翻译过程中离开聊天页面 | 退出后停止当前页面的可视区域翻译任务;再次进入时恢复翻译 |
| 3 | 消息被编辑 | 原译文失效,根据编辑后的新文本重新翻译 |
| 4 | 切换目标语言 | 当前界面消息翻译为新目标语言;不得将已翻译的译文再次当作原文翻译 |
| 5 | 翻译加载状态 | 显示加载但不阻塞滚动及其他操作,交互体验参考 Telegram |
| 6 | 消息被撤回 / 删除 | 对应译文同步移除 |
| 7 | 同一消息重复进入可视区域 | 命中缓存直接展示,不重复请求 |
| 8 | 目标语言 = 消息原文语言 | 建议不展示译文,避免无意义请求 待确认 |
| 9 | 快速连续切换目标语言 | 以最后一次选择为准;丢弃过期响应 |
| 10 | 超长文本译文 | 弹窗内容区独立滚动,标题栏与底部按钮固定 |
| 11 | 翻译服务超时 | 按失败态处理,提供「重试」 |
| 12 | 翻译栏隐藏后又触发滚动 | 继续自动翻译,不中断调度 |
| 13 | 深色模式 / 大字体 | 翻译栏、弹窗、菜单需适配,文本不截断溢出 |
Copy deck · 可直接用于 i18n
| 建议 Key | 位置 | 文案 | 备注 |
|---|---|---|---|
translate.entry | 长按操作菜单项 | 翻译 | 固定第 3 项 |
translate.sheet.title | 弹窗标题 | 翻译 | 居中 |
translate.sheet.source | 原文语言标签 | 从 {源语言} | 示例:从 英语 |
translate.sheet.target | 译文语言标签 | 到 {目标语言} | 右侧带下拉图标 |
translate.sheet.expand | 展开原文 | 更多 | 原文收起时 |
translate.sheet.collapse | 收起原文 | 折叠 | 原文展开时 |
translate.sheet.copy | 操作行 | 拷贝译文 | Toast:已拷贝 |
translate.sheet.translateAll | 操作行 | 翻译全部聊天记录 | 开启连续翻译 |
translate.sheet.close | 弹窗底部主按钮 | 关闭 | 品牌紫填充 |
translate.search.placeholder | 语言面板搜索框 | 搜索 | — |
translate.bar.toTarget | 翻译栏 · 原文态 | 翻译为中文 | 需动态化为「翻译为{目标语言}」 |
translate.bar.showOriginal | 翻译栏 · 译文态 | 显示原文 | 点击切回原文 |
translate.bar.menu.lang | 翻译栏菜单 | 选择其他语言 | — |
translate.bar.menu.hide | 翻译栏菜单 | 隐藏 | 需求说明称「隐藏此翻译栏」,见 §12 |
translate.lang.back | 语言面板顶部 | 返回 | 二级面板返回上级 |
translate.toast.copied | 拷贝成功 | 已拷贝 | — |
translate.error.network | 网络异常 | 当前网络不佳,请稍后重试 | 需求说明指定文案 |
translate.error.retry | 翻译失败 | 重试 | 建议文案 |
settings.section.translate | 设置分组标题 | 翻译消息 | — |
settings.translate.showEntry | 设置项 | 显示“翻译”按钮 | Switch |
settings.translate.none | 设置项 | 无需翻译 | 进入二级页 |
settings.translate.noneHint | 设置项说明 | 无需翻译:不要为该语言显示“翻译”按钮。 | — |
settings.section.interfaceLanguage | 设置分组标题 | 界面语言 | — |
Tokens · 从设计稿采样(375 × 812 基准)
| 元素 | 尺寸 | 说明 |
|---|---|---|
| 半屏弹窗(默认) | 375 × 505pt(约 62% 屏高) | 顶部圆角,含底部安全区 |
| 半屏弹窗(原文展开 / 超长) | 高度自适应,最高接近满屏 | 内容超高时内部滚动 |
| 弹窗内容左右内边距 | 16pt | 语言标签与正文对齐 |
| 弹窗底部按钮 | 345 × 48pt | 左右 15pt 边距,固定 |
| 顶部翻译栏 | 345 × 32pt,圆角 16pt | 距导航栏 15pt |
| 翻译栏内图标 | 16 × 16pt | 左侧翻译图标、「⋯」按钮 |
| 操作行(拷贝译文等) | 高 28pt,图标 28 × 28pt | 文案距图标 43pt |
| 语言菜单面板 | 宽约 166pt,行高 40pt | 圆角 14pt |
| 弹窗内语言下拉 | 宽约 200pt | 含搜索行 |
Analytics · 用于验证功能价值与效果
| 事件名 | 触发时机 | 关键参数 |
|---|---|---|
translate_entry_show | 长按菜单渲染完成 | chat_type、message_type、source_lang |
translate_click | 点击「翻译」 | chat_type、message_id、source_lang、target_lang |
translate_sheet_show | 半屏弹窗展示 | source_lang、target_lang |
translate_result | 译文返回 | result、duration_ms、cache_hit |
translate_expand_original | 点击「更多」/「折叠」 | action(expand/collapse) |
translate_copy | 点击「拷贝译文」 | target_lang |
translate_switch_lang | 切换目标语言 | from_lang、to_lang、entry(sheet/bar) |
translate_all_click | 点击「翻译全部聊天记录」 | chat_type、visible_message_count |
translate_viewport_batch | 可视区域批量翻译 | message_count、cache_hit_count、duration_ms |
translate_bar_toggle | 点击翻译栏文案 | from_state、to_state |
translate_bar_hide | 点击「隐藏」 | state |
translate_setting_change | 设置页变更 | key、value |
Non-functional · 性能 / 体验 / 合规
| 指标 | 目标 |
|---|---|
| 单条翻译首字返回 | P95 < 1.5s(正常网络) |
| 可视区域批量翻译 | P95 < 2.5s(一屏) |
| 缓存命中率 | 重复滑动场景 > 80% |
| 并发请求 | 同一会话并发上限 1 批,多余入队 |
| 滚动流畅度 | 翻译过程中不掉帧;译文高度变化时保持锚点稳定 |
| 内存 | 译文缓存设上限并做 LRU 淘汰,退出会话可释放 |
Open questions · 评审时逐条定稿
| # | 问题 | 设计稿 / 需求说明的差异 | 建议 | Owner |
|---|---|---|---|---|
| Q1 | 翻译栏菜单第 3 项文案 | 设计稿「隐藏」vs 需求说明「隐藏此翻译栏」 | 统一为设计稿的「隐藏」,或按需求说明补全文案 | 设计 / 产品 |
| Q2 | 「翻译全部聊天记录」控件形态 | 需求说明称「弹窗底部按钮」;设计稿为列表行,底部按钮是「关闭」 | 以设计稿为准:列表行 + 「关闭」按钮 | 产品 |
| Q3 | 翻译栏文案是否需要动态化 | 均写作「翻译为中文」,但支持切换目标语言 | 改为「翻译为{目标语言}」动态文案 | 设计 / 产品 |
| Q4 | 「显示"翻译"按钮」的语义边界 | — | 明确:仅控制长按菜单中「翻译」入口的显隐 | 产品 |
| Q5 | 「无需翻译」的判定依据 | — | 按消息语言识别结果判定,而非界面语言 | 产品 / 客户端 |
| Q6 | 隐藏翻译栏的状态作用域 | 需求未说明退出会话后是否恢复 | 建议会话内临时隐藏,重新进入会话默认显示 | 产品 |
| Q7 | 目标语言 = 原文语言时的表现 | — | 不展示译文 / 展示原文并给出轻提示 | 设计 / 产品 |
| Q8 | 译文态下是否继续自动翻译新入屏消息 | 需求未明确 | 建议继续(用户已在连续阅读模式) | 产品 |
| Q9 | 富文本 / @ 提及 / 链接卡片是否可翻译 | 需求仅列「普通文本消息」 | 纯文本 + @ 提及可翻译,其余不支持 | 产品 |
| Q10 | 译文缓存的生命周期与清除策略 | — | 会话级缓存 + LRU,退出会话可释放 | 客户端 |
| Q11 | 译文来源标识 | — | 是否需在译文旁展示「机器翻译」标识(合规建议需要) | 产品 / 法务 |
| Q12 | 界面语言列表范围 | 设计稿仅示例 Chinese / English | 需与 App 现有语言清单对齐 | 产品 |
Acceptance checklist · 提测与验收对照