fix(collaboration,i18n): PresenceAvatars 的三处硬编码英文接入 i18n (#3440) - #3445
Merged
Conversation
#3424 把 `@object-ui/collaboration` 整包接上了 `@object-ui/i18n`,但只改完 `CommentThread`。同包 `PresenceAvatars` 还剩三处英文字面量 —— 而它不是没人用的 导出:控制台在两个地方渲染它(`app-shell/src/layout/AppHeader.tsx` 的租户在线头像、 `app-shell/src/views/RecordDetailView.tsx` 的"谁也在看这条记录"),zh 会话下这三处 就是英文。 三处分别是: - 头像组的 `aria-label`:`` `${n} user${n !== 1 ? 's' : ''} present` ``; - 溢出徽标的 `title`:`` `${n} more user${n !== 1 ? 's' : ''}` ``; - 每个头像的 `title`:`` `${name} (${status})` ``。 第一处尤其要紧:这个控件只有图片和首字母,对读屏软件来说 aria-label 就是它的 全部可访问名,没有别的可回落。 和 #3424 的评论条数一样,前两处除了没翻译还多带一层缺陷:被编译进组件的不只是词, 还有**复数规则**。两处产出的英文都是对的(各自都有真正的单数分支,这不是 #3423 在页签徽标上修的 "1 items"),但 `n !== 1 ? 's' : ''` 是写死在渲染路径里的英文语法, 任何语言都无法套用自己的规则。两处改用本仓的**双 key** 约定 (`collaboration.presentUserCount`/`presentUserCountOne`、 `collaboration.moreUserCount`/`moreUserCountOne`),不用 i18next 的 `_one`/`_other` 后缀(zh/ja/ko 没有独立单数,parity gate 会把合理缺失读成丢键);count 以字符串插值, i18next 因此跳过自己的复数解析。见证这次"规则搬家"的是德语: "1 anwesender Benutzer" vs "2 anwesende Benutzer" 要变形容词词尾,原来的三元表达式 无论语言包怎么写都产不出来。 头像 tooltip 收成一个 `collaboration.userStatusTitle` 键(`{{name}} ({{status}})`), 括号连同空格都归翻译所有 —— CJK 语言包因此可以去掉英文在 `(` 前的那个空格, 与各包既有的 `edited: '(已编辑)'` 一致。 其中的 `status` 走**显示层翻译**(`collaboration.statusActive`/`statusIdle`/ `statusAway`):`PresenceUser['status']` 的枚举值仍是数据,存储、比较、传递 (包括 `statusColors` 查色)一律不动,只在这一个渲染出口翻译。落在联合类型之外的 status 原样渲染成它自己——presence 用户来自宿主提供的 `PresenceSource` 传输层, 类型再严运行时也可能收到未映射的值,兜底只回落到原始字符串,不臆造标签、 也不留下一对空括号。 新增 8 个键,十个语言包全部补齐真实翻译。 Fixes #3440 Refs #3424 Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt Co-authored-by: Claude <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3440
Refs #3424
#3424 把
@object-ui/collaboration整包接上了@object-ui/i18n,但只改完CommentThread。同包PresenceAvatars还剩三处英文字面量 —— 而它不是没人用的导出:控制台在两个地方渲染它(packages/app-shell/src/layout/AppHeader.tsx:894的租户在线头像、packages/app-shell/src/views/RecordDetailView.tsx:2066的「谁也在看这条记录」),zh 会话下这三处就是英文。改了什么
三处分别是:
aria-label(原`${n} user${n !== 1 ? 's' : ''} present`);title(原`${n} more user${n !== 1 ? 's' : ''}`);title(原`${name} (${status})`)。第一处尤其要紧:这个控件只有图片和首字母,对读屏软件来说 aria-label 就是它的全部可访问名,没有别的可回落。
复数规则也一并搬出组件
和 #3424 的评论条数一样,前两处除了没翻译还多带一层缺陷:被编译进组件的不只是词,还有复数规则。两处产出的英文本身都是对的(各自都有真正的单数分支,这不是 #3423 在页签徽标上修的 "1 items"),但
n !== 1 ? 's' : ''是写死在渲染路径里的英文语法,任何语言都套不上自己的规则。两处改用本仓的双 key 约定(
collaboration.presentUserCount/presentUserCountOne、collaboration.moreUserCount/moreUserCountOne),不用 i18next 的_one/_other后缀 —— zh/ja/ko 没有独立单数,那几个包会合理地缺_one半边,all-locales-key-parity会把它读成丢键。count 以字符串插值,i18next 因此跳过自己的复数解析。见证这次「规则搬家」的是德语:
1 anwesender Benutzervs2 anwesende Benutzer要变形容词词尾,原来的三元表达式无论语言包怎么写都产不出来。ru 钉住需要三种形式的语言,ja 钉住一种都不需要的语言。status:显示层翻译(按 PM 裁定)
头像 tooltip 收成一个
collaboration.userStatusTitle键({{name}} ({{status}})),括号连同空格都归翻译所有 —— CJK 语言包因此可以去掉英文在(前的那个空格,与各包既有的edited: '(已编辑)'一致。其中的
status走显示层翻译(collaboration.statusActive/statusIdle/statusAway):PresenceUser['status']的枚举值仍是数据,存储、比较、传递(包括statusColors查色)一律不动,只在这一个渲染出口翻译。落在联合类型之外的 status 原样渲染成它自己 —— presence 用户来自宿主提供的PresenceSource传输层(WebSocket/SSE,本包不拥有),类型再严运行时也可能收到未映射的值;兜底只回落到原始字符串,不臆造标签、也不留下一对空括号。顺带一提:单据正文猜的枚举值是
online/away,实际是active | idle | away(usePresence.ts),键按实际枚举建。新增 8 个键,十个语言包全部补齐真实翻译。
反向验证(方向先预测、后运行)
把
PresenceAvatars.tsx单独 checkout 回origin/main,两个测试文件不动:origin/main的三元本来就产出正确单数,这里若翻转反而说明文案被改动了)。Tests 10 failed | 14 passed (24)—— 与预测逐条一致。唯一一处新增的英文行为是 off-union status 的兜底:
origin/main直接插值原始值,现在仍然如此,所以那条也是两侧皆绿。测试
仓根跑(
packages/collaboration+packages/i18n+ 四个 mock 掉 PresenceAvatars 的 RecordDetailView 消费者测试):新增两个测试文件,按 #3438 立下的规矩拆开:
presence-avatars-i18n.test.tsx—— 挂I18nProvider的会话语言用例;presence-avatars-no-provider-fallback.test.tsx—— 无 provider 的英文兜底,整个文件不 importI18nProvider(createI18n会把实例注册成 react-i18next 的模块级默认实例,同文件内挂过一次就再也回不到「无 provider」)。另外补了一条 #3438 声明过、但没人守的不变量:
COLLAB_DEFAULT_TRANSLATIONS的collaboration.*子集与en.collaboration逐键逐值相等。本次正是往这两处各加同样 8 个键的形状 —— 只加一边在运行时完全隐形(有 provider 时语言包赢,无 provider 时 map 赢,两条路各看各的都正常)。type-check(先 build 依赖)与 lint 均通过,
scripts/check-control-bytes.mjs已跑。Generated by Claude Code