Repository navigation
fix(app-shell): Studio's field inspector says when a translation overrides the label being edited (objectui#11782) - #11859
Merged
objectstack-fleet[bot] merged 3 commits intoOct 8, 2026
Conversation
…s the label being edited Studio's field inspector edits a field's source label, while the Data pillar's grid headers and form canvas show the label resolved through @object-ui/i18n's useSafeFieldLabel().fieldLabel, where a translation for the active language wins. A muted line under the Label input now names the label the field is shown with and the language, read through that same resolver, whenever it differs from the input's current value. Claude-Session: https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8 Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8 Co-authored-by: Claude <noreply@anthropic.com>
…bel-translation-hint Claude-Session: https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8 Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
This was referenced Oct 8, 2026
objectstack-fleet
Bot
deleted the
claude/issue-11782-label-translation-hint
branch
October 8, 2026 03:00
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 #11782
Clause-②: no
What changes
Studio's field inspector (
ObjectFieldInspector, Basic section) now shows one muted line under the Label input when a translation overrides the label being edited. For the showcase'sshowcase_account.tax_idin an en session it reads:In zh:
在 zh-CN 中显示为“税号”:应用的翻译包覆盖了此显示名。label. This is the card's option A. Option B (swapping the title and the value) is not in this PR.packages/i18n/**is touched.inspectors/ObjectFieldInspector.tsx(the hint line underfield-label-input, plus one module-private component,LabelTranslationHint), two new rowsdesigner.field.labelTranslated(en and zh) inmetadata-admin/i18n.ts, the test beside the inspector, and apatchchangeset.StudioDesignSurface.tsxis not touched.ENGINE_STRINGS_EN/ENGINE_STRINGS_ZH, typed as plain string-to-string records).Mechanism (the dispatch's Zone 2 hypotheses, measured)
ObjectGrid'sresolveFieldLabel, which isuseSafeFieldLabel().fieldLabel(re-exported through@object-ui/react). Its form canvas gets field labels fromObjectFormDesigner'sfieldLabelOf, which isuseSafeFieldLabel().fieldLabelfrom@object-ui/i18n. Both areuseObjectLabel().fieldLabel(object, field, fallback)inpackages/i18n/src/useObjectLabel.ts. That function readsNS.fields.OBJECT.FIELDfrom the bundle the console'sloadLanguageinstalls from/api/v1/i18n/translations/LANG. The showcase's bundle hasobjects.showcase_account.fields.tax_id.label: 'Tax ID'(en) and'税号'(zh). The hint calls the same function, so the hint and the canvas cannot disagree.''as the fallback. The resolver returns the fallback exactly when no translation exists. So an empty answer means nothing overrides the source label, whatever the input currently holds.localeprop and the canvas's language are not the same value. Thelocaleprop (useMetadataLocale) picks one of the designer's two string tables, and it isen-USfor every language that is not zh. The resolver readsi18n.languagefrom the i18next instance. The hint names the resolver's language and writes its sentence from the designer's table. A pin checks this: ajasession with the en-US designer table namesja.PILLARS/OVERFLOW_PILLARSinStudioDesignSurface.tsx; the console's/studioroutes are:packageIdand:packageId/:tabonly). The translation editor is the metadata-admin resource page, and its base path depends on the host. Finding whichtranslationitem carries the key would need a server read that the inspector does not make. A link would need a new prop on the field-inspector mount inStudioDesignSurface.tsx, which objectui#11781 holds and which is off this claim's surface, or a hard-coded route. So the line names the bundle in words instead of linking to it.Tests
New:
inspectors/ObjectFieldInspector.labelTranslation-11782.test.tsx, 7 tests. Each one renders the inspector inside a realI18nProviderwith an app bundle in the runtime shapetransformSpecTranslationsproduces.en). The input still holds the source label.ja), not the collapsed designer locale.{ type: 'text', label: 'Employer ID' }exactly as before, and the translation never enters the draft.Ablation (
node scripts/ablation-replace.mjsfrom../objectstack, wrapping the run). The anchor was the hint's guardif (!translated || translated === sourceLabel) return null;, replaced byreturn null;. The anchor went from 1 hit to 0 and the replacement from 0 to 1. The blob went from432eb3a6763btobc44e7122d62, and the marker count on disk was 1. The run gave 4 failed / 3 passed: the four hint pins went red, and the three controls stayed green. The restore set the blob back to the HEAD blob432eb3a6763b,git diff HEADwas empty, andgit statuswas clean.Every command below ran from the worktree root on the final head
bc2bf4c(after mergingorigin/main5aa7f55). The heavy runs went throughos-verify-lock.sh.pnpm --filter @object-ui/app-shell^... run build: exit 0 (run at2ec68bc). After the merge,pnpm --filter @object-ui/data-objectstack run build(the merge changed that package): exit 0.pnpm --filter @object-ui/app-shell type-check(it echoestsc --noEmit && tsc -p tsconfig.test.json): exit 0.tsc -p tsconfig.test.json --listFilesOnlylists the new test file, andObjectFieldInspector.test.tsxas a control.pnpm exec vitest run --maxWorkers=2on 211 files: 211 passed, 2707 tests passed, 1 skipped, exit 0. The files are the wholemetadata-admin/inspectors/directory, every app-shell test that imports the metadata-admin string table, theDataPillar*and Studio tests that mount the field inspector,apps/console'spreview-samples-designer-optionstest, and the test files the merge brought in.pnpm exec vitest run packages/app-shell/(1085 test files) and stopped it myself after 10m33s under the lock, with no result read, because another seat was queued behind it. NOT MEASURED locally. The full package run is CI's.pnpm exec eslinton the three touched source and test files: exit 0, 0 errors. All 11 warnings are existingno-explicit-anyon code this diff does not add to.check:control-bytes,check:test-path-roots,check:changeset-claims,check:pending-changeset-literals,check:i18n-keys,check:i18n-drift,check:i18n-dead-keys,check:i18n-designer-parity,check:new-line-citations, andnode scripts/check-changeset-presence.mjs: all exit 0. Parity: "Every en row has a zh row, and every shared row carries the same placeholders." The new key is not in the dead-keys candidates.Real-browser reading
I read this in the console's preview gallery (
apps/console,vite --port 5297,/preview-gallery.html?only=object), not in Studio against the showcase backend. The sibling../objectstackcheckout has no install or build, and building the showcase backend on this shared box was out of proportion for a p3 hint. So the showcaseshowcase_account.tax_idStudio reading is NOT MEASURED.The run used Chromium (
/opt/pw-browsers/chromium) at 1440×900 against the gallery'ssales_ordersample. The bundleapp.fields.sales_order.amount = 'Order Total'was installed withaddResourceBundleon the provider's own i18next instance, the same callI18nProvidermakes for a bundleloadLanguagefetched.AmountAmountShown as “Order Total” in en: the app’s translation bundle overrides this label.Order TotalOrder TotalAmount (USD)Amount (USD)Order NameOrder NameWith
&locale=zh-CN(the zh designer table over aneni18next session), the hint read在 en 中显示为“Order Total”:应用的翻译包覆盖了此显示名。. That is the Zone 2 hypothesis 3 split, seen in a browser. No page errors.Acceptance notes (seen, not filed)
def.label). This PR only touches the Label input, which is what the claim covers. Carrier: none.InspectorTextFieldhas no description slot, so the hint is not tied to the input througharia-describedby. Adding one would mean editinginspectors/_shared.tsx, which is off this claim's surface. Carrier: none.getI18n()instance was not the instance the tree renders with. A bundle added there never reached the hint, while one added to theI18nextProvider'si18nprop did. My unverified guess is that StrictMode runs the provider'suseMemotwice, and the gallery's inlineconfigmakes each run callcreateI18n. This is a dev harness only. Carrier: none.Generated by Claude Code