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
---------
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,
)}