Repository navigation
feat(app-shell): edit a Studio translation item as a source-to-translation table with its gaps counted - #30457
Merged
Merged
Conversation
…ation table The table lists a row per string the package declares (the lint walk over the package's declared documents, plus the platform objects it points at), the source text beside the translation, grouped by item, with an untranslated count and filter. Each cell writes the item's JSON at its key, so the saved item and where it is saved are unchanged. The JSON stays as an advanced view. The item list labels a .custom pair's item customer-written. Claude-Session: https://claude.ai/code/session_01WGufzfqCqBH59yrHmuqXH3 Co-authored-by: Claude <noreply@anthropic.com>
… .custom pair with its base The layered read's code layer is what a package declares; the effective layer carries the fields the platform injects into every object. A database-authored object is read from its effective layer less those fields. The platform objects the injected lookups point at (an owner is a user) are still walked. An item opened in a code package's .custom pair is walked over the base package and the pair, and the editor loads the lint walk lazily, as the console build requires. Claude-Session: https://claude.ai/code/session_01WGufzfqCqBH59yrHmuqXH3 Co-authored-by: Claude <noreply@anthropic.com>
Contributor
Author
|
domain:ui#1 · os-support-ai · session_01WGufzfE4V9fzZgJLrLDmMC 维护者速读(席位终稿)
席位核对 · ACCEPT · head
|
This was referenced Nov 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.
Requested by Yibo Wang · project thread
Fixes #30285
Clause-②: no
Metadata-protocol: none
维护者速读
.custom包里的翻译显示为「运行时」,不再显示「代码包」。translation条目,存在同一个地方(只读代码包存在它的.custom包,ADR-0146 D2),没有新路由、新键或新存储。回滚即 revert 本 PR。ui/packages/app-shell/src/views/studio-design/translationTable.ts(行从哪来、怎样算已翻译、怎样读声明)、StudioTranslationTable.tsx(表格本身)、StudioBundleItemEditor.tsx(翻译条目改用表格)。.custom里的一个翻译条目,预期看到计数、分组的对照表、「只看未翻译」开关,没有「尚未注册自定义渲染器」提示。What changes
A
translationitem in Studio now opens on a table for its language, replacing the per-group JSON boxes the form fell back to.collectExpectedEntriesfrom@objectstack/lint(moved there in refactor(lint): move the i18n translatable-key walk from the CLI into @objectstack/lint #30375), the walkos i18n extractandos lint's coverage use, so a row's key is the key the runtime looks up.codelayer, or for a database-authored item its served document without thesystem: truefields the platform injects. It does not use the list read, which is translated into the reader's language and carries the injected owner, tenancy and audit fields. A view is keyed by its bare name, as bundles key it. The platform objects the items point at are walked too, including the lookups the platform injects (an owner is a user). That is the epic comment's case:sys_user,sys_organizationandsys_business_unitlabels ship in a few languages only, and under fr-FR or vi-VN they show as rows to translate. An item opened in a code package's.custompair is walked over the base package and the pair together./i18n/translations/<locale>, and used only when the server answers that language and not a fallback), or when the source is an inline locale map that names the language. The count and the "Untranslated only" filter use that.messages,settingsCommon, and the registry-drivenmetadataFormscopy, which is Studio's own form text and the same for every package. The "no custom renderer registered, editing as JSON" notice no longer appears on this page, and the side preview is not shown for a translation, because the table shows its gaps itself._packageIdis a code package's.custompair (isCustomizationPackagefrom@objectstack/spec/kernel) as customer-written (运行时 / Runtime) instead of shipped in a code package.await import('@objectstack/lint')when a translation item opens, ascapabilityLint.tsdoes. The console build asserts the linter stays out of the eager closure, andvite buildpasses that assertion.engine.studio.translationTable.*strings in English and Chinese. Group headings reuse the existingengine.translationPreview.category.*labels.Console chrome (新建, 保存…) is not a key of a translation item. It comes from the console's own language packs (
messagesmaps toapp.messages), so the table leaves it out. That was the card's first settlement, accepted by the seat.Tests
translationTable.test.ts(new, 10 tests):metadataFormsis left to JSON;sys_userin, a pair is read with its base, a view is keyed by its bare name, the request count, and at most 4 reads in flight.StudioTranslationTable.test.tsx(new, 5 tests), mounted over a mocked metadata client and SDK:N of M untranslatedcount;ResourceListPage.sourceLabel-30285.test.ts(new, 4 tests): a.custompair's item is customer-written, the code package's is not, a doubled or bare suffix is not a pair, and the server's own classification still wins.Ablations, each applied, run red, and restored (tree clean after each):
.customsource-label check removedAcceptance notes
com.example.crm.customitem): the table makes 28 list reads (14 types × base and pair), 28 layered reads (one per item), 3 platform-object reads (sys_user,sys_organization,sys_business_unit) and 1 served-translations read, so 60 requests, at most 4 in flight. There is no per-row request. Reading a pair with its base doubles the list reads. That is the cost of covering objects a customer adds in the pair.effectivelayer carries the injected fields, which produced rows such as "Created At" that no package declares: 508 rows dropped to 402. (2) An item opened from the list lives in the.custompair, which declares nothing of its own, so the table was empty until the pair was read with its base.enandzh-CNonly. A published vi-VN item is served by/i18n/translations/vi-VN(checked:objects.sys_user.label= "Người dùng"), but a metadata read underAccept-Language: vi-VNfalls back toen, so a vi-VN browser still sees "Accounts" (07-console-vi-VN-falls-back-to-en.png). Enabling the language is the deployment's locale setting, outside this card./studio/<base>/metadata/translation/<name>?package=<base>) loads an empty draft, because the editor reads the item at the base. The list links to the pair, so the normal path is unaffected.check:i18nandcheck:i18n-coveragederive their run frompackages/cli/src/**only. Since refactor(lint): move the i18n translatable-key walk from the CLI into @objectstack/lint #30375 moved the walk topackages/lint/src/i18n-walk.ts, an edit there alone does not derive them locally. CI still runs both. The fix is to addpackages/lint/src/i18n-walk.tsto their derivation roster.StudioBundleItemEditor.tsx,TranslationPreview.tsxorResourceListPage.tsx. feat(app-shell): Studio opens an off-nav list view on its object's page, lists only views no dropdown reaches, and reads form views as forms #30401 and feat(app-shell): configure a list view's selection-bar actions in Studio (#30089) #30339 add keys tostudio/en.ts/zh.tselsewhere in those files.check-governed-merges: 0 of 10 paths governed, 1328 ≤ 3000, ordinary queue landing.Verification
app-shell, i18n, type-check, eslint, under os-verify-lock (head c488a30)
dispatch-gates: 35 derived, 35 run, all exit 0 (--ran: 0 NOT-MEASURED, 0 UNRUN)
Live check, zh-CN console, CRM example, built console served with vite preview
Item
crm_vi(vi-VN) incom.example.crm.custom. Shots are in the project'sui-orders/30285-shots/.01-list-zh.png: the list showscrm_viwith source 运行时 and the 新增 mark.02-table-zh.png: 402 条中 401 条未翻译. Groups: 6 CRM objects,sys_business_unit,sys_organization,sys_user, the app, the dashboard, the dataset, 3 positions, 2 permission sets, the page and the flow.objects.crm_account.labelreads 已在此翻译 ("Khách hàng"). No 尚未注册自定义渲染器 notice.03-filter-untranslated-zh.png: 只看未翻译 shows onlymissingrows.04-edited-row-zh.png/04-edited-zh.png: typing "Người dùng" onobjects.sys_user.labelturns the row to here, the count goes to 402 条中 400 条未翻译, and the autosave sendsPUT /api/v1/meta/translation/crm_vi?mode=draft&package=com.example.crm.custom&surface=studio.05-publish-sheet-zh.png/06-published-zh.png: 发布 → 全部发布. Afterwards/api/v1/i18n/translations/vi-VNanswerslocale: vi-VN, withobjects.sys_user.label= "Người dùng" andobjects.crm_account.label= "Khách hàng".07-console-vi-VN-falls-back-to-en.png: see the locale finding above.Generated by Claude Code