Compare commits

...
Author SHA1 Message Date
Félix MalfaitandClaude Opus 4.6 4b93c277bd fix: stop "Uncompiled message detected" log flood from standard label translation
Resolvers re-hashed English labels via generateMessageId() and called i18n._()
against catalogs missing those ids, triggering >500 warnings/sec on self-hosted
instances (#19423).

Stores real MessageDescriptors (with extractor-computed ids) in a message-keyed
registry populated as a side effect of i18nLabel(msg`...`). Resolvers look up
the descriptor and only call i18n._() when the catalog actually has the id,
otherwise fall back to descriptor.message.

A module-load pass with placeholder args runs the standard object/field
builders once at boot so the registry is populated even on server restart
(workspace sync only runs builders for new workspaces).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-04-08 14:13:45 +02:00
15 changed files with 329 additions and 600 deletions
@@ -39,6 +39,7 @@ import { messages as ukMessages } from 'src/engine/core-modules/i18n/locales/gen
import { messages as viMessages } from 'src/engine/core-modules/i18n/locales/generated/vi-VN';
import { messages as zhHansMessages } from 'src/engine/core-modules/i18n/locales/generated/zh-CN';
import { messages as zhHantMessages } from 'src/engine/core-modules/i18n/locales/generated/zh-TW';
import 'src/engine/workspace-manager/twenty-standard-application/utils/populate-standard-metadata-descriptor-registry';
@Injectable()
export class I18nService implements OnModuleInit {
@@ -0,0 +1,15 @@
import { type MessageDescriptor } from '@lingui/core';
import { standardMetadataDescriptorByMessage } from 'src/engine/core-modules/i18n/standard-metadata-descriptor-registry/standard-metadata-descriptor-by-message.state';
export const rememberStandardMetadataDescriptor = (
descriptor: MessageDescriptor,
): void => {
const message = descriptor.message;
if (message === undefined || message === '') {
return;
}
standardMetadataDescriptorByMessage.set(message, descriptor);
};
@@ -0,0 +1,6 @@
import { type MessageDescriptor } from '@lingui/core';
export const standardMetadataDescriptorByMessage = new Map<
string,
MessageDescriptor
>();
@@ -0,0 +1,28 @@
import { type I18n } from '@lingui/core';
import { standardMetadataDescriptorByMessage } from 'src/engine/core-modules/i18n/standard-metadata-descriptor-registry/standard-metadata-descriptor-by-message.state';
// Skips Lingui's `_()` when the catalog is missing the id, which would
// otherwise trigger "Uncompiled message detected" warnings.
export const translateStandardMetadataLabel = (
i18n: I18n,
label: string | null | undefined,
): string | undefined => {
if (label == null || label === '') {
return undefined;
}
const descriptor = standardMetadataDescriptorByMessage.get(label);
if (descriptor === undefined) {
return undefined;
}
const id = descriptor.id;
if (typeof id === 'string' && i18n.messages?.[id] !== undefined) {
return i18n._(descriptor);
}
return descriptor.message;
};
@@ -1,11 +0,0 @@
import crypto from 'crypto';
const UNIT_SEPARATOR = '\u001F';
export function generateMessageId(msg: string, context = '') {
return crypto
.createHash('sha256')
.update(msg + UNIT_SEPARATOR + (context || ''))
.digest('base64')
.slice(0, 6);
}
@@ -1,15 +1,36 @@
import { type I18n } from '@lingui/core';
import { SOURCE_LOCALE } from 'twenty-shared/translations';
import { generateMessageId } from 'src/engine/core-modules/i18n/utils/generateMessageId';
import { translateStandardMetadataLabel } from 'src/engine/core-modules/i18n/standard-metadata-descriptor-registry/translate-standard-metadata-label.util';
import { type FieldMetadataDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto';
import { resolveFieldMetadataStandardOverride } from 'src/engine/metadata-modules/field-metadata/utils/resolve-field-metadata-standard-override.util';
jest.mock('src/engine/core-modules/i18n/utils/generateMessageId');
jest.mock(
'src/engine/core-modules/i18n/standard-metadata-descriptor-registry/translate-standard-metadata-label.util',
() => ({
translateStandardMetadataLabel: jest.fn(),
}),
);
const mockGenerateMessageId = generateMessageId as jest.MockedFunction<
typeof generateMessageId
const mockTranslateStandardMetadataLabel =
translateStandardMetadataLabel as jest.MockedFunction<
typeof translateStandardMetadataLabel
>;
type FieldFixture = Pick<
FieldMetadataDTO,
'label' | 'description' | 'icon' | 'isCustom' | 'standardOverrides'
>;
const baseFixture = (overrides: Partial<FieldFixture> = {}): FieldFixture => ({
label: 'Standard Label',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
standardOverrides: undefined,
...overrides,
});
describe('resolveFieldMetadataStandardOverride', () => {
let mockI18n: jest.Mocked<I18n>;
@@ -18,17 +39,15 @@ describe('resolveFieldMetadataStandardOverride', () => {
mockI18n = {
_: jest.fn(),
} as unknown as jest.Mocked<I18n>;
mockTranslateStandardMetadataLabel.mockReturnValue(undefined);
});
describe('Custom fields', () => {
it('should return the field value for custom label field', () => {
const fieldMetadata = {
const fieldMetadata = baseFixture({
label: 'Custom Label',
description: 'Custom Description',
icon: 'custom-icon',
isCustom: true,
standardOverrides: undefined,
};
});
const result = resolveFieldMetadataStandardOverride(
fieldMetadata,
@@ -41,13 +60,10 @@ describe('resolveFieldMetadataStandardOverride', () => {
});
it('should return the field value for custom description field', () => {
const fieldMetadata = {
label: 'Custom Label',
const fieldMetadata = baseFixture({
description: 'Custom Description',
icon: 'custom-icon',
isCustom: true,
standardOverrides: undefined,
};
});
const result = resolveFieldMetadataStandardOverride(
fieldMetadata,
@@ -60,13 +76,10 @@ describe('resolveFieldMetadataStandardOverride', () => {
});
it('should return the field value for custom icon field', () => {
const fieldMetadata = {
label: 'Custom Label',
description: 'Custom Description',
const fieldMetadata = baseFixture({
icon: 'custom-icon',
isCustom: true,
standardOverrides: undefined,
};
});
const result = resolveFieldMetadataStandardOverride(
fieldMetadata,
@@ -81,15 +94,9 @@ describe('resolveFieldMetadataStandardOverride', () => {
describe('Standard fields - Icon overrides', () => {
it('should return override icon when available for standard field', () => {
const fieldMetadata = {
label: 'Standard Label',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
standardOverrides: {
icon: 'override-icon',
},
};
const fieldMetadata = baseFixture({
standardOverrides: { icon: 'override-icon' },
});
const result = resolveFieldMetadataStandardOverride(
fieldMetadata,
@@ -104,11 +111,7 @@ describe('resolveFieldMetadataStandardOverride', () => {
describe('Standard fields - Translation overrides', () => {
it('should return translation override when available for non-icon fields', () => {
const fieldMetadata = {
label: 'Standard Label',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
const fieldMetadata = baseFixture({
standardOverrides: {
translations: {
'fr-FR': {
@@ -117,7 +120,7 @@ describe('resolveFieldMetadataStandardOverride', () => {
},
},
},
};
});
expect(
resolveFieldMetadataStandardOverride(
@@ -138,22 +141,13 @@ describe('resolveFieldMetadataStandardOverride', () => {
});
it('should fallback when translation override is not available for the locale', () => {
const fieldMetadata = {
label: 'Standard Label',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
const fieldMetadata = baseFixture({
standardOverrides: {
translations: {
'es-ES': {
label: 'Etiqueta en español',
},
'es-ES': { label: 'Etiqueta en español' },
},
},
};
mockGenerateMessageId.mockReturnValue('generated-message-id');
mockI18n._.mockReturnValue('generated-message-id');
});
const result = resolveFieldMetadataStandardOverride(
fieldMetadata,
@@ -166,22 +160,13 @@ describe('resolveFieldMetadataStandardOverride', () => {
});
it('should fallback when translation override is not available for the labelKey', () => {
const fieldMetadata = {
label: 'Standard Label',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
const fieldMetadata = baseFixture({
standardOverrides: {
translations: {
'fr-FR': {
label: 'Libellé traduit',
},
'fr-FR': { label: 'Libellé traduit' },
},
},
};
mockGenerateMessageId.mockReturnValue('generated-message-id');
mockI18n._.mockReturnValue('generated-message-id');
});
const result = resolveFieldMetadataStandardOverride(
fieldMetadata,
@@ -194,22 +179,13 @@ describe('resolveFieldMetadataStandardOverride', () => {
});
it('should not use translation overrides when locale is undefined', () => {
const fieldMetadata = {
label: 'Standard Label',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
const fieldMetadata = baseFixture({
standardOverrides: {
translations: {
'fr-FR': {
label: 'Libellé traduit',
},
'fr-FR': { label: 'Libellé traduit' },
},
},
};
mockGenerateMessageId.mockReturnValue('generated-message-id');
mockI18n._.mockReturnValue('generated-message-id');
});
const result = resolveFieldMetadataStandardOverride(
fieldMetadata,
@@ -224,17 +200,13 @@ describe('resolveFieldMetadataStandardOverride', () => {
describe('Standard fields - SOURCE_LOCALE overrides', () => {
it('should return direct override for SOURCE_LOCALE when available', () => {
const fieldMetadata = {
label: 'Standard Label',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
const fieldMetadata = baseFixture({
standardOverrides: {
label: 'Overridden Label',
description: 'Overridden Description',
icon: 'overridden-icon',
},
};
});
expect(
resolveFieldMetadataStandardOverride(
@@ -263,18 +235,9 @@ describe('resolveFieldMetadataStandardOverride', () => {
});
it('should not use direct override for non-SOURCE_LOCALE', () => {
const fieldMetadata = {
label: 'Standard Label',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
standardOverrides: {
label: 'Overridden Label',
},
};
mockGenerateMessageId.mockReturnValue('generated-message-id');
mockI18n._.mockReturnValue('generated-message-id');
const fieldMetadata = baseFixture({
standardOverrides: { label: 'Overridden Label' },
});
const result = resolveFieldMetadataStandardOverride(
fieldMetadata,
@@ -287,18 +250,9 @@ describe('resolveFieldMetadataStandardOverride', () => {
});
it('should not use empty string override for SOURCE_LOCALE', () => {
const fieldMetadata = {
label: 'Standard Label',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
standardOverrides: {
label: '',
},
};
mockGenerateMessageId.mockReturnValue('generated-message-id');
mockI18n._.mockReturnValue('generated-message-id');
const fieldMetadata = baseFixture({
standardOverrides: { label: '' },
});
const result = resolveFieldMetadataStandardOverride(
fieldMetadata,
@@ -311,18 +265,9 @@ describe('resolveFieldMetadataStandardOverride', () => {
});
it('should not use undefined override for SOURCE_LOCALE', () => {
const fieldMetadata = {
label: 'Standard Label',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
standardOverrides: {
label: undefined,
},
};
mockGenerateMessageId.mockReturnValue('generated-message-id');
mockI18n._.mockReturnValue('generated-message-id');
const fieldMetadata = baseFixture({
standardOverrides: { label: undefined },
});
const result = resolveFieldMetadataStandardOverride(
fieldMetadata,
@@ -335,47 +280,31 @@ describe('resolveFieldMetadataStandardOverride', () => {
});
});
describe('Standard fields - Auto translation fallback', () => {
it('should return translated message when translation is available', () => {
const fieldMetadata = {
label: 'Standard Label',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
standardOverrides: undefined,
};
mockGenerateMessageId.mockReturnValue('standard.label.message.id');
mockI18n._.mockReturnValue('Libellé traduit automatiquement');
describe('Standard fields - Registry-based translation', () => {
it('should return translated label when the registry has the descriptor', () => {
mockTranslateStandardMetadataLabel.mockReturnValue(
'Libellé traduit automatiquement',
);
const result = resolveFieldMetadataStandardOverride(
fieldMetadata,
baseFixture(),
'label',
'fr-FR',
mockI18n,
);
expect(mockGenerateMessageId).toHaveBeenCalledWith('Standard Label');
expect(mockI18n._).toHaveBeenCalledWith('standard.label.message.id');
expect(mockTranslateStandardMetadataLabel).toHaveBeenCalledWith(
mockI18n,
'Standard Label',
);
expect(result).toBe('Libellé traduit automatiquement');
});
it('should return original field value when no translation is found', () => {
const fieldMetadata = {
label: 'Standard Label',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
standardOverrides: undefined,
};
const messageId = 'standard.label.message.id';
mockGenerateMessageId.mockReturnValue(messageId);
mockI18n._.mockReturnValue(messageId);
it('should return original field value when registry has no descriptor', () => {
mockTranslateStandardMetadataLabel.mockReturnValue(undefined);
const result = resolveFieldMetadataStandardOverride(
fieldMetadata,
baseFixture(),
'label',
'fr-FR',
mockI18n,
@@ -387,20 +316,14 @@ describe('resolveFieldMetadataStandardOverride', () => {
describe('Priority order - Standard fields', () => {
it('should prioritize translation override over SOURCE_LOCALE override for non-SOURCE_LOCALE', () => {
const fieldMetadata = {
label: 'Standard Label',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
const fieldMetadata = baseFixture({
standardOverrides: {
label: 'Source Override',
translations: {
'fr-FR': {
label: 'Translation Override',
},
'fr-FR': { label: 'Translation Override' },
},
},
};
});
const result = resolveFieldMetadataStandardOverride(
fieldMetadata,
@@ -410,20 +333,13 @@ describe('resolveFieldMetadataStandardOverride', () => {
);
expect(result).toBe('Translation Override');
expect(mockGenerateMessageId).not.toHaveBeenCalled();
expect(mockI18n._).not.toHaveBeenCalled();
expect(mockTranslateStandardMetadataLabel).not.toHaveBeenCalled();
});
it('should prioritize SOURCE_LOCALE override over auto translation for SOURCE_LOCALE', () => {
const fieldMetadata = {
label: 'Standard Label',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
standardOverrides: {
label: 'Source Override',
},
};
const fieldMetadata = baseFixture({
standardOverrides: { label: 'Source Override' },
});
const result = resolveFieldMetadataStandardOverride(
fieldMetadata,
@@ -433,32 +349,20 @@ describe('resolveFieldMetadataStandardOverride', () => {
);
expect(result).toBe('Source Override');
expect(mockGenerateMessageId).not.toHaveBeenCalled();
expect(mockI18n._).not.toHaveBeenCalled();
expect(mockTranslateStandardMetadataLabel).not.toHaveBeenCalled();
});
it('should use auto translation when no overrides are available', () => {
const fieldMetadata = {
label: 'Standard Label',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
standardOverrides: {},
};
mockGenerateMessageId.mockReturnValue('auto.translation.id');
mockI18n._.mockReturnValue('Auto Translated Label');
it('should use registry translation when no overrides are available', () => {
mockTranslateStandardMetadataLabel.mockReturnValue('Auto Translated Label');
const result = resolveFieldMetadataStandardOverride(
fieldMetadata,
baseFixture({ standardOverrides: {} }),
'label',
'de-DE',
mockI18n,
);
expect(result).toBe('Auto Translated Label');
expect(mockGenerateMessageId).toHaveBeenCalledWith('Standard Label');
expect(mockI18n._).toHaveBeenCalledWith('auto.translation.id');
});
});
});
@@ -3,10 +3,9 @@ import { isNonEmptyString } from '@sniptt/guards';
import { type APP_LOCALES, SOURCE_LOCALE } from 'twenty-shared/translations';
import { isDefined } from 'twenty-shared/utils';
import { generateMessageId } from 'src/engine/core-modules/i18n/utils/generateMessageId';
import { translateStandardMetadataLabel } from 'src/engine/core-modules/i18n/standard-metadata-descriptor-registry/translate-standard-metadata-label.util';
import { type FieldMetadataDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto';
// TODO simplify
export const resolveFieldMetadataStandardOverride = (
fieldMetadata: Pick<
FieldMetadataDTO,
@@ -16,24 +15,22 @@ export const resolveFieldMetadataStandardOverride = (
locale: keyof typeof APP_LOCALES | undefined,
i18nInstance: I18n,
): string => {
const baseValue = fieldMetadata[labelKey] ?? '';
if (fieldMetadata.isCustom) {
return fieldMetadata[labelKey] ?? '';
return baseValue;
}
if (labelKey === 'icon' && isDefined(fieldMetadata.standardOverrides?.icon)) {
return fieldMetadata.standardOverrides.icon;
if (labelKey === 'icon') {
return fieldMetadata.standardOverrides?.icon ?? baseValue;
}
if (
isDefined(fieldMetadata.standardOverrides?.translations) &&
isDefined(locale) &&
labelKey !== 'icon'
) {
const translationValue =
fieldMetadata.standardOverrides.translations[locale]?.[labelKey];
if (isDefined(locale)) {
const translationOverride =
fieldMetadata.standardOverrides?.translations?.[locale]?.[labelKey];
if (isDefined(translationValue)) {
return translationValue;
if (isDefined(translationOverride)) {
return translationOverride;
}
}
@@ -44,13 +41,5 @@ export const resolveFieldMetadataStandardOverride = (
return fieldMetadata.standardOverrides[labelKey] ?? '';
}
const messageId = generateMessageId(fieldMetadata[labelKey] ?? '');
const translatedMessage = i18nInstance._(messageId);
if (translatedMessage === messageId) {
return fieldMetadata[labelKey] ?? '';
}
return translatedMessage;
return translateStandardMetadataLabel(i18nInstance, baseValue) ?? baseValue;
};
@@ -1,16 +1,46 @@
import { type I18n } from '@lingui/core';
import { SOURCE_LOCALE } from 'twenty-shared/translations';
import { generateMessageId } from 'src/engine/core-modules/i18n/utils/generateMessageId';
import { translateStandardMetadataLabel } from 'src/engine/core-modules/i18n/standard-metadata-descriptor-registry/translate-standard-metadata-label.util';
import { type ObjectMetadataDTO } from 'src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto';
import { resolveObjectMetadataStandardOverride } from 'src/engine/metadata-modules/object-metadata/utils/resolve-object-metadata-standard-override.util';
jest.mock('src/engine/core-modules/i18n/utils/generateMessageId');
jest.mock(
'src/engine/core-modules/i18n/standard-metadata-descriptor-registry/translate-standard-metadata-label.util',
() => ({
translateStandardMetadataLabel: jest.fn(),
}),
);
const mockGenerateMessageId = generateMessageId as jest.MockedFunction<
typeof generateMessageId
const mockTranslateStandardMetadataLabel =
translateStandardMetadataLabel as jest.MockedFunction<
typeof translateStandardMetadataLabel
>;
type ObjectFixture = Pick<
ObjectMetadataDTO,
| 'color'
| 'labelPlural'
| 'labelSingular'
| 'description'
| 'icon'
| 'isCustom'
| 'standardOverrides'
>;
const baseFixture = (
overrides: Partial<ObjectFixture> = {},
): ObjectFixture => ({
labelSingular: 'Standard Label',
labelPlural: 'Standard Labels',
description: 'Standard Description',
icon: 'default-icon',
color: 'blue',
isCustom: false,
standardOverrides: undefined,
...overrides,
});
describe('resolveObjectMetadataStandardOverride', () => {
let mockI18n: jest.Mocked<I18n>;
@@ -19,28 +49,15 @@ describe('resolveObjectMetadataStandardOverride', () => {
mockI18n = {
_: jest.fn(),
} as unknown as jest.Mocked<I18n>;
mockTranslateStandardMetadataLabel.mockReturnValue(undefined);
});
describe('Custom objects', () => {
it('should return the object value for custom labelSingular object', () => {
const objectMetadata = {
const objectMetadata = baseFixture({
labelSingular: 'My Custom',
labelPlural: 'My Customs',
description: 'Custom Description',
icon: 'custom-icon',
color: 'blue',
isCustom: true,
standardOverrides: undefined,
} satisfies Pick<
ObjectMetadataDTO,
| 'color'
| 'labelPlural'
| 'labelSingular'
| 'description'
| 'icon'
| 'isCustom'
| 'standardOverrides'
>;
});
const result = resolveObjectMetadataStandardOverride(
objectMetadata,
@@ -53,24 +70,10 @@ describe('resolveObjectMetadataStandardOverride', () => {
});
it('should return the object value for custom description object', () => {
const objectMetadata = {
labelSingular: 'My Custom',
labelPlural: 'My Customs',
const objectMetadata = baseFixture({
description: 'Custom Description',
icon: 'custom-icon',
color: 'blue',
isCustom: true,
standardOverrides: undefined,
} satisfies Pick<
ObjectMetadataDTO,
| 'color'
| 'labelPlural'
| 'labelSingular'
| 'description'
| 'icon'
| 'isCustom'
| 'standardOverrides'
>;
});
const result = resolveObjectMetadataStandardOverride(
objectMetadata,
@@ -83,24 +86,10 @@ describe('resolveObjectMetadataStandardOverride', () => {
});
it('should return the object value for custom icon object', () => {
const objectMetadata = {
labelSingular: 'My Custom',
labelPlural: 'My Customs',
description: 'Custom Description',
const objectMetadata = baseFixture({
icon: 'custom-icon',
color: 'blue',
isCustom: true,
standardOverrides: undefined,
} satisfies Pick<
ObjectMetadataDTO,
| 'color'
| 'labelPlural'
| 'labelSingular'
| 'description'
| 'icon'
| 'isCustom'
| 'standardOverrides'
>;
});
const result = resolveObjectMetadataStandardOverride(
objectMetadata,
@@ -113,24 +102,10 @@ describe('resolveObjectMetadataStandardOverride', () => {
});
it('should return the object value for custom color object', () => {
const objectMetadata = {
labelSingular: 'My Custom',
labelPlural: 'My Customs',
description: 'Custom Description',
icon: 'custom-icon',
const objectMetadata = baseFixture({
color: 'green',
isCustom: true,
standardOverrides: undefined,
} satisfies Pick<
ObjectMetadataDTO,
| 'color'
| 'labelPlural'
| 'labelSingular'
| 'description'
| 'icon'
| 'isCustom'
| 'standardOverrides'
>;
});
const result = resolveObjectMetadataStandardOverride(
objectMetadata,
@@ -145,16 +120,9 @@ describe('resolveObjectMetadataStandardOverride', () => {
describe('Standard objects - Icon overrides', () => {
it('should return override icon when available for standard object', () => {
const objectMetadata = {
labelSingular: 'My Custom',
labelPlural: 'My Customs',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
standardOverrides: {
icon: 'override-icon',
},
};
const objectMetadata = baseFixture({
standardOverrides: { icon: 'override-icon' },
});
const result = resolveObjectMetadataStandardOverride(
objectMetadata,
@@ -169,17 +137,9 @@ describe('resolveObjectMetadataStandardOverride', () => {
describe('Standard objects - Color overrides', () => {
it('should return override color when available for standard object', () => {
const objectMetadata = {
labelSingular: 'Company',
labelPlural: 'Companies',
description: 'Standard Description',
icon: 'default-icon',
color: 'blue',
isCustom: false,
standardOverrides: {
color: 'red',
},
};
const objectMetadata = baseFixture({
standardOverrides: { color: 'red' },
});
const result = resolveObjectMetadataStandardOverride(
objectMetadata,
@@ -192,18 +152,7 @@ describe('resolveObjectMetadataStandardOverride', () => {
});
it('should return base color when no override exists for standard object', () => {
const objectMetadata = {
labelSingular: 'Company',
labelPlural: 'Companies',
description: 'Standard Description',
icon: 'default-icon',
color: 'blue',
isCustom: false,
standardOverrides: undefined,
};
mockGenerateMessageId.mockReturnValue('generated-message-id');
mockI18n._.mockReturnValue('generated-message-id');
const objectMetadata = baseFixture();
const result = resolveObjectMetadataStandardOverride(
objectMetadata,
@@ -218,12 +167,7 @@ describe('resolveObjectMetadataStandardOverride', () => {
describe('Standard objects - Translation overrides', () => {
it('should return translation override when available for non-icon objects', () => {
const objectMetadata = {
labelSingular: 'Standard Label',
labelPlural: 'Standard Labels',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
const objectMetadata = baseFixture({
standardOverrides: {
translations: {
'fr-FR': {
@@ -233,7 +177,7 @@ describe('resolveObjectMetadataStandardOverride', () => {
},
},
},
};
});
expect(
resolveObjectMetadataStandardOverride(
@@ -262,12 +206,7 @@ describe('resolveObjectMetadataStandardOverride', () => {
});
it('should fallback when translation override is not available for the locale', () => {
const objectMetadata = {
labelSingular: 'Standard Label',
labelPlural: 'Standard Labels',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
const objectMetadata = baseFixture({
standardOverrides: {
translations: {
'es-ES': {
@@ -277,10 +216,7 @@ describe('resolveObjectMetadataStandardOverride', () => {
},
},
},
};
mockGenerateMessageId.mockReturnValue('generated-message-id');
mockI18n._.mockReturnValue('generated-message-id');
});
const result = resolveObjectMetadataStandardOverride(
objectMetadata,
@@ -293,12 +229,7 @@ describe('resolveObjectMetadataStandardOverride', () => {
});
it('should fallback when translation override is not available for the labelKey', () => {
const objectMetadata = {
labelSingular: 'Standard Label',
labelPlural: 'Standard Labels',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
const objectMetadata = baseFixture({
standardOverrides: {
translations: {
'fr-FR': {
@@ -307,10 +238,7 @@ describe('resolveObjectMetadataStandardOverride', () => {
},
},
},
};
mockGenerateMessageId.mockReturnValue('generated-message-id');
mockI18n._.mockReturnValue('generated-message-id');
});
const result = resolveObjectMetadataStandardOverride(
objectMetadata,
@@ -323,12 +251,7 @@ describe('resolveObjectMetadataStandardOverride', () => {
});
it('should not use translation overrides when locale is undefined', () => {
const objectMetadata = {
labelSingular: 'Standard Label',
labelPlural: 'Standard Labels',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
const objectMetadata = baseFixture({
standardOverrides: {
translations: {
'fr-FR': {
@@ -338,10 +261,7 @@ describe('resolveObjectMetadataStandardOverride', () => {
},
},
},
};
mockGenerateMessageId.mockReturnValue('generated-message-id');
mockI18n._.mockReturnValue('generated-message-id');
});
const result = resolveObjectMetadataStandardOverride(
objectMetadata,
@@ -356,19 +276,14 @@ describe('resolveObjectMetadataStandardOverride', () => {
describe('Standard objects - SOURCE_LOCALE overrides', () => {
it('should return direct override for SOURCE_LOCALE when available', () => {
const objectMetadata = {
labelSingular: 'Standard Label',
labelPlural: 'Standard Labels',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
const objectMetadata = baseFixture({
standardOverrides: {
labelSingular: 'Overridden Label',
labelPlural: 'Overridden Labels',
description: 'Overridden Description',
icon: 'overridden-icon',
},
};
});
expect(
resolveObjectMetadataStandardOverride(
@@ -405,17 +320,12 @@ describe('resolveObjectMetadataStandardOverride', () => {
});
it('should use direct override for non-SOURCE_LOCALE', () => {
const objectMetadata = {
labelSingular: 'Standard Label',
labelPlural: 'Standard Labels',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
const objectMetadata = baseFixture({
standardOverrides: {
labelSingular: 'Overridden Label',
labelPlural: 'Overridden Labels',
},
};
});
const result = resolveObjectMetadataStandardOverride(
objectMetadata,
@@ -428,19 +338,9 @@ describe('resolveObjectMetadataStandardOverride', () => {
});
it('should not use undefined override for SOURCE_LOCALE', () => {
const objectMetadata = {
labelSingular: 'Standard Label',
labelPlural: 'Standard Labels',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
standardOverrides: {
labelSingular: undefined,
},
};
mockGenerateMessageId.mockReturnValue('generated-message-id');
mockI18n._.mockReturnValue('generated-message-id');
const objectMetadata = baseFixture({
standardOverrides: { labelSingular: undefined },
});
const result = resolveObjectMetadataStandardOverride(
objectMetadata,
@@ -453,49 +353,31 @@ describe('resolveObjectMetadataStandardOverride', () => {
});
});
describe('Standard objects - Auto translation fallback', () => {
it('should return translated message when translation is available', () => {
const objectMetadata = {
labelSingular: 'Standard Label',
labelPlural: 'Standard Labels',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
standardOverrides: undefined,
};
mockGenerateMessageId.mockReturnValue('standard.label.message.id');
mockI18n._.mockReturnValue('Libellé traduit automatiquement');
describe('Standard objects - Registry-based translation', () => {
it('should return translated label when the registry has the descriptor', () => {
mockTranslateStandardMetadataLabel.mockReturnValue(
'Libellé traduit automatiquement',
);
const result = resolveObjectMetadataStandardOverride(
objectMetadata,
baseFixture(),
'labelSingular',
'fr-FR',
mockI18n,
);
expect(mockGenerateMessageId).toHaveBeenCalledWith('Standard Label');
expect(mockI18n._).toHaveBeenCalledWith('standard.label.message.id');
expect(mockTranslateStandardMetadataLabel).toHaveBeenCalledWith(
mockI18n,
'Standard Label',
);
expect(result).toBe('Libellé traduit automatiquement');
});
it('should return original object value when no translation is found', () => {
const objectMetadata = {
labelSingular: 'Standard Label',
labelPlural: 'Standard Labels',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
standardOverrides: undefined,
};
const messageId = 'standard.label.message.id';
mockGenerateMessageId.mockReturnValue(messageId);
mockI18n._.mockReturnValue(messageId);
it('should fall back to original label when registry has no descriptor', () => {
mockTranslateStandardMetadataLabel.mockReturnValue(undefined);
const result = resolveObjectMetadataStandardOverride(
objectMetadata,
baseFixture(),
'labelSingular',
'fr-FR',
mockI18n,
@@ -507,12 +389,7 @@ describe('resolveObjectMetadataStandardOverride', () => {
describe('Priority order - Standard objects', () => {
it('should prioritize translation override over SOURCE_LOCALE override for non-SOURCE_LOCALE', () => {
const objectMetadata = {
labelSingular: 'Standard Label',
labelPlural: 'Standard Labels',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
const objectMetadata = baseFixture({
standardOverrides: {
labelSingular: 'Source Override',
labelPlural: 'Source Overrides',
@@ -523,7 +400,7 @@ describe('resolveObjectMetadataStandardOverride', () => {
},
},
},
};
});
const result = resolveObjectMetadataStandardOverride(
objectMetadata,
@@ -533,22 +410,16 @@ describe('resolveObjectMetadataStandardOverride', () => {
);
expect(result).toBe('Translation Override');
expect(mockGenerateMessageId).not.toHaveBeenCalled();
expect(mockI18n._).not.toHaveBeenCalled();
expect(mockTranslateStandardMetadataLabel).not.toHaveBeenCalled();
});
it('should prioritize SOURCE_LOCALE override over auto translation for SOURCE_LOCALE', () => {
const objectMetadata = {
labelSingular: 'Standard Label',
labelPlural: 'Standard Labels',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
const objectMetadata = baseFixture({
standardOverrides: {
labelSingular: 'Source Override',
labelPlural: 'Source Overrides',
},
};
});
const result = resolveObjectMetadataStandardOverride(
objectMetadata,
@@ -558,48 +429,28 @@ describe('resolveObjectMetadataStandardOverride', () => {
);
expect(result).toBe('Source Override');
expect(mockGenerateMessageId).not.toHaveBeenCalled();
expect(mockI18n._).not.toHaveBeenCalled();
expect(mockTranslateStandardMetadataLabel).not.toHaveBeenCalled();
});
it('should use auto translation when no overrides are available', () => {
const objectMetadata = {
labelSingular: 'Standard Label',
labelPlural: 'Standard Labels',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
standardOverrides: {},
};
mockGenerateMessageId.mockReturnValue('auto.translation.id');
mockI18n._.mockReturnValue('Auto Translated Label');
it('should use registry translation when no overrides are available', () => {
mockTranslateStandardMetadataLabel.mockReturnValue('Auto Translated Label');
const result = resolveObjectMetadataStandardOverride(
objectMetadata,
baseFixture({ standardOverrides: {} }),
'labelSingular',
'de-DE',
mockI18n,
);
expect(result).toBe('Auto Translated Label');
expect(mockGenerateMessageId).toHaveBeenCalledWith('Standard Label');
expect(mockI18n._).toHaveBeenCalledWith('auto.translation.id');
});
});
describe('Undefined locale handling', () => {
it('should use SOURCE_LOCALE fallback when locale is undefined for standard object', () => {
const objectMetadata = {
labelSingular: 'Standard Label',
labelPlural: 'Standard Labels',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
standardOverrides: {
labelSingular: 'Source Override',
},
};
const objectMetadata = baseFixture({
standardOverrides: { labelSingular: 'Source Override' },
});
const result = resolveObjectMetadataStandardOverride(
objectMetadata,
@@ -609,33 +460,20 @@ describe('resolveObjectMetadataStandardOverride', () => {
);
expect(result).toBe('Source Override');
expect(mockGenerateMessageId).not.toHaveBeenCalled();
expect(mockI18n._).not.toHaveBeenCalled();
expect(mockTranslateStandardMetadataLabel).not.toHaveBeenCalled();
});
it('should fall back to auto translation when locale is undefined and no SOURCE_LOCALE override exists', () => {
mockI18n._.mockReturnValue('Auto Translated Label');
mockGenerateMessageId.mockReturnValue('auto.translation.id');
const objectMetadata = {
labelSingular: 'Standard Label',
labelPlural: 'Standard Labels',
description: 'Standard Description',
icon: 'default-icon',
isCustom: false,
standardOverrides: undefined,
};
it('should fall back to registry translation when locale is undefined and no SOURCE_LOCALE override exists', () => {
mockTranslateStandardMetadataLabel.mockReturnValue('Auto Translated Label');
const result = resolveObjectMetadataStandardOverride(
objectMetadata,
baseFixture(),
'labelSingular',
undefined,
mockI18n,
);
expect(result).toBe('Auto Translated Label');
expect(mockGenerateMessageId).toHaveBeenCalledWith('Standard Label');
expect(mockI18n._).toHaveBeenCalledWith('auto.translation.id');
});
});
});
@@ -3,7 +3,7 @@ import { isNonEmptyString } from '@sniptt/guards';
import { type APP_LOCALES, SOURCE_LOCALE } from 'twenty-shared/translations';
import { isDefined } from 'twenty-shared/utils';
import { generateMessageId } from 'src/engine/core-modules/i18n/utils/generateMessageId';
import { translateStandardMetadataLabel } from 'src/engine/core-modules/i18n/standard-metadata-descriptor-registry/translate-standard-metadata-label.util';
import { type ObjectMetadataDTO } from 'src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto';
export const resolveObjectMetadataStandardOverride = (
@@ -22,41 +22,26 @@ export const resolveObjectMetadataStandardOverride = (
i18nInstance: I18n,
): string => {
const safeLocale = locale ?? SOURCE_LOCALE;
const baseValue = objectMetadata[labelKey] ?? '';
if (objectMetadata.isCustom) {
return objectMetadata[labelKey] ?? '';
return baseValue;
}
if (
(labelKey === 'icon' || labelKey === 'color') &&
isDefined(objectMetadata.standardOverrides?.[labelKey])
) {
return objectMetadata.standardOverrides[labelKey];
if (labelKey === 'icon' || labelKey === 'color') {
return objectMetadata.standardOverrides?.[labelKey] ?? baseValue;
}
if (
isDefined(objectMetadata.standardOverrides?.translations) &&
labelKey !== 'icon' &&
labelKey !== 'color'
) {
const translationValue =
objectMetadata.standardOverrides.translations[safeLocale]?.[labelKey];
const translationOverride =
objectMetadata.standardOverrides?.translations?.[safeLocale]?.[labelKey];
if (isDefined(translationValue)) {
return translationValue;
}
if (isDefined(translationOverride)) {
return translationOverride;
}
if (isNonEmptyString(objectMetadata.standardOverrides?.[labelKey])) {
return objectMetadata.standardOverrides[labelKey] ?? '';
}
const messageId = generateMessageId(objectMetadata[labelKey] ?? '');
const translatedMessage = i18nInstance._(messageId);
if (translatedMessage === messageId) {
return objectMetadata[labelKey] ?? '';
}
return translatedMessage;
return translateStandardMetadataLabel(i18nInstance, baseValue) ?? baseValue;
};
@@ -1,17 +1,20 @@
import { t } from '@lingui/core/macro';
import { msg } from '@lingui/core/macro';
// This file exists solely for Lingui string extraction.
// The strings defined here correspond to standard page layout tab titles
// so they appear in the .po catalogs and can be translated at resolve time
// via generateMessageId hash lookups.
export const getStandardPageLayoutTabTitles = () => [
t`Home`,
t`Timeline`,
t`Tasks`,
t`Notes`,
t`Files`,
t`Emails`,
t`Calendar`,
t`Note`,
t`Flow`,
import { rememberStandardMetadataDescriptor } from 'src/engine/core-modules/i18n/standard-metadata-descriptor-registry/remember-standard-metadata-descriptor.util';
// MessageDescriptors (not plain strings) so the Lingui extractor picks them up.
const STANDARD_PAGE_LAYOUT_TAB_TITLE_DESCRIPTORS = [
msg`Home`,
msg`Timeline`,
msg`Tasks`,
msg`Notes`,
msg`Files`,
msg`Emails`,
msg`Calendar`,
msg`Note`,
msg`Flow`,
];
for (const descriptor of STANDARD_PAGE_LAYOUT_TAB_TITLE_DESCRIPTORS) {
rememberStandardMetadataDescriptor(descriptor);
}
@@ -1,14 +1,20 @@
import { type I18n } from '@lingui/core';
import { generateMessageId } from 'src/engine/core-modules/i18n/utils/generateMessageId';
import { translateStandardMetadataLabel } from 'src/engine/core-modules/i18n/standard-metadata-descriptor-registry/translate-standard-metadata-label.util';
import { resolvePageLayoutTabTitle } from 'src/engine/metadata-modules/page-layout-tab/utils/resolve-page-layout-tab-title.util';
import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications';
jest.mock('src/engine/core-modules/i18n/utils/generateMessageId');
jest.mock(
'src/engine/core-modules/i18n/standard-metadata-descriptor-registry/translate-standard-metadata-label.util',
() => ({
translateStandardMetadataLabel: jest.fn(),
}),
);
const mockGenerateMessageId = generateMessageId as jest.MockedFunction<
typeof generateMessageId
>;
const mockTranslateStandardMetadataLabel =
translateStandardMetadataLabel as jest.MockedFunction<
typeof translateStandardMetadataLabel
>;
describe('resolvePageLayoutTabTitle', () => {
let mockI18n: jest.Mocked<I18n>;
@@ -18,11 +24,11 @@ describe('resolvePageLayoutTabTitle', () => {
mockI18n = {
_: jest.fn(),
} as unknown as jest.Mocked<I18n>;
mockTranslateStandardMetadataLabel.mockReturnValue(undefined);
});
it('should return translated title when catalog has a match', () => {
mockGenerateMessageId.mockReturnValue('abc123');
mockI18n._.mockReturnValue('Accueil');
it('should return translated title when registry has the descriptor', () => {
mockTranslateStandardMetadataLabel.mockReturnValue('Accueil');
const result = resolvePageLayoutTabTitle({
title: 'Home',
@@ -30,14 +36,15 @@ describe('resolvePageLayoutTabTitle', () => {
i18nInstance: mockI18n,
});
expect(mockGenerateMessageId).toHaveBeenCalledWith('Home');
expect(mockI18n._).toHaveBeenCalledWith('abc123');
expect(mockTranslateStandardMetadataLabel).toHaveBeenCalledWith(
mockI18n,
'Home',
);
expect(result).toBe('Accueil');
});
it('should return original title when catalog returns the hash (no translation found)', () => {
mockGenerateMessageId.mockReturnValue('xyz789');
mockI18n._.mockReturnValue('xyz789');
it('should return original title when no descriptor is registered for it', () => {
mockTranslateStandardMetadataLabel.mockReturnValue(undefined);
const result = resolvePageLayoutTabTitle({
title: 'My Custom Tab',
@@ -45,15 +52,10 @@ describe('resolvePageLayoutTabTitle', () => {
i18nInstance: mockI18n,
});
expect(mockGenerateMessageId).toHaveBeenCalledWith('My Custom Tab');
expect(mockI18n._).toHaveBeenCalledWith('xyz789');
expect(result).toBe('My Custom Tab');
});
it('should return original title for empty string', () => {
mockGenerateMessageId.mockReturnValue('empty-hash');
mockI18n._.mockReturnValue('empty-hash');
const result = resolvePageLayoutTabTitle({
title: '',
applicationId: TWENTY_STANDARD_APPLICATION.universalIdentifier,
@@ -63,38 +65,7 @@ describe('resolvePageLayoutTabTitle', () => {
expect(result).toBe('');
});
it('should translate standard tab titles', () => {
const standardTabs = [
{ source: 'Home', translated: 'Accueil' },
{ source: 'Timeline', translated: 'Chronologie' },
{ source: 'Tasks', translated: 'Tâches' },
{ source: 'Notes', translated: 'Notes' },
{ source: 'Files', translated: 'Fichiers' },
{ source: 'Emails', translated: 'E-mails' },
{ source: 'Calendar', translated: 'Calendrier' },
{ source: 'Note', translated: 'Note' },
{ source: 'Flow', translated: 'Flux' },
];
standardTabs.forEach(({ source, translated }) => {
jest.clearAllMocks();
mockGenerateMessageId.mockReturnValue(`hash-${source}`);
mockI18n._.mockReturnValue(translated);
const result = resolvePageLayoutTabTitle({
title: source,
applicationId: TWENTY_STANDARD_APPLICATION.universalIdentifier,
i18nInstance: mockI18n,
});
expect(result).toBe(translated);
});
});
it('should not translate title when applicationId is not from standard app', () => {
mockGenerateMessageId.mockReturnValue('abc123');
mockI18n._.mockReturnValue('Accueil');
const customAppId = '11111111-1111-1111-1111-111111111111';
const result = resolvePageLayoutTabTitle({
@@ -103,8 +74,7 @@ describe('resolvePageLayoutTabTitle', () => {
i18nInstance: mockI18n,
});
expect(mockGenerateMessageId).not.toHaveBeenCalled();
expect(mockI18n._).not.toHaveBeenCalled();
expect(mockTranslateStandardMetadataLabel).not.toHaveBeenCalled();
expect(result).toBe('Home');
});
});
@@ -1,6 +1,6 @@
import { type I18n } from '@lingui/core';
import { generateMessageId } from 'src/engine/core-modules/i18n/utils/generateMessageId';
import { translateStandardMetadataLabel } from 'src/engine/core-modules/i18n/standard-metadata-descriptor-registry/translate-standard-metadata-label.util';
import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications';
export const resolvePageLayoutTabTitle = ({
@@ -16,12 +16,5 @@ export const resolvePageLayoutTabTitle = ({
return title;
}
const messageId = generateMessageId(title);
const translatedMessage = i18nInstance._(messageId);
if (translatedMessage === messageId) {
return title;
}
return translatedMessage;
return translateStandardMetadataLabel(i18nInstance, title) ?? title;
};
@@ -1,14 +1,12 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { APP_LOCALES, SOURCE_LOCALE } from 'twenty-shared/translations';
import { type APP_LOCALES } from 'twenty-shared/translations';
import { ViewType, ViewVisibility } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { Repository } from 'typeorm';
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
import { I18nService } from 'src/engine/core-modules/i18n/i18n.service';
import { generateMessageId } from 'src/engine/core-modules/i18n/utils/generateMessageId';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
@@ -46,7 +44,6 @@ export class ViewService {
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService,
private readonly applicationService: ApplicationService,
private readonly i18nService: I18nService,
) {}
async createOne({
@@ -393,39 +390,14 @@ export class ViewService {
processViewNameWithTemplate(
viewName: string,
isCustom: boolean,
_isCustom: boolean,
objectLabelPlural?: string,
locale?: keyof typeof APP_LOCALES,
_locale?: keyof typeof APP_LOCALES,
): string {
if (viewName.includes('{objectLabelPlural}') && objectLabelPlural) {
const messageId = generateMessageId(viewName);
const translatedTemplate = this.i18nService.translateMessage({
messageId,
values: {
objectLabelPlural,
},
locale: locale ?? SOURCE_LOCALE,
});
if (translatedTemplate !== messageId) {
return translatedTemplate;
}
return viewName.replace('{objectLabelPlural}', objectLabelPlural);
}
if (!isCustom) {
const messageId = generateMessageId(viewName);
const translatedMessage = this.i18nService.translateMessage({
messageId,
locale: locale ?? SOURCE_LOCALE,
});
if (translatedMessage !== messageId) {
return translatedMessage;
}
}
return viewName;
}
@@ -1,4 +1,9 @@
import { type MessageDescriptor } from '@lingui/core';
export const i18nLabel = (descriptor: MessageDescriptor): string =>
descriptor.message ?? '';
import { rememberStandardMetadataDescriptor } from 'src/engine/core-modules/i18n/standard-metadata-descriptor-registry/remember-standard-metadata-descriptor.util';
export const i18nLabel = (descriptor: MessageDescriptor): string => {
rememberStandardMetadataDescriptor(descriptor);
return descriptor.message ?? '';
};
@@ -0,0 +1,31 @@
import 'src/engine/metadata-modules/page-layout-tab/constants/standard-page-layout-tab-titles';
import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-flat-entity-maps.constant';
import { buildStandardFlatFieldMetadataMaps } from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/build-standard-flat-field-metadata-maps.util';
import { getStandardObjectMetadataRelatedEntityIds } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-object-metadata-related-entity-ids.util';
import { buildStandardFlatObjectMetadataMaps } from 'src/engine/workspace-manager/twenty-standard-application/utils/object-metadata/build-standard-flat-object-metadata-maps.util';
// `i18nLabel(msg`...`)` only registers descriptors when the builder lambdas
// run. Workspace sync runs them for real workspaces, but restarts don't —
// so we do one discard-only pass at module load to keep translations working.
const PLACEHOLDER_ARGS = {
now: '',
workspaceId: '',
twentyStandardApplicationId: '',
standardObjectMetadataRelatedEntityIds:
getStandardObjectMetadataRelatedEntityIds(),
};
const flatObjectMetadataMaps = buildStandardFlatObjectMetadataMaps({
...PLACEHOLDER_ARGS,
dependencyFlatEntityMaps: {
flatFieldMetadataMaps: createEmptyFlatEntityMaps(),
},
});
buildStandardFlatFieldMetadataMaps({
...PLACEHOLDER_ARGS,
dependencyFlatEntityMaps: {
flatObjectMetadataMaps,
},
});