Effective Error Handling with NestJS and Internationalization (i18n)

Introduction

In modern web applications, handling errors gracefully and providing meaningful messages to users is crucial. NestJS, a progressive Node.js framework, offers robust solutions for error handling and internationalization (i18n). This article explores how to implement error handling in a NestJS application with i18n support, ensuring that error messages are translated and user-friendly.

Nodejs Logo


1. Setting Up NestJS with i18n

Before diving into error handling, it’s essential to set up internationalization in your NestJS application. The nestjs-i18n package simplifies this process. Install it using npm:

npm install nestjs-i18n

Configure i18n in your application:

import { Module } from '@nestjs/common';
import { I18nModule, I18nJsonParser } from 'nestjs-i18n';
import * as path from 'path';

@Module({
  imports: [
    I18nModule.forRoot({
      fallbackLanguage: 'en',
      parser: I18nJsonParser,
      parserOptions: {
        path: path.join(__dirname, '/i18n/'),
      },
    }),
  ],
})
export class AppModule {}

In this configuration, we set up the nestjs-i18n module with a fallback language of English and specify the path to the JSON files containing our translations.


2. Creating an i18n Helper Service

To manage translations more conveniently, we can create an I18nHelper service. This service will translate keys with optional arguments and language parameters.

import { Injectable } from '@nestjs/common';
import { I18nContext, I18nService } from 'nestjs-i18n';

@Injectable()
export class I18nHelper {
  constructor(private readonly i18n: I18nService) {}

  /**
   * Translate a key
   * @param {string} key - The key to translate
   * @param {object} args - The arguments to pass to the translation
   * @param {string} lang - The language to translate to
   * @returns {string} The translated string
   */
  t(key: string, args: object = {}, lang?: string): string {
    const cLang = lang || I18nContext.current()?.lang || 'en';
    return this.i18n.t(`${cLang}.${key}`, { lang: cLang, args });
  }
}

This service uses the I18nService to fetch translations based on the provided key and language, defaulting to English if no language is specified.


3. Implementing Validation Filters

To handle validation errors and provide localized messages, you can create a custom filter. Here’s an example:

import { ArgumentsHost, Catch, ExceptionFilter, HttpStatus } from '@nestjs/common';
import { ValidationError } from 'class-validator';
import { I18nHelper } from './i18n-helper.service';

@Catch(ValidationError)
export class ValidationFilter implements ExceptionFilter {
  constructor(private readonly i18n: I18nHelper) {}

  catch(exception: ValidationError[], host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const result = exception.map(error => ({
      name: error.contexts?.errorCode,
      message: this.i18n.t(error.contexts?.errorCode) || error.constraints[Object.keys(error.constraints)[0]],
      developerMessage: error.contexts?.developerMessage || error.constraints[Object.keys(error.constraints)[0]],
      field: error.property,
      value: error.value,
    }));
    response.status(HttpStatus.BAD_REQUEST).json(result);
  }
}

This filter catches validation errors, translates the error messages, and formats the response object.


4. Defining DTOs with Validation Rules

Define your Data Transfer Objects (DTOs) with validation rules and error codes for i18n support. Here’s an example:

import { MaxLength } from 'class-validator';

export class CreateAliasDto {
  @MaxLength(20, {
    message: 'Alias must be less than or equal to 20 characters',
    context: {
      errorCode: 'ALIAS_LENGTH_EXCEEDED',
      developerMessage: 'Alias must be less than or equal to 20 characters'
    }
  })
  alias: string;
}

In this DTO, if the alias exceeds 20 characters, an error with the specified context will be thrown, which the ValidationFilter will handle.


Conclusion

Implementing i18n in error handling significantly enhances user experience by providing localized, meaningful error messages. NestJS, with its powerful decorators and validation tools, makes it easy to integrate i18n into your error handling logic. By following the steps outlined in this article, you can ensure your application handles errors gracefully and communicates effectively with users worldwide.