Skip to content

fix(i18n): 回填 perm + home 两命名空间 14 个缺失语言 key,十包补齐(#3546 切片六) - #3868

Merged
yinlianghui merged 2 commits into
mainfrom
claude/issue-3546-slice6-perm-home
Aug 8, 2026
Merged

fix(i18n): 回填 perm + home 两命名空间 14 个缺失语言 key,十包补齐(#3546 切片六)#3868
yinlianghui merged 2 commits into
mainfrom
claude/issue-3546-slice6-perm-home

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes-part-of: #3546 — 切片六。本单不关闭 #3546:回填后仍余 17 个缺失 key + 2 个整族缺失前缀。

分支自 origin/main@993336f7c 显式 sha 切出(main 其后前进五个提交,含 #3849;与本围栏零文件相交,已实测,见文末)。

分母:脚本实测,不手数

node scripts/check-i18n-call-site-keys.mjs(#3530 的守卫)的 analyze() 实测:

实测
不重复缺失 key 14(perm 9 + home 5)
对应调用点 14 —— 1:1,多站点 key 数 0
属本切片的 missing-prefix 0(棘轮里两条都不属这两个命名空间)
棘轮内本切片条目 14,与实测清单双向精确相等,无差集
en 新增 key 路径 18(14 实测 + 4 个复数族的 _one 伴生)
--- multi-site keys ---
(empty)
--- ratchet vs measured ---
ratchet slice keys: 14   measured: 14
in ratchet not measured: []
measured not in ratchet: []
--- ALL missing-prefix findings (repo-wide) ---
[ "…/InvitationsPage.tsx:161 organization.invitations.status.",
  "…/InvitationsPage.tsx:206 organization.invitations.status.",
  "…/GanttView.tsx:4577 gantt.linkEnd." ]        ← 一条也不属 perm/home

守卫读数,前后对照(同一命令):

前: 2372 pack-backed (2283/2320 literal keys resolve) … en pack (2876 keys)
后: 2372 pack-backed (2297/2320 literal keys resolve) … en pack (2894 keys)
Every in-scope call-site key resolves against the en pack (2894 keys).   GUARD EXIT=0

解析数 +14(= 14 个调用点)、en key 数 +18(14 + 4 个 _one),与清单精确相等。棘轮 ASSERT:

before: 31 after: 17 removed: 14
ASSERT removed===14 -> true
ASSERT entry lines deleted===14 -> true
ASSERT no perm.*/home.* key left -> true
ASSERT missingPrefixes unchanged at 2 -> true ["gantt.linkEnd.","organization.invitations.status."]
ASSERT file still valid JSON -> true (parsed)

remaining by namespace:
{"common":4,"dashboard":1,"detail":4,"empty":3,"kanban":1,"layout":3,"workspace":1}

棘轮按行删除而非重序列化(切片四量过:重序列化会把 diff 变成全文件重排)。最终 diff:14 deletions(-),零插入。

严重度:全部是「英文可见、十语不可译」

14 处全部带内联 defaultValue,无一渲染裸 key(那类由切片一 PR #3583 收)。两个现场:

  • 权限集记录的授权面摘要(PermissionFacetLink,ADR-0056 P1 —— Setup 只读展示 + 深链进 Studio 的结构化编辑器):空面的 None、系统能力芯片溢出的 +3 more、四个计数标签(3 objects / 2 field rules / 1 RLS policy / 4 tab rules)、Delegated admin configured,以及深链本身的 Design in Studio → 与无 app 上下文时的灰态 Design in Studio
  • 「一键发布全部草稿」的其余几条 toast(usePublishAllDrafts,Home 待发布横幅与 ADR-0037 草稿预览条共用同一条治理路径):Nothing to publish.、ADR-0038 L3 探针发现问题的 Published, but verification found problems.、示例数据未加载的 Published, but some sample data failed to load.、带计数的 Published & verified — 12 sample row(s) live.,以及 ADR-0066 ⑨ 能力引用巡检的 Authoring check: 2 capability reference(s) resolve nowhere.

en ↔ 内联 defaultValue:9/9 逐字节相同,另 5 处结构上不可能

slice call sites: 14  (literal defaultValue: 9, template: 5, none: 0)
en value === inline defaultValue: 9/9

无 defaultValue 的站点:0 处 —— 本切片不需要从组件语境取文案。

余下 5 处的 defaultValue模板串:

perm.facet.more     `+${extra} more`                                    → en "+{{count}} more"
perm.facet.objects  `${count} object${count === 1 ? '' : 's'}`           → en "{{count}} objects" / _one "{{count}} object"
perm.facet.fields   `${count} field rule${count === 1 ? '' : 's'}`       → "{{count}} field rules" / "{{count}} field rule"
perm.facet.rls      `${count} RLS polic${count === 1 ? 'y' : 'ies'}`     → "{{count}} RLS policies" / "{{count}} RLS policy"
perm.facet.tabs     `${count} tab rule${count === 1 ? '' : 's'}`         → "{{count}} tab rules" / "{{count}} tab rule"

逐字节比对对模板串结构上不可能(切片五在 marketplace.org.installed 上撞过同一面墙),但这次取到的等价关系更强:测试把模板串按 JS 的语义在 count = 1/2/3/5/11/21/100 上各渲染一遍,与包路径的输出逐个相等。也就是说英文渲染文本一字未变,只是换成 i18next 来插值和选形。模板串一移动,断言先红(expect(src).toContain(...) 钉住原文)。

check-i18n-en-drift.mjs 独立复核了同一件事:0 en value(s) changed (18 key(s) added, 0 removed)

复数族刻意带基础 key,而不是只写 _one/_other

四个计数标签需要两种英文形态,所以是 i18next 复数族。形状取 key + key_one,不是惯用的 key_one + key_other,依据是实测行为而非口味:

i18next 只向 Intl.PluralRules该语言该数字对应的那一个后缀,包里没有就沿 fallbackLng 链走到 en —— 渲染英文

十包各自只有 _one/_other 时的实测(装好的 i18next 26.3.6,与本仓 createI18n 配置一致,无 compatibilityJSON):

ru  0:EN_OTHER  1:RU_ONE  2:EN_OTHER  3:EN_OTHER  5:EN_OTHER  11:EN_OTHER  100:EN_OTHER
ar  0:EN_OTHER  1:AR_ONE  2:EN_OTHER  3:EN_OTHER  11:EN_OTHER  100:AR_OTHER
fr/es/pt  many(≥1e6) → EN

ru 的 few(2-4)与 many(5-20)、ar 的 two/few(3-10)/many(11-99) —— 恰好是用户最先遇到的计数。而给 ru 补 _few/_many 会被 all-locales-key-parity 判成"有 en 没有的 key"(该测试的不变量正是十包键名集合相同),所以那条路要先改一道共享门禁。

基础 key 是不用改门禁的那条路:i18next 的查找链里基础 key 始终在列,任何未枚举的类别都落到它,留在本语言:

ru  flat + _one → count 1 命中 _one;count 3 命中 flat("RU both-flat 3"),不再是 EN

十语 × counts 1/2/3/5/11/21/100 全量渲染断言(用 Intl.PluralRules.select() 预测该由哪个槽位作答,与 i18next 同一个解析器),外加 ru/ar 具名的五个未枚举槽位。

⚠️ 本仓唯一一个既有复数族 detail.showEmptyRelated_one/_other 没有基础 key,因此今天就有这个英文泄漏(ru 在 2-4/5-20、ar 在 2-99)。已立 #3863,含实测表与照搬本切片形状的修法;detail 命名空间的欠账属后续切片,本 PR 未动。

九包实译:逐包邻键取证

邻键证据 本切片落值举例
zh 本仓权限集设计器同一张表(metadata-admin 模块内 i18n):perm.stat.objectsSuffix = 个对象perm.rls.empty = 暂无行级策略。perm.tabs.title = 标签页可见性perm.admin.title = 委派管理范围perm.cap.none能力 —— 正是这个芯片点进去的那个界面;home.pendingDrafts.message—— {{count}} 个对象已配置委派管理范围编写检查:{{count}} 个能力引用无法解析。已发布并验证 —— {{count}} 行示例数据已生效。
ja appDesigner.objectManager.fieldCount = {{count}} フィールド 的「{{count}} + 単位」形;console.objectView.addRule = ルールを追加(rule = ルール);中間コロンは後続が単一トークンなら半角(AI 使用状況: {{status}})、日本語の文なら全角(現在の承認待ち:{{who}}。)—— 24:28 の条件式 {{count}} フィールドルール作成時チェック:…公開するものはありません。
ko fieldCount ko = {{count}}개 필드;appDesigner.objects = 오브젝트;全包 0 处全角冒号 {{count}}개 오브젝트작성 검사: …Studio에서 디자인 →
de 应用内页签是 Registerkarte(console.objectView.ufTabs,4 处),Tab 专留给浏览器页签(detail.openInNewTab,4 处);managedByBadge.systemWritable.bodydelegierte Administration {{count}} Registerkarten-RegelnDelegierte Administration konfiguriert
fr 直角撇号 U+0027(502:21)、冒号前留空格(6:0);administration déléguée {{count}} règles d'ongletContrôle de conception : …
es home.pendingDrafts.* 一致 usted;(s) 记法随同族 message(cambio(s)) {{count}} fila(s) de ejemplo activa(s).Administración delegada configurada
pt 同族 message = alteração(ões) não publicada(s) {{count}} linha(s) de exemplo ativa(s).{{count}} regras de aba
ru 「名词: {{count}}」写法全包 25 处(lookup.recordCount = Записей: {{count}}notifications.groupCountapprovalsInbox.bulkApproved …),且对任何俄语数字都正确 —— 正因如此基础 key 才能覆盖 few/many;ё 正字法(161 处) Объектов: {{count}}Политик RLS: {{count}}+{{count}} ещёПубликовать нечего.
ar 「{{count}} 单数(复数)」写法(fieldCount = {{count}} حقل(حقول)table.modified);动作链接的尾箭头保留 (marketplace.browseLink 十包 10/10),与该包 3 处把行内左右映射镜像成 的情形区分开 {{count}} كائن(كائنات)التصميم في Studio →

en 相同的字符串一律复用邻键既有译文而不另造,4 对,双向钉住(先验证两边 en 真的同字符串,再验证十包同值):perm.facet.nonelist.none;perm.facet.morecalendar.moreEvents(同为「+N more」溢出芯片,en 逐字节相同);perm.facet.designInStudioHinttopbar.designInStudio,且 designInStudio = 该值 + (十包统一按此构造);home.pendingDrafts.seedWarnconsole.ai.seedWarn(AiChatPage.tsx:2152,同一句英文)。

一处刻意不复用,也有断言:console.ai.designBuiltApp 的 en 同为 Design in Studio,但 zh/de/ru 早已按语境分开译(zh 进入 Studio 继续完善 —— agent 刚建好应用后"继续完善"),本切片这条是普通导航标签,取 topbar.designInStudio。这不是缺陷(两个 key 存在的意义就是可以分开),故未立单,只在测试里写明。

按概念找邻键(切片五教训)已按新规执行:RLS policies / field rules 这类词在 en 里逐字节搜不到邻键,是按概念找到了设计器同一张表与 fieldCount。另需说明两处确实没有仓内邻键、属新造词的:Authoring checkcapability(九包一个都没有;仅 zh 有依据 —— 设计器表的 能力 / 必需能力)。这两处的措辞在 PR 里点名,便于 review 直接推翻。

反抄袭断言:精确集合是空集,靠三条防空转顶住

实测"与 en 逐字节相同"的 lang :: key 对:0 / 162(十包 18 路径)。本切片确实没有一个合法同形词。空集是最容易空转的形状(切片二 B1 的教训),所以配三条:

  1. presence:十包 × 18 路径 = 180 个值全部是非空字符串(独立一条 it.each);
  2. 反面对照:空集也可能因为"译者绕开了所有像英文的词"而成立。这四条证明外来词确实在且仍不与 en 逐字节相同 —— de {{count}} RLS-Richtlinien、fr {{count}} politiques RLS、ja Studio でデザイン →、de 的 Capability-Verweis(e);
  3. 每包一条用户可见面的具名钉子(见下 provider 抽样)。

另加本切片特有的形状断言:插值恰 11 个路径{{count}}(按 key 具名列出,其余一律不许有洞);尾箭头十包镜像 en 且 designInStudioHint 不许有箭头;& 只出现在 en(九包各自改写);em dash 十包为 、zh 为该包自己的 ——;(s) 记法出现在 de/fr/es/pt(zh/ja/ko/ru 不许引入),且该断言的正则是 /\([\p{L}]{1,4}\)/u自带反例说明为什么不能用 ASCII \w(见下 #3866)。

provider-mounted 抽样钉扎(discrimination check)

usePublishAllDraftstuseObjectTranslation() 传入(HomePage 与 DraftPreviewBar 两个调用方都断言了);PermissionFacetLinkuseDetailTranslation,挂 provider 时该 hook 交出 i18next 的 t —— 这就是 console 的路径。这两条前提本身也断言了(读源码),而不是假设。

  • en / zh 各解析 6 个代表 key(每个 owner 一个),断言 not.toBe(key) 且等于包内值;
  • zh 具名六条(含两个插值:4 个对象已发布并验证 —— 12 行示例数据已生效。);
  • 另八包各钉一条用户可见面,横跨四种书写系统;
  • ar 的「RTL 句首不落拉丁 token」全量 18 路径(且插值后仍不以拉丁开头),RLS / Studio 两个不可避免的拉丁串都留在句中;
  • fr 的直角撇号全量 18 路径;ru 的 ё 一条;ja/zh/ko 三包在同一个 en 冒号上给出三种正确答案。

反向验证:四处方向跑前先判,四处全中

  1. 只把棘轮 14 行放回(包保留)→ 守卫报 14 条 stale,GUARD EXIT=1;总数钉子红:
    14 baseline entries are stale — the defect is gone, so the entry must go too
      missingKeys: home.pendingDrafts.capabilityWarn …(14 条)
    AssertionError: expected 31 to be 17
    AssertionError: expected [ …(14) ] to deeply equal []
    
  2. 只回退 en.ts(棘轮保持已删)→ 守卫报 14 条 unexpected / 14 distinct,GUARD EXIT=1,解析数回落 2297 → 2283;parity 九包各报 has 18 key(s) absent from en
  3. 只回退 zh.ts(en 保留)→ 守卫仍然绿(它只看 en),parity 与本切片测试红,失败文本就是把藏了这些 key 数月的机制摆出来 —— zh 缺 key 时 t() 返回的是 en 的值,不是 key、不报错:
    守卫: Every in-scope call-site key resolves against the en pack (2894 keys).  GUARD EXIT=0
    AssertionError: zh is missing 18 key(s)
    AssertionError: expected 'Delegated admin configured' to be '已配置委派管理范围'
    
  4. 只删掉 ru 四个基础 key(_one 保留)—— 本切片特有的一条,方向预判为"parity 红 + 渲染断言红且实际值是英文",命中:
    AssertionError: ru is missing 4 key(s)
    AssertionError: expected '3 objects' to be 'Объектов: 3'
    守卫 GUARD EXIT=0
    
    这一条就是复数族形状的全部理由:少了基础 key,俄语用户在 count=3 上看到英文,而三道门禁一条都不红。

顺手量出、未在本 PR 修的事

  1. detail.showEmptyRelated 的复数族只有 _one/_other,没有基础 key —— ru 在 2-4/5-20、ar 在 2-99 直接渲染英文 #3863(新立,concrete)detail.showEmptyRelated 的复数族缺基础 key,ru 在 2-4/5-20、ar 在 2-99 渲染英文;调用点 record-reference-rail.tsx:350 的 count 恰是 2-4 最常见。含十语实测表与修法。
  2. createSafeTranslation 的无 provider 兜底从不读调用点的内联 defaultValue —— 只认自己那张 defaults 表,表里没有就把 raw key 渲染给用户(useDetailTranslation 实测 16 个 key) #3865(新立,concrete)createSafeTranslation 的无 provider 兜底 fallbackT 读的是 defaults[key] || key,从不读调用点的 defaultValue(它只被当成一次 {{defaultValue}} 替换),所以表里没有的 key 在独立嵌入宿主上渲染 raw keyuseDetailTranslation 一个 hook 实测:146 条表 / 16 个 key 不在表内(9 个 perm.facet.* + 7 个 detail.*,其中 4 个包里已有值 —— 与"缺 key"无关)。这是 258 个 t() 调用点引用的 key 在任何语言包里都不存在(#3530 守卫首跑实测),其中 8 处直接把 raw key 渲染给用户 #3546 正文那个陷阱的镜像方向:正文是"表里有、包里没有 → 真实 console 露 key,无 provider 单测绿";这里是"表里没有 → 无 provider 露 key,挂 provider 的单测绿"。本 PR 因此零组件改动:补那张表会新增一个与包并列的真源,与本单的方向相反。
  3. [finding] PR #3847 的「括号复数记法」普查用了 ASCII \w,所以 ru 的结论(0 处)是错的(实为 13 处),同一写法的断言对全部非拉丁语言包空转 #3866(新立,finding) — PR fix(i18n): 回填 marketplace + preview 两命名空间 37 个缺失语言 key 及 marketplace.disclosure.runtime. 前缀家族,十包补齐 (#3546 切片五) #3847 的「括号复数记法」普查用了 ASCII \w,ru 的结论(0 处)是错的(实为 13 处,含 fieldCount = {{count}} поле(й)),且 marketplace-preview-namespace-3546.test.tsx 里同一写法的断言对 zh/ja/ko/ru/ar 五个包恒为 false(空转)。不影响该 PR 的落值,影响后续切片的取证方法;本切片已改用 \p{L} + u 并把反例钉进测试。
  4. [finding] 8 处 auth 调用点的内联 defaultValue 与 en 包值不一致 —— key 存在故兜底是死代码,三道 i18n 门禁按设计都看不见这一类 #3810(已存在,回填评论)perm.*/home.* 全部 153 个调用点(14 文件,不只本切片的 14 个)的普查:53 个带字面量 defaultValue,49/53 与 en 一致,4 处分歧(全在 HomePage.tsx,全是已存在的 key;home.welcome 包值 Build your business system with AI / 死句 Welcome to {{product}})。死兜底 t(key) || … / ?? …:0 处。另把 (2) 的机制交给该单的选项 C 作前提。
  5. [finding] marketplace.action.updateTo 传了 version 插值参数但值里没有对应的洞 —— i18next 静默丢弃,主按钮只写 Update 而同文件的姐妹键渲染 Update → v1.2.3(全仓 1/1055) #3845(已存在,回填评论)home.welcome 是休眠参数的第二个实例,并且说明该单的检测判据缺了一半:它按"参数名 vs defaultValue 的洞"判定,而这一处 defaultValue 有洞、en 包值没有 —— key 存在时包值才是渲染的东西。建议判据分两段,该单"1 / 1055"的分母只覆盖了第一段。

验证

node scripts/check-i18n-call-site-keys.mjs
  → Every in-scope call-site key resolves against the en pack (2894 keys).   EXIT=0
node scripts/check-i18n-en-drift.mjs
  → 0 en value(s) changed (18 key(s) added, 0 removed) — No en value changed in this range.   EXIT=0
node scripts/check-control-bytes.mjs
  → OK (scanned 3760 tracked text file(s); skipped 85 binary)                EXIT=0
node scripts/check-changeset-presence.mjs
  → 14 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)   EXIT=0
grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f]' 全部 17 个改动/新增文件   → 零命中(gate 之外的自扫,语言包全覆盖)
git log --format=%B origin/main..HEAD | grep -ci fable            → 0

flock -w 7200 /tmp/os-heavy-verify.lock -c 'NODE_OPTIONS=--max-old-space-size=4096 \
  pnpm exec vitest run packages/i18n \
  scripts/__tests__/check-i18n-call-site-keys.test.ts \
  scripts/__tests__/check-i18n-en-drift.test.ts --maxWorkers=2'
  → Test Files 32 passed (32) | Tests 585 passed (585)      (536 → 585,新增 49 条)

# 消费半径扫尾(本切片零组件改动,但语言包是这些包在消费)
flock … 'pnpm exec vitest run packages/app-shell/src/preview packages/plugin-detail/src/__tests__ --maxWorkers=2'
  → Test Files 53 passed (53) | Tests 329 passed (329)

pnpm --workspace-concurrency=2 --filter @object-ui/i18n type-check   → tsc --noEmit 通过
pnpm exec turbo run type-check --concurrency=2                       → 78 successful, 78 total(CI 同命令,末次编辑后全仓)
npx eslint 本 PR 改动的 15 个 i18n 文件                              → 0 problems

all-locales-key-parity.test.ts 含在上面 32 个文件内,已绿(它是补完 en 后立刻要求九包补齐的那道门禁)。@object-ui/i18n 无工作区内依赖,自身不需要先建依赖;@object-ui/reactTranslationKeys = typeof en 只是转出口,加 key 不窄化任何消费方 —— 全仓 turbo type-check 已实跑覆盖。

测试命令按 AGENTS.md §9 的唯一正确写法(仓根 pnpm exec vitest run 加相对仓根的路径),不用 pnpm --filter 包名 test;--workspace-concurrency 一律在 --filter 之前。

围栏

17 文件:packages/i18n/src/locales/*.ts(十包,仅新增本切片 18 个路径)、scripts/i18n-call-site-key-baseline.json(仅删本切片 14 行)、packages/i18n/src/__tests__/perm-home-namespace-3546.test.tsx(新增,49 条)、auth- + console- + marketplace-preview- + organization-namespace-3546.test.tsx(棘轮总数 31 → 17 —— 那个计数器每切片动一次且只降;missingPrefixes 钉子保持 2 条不动,本切片不含前缀家族)、changeset(@object-ui/i18n patch)。零组件改动(本切片 key 的死兜底量出为 0)。

与在飞 #3827(packages/cli)零相交;main 在分支点后落地的五个提交(#3849 / #3749 / #3738 / #3737 / #3827)与本围栏实测零文件相交 —— #3849 动的是 packages/components/src/renderers/action/**plugin-detail/src/renderers/record-quick-actions.tsx,本 PR 对 plugin-detail 只有测试里的读取(PermissionFacetLink.tsx / useDetailTranslation.ts),两者都不在其围栏内。未动 content/docs/releases/**


Generated by Claude Code

Fixes-part-of: #3546

守卫 scripts/check-i18n-call-site-keys.mjs 实测:14 个不重复 key / 14 个调用点
(1:1,无一 key 多站点),分别落在 PermissionFacetLink(权限集授权面只读摘要 +
Studio 深链,ADR-0056 P1)9 处与 usePublishAllDrafts(ADR-0038 L3 探针健康、
示例数据健康、ADR-0066 ⑨ 能力引用巡检)5 处。这两个命名空间不含 missing-prefix
家族,棘轮 missingPrefixes 保持 2 条不动。

英文一字未改:9 处静态 defaultValue 与 en 逐字节相同(9/9);另外 4 个计数标签的
defaultValue 是带英文单复数分支的模板串,改用 i18next 复数族后逐个计数渲染结果与
模板串一致(en 在 count 1/2/3/5/11/21/100 上全等)。

复数族刻意写成 key + key_one 而非 _one/_other:i18next 只按语言 CLDR 类别取一个
后缀,取不到就沿 fallbackLng 落到 en。ru(few 2-4、many 5-20)与 ar(two、
few 3-10、many 11-99)会因此在用户最先遇到的计数上显示英文;基础 key 让这些类别
落回本语言。ru 基础值取该包已用 25 次的「名词: {{count}}」写法,ar 取该包的
「{{count}} 单数(复数)」写法。

九包译文逐包取邻键证据(zh 取自本仓权限集设计器同一张表的 个对象/行级策略/
标签页/委派管理范围;de 区分 Registerkarte 与浏览器 Tab;fr 直角撇号与冒号前空格;
ru ё;ar 动作箭头保留 →)。4 处 en 同串直接复用邻键既有译文(list.none /
calendar.moreEvents / topbar.designInStudio / console.ai.seedWarn)。

棘轮 31 → 17(恰减 14,按行删除);四个既有 3546 家族测试的总数钉子同步同降一次。
@vercel

vercel Bot commented Aug 8, 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 8, 2026 10:32pm

Request Review

Copy link
Copy Markdown
Collaborator Author

修订记录

  • 7ca5bdeb7 回填本体(17 文件)。
  • 667962467 自查改正,仅注释一行,无值变动:ar.tsperm 注记原写作「السهم ← يبقى → في روابط الإجراء」—— 同一行里混用两个方向的箭头字形,在 RTL 语境下读者分不清"哪一个保留"。改为「لا نعكس سهم روابط الإجراء: يبقى كما في en، مثل marketplace.browseLink」(不镜像动作链接的箭头,与 en 一致)。

值一字未改,所以正文里的分母、9/9、18 个新增路径、棘轮 31 → 17、四方向反向验证与全部验证读数均不受影响;改正后复跑本切片测试仍 49 passed,ar.ts 的控制字符自扫零命中。


Generated by Claude Code

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Main entry (gzip) 28.1 KB 350 KB
Entry file index-BBO0GOml.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.39KB 106.34KB
core (index.js) 2.96KB 1.13KB
create-plugin (index.js) 10.08KB 3.26KB
data-objectstack (index.js) 139.61KB 35.99KB
fields (index.js) 230.82KB 56.70KB
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.04KB 17.31KB
plugin-chatbot (index.js) 180.33KB 42.79KB
plugin-dashboard (index.js) 117.21KB 30.27KB
plugin-designer (index.js) 210.51KB 42.51KB
plugin-detail (index.js) 236.17KB 58.82KB
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) 105.12KB 25.48KB
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) 19.28KB 6.38KB
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

✅ 验收(PM,session session_01GTRjn8xBqp75dk7kFupVRt)—— #3546 切片六

实物核验:头 667962467,17 文件 +994/−28;棘轮 diff 逐行读过 —— 恰好删除 perm 9 + home 5 共 14 行、零插入,missingPrefixes 保持 2 不动;十包 + en 全部就位;五处总数钉子(四既有 + 新增 perm-home)同步 31→17 一次;trailer 0。
CI 终态(独立复核):19 检查全部 completed,零失败。

裁定要点:

转 ready 并挂 auto-merge。#3546 棘轮余 17 key + 2 前缀,切片七候选(gantt.linkEnd. / organization.invitations.status. 前缀族等)待本片落 main 后排。越界 #3863/#3865/#3866#3810/#3845 追评归分诊席。


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.

1 participant