Found while implementing #7230 (packages/plugins/plugin-audit/src/audit-writers.ts). Filed rather than fixed: #7230's scope is recommendation A's two halves (field label + lookup value), and this is a third change to the same function.
Mechanism
displayFieldValue renders a select/picklist value by scanning field.options[] and returning the matching option's label:
const ov = o && typeof o === 'object' ? (o.value ?? o.name ?? o.label) : o;
if (ov === value) {
const ol = o && typeof o === 'object' ? (o.label ?? o.name ?? ov) : o;
return String(ol);
}
field.options comes from engine.getSchema(name) — the authored metadata, which is locale-independent. The shipped translation bundles carry option labels under objects.[object].fields.[field].options.[value] (see packages/plugins/plugin-audit/src/translations/zh-CN.objects.generated.ts, e.g. sys_audit_log.fields.action.options.create = "创建"), and nothing on this path reads them.
Net effect on a zh-CN workspace, after #7230 lands: the field label is localized and the reference value resolves to a title, but a select value still renders its authored-language label —
阶段: Proposal → Closed Won
— a half-localized string on a fully-localized page. Before #7230 the whole thing was English, so the mixed rendering is new visibility, not a new defect.
Why it is the same class as #7230, and why it is still separate
Same root shape (a display string composed at write time that skips the locale-bound translator), same function, same blast radius — every sys_activity.summary consumer at once: record discussion feed, console home activity, header inbox, the Setup sys_activity list, mobile/REST/SDUI. But it is a distinct decision: the fix has to thread translate and the object name into displayFieldValue itself (today it receives neither, and #7230 deliberately kept it synchronous and translator-free so matchMilestone could keep calling it unchanged).
Suggested shape, if taken
In displayFieldValue's option branch, prefer translate(\objects.${objectName}.fields.${key}.options.${value}`)overo.label, with the authored label as the fallback — mirroring exactly what #7230 did for the field label. matchMilestone`'s call site would need the same two arguments or an explicit opt-out.
Anchors at a768f81a1 (pre-#7230): displayFieldValue audit-writers.ts:308, option branch :310-319.
Refs: #7230, ADR-0053, #3039.
Found while implementing #7230 (
packages/plugins/plugin-audit/src/audit-writers.ts). Filed rather than fixed: #7230's scope is recommendation A's two halves (field label + lookup value), and this is a third change to the same function.Mechanism
displayFieldValuerenders a select/picklist value by scanningfield.options[]and returning the matching option'slabel:field.optionscomes fromengine.getSchema(name)— the authored metadata, which is locale-independent. The shipped translation bundles carry option labels underobjects.[object].fields.[field].options.[value](seepackages/plugins/plugin-audit/src/translations/zh-CN.objects.generated.ts, e.g.sys_audit_log.fields.action.options.create = "创建"), and nothing on this path reads them.Net effect on a zh-CN workspace, after #7230 lands: the field label is localized and the reference value resolves to a title, but a select value still renders its authored-language label —
— a half-localized string on a fully-localized page. Before #7230 the whole thing was English, so the mixed rendering is new visibility, not a new defect.
Why it is the same class as #7230, and why it is still separate
Same root shape (a display string composed at write time that skips the locale-bound translator), same function, same blast radius — every
sys_activity.summaryconsumer at once: record discussion feed, console home activity, header inbox, the Setupsys_activitylist, mobile/REST/SDUI. But it is a distinct decision: the fix has to threadtranslateand the object name intodisplayFieldValueitself (today it receives neither, and #7230 deliberately kept it synchronous and translator-free somatchMilestonecould keep calling it unchanged).Suggested shape, if taken
In
displayFieldValue's option branch, prefertranslate(\objects.${objectName}.fields.${key}.options.${value}`)overo.label, with the authored label as the fallback — mirroring exactly what #7230 did for the field label.matchMilestone`'s call site would need the same two arguments or an explicit opt-out.Anchors at
a768f81a1(pre-#7230):displayFieldValueaudit-writers.ts:308, option branch:310-319.Refs: #7230, ADR-0053, #3039.