Lỗi được quốc tế hóa
Exception của thư viện dùng một error code ổn định cùng fallback tiếng Anh. Khi bật i18n, hệ thống có thêm cơ chế phân giải ngôn ngữ, catalog, nội suy và global exception filter.
Cấu hình catalog
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ự',
},
},
},
});Catalog của ứng dụng được merge đè lên catalog core.* tiếng Anh/Việt tích hợp. Code không xác định sẽ fallback về catalog của ngôn ngữ fallback rồi mới đến chính code đó. Resolver mặc định phân tích trọng số chất lượng Accept-Language và chuyển thẻ khu vực như vi-VN thành vi.
Error envelope
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 }),
);Với global filter mặc định, response body là:
{
"error": {
"code": "app.product.name.min",
"message": "Name must contain at least 3 characters",
"data": { "minimum": 3 }
}
}Exception không phải apiError được giữ nguyên. ApiResponse.noContent() trả về { data: null }; bản thân nó không đặt HTTP status 204.
Vấn đề validation
Khi data.issues chứa chi tiết issue của Zod, filter dịch từng chuỗi issues[].message bằng params tương ứng. Đặt i18n code trong message của schema:
import { z } from 'zod';
const schema = z.object({
name: z.string().min(3, 'app.product.name.min'),
});Resolver tùy chỉnh
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;
}
}Đăng ký bằng i18n: { resolver: AppI18nResolver }. Chỉ đặt useGlobalFilter: false khi ứng dụng tự cài đặt SdI18nExceptionFilter hoặc có filter tương đương vẫn giữ nguyên envelope.
