Most i18n tutorials stop at English and Spanish. If you're building for Vietnamese users, you need proper tone marks, natural phrasing, and a setup that doesn't fight you.
Here's how I built a NestJS i18n system that auto-detects Accept-Language and returns error messages in Vietnamese or English.
1. Install nestjs-i18n
npm install nestjs-i18n
2. Create translation files
src/i18n/
├── vi/
│ ├── validation.json
│ └── response.json
└── en/
├── validation.json
└── response.json
vi/validation.json:
{
"EMAIL_INVALID": "Email không hợp lệ",
"PASSWORD_MIN_LENGTH": "Mật khẩu phải có ít nhất 6 ký tự",
"USER_NOT_FOUND": "Không tìm thấy người dùng",
"EMAIL_EXISTS": "Email đã tồn tại",
"FORBIDDEN": "Bạn không có quyền truy cập"
}
vi/response.json:
{
"LOGIN_SUCCESS": "Đăng nhập thành công",
"REGISTER_SUCCESS": "Đăng ký thành công",
"LOGOUT_SUCCESS": "Đăng xuất thành công"
}
3. Register I18nModule
// app.module.ts
import { I18nModule, HeaderResolver } from 'nestjs-i18n';
import * as path from 'path';
@Module({
imports: [
I18nModule.forRoot({
fallbackLanguage: 'vi',
loaderOptions: {
path: path.join(__dirname, '/i18n/'),
watch: true,
},
resolvers: [new HeaderResolver(['accept-language'])],
}),
// ... other imports
],
})
export class AppModule {}
4. Use in exception filters
// http-exception.filter.ts
import { I18nContext } from 'nestjs-i18n';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const i18n = I18nContext.current();
const response = ctx.getResponse<Response>();
const status = exception.getStatus();
const message = exception.message;
// Translate if the message is a dot-notation key like "validation.EMAIL_INVALID"
const translated = i18n?.translate(message) ?? message;
response.status(status).json({
statusCode: status,
message: translated,
timestamp: new Date().toISOString(),
});
}
}
5. Auto-detect language from headers
The Accept-Language header resolver does this automatically. The frontend sends Accept-Language: vi or en — NestJS picks it up. Zero extra code.
Vietnamese-specific gotchas
-
Tone marks:
nest-i18nstores JSON as UTF-8. Vietnamese characters (ắ, ễ, ở) work natively. No special handling needed. - Polite phrasing: Vietnamese error messages should sound respectful. "Vui lòng nhập email" (Please enter email) not "Nhập email" (Enter email).
-
Placeholders: Use
{min}and{max}— they work with nestjs-i18n's interpolation:
"NAME_LENGTH": "Tên phải có từ {min} đến {max} ký tự"
That's it. Your NestJS API now speaks Vietnamese natively.
If you don't want to set this up from scratch, I built a NestJS Vietnam Starter Kit with i18n, JWT auth, RBAC, Docker, and 36 tests — ready to go.
Top comments (0)