Skip to content

fix(metadata-admin): 页面块检查器 curated 属性 label 跟随会话语言 (#3913) - #3970

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-3913-block-inspector-i18n
Aug 9, 2026
Merged

fix(metadata-admin): 页面块检查器 curated 属性 label 跟随会话语言 (#3913)#3970
yinlianghui merged 1 commit into
mainfrom
claude/issue-3913-block-inspector-i18n

Conversation

@yinlianghui

@yinlianghui yinlianghui commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Fixes #3913

症状与机制

PageBlockInspector 的外围 chrome 从一开始就走翻译表(t('engine.inspector.pageBlock.properties') 等),但面板的内容 —— previews/block-config.ts 里每个块类型的 curated 字段 label —— 是英文字面量,renderField 原样交给字段组件。于是 zh-CN 管理员打开任意页面块,看到的是「属性」标题下面一摞英文字段名:同一面板两种语言,任意块、无需特殊数据即可复现。

改法:label 存翻译键,渲染处过 t()

157 个字面量(152 个字段/选项 label + 5 个 addLabel)全部改为翻译键,t(key, locale) 在渲染处解析;154 个去重后的键同时补进 views/metadata-admin/i18n.ts 的 en-US 与 zh-CN 两侧(该表只有这两种语言)。t() 未命中时原样返回键,所以漏译在每种语言里都是显眼的键串,而不是在一种语言里静默显示英文。

键形状由 label 在 BLOCK_CONFIG 里的位置决定,这一点是承重的而非命名偏好:

位置
字段 label engine.inspector.pageBlock.field.{blockType}.{name}
嵌套 item label engine.inspector.pageBlock.field.{blockType}.{array}.{name}
array 添加按钮 engine.inspector.pageBlock.add.{blockType}.{name}
select/color 选项 engine.inspector.pageBlock.option.{fieldName}.{value}

选项键故意不带块类型,所以 format 的 number/currency/percent 在 object-metricelement:number 之间共享一份翻译(154 = 157 去掉 3 个这样的重复);字段键故意带块类型,因为同一个英文词在不同块里需要不同中文 —— element:button.label 是按钮文案「按钮文字」,page:tabs.items.label 是标签页标题「标签」;Add section 在这里是「添加分区」,而表单布局画布的 designer.canvas.addSection 仍是「添加分组」。一键一义,这些区分才表达得出来。

en 逐字节未变(已实测,非抽样)

en-US 是本仓基准语言。把全部 157 个键按 en 值反向代回,与改动前的文件做字节比对,数据区完全一致:

substituted 157 key literals back to their en values
data region byte-identical to pre-change: true

addLabel 由可选改为必填

addLabel 原是可选的,array 分支在缺失时渲染裸英文 'Add' —— 一个任何翻译表都碰不到的字面量。这里删掉这个兜底而不是翻译它:类型改成必填,新增 array 字段不写 add 按钮键就编译不过。这条比加一个 ?? 'Add' 的默认键更符合契约优先 —— 宽容的消费端正是漏译藏身之处。

钉子

previews/__tests__/block-config-i18n.test.ts(结构)+ inspectors/PageBlockInspector.i18n.test.tsx(渲染),两者钉的是不同的事实:一个是表数据,一个是屏幕。renderField 有 11 处读 f.label(8 处作 label= 属性、3 处作 Label 元素的子节点),外加两处选项列表,每一处都是一次「忘记过 t()」的机会 —— 键全对的表照样能在屏幕上渲染出裸键。

结构钉的关键一条不是「键在不在」,而是键等于位置推导出的那个键:这些键之间只差一个 segment,新增块时现实的失误不是拼错,而是从邻块复制粘贴 —— 那样的键在两种语言里都存在、渲染出一个看起来合理但属于另一个属性的 label,只查存在性的断言对此全绿。所以测试从 BLOCK_CONFIG 的结构重新推导四种键形并与表里存的比对。

渲染钉覆盖 zh-CN/en-US 同块对照、嵌套 item label、select 选项、以及 ColorVariantPicker 只以 aria-label/title 渲染的色板选项(文本查询看不见,恰是漏译藏身处)。

反向验证(方向先预判,再跑;两条逐条吻合。完整输出见本 PR 首条评论)

两个变异的预判方向在写代码时就已记录,变异不提交,跑完均已回退:

  • 删 1 个 zh 键(field.record:alert.dismissible)—— 预判:zh 完整性断言精确翻红并指名该键;「zh 不等于 en」断言保持绿(t() 兜底返回键本身,与英文值不同);渲染钉在中文文本与裸键守卫两处翻红。
  • 把某个 label 指向邻块一个已存在的键(record:alert.title 指向 page:card.title)—— 预判:两条完整性断言都保持绿(该键在两语里确实存在),只有推导断言翻红。这一条是本 PR 里推导断言存在的全部理由:它是「只查键在不在」结构上看不见的那类失误。

实测结果与两条预判逐条吻合:

  • A 只翻红 2 条(× every key resolves in zh-CN 精确指名 field.record:alert.dismissible,渲染钉找不到「可关闭」),Tests 2 failed | 15 passed。「zh 不等于 en」未翻红 —— 正如预判,t() 兜底返回键本身、与英文值不同,那条断言无从触发;这也说明完整性必须单独断一条,不能靠它间接覆盖。
  • B 只翻红 1 条(× stores exactly the key its position implies,消息里同时给出存的键与位置应得的键),Tests 1 failed | 16 passed两条完整性断言全绿,渲染钉也全绿 —— 两个键的英文都是 Title、中文都是「标题」,屏幕上看不出异常。即:只断言「键在两语里都存在」时,这个把 label 指到别的属性上的失误会完全静默。推导断言的存在理由由此是实测,而非论证。

边界

校验记录(全部已实测)

  • pnpm exec vitest run packages/app-shell/src/views/metadata-admin(仓根,--maxWorkers=2,持共享 verify 锁,NODE_OPTIONS=--max-old-space-size=4096)—— 首轮 1350 passed / 1 failed,那一条即上述写过头的断言,已改正。
  • 改正后受影响的 4 个文件重跑:Test Files 4 passed (4) / Tests 41 passed (41)(含 PageBlockInspector.sectionName.test.tsx 在 en-US 下对 Add section 的现成断言,未改一行仍绿 —— 这本身就是 en 未漂移的一个钉)。
  • 仓根 pnpm exec turbo run type-check --concurrency=2:78 successful, 78 total
  • pnpm check:i18n-keys exit=0(2316/2316 literal keys resolve;本表计入 1076 module-local table,按设计跳过),pnpm check:i18n-drift exit=0(0 en value(s) changed),两个 baseline 文件均未改动。
  • en 逐字节回代(上文);154 键在两张表里无重复键;en/zh 两表原有的 44 键差值未变 —— 即两侧各正好新增 154 条。
  • node scripts/check-control-bytes.mjs OK,另对 7 个改动文件做了 grep -naP 控制字节自扫(gate 有已知盲区),干净。

关于两张 i18n 门:pnpm check:i18n-keysmetadata-admin/i18n.ts 明确列在 EXCLUDED_TRANSLATORS(模块内私有 label 表,按设计不进 locale pack,forwardedScope 覆盖整棵 metadata-admin 子树),pnpm check:i18n-drift 只读 packages/i18n/src/locales/*.ts —— 两张门都不覆盖这张表,所以它们的绿是「未被本改动破坏」,不是「本表已被门保护」;表内的完整性由上面那两个钉负责。

复用 spec 侧翻译面的取舍(PM 要求论证)

查过复用路径,结论是维持包内新增键。packages/i18n/src/locales/en.ts 里确有字面重合的条目(groupByField: 'Group by field'striped: 'Striped rows'),但它们在 console.* 命名空间下、属于视图设计器那个面,与页面块检查器只是词面撞车;复用会让这里的 label 随另一个面板的措辞改动而变,且只覆盖 154 个键里的少数几个,剩下的仍要新建 —— 反而做出一张 split-brain 的表。跨进 i18next pack 还会把 metadata-admin 子树的一部分拖进 check-i18n-call-site-keys 的面(而 EXCLUDED_TRANSLATORS 声明整棵子树是本地表),并要求给设计器内部文案凑齐 10 种语言。

浏览器验证为何跳过

locale prop 在真实 zh-CN 会话里确实到位这件事,由本 issue 的症状本身证明 —— 报告说 chrome 的「属性」是中文而内容是英文,两者读的是同一个 locale 变量,所以管线无需浏览器再确认,变的只有内容。渲染钉用真实组件跑了 7 个块类型,含浏览器截图也看不见的 aria-label 色板选项。

…ocale (#3913)

The inspector's chrome went through `t('engine.inspector.pageBlock.*')` from the
start while the panel's CONTENTS did not: every `label` in
`previews/block-config.ts` was an English literal handed straight to the field
components. A zh-CN admin opening any page block read 「属性」 over a stack of
English field names.

All 157 label literals (152 field/option labels + 5 addLabel) are now
translation keys resolved through `t(key, locale)` at render, with 154 distinct
keys added to both the en-US and zh-CN sides of `metadata-admin/i18n.ts`. The
English text is unchanged: substituting every key back to its en value
reproduces the pre-change data region byte-for-byte.

Key shape is derived from the label's POSITION in BLOCK_CONFIG
(`.field.<blockType>.<name>`, `.add.<blockType>.<name>`,
`.option.<fieldName>.<value>`) and a test re-derives it, because these keys
differ by one segment: copy-pasting a neighbouring block's key yields one that
EXISTS in both locales and renders a plausible label for the wrong property, so
an existence-only check is green for it. Positional keys also let one English
word take different Chinese per block (`element:button.label` is 「按钮文字」,
`page:tabs.items.label` is 「标签」).

`addLabel` becomes REQUIRED on the array variant: it was optional and the
inspector fell back to a bare English 'Add' that no locale table could reach.
Requiring it deletes the fallback rather than translating it.

Option labels are translated too, including the ones ColorVariantPicker renders
only as aria-label/title.
@vercel

vercel Bot commented Aug 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectui Ignored Ignored Aug 9, 2026 6:29pm

Request Review

@github-actions github-actions Bot added the tests label Aug 9, 2026
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Main entry (gzip) 28.1 KB 350 KB
Entry file index-DkXXb0uV.js
Status PASS

📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 8.66KB 3.13KB
app-shell (runtime-config.js) 7.42KB 2.32KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 7.57KB 2.97KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 1.17KB 0.53KB
auth (AuthProvider.js) 22.10KB 4.37KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.13KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.64KB 2.21KB
auth (SocialSignInButtons.js) 9.60KB 3.89KB
auth (UserMenu.js) 3.40KB 1.22KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 35.76KB 9.11KB
auth (createAuthenticatedFetch.js) 4.37KB 1.69KB
auth (index.js) 2.35KB 1.07KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 4.91KB 0.87KB
auth (useIsWorkspaceAdmin.js) 1.61KB 0.85KB
collaboration (CommentThread.js) 26.07KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.65KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 482.58KB 106.41KB
core (index.js) 3.00KB 1.14KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 139.61KB 35.99KB
fields (index.js) 227.45KB 56.31KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.32KB 1.77KB
i18n (index.js) 2.65KB 1.06KB
i18n (pickLocalized.js) 1.70KB 0.83KB
i18n (provider.js) 9.48KB 3.27KB
i18n (useObjectLabel.js) 27.59KB 6.63KB
i18n (useSafeTranslation.js) 4.52KB 1.96KB
layout (index.js) 38.53KB 10.71KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.74KB
mobile (index.js) 1.50KB 0.62KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.71KB 0.42KB
mobile (useResponsiveConfig.js) 1.36KB 0.63KB
mobile (useSpecGesture.js) 4.32KB 1.64KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 8.75KB 3.06KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 3.67KB 1.12KB
permissions (evaluator.js) 4.41KB 1.44KB
permissions (index.js) 0.91KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.52KB
permissions (usePermissions.js) 1.55KB 0.71KB
plugin-ai (index.js) 15.71KB 3.79KB
plugin-calendar (index.js) 44.98KB 12.37KB
plugin-charts (index.js) 61.17KB 17.35KB
plugin-chatbot (index.js) 180.33KB 42.79KB
plugin-dashboard (index.js) 118.02KB 30.47KB
plugin-designer (index.js) 210.51KB 42.51KB
plugin-detail (index.js) 236.63KB 59.02KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 112.10KB 27.10KB
plugin-gantt (index.js) 162.55KB 39.57KB
plugin-grid (index.js) 187.63KB 49.66KB
plugin-kanban (index.js) 48.30KB 13.28KB
plugin-list (index.js) 109.73KB 26.55KB
plugin-map (index.js) 16.81KB 5.24KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 40.58KB 10.58KB
plugin-timeline (index.js) 25.76KB 7.33KB
plugin-tree (index.js) 8.50KB 2.88KB
plugin-view (index.js) 84.03KB 20.55KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.71KB 3.53KB
providers (index.js) 0.44KB 0.22KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.67KB 2.37KB
react (LazyPluginLoader.js) 3.77KB 1.33KB
react (SchemaRenderer.js) 22.31KB 7.59KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.02KB 0.55KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 4.09KB 1.74KB
sdui-parser (index.js) 4.47KB 2.03KB
sdui-parser (parse.js) 10.04KB 2.82KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 4.69KB 1.48KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 0.99KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (data-display.js) 0.20KB 0.18KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.87KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-retry.js) 4.32KB 2.02KB
types (index.js) 2.71KB 1.34KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 2.59KB 1.31KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (spec-report.js) 5.05KB 1.93KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 0.20KB 0.18KB
types (ui-action.js) 3.40KB 1.71KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

Copy link
Copy Markdown
Collaborator Author

补:等到共享锁了,上面标为「尚未实测」的四项全部跑出,两个反向验证与预判逐条吻合

开 PR 时这些还卡在共享 verify 锁上(容器内 4 个以上并行 agent 排队)。现已全部取得实测输出。

1. 改正后的四个受影响文件

Test Files  4 passed (4)
     Tests  41 passed (41)
  Duration  12.29s

跑的是新增两个钉 + 两个既有受影响文件(block-config.test.ts 的 fixture 改判、PageBlockInspector.sectionName.test.tsxgetByText('Add section') —— 后者在 en-US 下断言 addLabel 文案,是 en 未漂移的现成钉,未改一行仍绿)。

2. type-check(仓根)

Tasks:    78 successful, 78 total
Cached:    73 cached, 78 total
Time:     1m10.897s

3. 两张 i18n 门 + 控制字节

Scanned 1468 files, 3485 t()/tt() call sites: 2368 pack-backed (2316/2316 literal keys resolve),
  63 dynamic-key (report-only), 2 probe-flagged, 1076 module-local table, ...
Every in-scope call-site key resolves against the en pack (2918 keys).
  i18n-keys exit=0

Compared the ten locale packs at 69becd2d1 (merge-base with origin/main) with the working tree:
  0 en value(s) changed (0 key(s) added, 0 removed), 0 pack value(s) followed, ...
No en value changed in this range.
  i18n-drift exit=0

check-control-bytes: OK (scanned 3855 tracked text file(s); skipped 85 binary).
baseline files changed? (empty = no):

两个 baseline 文件确认未被改动。注意 1076 module-local table 那一项就是本表 —— 门按设计跳过它,本 PR 新增的 t() 调用点也落在这个跳过集合里,所以门的计数只增在 module-local,pack-backed 一项不变。

4. 反向验证 A —— 删 1 个 zh 键

预判:zh 完整性断言精确翻红并指名该键;「zh 不等于 en」断言保持绿;渲染钉翻红。

× every key resolves in zh-CN 15ms
FAIL ... > block-config labels are translation keys (#3913) > every key resolves in zh-CN
+   "engine.inspector.pageBlock.field.record:alert.dismissible",

TestingLibraryElementError: Unable to find an element with the text: 可关闭
    146|     expect(screen.getByText('可关闭')).toBeTruthy();

Test Files  2 failed (2)
     Tests  2 failed | 15 passed (17)

逐条吻合。只有 2 条红,「zh 不等于 en」不在其中 —— 正如预判:t() 兜底返回键本身,与英文值不同,所以那条断言无从触发。这也是为什么完整性要单独断一条,而不能靠「zh 与 en 不同」间接覆盖。

5. 反向验证 B —— 把 label 指向邻块一个已存在的键

预判:两条完整性断言都保持绿(键确实存在),只有推导断言翻红

× stores exactly the key its position implies 10ms
FAIL ... > block-config labels are translation keys (#3913) > stores exactly the key its position implies
+   "record:alert.title (label): stored 'engine.inspector.pageBlock.field.page:card.title'
      but position implies 'engine.inspector.pageBlock.field.record:alert.title'",

Test Files  1 failed | 1 passed (2)
     Tests  1 failed | 16 passed (17)

逐条吻合,而且这一条是本 PR 里最值钱的一次测量:红的只有 1 条,两条完整性断言全绿,渲染钉也全绿(两个键的英文都是 Title、中文都是「标题」,屏幕上看不出任何异常)。即:如果只断言「键在两语里都存在」,这个把 label 指到别的属性上去的失误会完全静默。推导断言的存在理由,由此是实测而非论证。

两个变异均已回退,git diff --numstat 为空,工作树干净(git status --short 无输出)。


Generated by Claude Code

Copy link
Copy Markdown
Collaborator Author

PM 验收(session_01GTRjn8xBqp75dk7kFupVRt):通过,转 ready 并挂 auto-merge。#3913 落地。

核验记录(head 36404e7a5,基 69becd2d1,实物核验 + CI 亲读):

  1. 键形状按 PM 定向落地且论证升级:包内新增键、engine.inspector.pageBlock.* 命名空间(实物 grep:block-config 161 处键引用、i18n.ts 328 处)。位置式 vs 语义去重的取舍被反向验证 B 从论证变成实测 —— 邻块键复用错误在「只查存在性」下完全静默(1 failed | 16 passed,完整性与渲染钉全绿),推导断言是唯一检测器;这是本单最值钱的一次测量。spec 侧复用被否的理由(词面撞车、split-brain、EXCLUDED_TRANSLATORS 边界)核验成立,维持定向正确。
  2. 诚实修正三处派发词锚点(163 行计数 vs 157 字面量/154 键、8 站点 vs 14 接入点、2 addLabel vs 5)—— 全部以 worktree 实测为准并披露。
  3. en 零漂移的证明方式得当:157 键逐字节回代(data region byte-identical: true)+ 23 键抽样钉 + 既有 sectionName 断言未改仍绿 —— 拒绝把 154 条 en 值复制进测试(那份复制自身会走旧)的判断正确。
  4. 契约收紧一处(addLabel 可选→必填,删裸 'Add' 兜底):消费端宽容兜底正是漏译藏身处,按契约优先处置,changeset/类型注释齐备 —— 接受。
  5. 钉子与边界:zh/en 对照渲染钉(含 aria-label 色板选项)、expectNoRawKeys 守裸键、与 PageBlockInspector 自身的 chrome 字面量未过 t() —— 列表「Add」按钮、Remove aria-label、Invalid JSON、两个 placeholder 在 zh-CN 下仍是英文 #3963 的边界钉(其落地时精确翻红防静默重叠);反向验证 A/B 均先预判后跑、逐条吻合、变异清零。
  6. 门与规程:metadata-admin 全量 1350 绿(首轮)+ 改正后 4 文件 41 绿(改正内容为删自写过头断言,风险披露成立,CI 全量补证);i18n 双门绿;type-check 78/78;控制字节门 + 盲区自查 + PR 正文 sanitizer 检查;changeset patch;提交文案控制词 0;⛔ releases/ 未触碰;flock 排队仅按自记 PID 终止自己的作业 —— 合规。
  7. CI 亲读终态:20/20 全 completed、0 失败(Test shard×4 至 18:35:10Z、Type Check 18:34:48Z)。

154 条 zh 译文为非母语审校(dev 已披露)—— 维护者若调词只动 i18n.ts 单点。out-of-scope #3963 由 PM 分诊(另评)。


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

页面块检查器的 PROPERTIES 面在 zh-CN 会话下是英文的 —— curated 字段 label 走字面量、只有外围章节标题走 t()

2 participants