fix(components,i18n): 把 form.tsx 剩余的用户可见硬编码英文接入 i18n (#3272) - #3392
Merged
Conversation
… through i18n (#3272) The fullscreen long-text dialog (title, sr-only description, footer buttons, trigger accessible name) now reads `form.fullscreen.*`; the action bar's `submitLabel`/`cancelLabel` lose their English literal defaults and fall back at render through `common.submit`/`common.cancel`, so an authored label still wins verbatim while an unset one follows the session language. The built-in select branch's second `|| 'Select an option'` fallback is dropped — the call site already supplies `t('common.selectOption')`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
…edence (#3272) Three suites: the fullscreen dialog in en/zh/ja (positive per locale plus the English literals asserted absent, and a commit-the-draft case so the translated Done button is still the one wired to the handler); the action bar's submit/cancel fallback with the authored-label-wins-verbatim nail in both directions and the `submitLabel: ''` case that pins `??` over `||`; and the built-in select placeholder, whose authored-empty case is the one stack the deleted `|| 'Select an option'` literal actually reached. Also adds the changeset — the item-2 default-value semantics change is spelled out there for release notes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
yinlianghui
marked this pull request as ready for review
August 5, 2026 15:42
This was referenced Aug 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3272
背景
packages/components/src/renderers/form/form.tsx顶部早有useSafeFormTranslation,校验消息、门控提示、选项空态都已接 i18n,但同一文件里还剩几处用户可见的英文字面量从来没接过 —— zh/ja/ar 会话下,同一张表单里一半句子是中文、一半是英文。逐项复核
issue 的行号基于 08-03 快照,今日 main 已被 #5407 / #3290 等改过,四条先各自对着
origin/main复核:submitLabel/cancelLabel英文默认值aria-label="required"aria-hidden="true"+data-required-marker),aria-required改由控件自身承载。原位置现在是一段解释这件事的注释placeholder || 'Select an option'第 3 条的前提已经失效,如实报告,不强凑改动。
第 1 项 —— 全屏对话框
新增
form.fullscreen.*,十个语言包齐:title(标题回落)、description(sr-only 描述)、done(底部确认按钮)。底部的
Cancel复用已有的common.cancel,不另起form.fullscreen.cancel—— 「Cancel」这个词全仓十包早就有了,再抄一份正是 #3231 / #3263 花力气收掉的那种漂移。顺带把同一组件里展开按钮的
aria-label(原文是模板串Edit ${label ?? 'text'} fullscreen)也接上了。issue 的条目里没逐字点到它,但它就在同一个组件里、是同一类缺陷(屏幕阅读器在任何语言下都念英文),留一处不修会很怪。这里有一个刻意的取舍:它做成一个带插值的句子
toggle: 'Edit {{label}} fullscreen'加一个被翻译的通用名词textFallback: 'text',而不是「有 label 一句 / 没 label 另一句」两个 key。原因是label目前恒为undefined(见下方「顺带发现」#3393),两 key 写法会让「有 label」那个 key 在十个包里全是死翻译;插值写法则两个 key 都在活路径上,而且将来label补通了句子直接就对。第 2 项 —— Submit / Cancel 默认值(按 PM 裁定)
组件侧 prop 默认值从字面量改为
undefined加渲染时t()回落:submitLabel = 'Submit',渲染处写submitLabel ?? t('common.submit');Create account照旧是Create account;en 会话下作者写的中文「立即提交」照旧是「立即提交」;??而不是||:submitLabel: ''是「作者要一个空按钮」的显式声明,不是「没写」。||会把它悄悄覆盖掉 —— 那正是英文默认值当初干的事,不该换个方式再干一遍;common.submit/common.cancel(十包早已齐备),不新造form.submit/form.cancel孪生 key;FormSchema.submitLabel/cancelLabel在@object-ui/types里本来就是z.string().optional(),本 PR 没改 types / zod / spec。行为变化面很窄:只有「从来没写过 label、且在非英文会话下看」的表单渲染文本会变 —— 那正是 bug 本身。已写进 changeset。
第 4 项 —— select 的第二层 placeholder 兜底
issue 说它是「够不到的死兜底」,复核下来不完全准确,这里如实修正。
唯一调用点是
placeholder: fieldProps.placeholder ?? (resolvedType === 'select' ? t('common.selectOption') : undefined)。??只在 null/undefined 时回落,所以作者写placeholder: ''时空串会原样传下去;而分支里的placeholder || 'Select an option'用的是||,空串是 falsy —— 于是「作者刻意要一个空 placeholder」这条路径真的能走到那个英文字面量,拿到一个没被翻译的英文词覆盖掉自己的显式声明。所以它不是无害的死代码,删掉是有可观察行为的,也是本 PR 里唯一能做「装回去看它变红」的一处。
反向验证(先定方向,再跑)
把三处改动整体还原成字面量,事先的预测是:凡是「英文与译文字节相同」的用例应当保持绿(它们本来就不区分),凡是断言译文出现、或断言英文缺席的用例应当变红。实测 6 红 8 绿,与预测逐条吻合。
变红(6,如预测):全屏对话框 zh / ja / 「Done 按钮仍然接着 handler」,动作栏 zh / ja,select 的
placeholder: ''。保持绿(8,如实说明为何不是漏网):
= 'Submit'解构默认值本来也不会覆盖显式值。这两条钉的是新回落不许越界,不是旧行为的回归;submitLabel: ''一条 —— 解构默认值只对undefined生效,空串在新旧代码下都渲染成空。它钉的是渲染处必须用??而不是||,还原实验不涉及这个选择,所以它绿是对的;t()」那条路,本来就够不到被删的字面量。它们留下来是删除之后的续钉:哪天有人把调用点的t()去掉,不再有第二层兜底替它遮丑,zh 那条会直接红。边界
form.tsx加packages/i18n/src/locales/*.ts(10 个)加 3 个新测试加 1 个 changeset。mobile_fullscreen || fullscreen读全屏开关,而fullscreen这个别名全仓无人产出(消费侧宽容兜底) #3303 的mobile_fullscreen || fullscreen别名逻辑(同文件、串行在本单之后)。测试 fixture 一律拼mobile_fullscreen这个有生产者的规范键,所以 form.tsx 的内置 textarea 分支用mobile_fullscreen || fullscreen读全屏开关,而fullscreen这个别名全仓无人产出(消费侧宽容兜底) #3303 删掉别名之后这些测试依然绿。content/docs/releases/。顺带发现(已另开 issue,不在本 PR 修)
labelprop 恒为undefined:label在renderFormField的字段解构里就被单独取走,唯一调用点展开的...fieldProps里没有它。后果是全屏对话框标题恒为通用的「编辑文本」而不是字段名,展开按钮的无障碍名也无法区分同一表单上的多个长文本字段。mobile_fullscreen || fullscreen读全屏开关,而fullscreen这个别名全仓无人产出(消费侧宽容兜底) #3303 会改到同一行。defaultProps: { submitLabel: 'Submit', cancelLabel: 'Cancel' }仍是英文字面量(本仓运行期无人读,但会绕过 #3272 的渲染期回落) #3394(finding)—— 组件注册元数据里的设计器默认值defaultProps: { submitLabel: 'Submit', cancelLabel: 'Cancel' }仍是英文字面量。本仓运行期没有任何地方读defaultProps,所以今天不影响渲染;但若设计器把它物化进作者的 schema,新的渲染期回落就够不到了(对渲染器而言那就是「作者显式写的值」)。测试
从仓根跑(包内跑 vitest 假绿 / 路径过滤被吞,见 #3288 / #3378),全程持
flock /tmp/os-heavy-verify.lock加NODE_OPTIONS=--max-old-space-size=4096加--maxWorkers=2。三个新测试文件:
form 渲染器全部测试加 i18n 全部测试(含
all-locales-key-parity.test.ts,它机械校验新 key 十包齐、插值占位符与 en 一致):按规则消费半径(而不是被改的包)扫的下游 fixture —— plugin-form / plugin-detail / fields / app-shell FlowRunner / components 里所有按
/submit/i、Cancel取按钮的测试:反向验证(三处改动整体还原):
类型检查(先
pnpm --filter '@object-ui/components^...' build建好依赖,新 worktree 不建会报一片假的 TS2307):其余闸门:
check-control-bytesOK(另做了一次grep -naP自扫,changed files 无控制字节);check-changeset-fixed/check-changeset-no-major均 OK;改动文件 eslint 0 error。远端 CI 已全绿:Lint / Type Check / Test shard 1-4 / Build & E2E / Build Docs / Control Byte Scan / Changeset Fixed Group / Changeset Bump Policy / Bundle Analysis 全部 success(
Test (coverage)与dependabot按 path filter skipped)。🤖 Generated with Claude Code
https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt