Skip to content

fix(i18n): 组织写入目标徽标在十种语言下都渲染译文,而不是英文兜底 - #3526

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-3517-create-target-org-key
Aug 7, 2026
Merged

fix(i18n): 组织写入目标徽标在十种语言下都渲染译文,而不是英文兜底#3526
yinlianghui merged 1 commit into
mainfrom
claude/issue-3517-create-target-org-key

Conversation

@yinlianghui

@yinlianghuiyinlianghui commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Fixes#3517

form.createTargetOrg(ADR-0105 集团租户「写入目标」徽标,RecordFormPage create 模式渲染)在十个语言包里一个都没有定义,连 en 都没有。i18next 是真的 miss,渲染出来的是调用点的内联 defaultValue,所以该徽标在十种语言下全是英文 —— 中文控制台在组织隔离对象上新建记录时,头部会出现一句 Creates in 某某组织

all-locales-key-parity.test.ts 看不见这条:它断言的是「每个包定义了 en 的每个 key」,en 自己没有的 key 不在比较范围内,十个包一致地缺失反而让 parity 完全绿。

改了什么

  1. en.ts 回填createTargetOrg: 'Creates in {{org}}',parity 门禁随即要求其余九包跟上。
  2. 九个语言实译,按各包既有 form 段的语气与词汇,不是机翻占位、也不是英文复制(逐条理由见下表)。
  3. 删掉 RecordFormPage.tsx 的内联 defaultValue 及其说明注释 —— 这是 [finding][i18n] RecordFormPage 给 form.createTitle 传的 defaultValue 是 New ${label},与 en 包的 Create {{object}} 动词不一致(当前不可达) #3469 留下的最后一条例外,现在该文件每一处 t() 都是裸调用。Declared = enforced:语言包是这份文案的唯一来源,key 缺失必须显形(裸 key + dev missing-key 告警),而不是在调用点糊过去。
  4. 反转 refactor(app-shell): 删除 RecordFormPage 中不可达的 i18n defaultValue 兜底 #3516 留下的两条例外钉扎:form.createTargetOrg 并入 BARE_KEYS(钉住十包都有),渲染断言改为按语言包取值,并按该文件既有的写法同时断言 zh —— 被删掉的英文默认值无论如何都满足不了中文断言。

九个语言的取词依据

译文依据
zh创建到{{org}}新建{{object}} 一致,插值前后不加空格;「创建到」表达写入方向
ja作成先: {{org}}沿用 相手の保存時刻: {{time}} 的「名词 + 半角冒号 + 值」徽标句式;作成先 正是写入目标
ko{{org}}에 생성{{object}} 생성 同词(생성);조사 不随收音变化,插值安全
deWird in {{org}} erstellt{{object}} erstellen 同词根,被动现在时对应 "Creates in"
frCréation dans {{org}}名词式,避免与按钮态 Créer {{object}} 混淆
esSe crea en {{org}}自反被动,西语 UI 常见("se crea en / se guarda en")
ptCriação em {{org}}名词式;刻意不用Criado em,它会与日期字段「Criado em 某日期」歧义
ruСоздаётся в {{org}}Создать {{object}} 同词根;用 ё,与该包 несохранённые/обновлён 的正字法一致
arالإنشاء في {{org}}إنشاء {{object}} 同词根;占位符置于句末,与该包 تحرير {{label}}الخطوة {{current}} من {{total}} 的 RTL 语序一致

测试方向(先预测再跑)

  • 改动前(fresh main):两条例外钉扎绿(它们断言「缺失」)—— 实测 36 passed。

  • 仅做第 1 步(只改 en.ts)——刻意跑的中间态:parity 红 + 例外钉扎红,共 10 failed。九条形如(以 ar 为例,zh/ja/ko/de/fr/es/pt/ru 同形):

    ar is missing 1 key(s): expected [ 'form.createTargetOrg' ] to deeply equal []
    

    外加例外钉扎打出它自己写好的指令:

    form.createTargetOrg is now translated — backfill done, so remove the inline
    defaultValue in RecordFormPage.tsx: expected [ 'en' ] to deeply equal []
    

    两道门禁都确实会响。

  • 全部改完:全绿。

反向验证的方向是「无变化」,不是「变红」,这里如实记录:把 RecordFormPage.tsx 从 origin/main 检出(把 defaultValue 装回去),测试文件 17 passed 依旧全绿 —— 因为 key 现在能从语言包解析,i18next 根本不会去看 defaultValue,它又变回死代码。这正是本 issue 描述的缺陷形态(没有测试能看见的死分支),所以真正的红色方向是上面那个中间态,而不是「把删掉的肢体装回去」。

验证

pnpm exec vitest run packages/i18n packages/app-shell
Test Files 305 passed (305)
Tests 2732 passed | 1 skipped (2733)
pnpm --filter @object-ui/i18n type-check # tsc --noEmit,无输出
pnpm --filter @object-ui/app-shell type-check # tsc --noEmit && tsc -p tsconfig.typetests.json,无输出
node scripts/check-control-bytes.mjs # OK(3690 个文本文件)

Changeset:.changeset/create-target-org-translated-3517.md,@object-ui/i18n@object-ui/app-shell 各一条 patch。未触碰 content/docs/releases/

🤖 Generated with Claude Code

…locales
`form.createTargetOrg` was defined in no locale pack — not even `en` — so
i18next genuinely missed it and `RecordFormPage`'s inline `defaultValue`
rendered instead. The ADR-0105 badge therefore read English `Creates in <org>`
in all ten languages (a Chinese console creating a record on an org-walled
object showed `Creates in 某某组织`).
`all-locales-key-parity.test.ts` could not see this: it asserts every pack
defines every `en` key, so a key `en` itself lacks is outside the comparison,
and ten packs missing it identically kept parity green.
Backfill `createTargetOrg: 'Creates in {{org}}'` into `en` (the parity gate then
demands it from the other nine, each translated to its pack's existing form
tone), delete the inline default, and invert the two exception pins #3516 left:
the key joins BARE_KEYS, and the render assertion checks the badge against the
pack copy in both `en` and `zh`.
Fixes#3517
@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 2:49am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Main entry (gzip)28.1 KB350 KB
Entry fileindex-B6qcwYJ8.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)479.63KB105.43KB
core (index.js)2.47KB0.91KB
create-plugin (index.js)9.28KB2.98KB
data-objectstack (index.js)136.30KB34.76KB
fields (index.js)229.82KB56.53KB
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.05KB1.53KB
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)112.03KB28.88KB
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)111.54KB26.97KB
plugin-gantt (index.js)162.55KB39.57KB
plugin-grid (index.js)185.25KB49.08KB
plugin-kanban (index.js)48.03KB13.22KB
plugin-list (index.js)104.72KB25.36KB
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.46KB1.21KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)0.20KB0.18KB
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

Sign up for freeto 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.

[i18n] form.createTargetOrg 在十个语言包里全部缺失,组织写入目标徽标在所有非英文语言下都渲染英文兜底

2 participants

@yinlianghui@claude