fix(i18n): es 的 preview.draftBar 统一 usted,横幅不再在发布后换人称 (#3844) - #3874
Merged
Conversation
`DraftPreviewBar` 在同一条横幅的同一行渲染两句互斥文案:有待发布变更时是 `message`,没有时是 `messageClean`。es 包里这两句的第二人称不一致 —— `message` 是 tú(`estás viendo`、`publiques`),而 `messageClean`(`ve`)与 `sampleDataBody`(`Está`、`su`、`Publíquela`)是 usted。后果:西语用户按下 「发布」之后,横幅当场从 tú 切到 usted —— 同一个组件、同一个位置、同一次会话。 这是 #3582 / #3625 之后值域盲区的第三类,三道 i18n 门禁都看不见:两条 es 译文 都正确表达了各自的 en 原意,不缺 key、不陈旧、也没有存英文;不一致是**同一 语言包内部、同一 UI 表面上的语域分裂**。`check-i18n-call-site-keys.mjs` 只问 key 在 en 存不存在;`all-locales-key-parity` 只比键名集合与占位符形状,从不读 值;`check-i18n-en-drift.mjs` 只在 en 值变化时要求九包跟改,而这两条 en 值静止 不动。 改 `message` 而不是改另外两条,依据是包里它周围本来就说 usted:es 全包普查 usted 102 : tú 30(tú 是有标记的例外,集中在 #3546 切片二明确裁定为非正式的 auth、report editor、organizations 几个邻域);同一个对象里另外三条本来就是 usted;#3546 切片五给新增的 19 个 `preview.unpublishedBar.*` / `preview.history.*` 定 usted,依据是结构孪生 `home.pendingDrafts.published` (「¡Publicado! Sus cambios están activos.」)。同一句内另外两处小分歧一并收口, 使横幅两半不再连措辞也互相矛盾: - `messageClean` 的分隔符 `:` 还原为 `—`,与 en 对齐(en 两句都以 `Draft preview — ` 起头)。这就是 `messageClean` 全部的 diff。 - 「live」用包里的 `activo` 而不是 `en producción`。这个概念在包里四处邻近位置 都写 `activo`,含同一对象内的 `publishCta`(「Publicar para verlo activo」); 而 producción 在包里留给真正的生产环境 (`environment.entitlement.planLockedBody`),所以原值不只是不一致,还有歧义。 - 共同的开头统一为 `Vista previa del borrador`,`del` 是 `messageClean` 本来 就在用的形式。 未动任何 en 值(en-drift 门禁报 0 处变化),未增删任何 key(`all-locales-key-parity` 按构造不受影响),其余九个语言包一律不碰。diff 是一个文件里的两个值。 把整个 `preview` 命名空间改成 tú 的方向经权衡后否决:改动面大得多,且会与紧邻的 `marketplace.*`(9:0 usted)与 `console.ai.*` 冲突。因此 `preview.empty.notReadyDescription` 刻意保持 tú —— 它是另一个表面(空态,不是这条 横幅),不存在会话中途在用户眼前切换的问题,#3844 正文已记录在案。「同一命名空间 一个语域」的门禁刻意**不做**:识别 usted / tú 需要真正的形态学(本次普查用的临时 正则就把命令式 `Revisa` 误算成 tú 标记),而这种门禁要police的邻域边界本身得人来划 —— 即 #3546 切片二「同一规则、不同答案」的先例。改为新增 `draftBar-es-register-3844.test.ts`,把四个 es 值连同两条 en 原文逐字节钉住, 这样将来任何一次 en 改写都会在改写它的那个 PR 里当场红,而不是悄悄把译文孤立掉。 Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
自查发现第一版注释照抄了 #3844 正文的一句未经复核的说法(「普查正则把命令式 `Revisa` 误算成 tú 标记」),而实测机制不是这样 —— 不该把一句没验证过的断言 固化进永久注释: - es.ts:1918 `auth.forgotPassword.successTitle`(`Revisa tu correo electrónico`) 的 `Revisa` 是**真的** tú 命令式,不是误判; - 真正的假阳性在 es.ts:1365 `console.ai.empty.build` (`…y usted revisa y publica.`)—— 那里的 `revisa` 是带显式主语 `usted` 的 陈述式,是 **usted** 串。同一个 token 在两处敬称相反,任何字符串正则都分不开。 - 反向误判同样容易:粗正则扫 `approvalsInbox` 得到 5 个「usted」全是假阳性 (`puede` 说的是第三人称的申请人 / 被指派人,`No se puede determinar` 是无人称), 而该命名空间的第二人称称呼实为一致 tú(9 条)—— 它属于切片二「按邻域裁定」的 正当情形,注释里写明以免下一个人误伤。 这组实测比原说法更有力地支持否决方向 C(敬称门禁),故写进注释。 另一处更正:`preview.empty.notReadyDescription` 原注释写「不存在会话中途在用户 眼前切换」,过弱且不准 —— `PreviewDraftEmptyState`(`AppContent.tsx`, `previewDrafts` 且应用未就绪时返回)渲染在 `DraftPreviewBar` (`ConsoleLayout.tsx`)**下方的内容区**,两者会**同屏**:横幅 usted、下面的空态 tú。这比 #3844 本身的先后切换更尖,已单独立单 #3875(未认领、未打标,交 PM 分诊), 注释与 changeset 一并改为指向它。本单仍只改 draftBar 那两个值,不越界。 es.ts 两个值一字未动(本次提交只碰注释与 changeset 文案)。 Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
Collaborator
Author
|
✅ 验收(PM,session 实物核验:头 裁定要点:
转 ready 并挂 auto-merge。 Generated by Claude Code |
yinlianghui
marked this pull request as ready for review
August 8, 2026 23:29
This was referenced Aug 8, 2026
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 #3844
现象
DraftPreviewBar在同一条横幅的同一行渲染两句互斥文案:有待发布变更时是message,没有时是messageClean(packages/app-shell/src/preview/DraftPreviewBar.tsx:104-111)。es 包里这两句的第二人称不一致:preview.draftBar.messageVista previa de borrador — estás viendo cambios sin publicar. Nada está en producción hasta que publiques.estás、publiques)preview.draftBar.messageCleanVista previa del borrador: no hay cambios sin publicar; todo lo que ve aquí ya está activo.ve)preview.draftBar.sampleDataBodyEstá viendo la estructura de su aplicación. Publíquela para cargar registros de ejemplo y activarla.后果:西语用户按下「发布」之后,横幅当场从 tú 切到 usted —— 同一个组件、同一个位置、同一次会话。
前提已在本单基线复核(base
39136cccb69cd33482fe6886e7142def87e4493c):三个值逐字节如上,分隔符分歧也在(message用—、messageClean用:,而 en 两条都是—)。为什么三道 i18n 门禁都看不见
这是 #3582 / #3625 之后值域盲区的第三类:两条 es 译文都正确表达了各自 en 原意,不缺 key、不陈旧、也没有存英文;不一致是同一语言包内部、同一 UI 表面上的语域分裂。
scripts/check-i18n-call-site-keys.mjs([finding] 没有任何守卫断言组件 t() 引用的 key 存在于 en 包 —— parity 测试只管包际一致,调用点→包的一致性是盲区 #3530):只问 key 在 en 存不存在。all-locales-key-parity.test.ts:只比键名集合与占位符形状,从不读值。scripts/check-i18n-en-drift.mjs(i18n 门禁:en 文案变更时其余九包必须同批跟改(或显式挂账)——#3582/#3625 族缺陷缺的那道不变量 #3650):只在 en 值变化时要求九包跟改;这两条 en 值静止不动。方向 A:改
message,依据是包里它周围本来就说 usted三条独立读数,都是量出来的:
preview不在其中。messageClean、sampleDataBody、publishCta)本来就是 usted。对齐这一处离群值,比给整个命名空间重新配音小得多,而且它正是消除「用户眼前切换」的那一处改动。preview.unpublishedBar.*/preview.history.*定 usted,最强依据是结构孪生home.pendingDrafts.published(¡Publicado! Sus cambios están activos.)。留着draftBar.message是 tú,会让旧横幅和刚翻好的姐妹横幅互相矛盾。改了什么(两个值,一个文件)
packages/i18n/src/locales/es.ts:messageClean的全部 diff 就是分隔符:还原为—(与 en 对齐,en 两句都以Draft preview —起头)。message除敬称形态(estás viendo→está viendo、publiques→publique)外,一并收口同一句内另外两处措辞分歧,使横幅两半不再连用词也互相矛盾:activo而不是en producción—— 这个概念在包里四处邻近位置都写activo,含同一对象内的publishCta(Publicar para verlo activo)、home.pendingDrafts.published、sampleDataBody的activarla;而 producción 在包里留给真正的生产环境(environment.entitlement.planLockedBody:un entorno de producción),所以原值不只是不一致,还有歧义。Vista previa del borrador——del是messageClean本来就在用的形式(两种形式在包里各只出现在这两个 key 上,是这条横幅自己跟自己不一致);因为messageClean只许动分隔符,统一只能落在message一侧。em dash 已核为与 en 同一码位 U+2014(四条值全部
—=U+2014)。调用点只传defaultValue、无插值参数,占位符形状不受影响。钉子
新增
packages/i18n/src/__tests__/draftBar-es-register-3844.test.ts(独立文件,名带 3844),10 个用例:四个 es 值按修后终值逐字节精确断言,加 en 两条原文的 tripwire(将来任何一次 en 改写会在改写它的那个 PR 里当场红),外加 presence 防空转、退役拼写字面量、横幅两半同开头/同 em dash、activ词干在位。注释写明语域裁定依据(102:30 普查、同横幅一致性、切片五的 19 个 key、#3844)。不做敬称形态学检测:识别 usted / tú 需要真正的形态学,而 token 级正则实测做不到 —— 同一个 token
revisa在console.ai.empty.build(es.ts:1365,…y usted revisa y publica.,带显式主语usted的陈述式)是 usted,在auth.forgotPassword.successTitle(es.ts:1918,Revisa tu correo electrónico,命令式)是 tú —— 同样八个字母、敬称相反,任何字符串正则都分不开。反向误判同样容易:粗正则扫approvalsInbox得到的 5 个「usted」全是假阳性(puede说的是第三人称的申请人 / 被指派人,No se puede determinar是无人称),而该命名空间的第二人称称呼实为一致 tú(9 条)—— 属于切片二「按邻域裁定」的正当情形,已在注释里写明以免下一个人误伤。而这种门禁要 police 的邻域边界本身得人来划(#3546 切片二「同一规则、不同答案」的先例)。退役拼写检查是从这一个 key 的修前值里摘出的精确子串(与
viewReadonlyTooltip-semantics-3625.test.ts同一手法),不推广到任何别处。反向验证(方向先判后跑,两次都与预判一致)
预判:钉子是对修后终值的正向逐字节断言,加 presence 防空转,所以两次都只能是朴素的红(不存在反转,也不存在「诊断变多」的方向)。
message为 tú 旧值 → 预判 4 红且逐条点名message。实跑正是 4 红:byte pinexpected 'Vista previa de borrador — estás vien…' to be 'Vista previa del borrador — está vien…';退役拼写es preview.draftBar.message reintroduced "estás viendo";横幅同开头检查红;es preview.draftBar.message lost the pack's word for "live"。Tests 4 failed | 6 passed (10)messageClean分隔符为:→ 预判 2 红。实跑 2 红:byte pinexpected 'Vista previa del borrador: no hay cam…' to be 'Vista previa del borrador — no hay ca…',以及横幅同开头/同 em dash(内含not.toContain('borrador:'))。Tests 2 failed | 8 passed (10)两次实验后均已还原,最终 diff 只有两个值行。
验证
node scripts/check-i18n-en-drift.mjs→0 en value(s) changed (0 key(s) added, 0 removed),No en value changed in this range.(本单不碰 en)packages/i18n全包 +packages/app-shell/src/preview(横幅自己的消费者测试)→ 35 文件 / 554 用例全绿(更正提交后复跑同样 35/554 绿);新钉子单跑 10/10 绿;all-locales-key-parity、marketplace-preview-namespace-3546、objectView-value-language-3582、viewReadonlyTooltip-semantics-3625一并绿(只改值不改键,parity 按构造不受影响)。turbo run type-check --concurrency=2→ 78/78 successful(两次编辑后各跑一次)。刻意不做
preview改成 tú):改动面大得多,且会与紧邻的marketplace.*(9:0 usted)与console.ai.*冲突。preview.empty.notReadyDescription(es.ts:3286,Revisa)保持 tú,但已单独立单 es 的 preview.empty.notReadyDescription 用 tú,与同屏的 preview.draftBar(usted)混用 —— 草稿预览未就绪时一屏两种敬称 #3875 —— es 语言包的 preview.draftBar 同一条横幅两种敬称 —— messageClean 用 usted、message 用 tú,西语用户按「有无待发布变更」看到不同人称 #3844 的裁定只覆盖这条横幅,所以本单不动它;但它不是无害的:PreviewDraftEmptyState(AppContent.tsx,previewDrafts且应用未就绪时返回)渲染在DraftPreviewBar(ConsoleLayout.tsx)下方的内容区,两者会同屏 —— 横幅 usted、下面的空态 tú,比 es 语言包的 preview.draftBar 同一条横幅两种敬称 —— messageClean 用 usted、message 用 tú,西语用户按「有无待发布变更」看到不同人称 #3844 本身的先后切换更尖。本单落地后preview命名空间为 23 usted : 1 tú。(第一版正文曾写「不存在会话中途切换」,过弱且不准,已更正。)协调
origin/main上仍是修前值(推送前复核)。*-namespace-3546.test.tsx家族 ——marketplace-preview-namespace-3546.test.tsx只在注释里提到这两个 key(第 434-436 行「genuinely split before this slice — filed as a finding」,作为历史陈述在本单落地后依然成立),其断言只覆盖unpublishedBar.*/marketplace.*/home.pendingDrafts.published/ zh 的draftBar.sampleDataBody,与本单零相交,实跑亦绿。packages/core)零相交 —— 推送后 main 前进了这一个提交,git diff --name-only与本单三个文件无交集。