Skip to content

fix(i18n): 八包按 en 当前的 read-only 语义重译 view.readonlyTooltip (#3625) - #3642

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-3625-readonly-tooltip-stale
Aug 7, 2026
Merged

fix(i18n): 八包按 en 当前的 read-only 语义重译 view.readonlyTooltip (#3625)#3642
yinlianghui merged 1 commit into
mainfrom
claude/issue-3625-readonly-tooltip-stale

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes#3625

view.readonlyTooltip(视图页签只读锁的 tooltip,消费点唯一:packages/plugin-view/src/ViewTabBar.tsx:489)在 ja/ko/de/fr/es/pt/ru/ar 八个包里描述的是产品已不提供的「复制一份来自定义」路径。按 en当前的 read-only 语义整句重译八包。

en / zh一字节未动,不增删任何 key(八个包各 1 行,+8/-8 严格对称),未碰ViewTabBar.tsx、棘轮基线,未改动#3627 落地测试的任何既有断言。

前置测量:en/zh 现状(硬约束 1)

动笔前先证伪 issue 的前提。enzh 都已经是 read-only 口径,因此本单只动八包:

语义
enSystem view — defined in code, read-only.read-only,当前口径 ✅
zh系统视图 — 由代码定义,只读。read-only,已对齐 ✅

为什么 #3627 的判据看不见这一条(这才是本单的重点)

#3582 是同一句废弃语义在隔壁命名空间,八包存的是英文原文,所以两条便宜判据都能抓:值等于 en、非拉丁包里出现纯 ASCII。这个 key 两条都抓不到 —— 八个值是地道译文(ja 是日文、ru 是西里尔、ar 是阿拉伯文),只是译了一句 en 自己已经废弃的话。形态全对,语义全错。

实测:修前八包 10/10 互不相同五个非拉丁包全部通过本文字系统判据、键集合完整。也就是说 all-locales-key-parity、调用点 key 守卫及其棘轮、#3582「建议 2」设想的那道 ASCII 门禁,修前修后全绿

因此本单的断言按语义而非等值/形态设计,且两个方向同时钉

八包新旧对照表

修前(废弃语义)修后(read-only)
jaシステムビュー — 複製してカスタマイズしてください。システムビュー — コードで定義され、読み取り専用です。
ko시스템 보기 — 사용자 지정하려면 복제하세요.시스템 보기 — 코드에 정의되어 있으며 읽기 전용입니다.
deSystemansicht — zum Anpassen duplizieren.Systemansicht — im Code definiert, schreibgeschützt.
frVue système — dupliquer pour personnaliser.Vue système — définie dans le code, en lecture seule.
esVista del sistema — duplique para personalizar.Vista del sistema — definida en el código, solo lectura.
ptExibição do sistema — duplique para personalizar.Exibição do sistema — definida no código, somente leitura.
ruСистемное представление — скопируйте для настройки.Системное представление — определено в коде, только для чтения.
arعرض النظام — انسخ للتخصيص.عرض النظام — معرَّف في الكود، للقراءة فقط.

译文溯源:每个词都指回同包既有 key,没有一句自创

照抄 #3627 的邻键溯源纪律。en 的句子是三段式(System view + defined in code + read-only),逐段取词:

语义段取自(同包)
「系统视图」本 key 自己的前半句(八包这半句本来就是对的,只有后半句过期)+ console.objectView.systemViewReadonly(#3627 刚落)
「由代码定义」console.objectView.systemViewReadonly / console.objectView.cannotEditMetaView(#3583 落的)
「只读」view.readOnly / view.readonlyAriaLabel(与本 key 同命名空间、同一屏)

标点与正式度随各包邻域,不自创:

  • 破折号:十个包本 key 修前就都用 (含 en/zh),沿用。es 这里用 而非 : —— fix(i18n): 八包补上 console.objectView 两个 key 的真译,systemViewReadonly 按 en 当前的 read-only 语义 (#3582) #3627 的冒号选择是 console.objectView 命名空间局部的(该命名空间 cannotEditMetaView / filterOrNotSavable 用冒号);而在 view 命名空间里,es 的同类 tooltip view.subscribedTooltip(Suscrito — clic para cancelar suscripción)和本 key 自己修前的值都用破折号。
  • 逗号:ja 用 ,zh 用 ,ar 用 ،(该包 60 处在用),其余 ASCII ,
  • 性数一致,全部与同包 systemViewReadonly 保持同一选择:fr Vue 阴性 → définie;pt Exibição 阴性 → definida;es Vista 阴性 → definida;ru представление 中性 → определено;ar عرض 阳性 → معرَّف
  • es 祈使语气邻域现状是 usted —— 本句是陈述句,不涉及。

de 的两处落到同一句,是有意接受的,不是疏漏

en 区分这两个 key 靠的只是破折号落点(System view — defined in code, read-only.System view defined in code — read-only.),这个区分多数语言承载不了。#3627 为 de 的 systemViewReadonly 选的正是本 key 的破折号结构,于是德文两处重合。不为造差异而改写译文 —— #3627 自己把 console.objectView.expandToPagedetail.openAsFullPage 在十个包里逐字节对齐,已经立下「同义即可同文」的先例。测试把「只有 de 重合」这个事实钉住,将来哪个包重合状况变了会浮出来给人看。

测试:与 #3627 的分工(硬约束 4)

新开文件packages/i18n/src/__tests__/viewReadonlyTooltip-semantics-3625.test.ts,不改objectView-value-language-3582.test.ts 一行。理由三条:

  1. fix(i18n): 八包补上 console.objectView 两个 key 的真译,systemViewReadonly 按 en 当前的 read-only 语义 (#3582) #3627 那个文件的 docblock 与模块级 helper(objectViewOf / readonlyOf / EN_CURRENT)整体锚定在 console.objectView 一个命名空间上,塞进第二个命名空间会让它自己的作用域声明失真;
  2. 它的 duplicate to customize 扫描面特意限定在那两个 key,并在注释里点名 view.readonlyTooltip 在 8 个语言包里译的是「duplicate to customize」这句已废弃语义 —— 因为它是真译文,任何「值是英文」判据都看不见它 #3625 是另一单 —— 分文件放,这句注释保持为真;
  3. 两个钉子面各自独立后,红灯能直接指认是哪一单回归了

扫描面同样必须窄(与 #3627 同理,但踩点不同)

废弃语义扫描只限本 key。同命名空间的 view.duplicateView(es 是 Duplicar vista)是合法的「复制视图」动作,含 duplic 词干 —— 包级词干扫描会误红它。这条不变量天生是 per-key 的,推不成仓级门禁。

禁用词干表按包内实际旧值测量修正

派发口径给的表里 es/pt 是 duplic,实测旧值是 duplique,duplic 并不是它的子串(dupliqu 才是),照抄会漏。实际落地的词干:

禁用词干(负向)正向锚点(三段全钉)
ja複製 / コピーシステムビュー + コード + 読み取り専用
ko복제 / 복사시스템 보기 + 코드 + 읽기 전용
deduplizier / kopierSystemansicht + Code + schreibgeschützt
frdupliqu / duplic / copiVue système + code + lecture seule
esdupliqu / duplic / copiVista del sistema + código + solo lectura
ptdupliqu / duplic / copiExibição do sistema + código + somente leitura
ruкопир / скопирСистемное представление + код + чтени
arنسخ / انسخعرض النظام + كود + قراءة

正向锚点是防空绿的那一半:只有负向断言的话,把值删空也能全绿。

另外钉了 en 字面量 —— en 下次改文案时,在改文案的那个 PR 里就红,而不是再放九个包漂一个版本。这才是这一族缺陷真正缺的那道不变量。

逆向验证(先预测,后运行)

预测:回退八包值 →

  • :no pack names the retired… 1 条(八包全命中词干)+ 正向锚点 8 条(ja/ko/de/fr/es/pt/ru/ar,en/zh 保持绿);
  • 红,但方向是反的:de is the only pack… —— 回退让 de 不再systemViewReadonly 重合,断言是从 ['de'] 掉成 [],与上面九条的红法相反;
  • 绿(不翻转,如实记):互异断言、五条文字系统断言、en 钉子、英文字面量断言、非空断言 —— 因为八个废弃值本来就是互异的地道译文;
  • objectView-value-language-3582.test.ts 全绿、all-locales-key-parity 全绿。

合计预测 10 红。实测完全吻合:

× no pack names the retired duplicate-to-customize workflow
packs still offering duplicate-to-customize: ja, ko, de, fr, es, pt, ru, ar: expected [ 'ja', 'ko', 'de', 'fr', 'es', …(3) ] to deeply equal []
× ja carries all three pieces of the read-only sentence
ja tooltip lost "defined in code": システムビュー — 複製してカスタマイズしてください。
× ko / de / fr / es / pt / ru / ar carries all three pieces … (同款,共 8 条)
× de is the only pack where this tooltip reads identically to console.objectView.systemViewReadonly
expected [] to deeply equal [ 'de' ]
Test Files 1 failed | 2 passed (3)
Tests 10 failed | 63 passed (73)

两个 passed 文件正是 objectView-value-language-3582.test.tsall-locales-key-parity.test.ts

all-locales-key-parity 修前修后都绿是本 PR 的预期结论,不是缺陷 —— 它比的是键集合与占位符形状,本缺陷不动键集合、本 key 不带占位符。互异与文字系统判据同样不翻转,原因已在上面写明;它们保留是为了防「把一种语言粘进另一种」,不是本单的证据。这一点如实写出来,而不是把它们包装成红。

测试

# 新测试 + #3627 落地测试 + 键集合门禁
npx vitest run --maxWorkers=2 packages/i18n/src/__tests__/viewReadonlyTooltip-semantics-3625.test.ts \
packages/i18n/src/__tests__/objectView-value-language-3582.test.ts \
packages/i18n/src/__tests__/all-locales-key-parity.test.ts
Test Files 3 passed (3) / Tests 73 passed (73)
# i18n 全量(#3627 落地时是 25 文件 / 326 测试,本单 +1 文件 / +31 测试)
npx vitest run --maxWorkers=2 packages/i18n/src/__tests__/
Test Files 26 passed (26) / Tests 357 passed (357)
pnpm --workspace-concurrency=2 --filter @object-ui/i18n type-check
tsc --noEmit → 通过(无输出)
node scripts/check-changeset-no-major.mjs → ✅ No changeset declares a `major` bump.
node scripts/check-changeset-fixed.mjs → ✅ All workspace packages are in the changeset fixed group.
eslint(9 个改动 .ts 文件) → 0 errors,2 warnings(`as any`,与 #3627 落地的同目录测试同款)
控制字符自查:grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f]' (8 个包 + 测试 + changeset) → 无匹配

消费半径清扫:全仓 grep readonlyTooltip 与八句废弃文案字面量,除本 PR 改的八个包外,只有 ViewTabBar.tsx:489(唯一消费点,本 PR 不碰)与 #3627 测试里指向本单的那句注释、其 changeset 里的一处引用 —— 没有任何 fixture 或组件测试断言这八个旧值,故无需改动包外测试。

范围

  • 改:8 个语言包各 1 个值;新增 1 个测试文件 + 1 个 changeset(patch,@object-ui/i18n,用户可见:八语言视图页签 tooltip 语义修正)
  • 未改:en.ts / zh.tspackages/plugin-view/src/ViewTabBar.tsxobjectView-value-language-3582.test.ts、棘轮基线、任何组件代码

🤖 Generated with Claude Code

https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt


Generated by Claude Code

…'s current read-only meaning (#3625)
The eight packs (ja/ko/de/fr/es/pt/ru/ar) described the retired
"duplicate to customize" workflow. Unlike #3582 one namespace over, these
values were idiomatic translations, so no equality-with-en or ASCII
heuristic could see them: only their meaning was wrong.
en and zh unchanged byte for byte; no key added or removed.
New test asserts semantics in both directions (no duplicate/copy stem in
each pack's own language, plus all three positive anchors) and pins the
en literal so the next rewording fails loudly.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
@vercel

vercelBot commented Aug 7, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectuiIgnoredIgnoredAug 7, 2026 4:52pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Main entry (gzip)28.1 KB350 KB
Entry fileindex-BQH4Mpby.js
StatusPASS

📦 Bundle Size Report

PackageSizeGzipped
app-shell (index.js)8.66KB3.13KB
app-shell (runtime-config.js)7.42KB2.32KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)7.57KB2.97KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)1.17KB0.53KB
auth (AuthProvider.js)22.10KB4.37KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.13KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.64KB2.21KB
auth (SocialSignInButtons.js)9.60KB3.89KB
auth (UserMenu.js)3.40KB1.22KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)35.76KB9.11KB
auth (createAuthenticatedFetch.js)4.37KB1.69KB
auth (index.js)2.35KB1.07KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)4.91KB0.87KB
auth (useIsWorkspaceAdmin.js)1.61KB0.85KB
collaboration (CommentThread.js)26.07KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.65KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)480.72KB105.64KB
core (index.js)2.96KB1.13KB
create-plugin (index.js)9.28KB2.98KB
data-objectstack (index.js)137.51KB35.11KB
fields (index.js)230.87KB56.83KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (i18n.js)4.32KB1.77KB
i18n (index.js)2.65KB1.06KB
i18n (pickLocalized.js)1.70KB0.83KB
i18n (provider.js)9.48KB3.27KB
i18n (useObjectLabel.js)26.14KB6.07KB
i18n (useSafeTranslation.js)4.52KB1.96KB
layout (index.js)38.53KB10.71KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.74KB
mobile (index.js)1.50KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.71KB0.42KB
mobile (useResponsiveConfig.js)1.36KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)8.75KB3.06KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)3.67KB1.12KB
permissions (evaluator.js)4.41KB1.44KB
permissions (index.js)0.91KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.52KB
permissions (usePermissions.js)1.55KB0.71KB
plugin-ai (index.js)15.71KB3.79KB
plugin-calendar (index.js)44.98KB12.37KB
plugin-charts (index.js)61.04KB17.31KB
plugin-chatbot (index.js)180.09KB42.72KB
plugin-dashboard (index.js)115.50KB29.96KB
plugin-designer (index.js)210.51KB42.51KB
plugin-detail (index.js)232.79KB57.42KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)112.10KB27.10KB
plugin-gantt (index.js)162.55KB39.57KB
plugin-grid (index.js)186.61KB49.34KB
plugin-kanban (index.js)48.30KB13.28KB
plugin-list (index.js)105.12KB25.48KB
plugin-map (index.js)16.81KB5.24KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)40.58KB10.58KB
plugin-timeline (index.js)25.76KB7.33KB
plugin-tree (index.js)8.50KB2.88KB
plugin-view (index.js)84.03KB20.55KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.71KB3.53KB
providers (index.js)0.44KB0.22KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.67KB2.37KB
react (LazyPluginLoader.js)3.77KB1.33KB
react (SchemaRenderer.js)19.28KB6.38KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)1.02KB0.55KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)4.09KB1.74KB
sdui-parser (index.js)4.47KB2.03KB
sdui-parser (parse.js)10.04KB2.82KB
sdui-parser (types.js)0.29KB0.24KB
sdui-parser (validate.js)4.69KB1.48KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)0.20KB0.18KB
types (crud.js)0.20KB0.18KB
types (data-display.js)0.20KB0.18KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.87KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-retry.js)4.32KB2.02KB
types (index.js)2.71KB1.34KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)0.20KB0.18KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

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

@yinlianghui
yinlianghui marked this pull request as ready for review August 7, 2026 17:02
@yinlianghui
yinlianghui added this pull request to the merge queueAug 7, 2026
Merged via the queue into main with commit 33526fdAug 7, 2026
19 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-3625-readonly-tooltip-stale branch August 7, 2026 17:53
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

2 participants

@yinlianghui@claude