Skip to main content

API Translation Keys

The API returns user-facing error and success messages. For i18n, the frontend needs stable translation keys instead of raw English strings. The API includes optional messageKey and messageParams in responses so the client can call t(messageKey, messageParams).

Error response shape

Normal error payload (from HttpExceptionFilter):

{
"statusCode": 404,
"message": "Participation not found",
"messageKey": "errors.participation.notFound",
"messageParams": {},
"errors": null,
"timestamp": "...",
"path": "/api/v1/...",
"method": "PATCH"
}
  • message: Always present; English text for logging and fallback.
  • messageKey: Optional. i18n key for the frontend (e.g. errors.participation.notFound).
  • messageParams: Optional. Object for interpolation (e.g. { min: 1, max: 240 }).

Throwing with translation keys (backend)

Use the object form of Nest HTTP exceptions:

throw new NotFoundException({
message: 'Participation not found',
messageKey: 'errors.participation.notFound',
messageParams: {},
});

throw new BadRequestException({
message: 'Delay must be between 1 and 240 minutes',
messageKey: 'errors.event.delayOutOfRange',
messageParams: { min: 1, max: 240 },
});

HttpExceptionFilter passes through messageKey and messageParams when present.

Key naming convention

  • Errors: errors.<domain>.<reason>
    Examples: errors.participation.notFound, errors.event.notFound, errors.event.delayOutOfRange, errors.participation.characterNotFoundOrNotMember.
  • Success (when controllers return { message, messageKey }): success.<domain>.<action>
    Examples: success.role.deleted, success.character.archived.

Params use camelCase and match what the frontend needs for interpolation (e.g. {{min}}, {{max}}, {{eventId}}).

Frontend consumption

When displaying API errors (e.g. in toasts), prefer the key:

  • If error.data?.messageKey is present: t(error.data.messageKey, error.data.messageParams || {}).
  • Else: fallback to t('errors.generic') or error.data?.message.