Skip to Content
Message Documentation

Message Documentation

This documentation explains the features and usage of Message Module: Located at src/common/message

Overview

Message Service provides internationalization (i18n) support using nestjs-i18n  to manage multi-language messages. All message files are stored in src/languages/{language} directory in JSON format. Currently, only English (en) is available.

The MessageModule is imported globally via CommonModule in src/common/common.module.ts, making MessageService available throughout the application without additional imports.

Table of Contents

Configuration

Default language is configured via environment variable:

APP_LANGUAGE=en

Configuration structure:

// src/config/message.config.ts export default registerAs( 'message', (): IConfigMessage => ({ availableLanguage: Object.values(EnumMessageLanguage), language: process.env.APP_LANGUAGE ?? EnumMessageLanguage.EN, }) );

Language options are defined in the enum:

export enum EnumMessageLanguage { en = 'en', }

Message Files

Message files use JSON format with nested structure. Key paths follow the pattern: filename.field.nested. Files are located in src/languages/en/:

FileDescription
activityLog.jsonActivity log messages
apiKey.jsonAPI key messages
app.jsonGeneral application messages
auth.jsonAuthentication messages
country.jsonCountry-related messages
device.jsonDevice management messages
featureFlag.jsonFeature flag messages
file.jsonFile upload messages
health.jsonHealth check messages
hello.jsonHello endpoint messages
http.jsonHTTP error messages
notification.jsonNotification messages
pagination.jsonPagination messages
passwordHistory.jsonPassword history messages
policy.jsonPolicy messages
request.jsonRequest validation messages
role.jsonRole messages
session.jsonSession messages
termPolicy.jsonTerms & policy messages
user.jsonUser messages

Example structure:

// src/languages/en/auth.json { "login": { "success": "Login successful", "error": { "notFound": "Email not found", "passwordNotMatch": "Password does not match" } } }

Access pattern:

// Key path: auth.login.success // Output: "Login successful" // Key path: auth.login.error.notFound // Output: "Email not found"

Usage

Basic Translation

Inject MessageService and use setMessage method:

@Injectable() export class UserService { constructor(private readonly messageService: MessageService) {} getWelcomeMessage(): string { return this.messageService.setMessage('user.welcome'); } }

Filter Language

Use filterLanguage to validate if a language is supported before using it:

const validLang = this.messageService.filterLanguage('id'); // Returns 'id' if supported, undefined if not

Bulk Import Validation Messages

Use setValidationImportMessage to format validation errors for bulk/import operations:

const errors = this.messageService.setValidationImportMessage([ { row: 1, errors: validationErrors } ]); // Returns: [{ row: 1, errors: [{ key, property, message }] }]

Translation with Variables

Pass variables through the properties option:

// src/languages/en/user.json { "greeting": "Hello, {name}!", "itemCount": "You have {count} items" }
const greeting = this.messageService.setMessage('user.greeting', { properties: { name: 'John' } }); // Output: "Hello, John!" const itemCount = this.messageService.setMessage('user.itemCount', { properties: { count: 5 } }); // Output: "You have 5 items"

Custom Language

Override default language using the customLanguage option:

const message = this.messageService.setMessage('user.welcome', { customLanguage: 'id' // Indonesian });

Request-specific language can be set via the x-custom-lang header:

await axios.get('http://localhost:3000/api/users', { headers: { 'x-custom-lang': 'id' } });

Integration

Exception Filters

Exception filters automatically translate message paths. The exception body follows the IAppException interface.

throw new BadRequestException({ statusCode: EnumUserStatusCodeError.emailExist, message: 'user.error.emailExists', // Will be translated });

With variables, pass messageProperties directly in the exception body:

throw new NotFoundException({ statusCode: EnumUserStatusCodeError.notFound, message: 'user.error.notFoundWithId', messageProperties: { id: userId }, });

Response Decorator

The @Response decorator translates success message paths. See Response Documentation for details.

@Response('user.create') @Post('/') async create(@Body() dto: CreateUserRequestDto): Promise<IResponseReturn<UserResponseDto>> { const user = await this.userService.create(dto); return { data: user }; }

With variables, pass messageProperties via the metadata field on IResponseReturn:

@Response('user.update') @Patch('/:id') async update( @Param('id') id: string, @Body() dto: UpdateUserDto ): Promise<IResponseReturn<UserResponseDto>> { const user = await this.userService.update(id, dto); return { data: user, metadata: { messageProperties: { name: user.name }, }, }; }

Validation Pipe

Validation errors are automatically translated by MessageService. The service handles both flat and nested validation errors by traversing the error tree and extracting constraints at each level. See Request Validation Documentation for details.

Message Resolution Strategy:

  1. Primary: Tries to resolve message from request.error.{constraint} path
  2. Fallback: If translation not found, uses the raw message from class-validator

Example message file:

// src/languages/en/request.json { "error": { "isNotEmpty": "{property} should not be empty", "isEmail": "{property} must be a valid email", "minLength": "{property} must be at least {min} characters" } }

Nested Validation:

For nested objects, the service return the full property path by traversing child errors:

// Input DTO with nested validation class AddressDto { @IsNotEmpty() street: string; } class UserDto { @ValidateNested() address: AddressDto; } // Validation error output: { "key": "isNotEmpty", "property": "address.street", "message": "street should not be empty" }

Standard validation response:

// Automatic transformation { "statusCode": 400, "message": "Validation error", "errors": [ { "key": "isNotEmpty", "property": "email", "message": "email should not be empty" }, { "key": "isEmail", "property": "email", "message": "email must be a valid email" } ] }

Adding New Language

  1. Create a new language directory:
mkdir -p src/languages/id
  1. Copy and translate JSON files:
cp src/languages/en/*.json src/languages/id/
  1. Update the enum:
export enum EnumMessageLanguage { en = 'en', id = 'id', // Add new language }
  1. Restart the application to load new language files.
Last updated on