You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ViewTabSchema.label is declared as an I18nLabelSchema, whose description promises
"i18n keys are auto-generated by the framework". No such key exists. A view tab's label
is structurally unreachable by translation: there is no slot for it in the translation
schema and no resolver that would read one.
The result is a list-page tab bar that stays in the source language no matter how
complete a locale bundle is.
Why this is now the whole remaining gap downstream
HotCRM has just finished all four of its locales (en, zh-CN, ja-JP, es-ES): objectstack lint reports zero i18n warnings for every one of them, across fields,
options, views, sections, actions, pages, navigation, dashboards and empty states.
The tab bar is the only user-visible surface still in English — and it sits at the top
of every object's list page, directly above content that is translated. A reviewer
opening the Chinese or Japanese app sees "All / Cards / Map / Enterprise / My Accounts /
Renewals / At Risk" above a fully localized grid. There is no authoring workaround: the
bundle has no key to put the translation in.
Evidence
1. The label is declared translatable.packages/spec/src/ui/view.zod.ts:483
exportconstViewTabSchema=lazySchema(()=>strictObject({surface: 'this view tab',history: VIEW_HISTORY,},{name: SnakeCaseIdentifierSchema.describe('Tab identifier (snake_case)'),label: I18nLabelSchema.optional().describe('Display label'),
...
view: z.string().optional().describe('Referenced list view name from listViews'),
packages/spec/src/ui/i18n.zod.ts:46
exportconstI18nLabelSchema=lazySchema(()=>z.string().describe('Display label (plain string; i18n keys are auto-generated by the framework)'));
2. There is no key to translate it into.ObjectTranslationDataSchema
(packages/spec/src/system/translation.zod.ts:143) is a strictObject whose only
grouped members are _views, _actions and _sections. There is no _tabs — and
because it is strictObject, an author cannot add one: it is rejected, not ignored.
3. Nothing resolves it.packages/spec/src/system/i18n-resolver.ts contains no
tab-label resolver; the string tab appears in that file only inside prose comments. resolveViewLabel (line 149) reads objects.<object>._views.<view.name>.label and
nothing else.
Why this may be fixable without a schema change
Every tab in the HotCRM corpus points at a named list view via tabs[].view, and that
view's label is translatable through _views.<name>.label:
tabs[].label is already .optional(). If the console fell back to resolveViewLabel(referenced view) when label is omitted, the whole class would close
with no schema change and no new translation key — downstream apps would just delete
their inline tab labels.
I could not confirm whether that fallback exists. The console/renderer is not in this
repository (apps/ holds only docs), and ViewTabBar appears only in schema comments
and lint rules, never in an implementation. So this is a question for whoever owns the
renderer, not a claim.
If that route is taken, #5164 is a prerequisite to check. It reports that the _views key for a default-only list container is spelled three different ways by the
composer (default), the extractor (list) and the lint rule (either) — so a tab
falling back to such a container would resolve to nothing. HotCRM's tabs all reference
explicitly-named listViews keys and so avoid that case, but a fallback design should
not assume every app does.
Possible resolutions, roughly in order of preference
Add a _tabs group to ObjectTranslationDataSchema plus a resolveTabLabel
helper, mirroring _views / _sections. Explicit and unambiguous, but adds a key for
something the view reference arguably already addresses. Note that tabs may also
carry a filter and no view at all, in which case there is no view to fall back to
— which is an argument for this option over (1).
Document tabs[].label as untranslatable and change it from I18nLabelSchema to
a plain z.string(). Least work, but the tab bar stays monolingual — hard to defend
for a list page's primary navigation.
Whichever way it goes, the I18nLabelSchema description on this field is inaccurate
today and worth correcting either way: no key is auto-generated for it. The same
description is attached to AriaPropsSchema.ariaLabel, which is worth auditing for the
same problem.
Reproduction
Author an object view with a tabs array where each tab has a label and a view.
Provide a complete locale bundle including objects.<object>._views.<name>.label for
every referenced view.
Load the list page with that locale active. Every view's own heading resolves; the tab
bar above it stays in the source language.
ViewTabSchema.labelis declared as anI18nLabelSchema, whose description promises"i18n keys are auto-generated by the framework". No such key exists. A view tab's label
is structurally unreachable by translation: there is no slot for it in the translation
schema and no resolver that would read one.
The result is a list-page tab bar that stays in the source language no matter how
complete a locale bundle is.
Verified against:
9f601e8(main)Downstream: objectstack-ai/hotcrm#661 — 59 tab labels across 15 objects.
Why this is now the whole remaining gap downstream
HotCRM has just finished all four of its locales (
en,zh-CN,ja-JP,es-ES):objectstack lintreports zero i18n warnings for every one of them, across fields,options, views, sections, actions, pages, navigation, dashboards and empty states.
The tab bar is the only user-visible surface still in English — and it sits at the top
of every object's list page, directly above content that is translated. A reviewer
opening the Chinese or Japanese app sees "All / Cards / Map / Enterprise / My Accounts /
Renewals / At Risk" above a fully localized grid. There is no authoring workaround: the
bundle has no key to put the translation in.
Evidence
1. The label is declared translatable.
packages/spec/src/ui/view.zod.ts:483packages/spec/src/ui/i18n.zod.ts:462. There is no key to translate it into.
ObjectTranslationDataSchema(
packages/spec/src/system/translation.zod.ts:143) is astrictObjectwhose onlygrouped members are
_views,_actionsand_sections. There is no_tabs— andbecause it is
strictObject, an author cannot add one: it is rejected, not ignored.3. Nothing resolves it.
packages/spec/src/system/i18n-resolver.tscontains notab-label resolver; the string
tabappears in that file only inside prose comments.resolveViewLabel(line 149) readsobjects.<object>._views.<view.name>.labelandnothing else.
Why this may be fixable without a schema change
Every tab in the HotCRM corpus points at a named list view via
tabs[].view, and thatview's label is translatable through
_views.<name>.label:tabs[].labelis already.optional(). If the console fell back toresolveViewLabel(referenced view)whenlabelis omitted, the whole class would closewith no schema change and no new translation key — downstream apps would just delete
their inline tab labels.
I could not confirm whether that fallback exists. The console/renderer is not in this
repository (
apps/holds onlydocs), andViewTabBarappears only in schema commentsand lint rules, never in an implementation. So this is a question for whoever owns the
renderer, not a claim.
If that route is taken, #5164 is a prerequisite to check. It reports that the
_viewskey for a default-only list container is spelled three different ways by thecomposer (
default), the extractor (list) and the lint rule (either) — so a tabfalling back to such a container would resolve to nothing. HotCRM's tabs all reference
explicitly-named
listViewskeys and so avoid that case, but a fallback design shouldnot assume every app does.
Possible resolutions, roughly in order of preference
tabs[].labelis absent. No schema change; the downstream fix is deleting inline labels. Needs the
renderer to confirm, and interacts with
_viewstranslation keys have three producers that disagree on the spelling — a default-onlylistcontainer can never resolve #5164._tabsgroup toObjectTranslationDataSchemaplus aresolveTabLabelhelper, mirroring
_views/_sections. Explicit and unambiguous, but adds a key forsomething the
viewreference arguably already addresses. Note that tabs may alsocarry a
filterand noviewat all, in which case there is no view to fall back to— which is an argument for this option over (1).
tabs[].labelas untranslatable and change it fromI18nLabelSchematoa plain
z.string(). Least work, but the tab bar stays monolingual — hard to defendfor a list page's primary navigation.
Whichever way it goes, the
I18nLabelSchemadescription on this field is inaccuratetoday and worth correcting either way: no key is auto-generated for it. The same
description is attached to
AriaPropsSchema.ariaLabel, which is worth auditing for thesame problem.
Reproduction
tabsarray where each tab has alabeland aview.objects.<object>._views.<name>.labelforevery referenced view.
bar above it stays in the source language.
Related
_viewstranslation keys have three producers that disagree on the spelling — a default-onlylistcontainer can never resolve #5164 —_viewskey spelling disagreement; a prerequisite for resolution (1).AddressFieldsub-labels and placeholders are hardcoded English literals — an address field is untranslatable on any non-English console #5083 —AddressFieldsub-labels are hardcoded English literals. Same class of defect(a surface with no reachable translation key) on a different component.