Uh oh!
There was an error while loading. Please reload this page.
fix(components): translate the built-in select branch's empty copy (#3263) - #3271
Merged
Merged
Conversation
…3263) The inline `type: 'select'` branch — the one taken before the `field:` registry is consulted (BUILTIN_FIELD_TYPES) — rendered a hardcoded `'No options available'`, while the dependency-gate sentence right next to it already went through `t()` (`fields.options.selectFirst`, #3231). A `zh` session therefore saw one widget switch languages mid-interaction: gated read Chinese, and the moment the parent value matched no option it flipped to English. It now renders `t('fields.options.empty')` — the same key the registered option widgets fall back to — with the English default added to `useSafeFormTranslation`'s defaults map, so a form with no I18nProvider produces the byte-identical string it produced before. The box moved into a small `BuiltinSelectEmptyState` component in the same file: `renderFieldComponent` is a plain helper that early-returns on the registered-widget path, so a hook called there would run conditionally. It forwards its rest props because `<FormControl>` is a Radix `Slot` supplying the control's `id`/`aria-describedby`. Not unified with `@object-ui/fields`' `OptionsEmptyState` — different package, different render path. The two share the i18n key, not a component. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NVPjPzmmAJ2Ngtvgg5MSRa
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
xuyushun441-sys
marked this pull request as ready for review
August 3, 2026 10:08
Uh oh!
There was an error while loading. Please reload this page.
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 freeto 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#3263
问题
packages/components/src/renderers/form/form.tsx的内建select分支(命中BUILTIN_FIELD_TYPES时的内联渲染,走不到field:注册表)渲染的是硬编码英文:而紧挨着它的门控提示早就走了 i18n(
t('fields.options.selectFirst'),objectui#3231)。也就是说同一个 widget 在 zh 会话里会中途换语言:被dependsOn门控时读到「请先选择Country」,用户把父字段填成一个匹配不到任何选项的值之后,同一个框立刻变成英文 "No options available"。这是 #3231 scope fence 刻意留下的最后一块,不是遗漏。改动
t('fields.options.empty')—— 与已注册选项 widget(packages/fields的OptionsEmptyState)回落时用的同一个 key,十个语言包里已就位,packages/i18n不需要改。useSafeFormTranslation的 defaults map 里补'fields.options.empty': 'No options available'—— 与fields.options.selectFirst在那里的做法一致。无 provider 时渲染结果逐字不变,所以现有的英文断言(form-cascading-select.test.tsx、plugin-form/selectOptions.test.tsx)不需要动,也确实全绿。BuiltinSelectEmptyState。原因:renderFieldComponent是普通 helper 而非组件,它在「已注册 widget」那条路径上会提前 return,在那里调 hook 就是条件调用(rules-of-hooks)。组件里...rest会转发下去,因为FormControl是 Radix Slot,控件的id/aria-describedby/aria-invalid是它塞进来的 —— 丢掉 rest props 会让该字段的 label 指向一个不存在的 id,这一点有测试钉住。边界(按 issue 与派发说明)
没有把内建分支和
packages/fields的OptionsEmptyState统一成一个组件:不同包、不同渲染路径(内联分支 vs. 注册表),该共享的只有 i18n key,不是组件 —— 合并会把一条路径的 DOM 结构和 props 约束强加给另一条。packages/i18n未改动(两个 key 由 #3231 补齐,已核对en.ts/zh.ts)。测试
两个新文件,拆开是必须的:挂载
I18nProvider会把它的实例注册成 react-i18next 的全局默认,同一模块图里就再也观察不到「无 provider」状态(与OptionsEmptyState.test.tsx/OptionsEmptyState.no-provider.test.tsx的拆法一致)。form-builtin-select-empty-i18n.test.tsx—— zh 下渲染「暂无可选项」;门控句渲染「请先选择Country」;以及门控解除后两句话仍在同一种语言里(这条正是原缺陷暴露的那个转换)。form-builtin-select-empty-default.test.tsx—— 无 provider 时回落到逐字相同的英文;以及空状态仍是被 label 关联的表单控件(label 的for等于该 div 的id,且带aria-describedby)。变异验证(把
t('fields.options.empty')改回英文字面量后重跑):失败现场的 DOM dump 里,zh provider 下那个 div 渲染的正是
No options available;顺带确认id="_r_4_-form-item"与aria-describedby仍然落在这个 div 上(即 rest props 转发是对的)。Changeset:
.changeset/builtin-select-empty-state-translated.md(patch,仅@object-ui/components)—— 非英文会话不再在这里看到英文,属用户可见变化。🤖 Generated with Claude Code
https://claude.ai/code/session_01NVPjPzmmAJ2Ngtvgg5MSRa
Generated by Claude Code