From 7e48d36c988ed8ef95e4aaceee99620f2d8a7b5a Mon Sep 17 00:00:00 2001 From: Mani bharadwaj <111006838+Manibharadwaj@users.noreply.github.com> Date: Fri, 26 Jun 2026 13:40:55 +0530 Subject: [PATCH] fix(twenty-front): apply object type translations to details panel relation labels (#22090) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem When users customize or translate object type names (e.g. "Company" → "Unternehmen" in German), the translated/customized names do **not** appear in the details panel. The default English names still show instead. This is because the frontend's relation metadata only carried `nameSingular`/`namePlural` (internal API identifiers), not `labelSingular`/`labelPlural` (user-facing display labels). Components that display relation names had no choice but to use the internal identifiers. Fixes #19790 ## Changes ### Data layer — add labels to the pipeline - **GraphQL fragment** (`fragment.ts`): Added `labelSingular`/`labelPlural` to `sourceObjectMetadata` and `targetObjectMetadata` in both `relation` and `morphRelations` - **Type** (`FieldMetadataItemRelation.ts`): Extended the `Pick` type to include `labelSingular`/`labelPlural` - **Field metadata type** (`FieldMetadata.ts`): Added `relationObjectMetadataLabelSingular`/`LabelPlural` to `FieldRelationMetadata` - **Mapping** (`formatFieldMetadataItemAsFieldDefinition.ts`): Maps the new label fields with `label ?? name` fallback for backwards compatibility ### Display layer — use labels for user-facing text - **RecordDetailRelationRecordsListItem**: Uses `relationObjectMetadataLabelSingular` for delete confirmation dialog title, subtitle, and button text (falls back to `nameSingular`) - **RecordDetailRelationRecordsList**: Threads `objectLabelSingular` prop through - **RecordDetailRelationSection**: Passes `labelSingular ?? nameSingular` from the looked-up object metadata - **FieldWidgetRelationCard**: Passes `relationObjectMetadataLabelSingular` from field metadata - **FieldWidgetJunctionRelationCard**: Passes `labelSingular ?? nameSingular` from object metadata lookup - **FieldWidgetMorphRelationCard**: Passes label from morph relation hook result - **useGetMorphRelationRelatedRecordsWithObjectNameSingular**: Carries `labelSingular` from matched morph relation ### Test data - Updated story/mock files with `relationObjectMetadataLabelSingular`/`LabelPlural` fields - Updated `SettingsDataModelRelationFieldPreview` with label fields in morph relation objects ## Design decisions - **Backwards compatible**: All new props are optional. Every display usage uses `label ?? name` fallback, so if `labelSingular` isn't available yet (e.g. before GraphQL regeneration), it falls back to the old behavior - **Lookup vs display separation**: `nameSingular` continues to be used for lookups, routing, and GraphQL queries (it's the identifier). `labelSingular` is only used for user-facing display text - **Minimal scope**: Only changes the display paths identified in the bug report — confirmation dialogs and relation labels in the details panel ## Test plan 1. Set workspace language to a non-English locale (e.g. German) 2. Navigate to a record with relation fields 3. Verify relation section titles and labels show translated names 4. Try to delete a related record — verify the confirmation dialog uses the translated name 5. Switch language back to English — verify everything still works correctly Review in cubic --------- Co-authored-by: Charles Bochet --- .../RecordDetailRelationRecordsListItem.tsx | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationRecordsListItem.tsx b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationRecordsListItem.tsx index 0dd018fd66..2d4684c643 100644 --- a/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationRecordsListItem.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field-list/record-detail-section/relation/components/RecordDetailRelationRecordsListItem.tsx @@ -5,7 +5,6 @@ import { useCallback, useContext } from 'react'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; import { CoreObjectNameSingular } from 'twenty-shared/types'; -import { getObjectTypename } from '@/object-record/cache/utils/getObjectTypename'; import { RecordChip } from '@/object-record/components/RecordChip'; import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord'; import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject'; @@ -110,9 +109,7 @@ export const RecordDetailRelationRecordsListItem = ({ objectNameSingular: relationObjectMetadataNameSingular, }); - const relationObjectTypeName = getObjectTypename( - relationObjectMetadataNameSingular, - ); + const relationObjectLabelSingular = relationObjectMetadataItem.labelSingular; const relationObjectPermissions = useObjectPermissionsForObject( relationObjectMetadataItem.id, @@ -279,17 +276,17 @@ export const RecordDetailRelationRecordsListItem = ({ {createPortal( Are you sure you want to delete this related{' '} - {relationObjectMetadataNameSingular}? + {relationObjectLabelSingular}?
This action will break all its relationships with other objects. } onConfirmClick={handleConfirmDelete} - confirmButtonText={t`Delete ${relationObjectTypeName}`} + confirmButtonText={t`Delete ${relationObjectLabelSingular}`} />, document.body, )}