Internationalized errors
Library exceptions use a stable error code plus an English fallback. Enabling i18n adds language resolution, catalogs, interpolation, and a global exception filter.
Configure catalogs
import { SdCoreModule } from '@sdcorejs/nestjs';
SdCoreModule.forRoot({
i18n: {
supportedLanguages: ['en', 'vi'],
fallbackLanguage: 'en',
catalogs: {
en: {
'app.product.name.required': 'Product name is required',
'app.product.name.min': 'Name must contain at least {minimum} characters',
},
vi: {
'app.product.name.required': 'Tên sản phẩm là bắt buộc',
'app.product.name.min': 'Tên phải có ít nhất {minimum} ký tự',
},
},
},
});Application catalogs merge over built-in English/Vietnamese core.* catalogs. Unknown codes fall back to the fallback-language catalog and then to the code itself. The default resolver parses Accept-Language quality weights and converts regional tags such as vi-VN to vi.
Error envelopes
import { BadRequestException } from '@nestjs/common';
import { apiError } from '@sdcorejs/nestjs/core';
throw new BadRequestException(
apiError('app.product.name.min', 'Product name is too short', { minimum: 3 }),
);With the default global filter, the response body is:
{
"error": {
"code": "app.product.name.min",
"message": "Name must contain at least 3 characters",
"data": { "minimum": 3 }
}
}Non-apiError exceptions pass through unchanged. ApiResponse.noContent() returns { data: null }; it does not set HTTP status 204 by itself.
Validation issues
When data.issues contains Zod issue details, the filter translates each string issues[].message with its params. Put i18n codes in schema messages:
import { z } from 'zod';
const schema = z.object({
name: z.string().min(3, 'app.product.name.min'),
});Custom resolver
import { Injectable } from '@nestjs/common';
import type { II18nResolver } from '@sdcorejs/nestjs/i18n';
@Injectable()
class AppI18nResolver implements II18nResolver {
translate(
code: string,
lang: string | undefined,
data?: Record<string, unknown>,
): string {
const suffix = data ? ' ' + JSON.stringify(data) : '';
return (lang ?? 'en') + ':' + code + suffix;
}
}Register with i18n: { resolver: AppI18nResolver }. Set useGlobalFilter: false only when the application installs SdI18nExceptionFilter itself or has an equivalent envelope-preserving filter.
