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
analytics: chart category labels drawn from a select field's options render untranslated on a SAME-object dataset dimension, while the identical values translate on a dotted cross-object one #16773
Split off #16735 (finding 4) by the triage seat. It is its own card because — unlike findings 1–3 — it has no workaround, and because triage's own reading puts its mechanism in packages/services/service-analytics, a different lane from its siblings.
Original provenance: filed from an app repo (objectstack-ai/hotclm, @objectstack/* 17.3.0, @objectstack/console as shipped) after translating it end to end into en + zh-CN — objectstack-ai/hotclm#32, PR objectstack-ai/hotclm#33.
The finding
On dataset-backed charts, category and series labels drawn from a select field's option values render the inline English option label, while the identical values render the translation in the list grid on the same console.
Same option values, same console, same session. Also affects a status funnel (Draft/Submitted/In Review/…) and a currency_code bar (EUR — Euro).
A widget has no authoring surface for category labels, so unlike findings 1–3 this one cannot be worked around. It is the residue left visible on two of that app's three dashboards.
⭐ Triage's own reading — a mechanism the card did not have
The same-object dimension's labels are resolved by packages/services/service-analytics/src/dimension-labels.ts, which reads the option label straight out of the field metadata:
packages/services/service-analytics/src/dimension-labels.ts:32
/** Select options — the value→label source. */
:33 options?: Array<{ value: unknown; label?: string }>;
:146 if (Array.isArray(meta.options) && meta.options.length > 0) {
:148 for (const opt of meta.options) {
:312 if (Array.isArray(meta.options) && meta.options.length > 0) {
:314 for (const opt of meta.options) {
That file consults no translation bundle at all. Measured on origin/main:
⇒ the zero is a reading, not a silence: i18n vocabulary demonstrably reaches this package, and this one file has none of it. So the same-object arm returns opt.label verbatim — the authored English — with nothing in the path that could ever translate it.
⚠️Not verified by triage:why the dotted cross-object arm works. The hypothesis is that a dotted dimension resolves through the object-metadata pipeline, which is translated, so it never reaches this file's option branch. That would explain the correlation exactly, but it is a hypothesis — ⛔ do not build on it without measuring. Establishing which path the dotted arm takes is the first step of this card, because it also names where the fix belongs: teaching this file the bundle, or routing the same-object arm through whatever the dotted arm already uses.
⭐ Prefer the second if it is available. A second copy of "how to translate a select option" is the multi-copy failure mode this repo keeps burning down.
Relationship to #16390 — adjacent, ⛔ neither subsumes the other
#16390 (domain:services, Bug, p2) is about the same file and the same LOOKUP_TYPES neighbourhood: there, user and tree dimensions are not label-resolved at all because LOOKUP_TYPES is a two-member subset of the spec's four-member REFERENCE_VALUE_TYPES.
this card — whether a resolved label is translated (select options resolved, but from raw metadata).
Same file, same lane, no overlap in the change. ⇒ schedule them in the same window so two PRs do not collide on dimension-labels.ts; ⛔ do not merge the cards.
Etiquette note if both land together
#16390's acceptance requires widening LOOKUP_TYPESand the #3602 read-scope resolution together. If this card lands first and teaches the file a bundle, that bundle plumbing must be carried into the widened arms too, or user/tree labels arrive untranslated the day #16390 lands.
Acceptance
A same-object select dimension on a dataset-backed chart renders its option labels in the console's locale, matching what the list grid renders for the identical values.
The dotted cross-object arm is unchanged (it works today — it is the control).
Whatever mechanism is chosen, there is one copy of "translate a select option label", not two.
⚠️ Triage independently verified only the code reading above (dimension-labels.ts reads meta.options[].label and consults no bundle, with a firing control). The browser observations, the object names and the counts are not triage's readings.
⛔ Dedup could not be run from the reporting session: search_issues returned total_count: 0 for the app's own repo even on a control term certainly present in an open issue's title. ⚠️ Re-run the duplicate search at claim.
One app, one console build, one dialect. Re-confirm before acting.
Split off #16735 (finding 4) by the triage seat. It is its own card because — unlike findings 1–3 — it has no workaround, and because triage's own reading puts its mechanism in
packages/services/service-analytics, a different lane from its siblings.Original provenance: filed from an app repo (
objectstack-ai/hotclm,@objectstack/*17.3.0,@objectstack/consoleas shipped) after translating it end to end intoen+zh-CN—objectstack-ai/hotclm#32, PRobjectstack-ai/hotclm#33.The finding
On dataset-backed charts, category and series labels drawn from a
selectfield's option values render the inline English option label, while the identical values render the translation in the list grid on the same console.The correlation is exact and is the useful part:
contract_metrics.directionfield: 'direction'(same object)Purchase/Sales❌payment_metrics.directionfield: 'contract.direction'(dotted, cross-object)Same option values, same console, same session. Also affects a
statusfunnel (Draft/Submitted/In Review/…) and acurrency_codebar (EUR — Euro).A widget has no authoring surface for category labels, so unlike findings 1–3 this one cannot be worked around. It is the residue left visible on two of that app's three dashboards.
⭐ Triage's own reading — a mechanism the card did not have
The same-object dimension's labels are resolved by
packages/services/service-analytics/src/dimension-labels.ts, which reads the option label straight out of the field metadata:That file consults no translation bundle at all. Measured on
origin/main:⇒ the zero is a reading, not a silence: i18n vocabulary demonstrably reaches this package, and this one file has none of it. So the same-object arm returns
opt.labelverbatim — the authored English — with nothing in the path that could ever translate it.⭐ Prefer the second if it is available. A second copy of "how to translate a select option" is the multi-copy failure mode this repo keeps burning down.
Relationship to #16390 — adjacent, ⛔ neither subsumes the other
#16390 (
domain:services,Bug,p2) is about the same file and the sameLOOKUP_TYPESneighbourhood: there,userandtreedimensions are not label-resolved at all becauseLOOKUP_TYPESis a two-member subset of the spec's four-memberREFERENCE_VALUE_TYPES.Different axis:
Same file, same lane, no overlap in the change. ⇒ schedule them in the same window so two PRs do not collide on
dimension-labels.ts; ⛔ do not merge the cards.Etiquette note if both land together
#16390's acceptance requires widening
LOOKUP_TYPESand the #3602 read-scope resolution together. If this card lands first and teaches the file a bundle, that bundle plumbing must be carried into the widened arms too, oruser/treelabels arrive untranslated the day #16390 lands.Acceptance
selectdimension on a dataset-backed chart renders its option labels in the console's locale, matching what the list grid renders for the identical values.Provenance and boundaries
record:details: the #13855sections[].groupreference form crashes the renderer, and the enumeratedfieldsform renders raw field keys instead of declared labels #16695).dimension-labels.tsreadsmeta.options[].labeland consults no bundle, with a firing control). The browser observations, the object names and the counts are not triage's readings.search_issuesreturnedtotal_count: 0for the app's own repo even on a control term certainly present in an open issue's title.Split siblings
_views.VIEW.descriptionis declared, walked and counted as covered but never rendered — plus three surfaces a bundle cannot address at all #16735 — finding 1,_views.VIEW.descriptiondeclared, walked, counted as covered, never rendered.repo:objectui. The one with a gate consequence.walkAddressedPageComponentsmisses a slotted page'sslotsand a tabs node'sitems[].children, anddashboards.NAMEhas noglobalFiltersgroup #16772 — findings 2 and 3, two surfaces a bundle cannot address at all.domain:spec.https://claude.ai/code/session_01SwJQDFKe8tVit3BXQ9EfR5