Update user friendly errors for translations (#15000)

Force msg typing instead of string for user friendly errors
This commit is contained in:
Félix Malfait
2025-10-09 18:17:32 +02:00
committed by GitHub
parent 660cd38f35
commit e577c2d746
124 changed files with 796 additions and 563 deletions
@@ -24,6 +24,7 @@ import { CoreEngineModule } from 'src/engine/core-modules/core-engine.module';
import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service';
import { useSentryTracing } from 'src/engine/core-modules/exception-handler/hooks/use-sentry-tracing';
import { useGraphQLErrorHandlerHook } from 'src/engine/core-modules/graphql/hooks/use-graphql-error-handler.hook';
import { I18nService } from 'src/engine/core-modules/i18n/i18n.service';
import { MetricsService } from 'src/engine/core-modules/metrics/metrics.service';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { type User } from 'src/engine/core-modules/user/user.entity';
@@ -47,6 +48,7 @@ export class GraphQLConfigService
private readonly moduleRef: ModuleRef,
private readonly metricsService: MetricsService,
private readonly dataloaderService: DataloaderService,
private readonly i18nService: I18nService,
) {}
createGqlOptions(): YogaDriverConfig {
@@ -63,6 +65,7 @@ export class GraphQLConfigService
useGraphQLErrorHandlerHook({
metricsService: this.metricsService,
exceptionHandlerService: this.exceptionHandlerService,
i18nService: this.i18nService,
twentyConfigService: this.twentyConfigService,
}),
];
@@ -1,6 +1,6 @@
import { Injectable } from '@nestjs/common';
import { t } from '@lingui/core/macro';
import { msg } from '@lingui/core/macro';
import { QUERY_MAX_RECORDS } from 'twenty-shared/constants';
import { capitalize, isDefined } from 'twenty-shared/utils';
import {
@@ -47,7 +47,7 @@ export class GraphqlQueryCreateManyResolverService extends GraphqlQueryBaseResol
`Maximum number of records to upsert is ${QUERY_MAX_RECORDS}.`,
GraphqlQueryRunnerExceptionCode.UPSERT_MAX_RECORDS_EXCEEDED,
{
userFriendlyMessage: t`Maximum number of records to upsert is ${QUERY_MAX_RECORDS}.`,
userFriendlyMessage: msg`Maximum number of records to upsert is ${QUERY_MAX_RECORDS}.`,
},
);
}
@@ -359,7 +359,7 @@ export class GraphqlQueryCreateManyResolverService extends GraphqlQueryBaseResol
`Multiple records found with the same unique field values for ${conflictingFieldsValues}. Cannot determine which record to update.`,
GraphqlQueryRunnerExceptionCode.UPSERT_MULTIPLE_MATCHING_RECORDS_CONFLICT,
{
userFriendlyMessage: t`Multiple records found with the same unique field values for ${conflictingFieldsValues}. Cannot determine which record to update.`,
userFriendlyMessage: msg`Multiple records found with the same unique field values for ${conflictingFieldsValues}. Cannot determine which record to update.`,
},
);
}
@@ -7,6 +7,8 @@ import { GraphQLConfigModule } from 'src/engine/api/graphql/graphql-config/graph
import { metadataModuleFactory } from 'src/engine/api/graphql/metadata.module-factory';
import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum';
import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service';
import { I18nModule } from 'src/engine/core-modules/i18n/i18n.module';
import { I18nService } from 'src/engine/core-modules/i18n/i18n.service';
import { MetricsModule } from 'src/engine/core-modules/metrics/metrics.module';
import { MetricsService } from 'src/engine/core-modules/metrics/metrics.service';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
@@ -21,13 +23,19 @@ import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/wor
GraphQLModule.forRootAsync<YogaDriverConfig>({
driver: YogaDriver,
useFactory: metadataModuleFactory,
imports: [GraphQLConfigModule, DataloaderModule, MetricsModule],
imports: [
GraphQLConfigModule,
DataloaderModule,
MetricsModule,
I18nModule,
],
inject: [
TwentyConfigService,
ExceptionHandlerService,
DataloaderService,
CacheStorageNamespace.EngineWorkspace,
MetricsService,
I18nService,
],
}),
MetadataEngineModule,
@@ -9,6 +9,7 @@ import { MetadataGraphQLApiModule } from 'src/engine/api/graphql/metadata-graphq
import { type CacheStorageService } from 'src/engine/core-modules/cache-storage/services/cache-storage.service';
import { type ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service';
import { useGraphQLErrorHandlerHook } from 'src/engine/core-modules/graphql/hooks/use-graphql-error-handler.hook';
import { type I18nService } from 'src/engine/core-modules/i18n/i18n.service';
import { type MetricsService } from 'src/engine/core-modules/metrics/metrics.service';
import { type TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { type DataloaderService } from 'src/engine/dataloaders/dataloader.service';
@@ -20,6 +21,7 @@ export const metadataModuleFactory = async (
dataloaderService: DataloaderService,
cacheStorageService: CacheStorageService,
metricsService: MetricsService,
i18nService: I18nService,
): Promise<YogaDriverConfig> => {
const config: YogaDriverConfig = {
autoSchemaFile: true,
@@ -39,6 +41,7 @@ export const metadataModuleFactory = async (
useGraphQLErrorHandlerHook({
metricsService: metricsService,
exceptionHandlerService,
i18nService,
twentyConfigService,
}),
useCachedMetadata({
@@ -1,3 +1,4 @@
import { msg } from '@lingui/core/macro';
import { isDefined } from 'twenty-shared/utils';
import { type QueryFailedError } from 'typeorm';
@@ -42,7 +43,7 @@ export const handleDuplicateKeyError = (
`A duplicate entry was detected`,
TwentyORMExceptionCode.DUPLICATE_ENTRY_DETECTED,
{
userFriendlyMessage: `This record already exists. Please check your data and try again.`,
userFriendlyMessage: msg`This record already exists. Please check your data and try again.`,
},
);
}
@@ -50,20 +51,26 @@ export const handleDuplicateKeyError = (
const columnNames = affectedColumns.join(', ');
if (affectedColumns?.length === 1) {
const fieldName = columnNames.toLowerCase();
throw new UserInputError(
`Duplicate ${columnNames} ${duplicatedValues ? `with value ${duplicatedValues}` : ''}. Please set a unique one.`,
{
userFriendlyMessage: `This ${columnNames.toLowerCase()} ${duplicatedValues ? `with value ${duplicatedValues}` : ''} is already taken. Please choose a different value.`,
userFriendlyMessage: duplicatedValues
? msg`This ${fieldName} with value ${duplicatedValues} is already taken. Please choose a different value.`
: msg`This ${fieldName} is already taken. Please choose a different value.`,
isExpected: true,
},
);
}
const fieldNames = columnNames.toLowerCase();
throw new TwentyORMException(
`A duplicate entry was detected. The combination of ${columnNames} must be unique.`,
TwentyORMExceptionCode.DUPLICATE_ENTRY_DETECTED,
{
userFriendlyMessage: `This combination of ${columnNames.toLowerCase()} already exists. Please use different values.`,
userFriendlyMessage: msg`This combination of ${fieldNames} already exists. Please use different values.`,
},
);
}