由 #3530 的守卫(scripts/check-i18n-call-site-keys.mjs)在 main@a2c8f2a29 上首次全量扫描量出。本单是存量缺 key 的账,守卫本身以 baseline 落地(不修包,越界),这里立单跟踪修复。
量出来的数
扫描面:packages/** + apps/** 的非测试 .ts/.tsx(1456 个文件),共 3485 个 t()/tt() 调用点,其中 2370 个是包驱动的(绑定来自 use*Translation/use*Translate/use*T 钩子;另有 1074 个走 packages/app-shell/src/views/metadata-admin/i18n.ts 这张模块内标签表,不在本单范围)。
| 项 |
数 |
| 包驱动调用点的字面量 key |
2319 |
能在 en 解析 |
2043 |
| 解析不到(缺 key) |
276 处 / 258 个不重复 key |
模板 key 静态前缀在 en 一条都不匹配(整族缺失) |
5 处 / 4 个前缀 |
| 动态拼 key(仅计数,不判定) |
62 |
all-locales-key-parity.test.ts 对这 258 个 key 全绿 —— 十个包一致地都没有,包际一致性成立。这正是 #3530 记录的门禁盲区。
按命名空间(不重复 key 数)
organization 90、console 43、auth 26、marketplace 19、preview 18、oauth 16、acceptInvitation 12、perm 9、detail 5、home 5、common 4、empty 3、layout 3,以及 dashboard/gantt/kanban/wizard/workspace 各 1。
按包(调用点数):packages/app-shell 204、apps/console 54、packages/plugin-detail 14,plugin-dashboard/plugin-form/plugin-gantt/plugin-kanban 各 1。
建议的拆单轴 = 命名空间:organization(90)、console(43)、auth + oauth + acceptInvitation(54)、marketplace(19)、preview(18)是五坨可以并行、互不冲突地补进 en.ts 的工作;剩下的零散 key 一单收尾。补进 en.ts 之后 all-locales-key-parity.test.ts 会立刻要求另外九包补齐 —— 那是正确的顺序,不是额外负担。
严重度不均:8 处没有内联 defaultValue,用户直接看到 raw key
其余 268 处都写了 t(key, { defaultValue: '英文' }),英文照常渲染、只是十种语言都翻不了(#3517 那一类,静默数月)。下面这 8 处连兜底都没有:
packages/app-shell/src/views/ObjectView.tsx:854:25 console.objectView.cannotEditMetaView
packages/app-shell/src/views/ObjectView.tsx:872:25 console.objectView.cannotDeleteMetaView
packages/app-shell/src/views/ObjectView.tsx:906:25 console.objectView.cannotEditMetaView
packages/app-shell/src/views/ObjectView.tsx:923:17 console.objectView.cannotEditMetaView
packages/app-shell/src/views/ObjectView.tsx:976:17 console.objectView.cannotEditMetaView
packages/plugin-detail/src/RecordActivityTimeline.tsx:486:30 detail.viewSource
packages/plugin-form/src/WizardForm.tsx:403:11 wizard.missingRequired
packages/plugin-gantt/src/GanttView.tsx:3269:27 gantt.toolbar.refresh
两个已核实的现场:
ObjectView.tsx:854 写的是 toast.error(t('console.objectView.cannotEditMetaView') || 'Built-in views cannot be renamed.')。i18next 缺 key 时返回 key 本身(真值),|| 兜底永远不触发 —— toast 上显示的就是 console.objectView.cannotEditMetaView 这行字。
GanttView.tsx:3269 是 aria-label={t('gantt.toolbar.refresh')}。该 key 在 packages/plugin-gantt/src/useGanttTranslation.ts:39 的 defaults map 里有,但 defaults map 只在没有 provider 时生效;console 里 provider 是挂着的,于是 useGanttTranslation 交出 i18next 的 t,刷新按钮的无障碍名就是 gantt.toolbar.refresh。屏幕阅读器用户听到的是这个。
useSafeTranslation/createSafeTranslation 这一族的 defaults map 都有同样的语义陷阱:map 里有、包里没有的 key,恰恰在真实 console 里退化成 raw key,而在无 provider 的单测里是绿的。
4 个整族缺失的模板 key
en 里没有任何 key 以这些前缀开头,所以插值取什么值都是缺的:
packages/app-shell/src/console/ai/ConversationsSidebar.tsx:277:20 console.ai.group.
packages/app-shell/src/console/marketplace/PluginDisclosure.tsx:70:14 marketplace.disclosure.runtime.
packages/app-shell/src/console/organizations/manage/InvitationsPage.tsx:161 organization.invitations.status.
packages/app-shell/src/console/organizations/manage/InvitationsPage.tsx:206 organization.invitations.status.
packages/plugin-gantt/src/GanttView.tsx:4577:60 gantt.linkEnd.
修复方式与验收
对每个 key:补进 packages/i18n/src/locales/en.ts,再从 scripts/i18n-call-site-key-baseline.json 删掉对应条目(该文件是棘轮:条目已修好却还留着,守卫同样会红)。补完 en 后 all-locales-key-parity.test.ts 会要求另外九包补齐。⛔ 不要用加 defaultValue 的方式"修" —— 那正是让这 258 个 key 藏了几个月的机制。
全部清零后,scripts/i18n-call-site-key-baseline.json 应当只剩空的 missingKeys/missingPrefixes。
关联:#3530(门禁本体)、#3517 / PR #3526(单个实例与修复)、#3469 / PR #3516(发现路径)。
由 #3530 的守卫(
scripts/check-i18n-call-site-keys.mjs)在main@a2c8f2a29上首次全量扫描量出。本单是存量缺 key 的账,守卫本身以 baseline 落地(不修包,越界),这里立单跟踪修复。量出来的数
扫描面:
packages/**+apps/**的非测试.ts/.tsx(1456 个文件),共 3485 个t()/tt()调用点,其中 2370 个是包驱动的(绑定来自use*Translation/use*Translate/use*T钩子;另有 1074 个走packages/app-shell/src/views/metadata-admin/i18n.ts这张模块内标签表,不在本单范围)。en解析en一条都不匹配(整族缺失)all-locales-key-parity.test.ts对这 258 个 key 全绿 —— 十个包一致地都没有,包际一致性成立。这正是 #3530 记录的门禁盲区。按命名空间(不重复 key 数)
organization90、console43、auth26、marketplace19、preview18、oauth16、acceptInvitation12、perm9、detail5、home5、common4、empty3、layout3,以及dashboard/gantt/kanban/wizard/workspace各 1。按包(调用点数):
packages/app-shell204、apps/console54、packages/plugin-detail14,plugin-dashboard/plugin-form/plugin-gantt/plugin-kanban各 1。建议的拆单轴 = 命名空间:
organization(90)、console(43)、auth+oauth+acceptInvitation(54)、marketplace(19)、preview(18)是五坨可以并行、互不冲突地补进en.ts的工作;剩下的零散 key 一单收尾。补进en.ts之后all-locales-key-parity.test.ts会立刻要求另外九包补齐 —— 那是正确的顺序,不是额外负担。严重度不均:8 处没有内联 defaultValue,用户直接看到 raw key
其余 268 处都写了
t(key, { defaultValue: '英文' }),英文照常渲染、只是十种语言都翻不了(#3517 那一类,静默数月)。下面这 8 处连兜底都没有:两个已核实的现场:
ObjectView.tsx:854写的是toast.error(t('console.objectView.cannotEditMetaView') || 'Built-in views cannot be renamed.')。i18next 缺 key 时返回 key 本身(真值),||兜底永远不触发 —— toast 上显示的就是console.objectView.cannotEditMetaView这行字。GanttView.tsx:3269是aria-label={t('gantt.toolbar.refresh')}。该 key 在packages/plugin-gantt/src/useGanttTranslation.ts:39的 defaults map 里有,但 defaults map 只在没有 provider 时生效;console 里 provider 是挂着的,于是useGanttTranslation交出 i18next 的t,刷新按钮的无障碍名就是gantt.toolbar.refresh。屏幕阅读器用户听到的是这个。useSafeTranslation/createSafeTranslation这一族的 defaults map 都有同样的语义陷阱:map 里有、包里没有的 key,恰恰在真实 console 里退化成 raw key,而在无 provider 的单测里是绿的。4 个整族缺失的模板 key
en里没有任何 key 以这些前缀开头,所以插值取什么值都是缺的:修复方式与验收
对每个 key:补进
packages/i18n/src/locales/en.ts,再从scripts/i18n-call-site-key-baseline.json删掉对应条目(该文件是棘轮:条目已修好却还留着,守卫同样会红)。补完en后all-locales-key-parity.test.ts会要求另外九包补齐。⛔ 不要用加defaultValue的方式"修" —— 那正是让这 258 个 key 藏了几个月的机制。全部清零后,
scripts/i18n-call-site-key-baseline.json应当只剩空的missingKeys/missingPrefixes。关联:#3530(门禁本体)、#3517 / PR #3526(单个实例与修复)、#3469 / PR #3516(发现路径)。