i18n API
Import path: @sdcorejs/nestjs/i18n
The i18n package localizes library apiError envelopes. It ships English and Vietnamese catalogs, an Accept-Language resolver, a simple template resolver and an optional global exception filter.
Exports
| Export | Kind | Purpose |
|---|---|---|
MessageCatalog, Catalogs | types | code -> template and language -> catalog maps |
II18nResolver | interface | translate(code, rawLang, data?) contract |
ILanguageResolver | interface | resolve(raw): locale contract |
I18N_RESOLVER, LANGUAGE_RESOLVER | values | DI tokens |
LanguageResolverOptions | interface | Supported languages and fallback |
DefaultLanguageResolver | class | Weighted Accept-Language parser |
SimpleI18nOptions | interface | Catalogs, fallback and optional language resolver |
SimpleI18nResolver | class | Catalog lookup and {var} interpolation |
CORE_CATALOG_EN, CORE_CATALOG_VI, CORE_CATALOGS | values | Built-in library messages |
SdI18nExceptionFilter | class | Localizes HttpException apiError bodies |
I18nModule, I18nModuleOptions | class/type | Global providers and optional APP_FILTER |
Module configuration
I18nModule.forRoot({
supportedLanguages: ['en', 'vi'],
fallbackLanguage: 'en',
catalogs: {
en: { 'catalog.product.not-found': 'Product {id} was not found' },
vi: { 'catalog.product.not-found': 'Không tìm thấy sản phẩm {id}' },
},
});| Option | Default | Behavior |
|---|---|---|
catalogs | {} | Shallow-merged per language over built-in core.* messages; consumer wins |
supportedLanguages | ['en', 'vi'] | Base locale codes accepted by default resolver |
fallbackLanguage | 'en' | Fallback locale and catalog |
resolver | SimpleI18nResolver | Custom DI class implementing II18nResolver |
useGlobalFilter | true | Registers SdI18nExceptionFilter as APP_FILTER |
SdCoreModule wires i18n only when its i18n option is present.
Language resolution
const resolver = new DefaultLanguageResolver({
supported: ['en', 'vi'],
fallback: 'en',
});
resolver.resolve('fr;q=0.4, vi-VN;q=0.9'); // 'vi'The resolver splits comma-separated tags, reads q weights (default 1), sorts descending, lowercases and strips the region (vi-VN becomes vi). Unknown or invalid tags fall back.
Translation contract
interface II18nResolver {
translate(
code: string,
lang: string | undefined,
data?: Record<string, unknown>,
): string;
}SimpleI18nResolver looks up target language, then fallback language, then returns the stable code. It replaces {word} placeholders from data and leaves unmatched placeholders unchanged. For ICU, pluralization or remote catalogs, register a custom resolver class.
Exception filter behavior
throw new NotFoundException(
apiError('catalog.product.not-found', 'Product not found', { id }),
);With the filter enabled, the HTTP response becomes:
{
"error": {
"code": "catalog.product.not-found",
"message": "Không tìm thấy sản phẩm 123",
"data": { "id": "123" }
}
}The raw ContextService.lang header is passed to the resolver. Validation issues are localized individually using their message as a code and params as interpolation data. Non-apiErrorHttpException responses pass through unchanged. With no resolver, code and default message pass through unchanged.
Set useGlobalFilter: false only when you register SdI18nExceptionFilter yourself or have an application filter that preserves the same error contract.
Security notes
- Treat catalog text as presentation, not authorization logic. Clients should branch on stable
code, never translatedmessage. - Keep interpolation data bounded and non-sensitive; the filter retains it in the response.
ContextService.langis untrusted input. Custom resolvers must normalize it before filesystem, network or dynamic-module lookup.
