Internationalization (i18n)
QuickModel's @QRule validation produces error messages as strings. When your application supports multiple languages, you can plug in any i18n library to translate those strings automatically — without changing your model definitions.
How it works
Configure a resolver function in QConfig. Every time a rule fails, QuickModel passes the raw error message (or key) through the resolver before returning it to the caller:
import { QConfig } from 'quickmodel';
QConfig.configure({
i18n: {
resolver: (key) => myI18nLibrary.translate(key),
},
});The resolver is called only for failing rules — never for passing ones.
Basic example
QConfig.configure({
i18n: {
resolver: (key) => t(key), // any translation function
},
});
@Quick()
class UserModel extends QModel<IUser> {
@QRule(
(val: string) => val.length >= 3,
'validation.name.minLength' // i18n key
)
declare name: string;
}
const result = new UserModel({ name: 'Al' }).$qCheckRules();
// → { valid: false, errors: [{ field: 'name', message: 'Name must be at least 3 characters' }] }
// The resolver translated 'validation.name.minLength' for the active localeIntegration with common i18n libraries
vue-i18n
import { createI18n } from 'vue-i18n';
import { QConfig } from 'quickmodel';
const i18n = createI18n({ ... });
QConfig.configure({
i18n: {
resolver: (key) => String(i18n.global.t(key)),
},
});react-i18next
import i18next from 'i18next';
import { QConfig } from 'quickmodel';
QConfig.configure({
i18n: {
resolver: (key) => i18next.t(key),
},
});Angular TranslateService
import { TranslateService } from '@ngx-translate/core';
export function setupQuickModelI18n(translate: TranslateService): void {
QConfig.configure({
i18n: {
resolver: (key) => translate.instant(key),
},
});
}No library — static map
const messages: Record<string, string> = {
'validation.name.minLength': 'Name must be at least 3 characters',
'validation.email.format': 'Invalid email format',
};
QConfig.configure({
i18n: {
resolver: (key) => messages[key] ?? key, // fallback to key if missing
},
});Strategy 1 — i18n keys in @QRule
Store translation keys instead of inline strings. The resolver translates them at runtime:
@Quick()
class ProductModel extends QModel<IProduct> {
@QRule((v: string) => v.length > 0, 'validation.title.required')
@QRule((v: string) => v.length <= 200, 'validation.title.maxLength')
declare title: string;
@QRule((v: number) => v > 0, 'validation.price.positive')
declare price: number;
}Advantages: Model is completely locale-agnostic. Changing translations doesn't require touching the model.
Strategy 2 — Lazy () => string resolver in @QRule
Pass a function instead of a string. It is evaluated at checkRules() call-time, picking up the current locale:
import { t } from './i18n';
@Quick()
class UserModel extends QModel<IUser> {
@QRule(
(val: string) => val.length >= 3,
() => t('validation.name.minLength') // called at rule-check time
)
declare name: string;
}Advantages: No global QConfig.i18n resolver needed. Works when different parts of the app have different locale contexts.
Strategy 3 — Combine both
Use lazy resolvers in @QRule for field-specific messages, and a global QConfig.i18n.resolver as a universal fallback for any remaining keys:
QConfig.configure({
i18n: {
resolver: (key) => t(key), // global fallback for all models
},
});
@Quick()
class UserModel extends QModel<IUser> {
@QRule(
(val: string) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val),
() => t('validation.email.format') // lazy, locale-aware
)
declare email: string;
@QRule((v: string) => v.length >= 8, 'validation.password.minLength')
declare password: string; // uses global resolver via QConfig
}Angular template pipe pattern
In Angular, you can store plain keys and apply | translate in templates — no global resolver needed:
@Quick()
class FormModel extends QModel<IFormData> {
@QRule((v: string) => v !== '', 'FORM.NAME_REQUIRED')
declare name: string;
}<!-- Template: translate the key returned in e.message -->
<span *ngFor="let e of errors">{{ e.message | translate }}</span>Async rules and i18n
The resolver also applies to errors from checkRulesAsync():
const result = await model.$qCheckRulesAsync();
// → errors[].message is also passed through the resolverAPI reference
| Symbol | Description |
|---|---|
QConfig.configure({ i18n: { resolver } }) | Registers a global message resolver |
resolver(key: string): string | Receives the raw message or key, returns the translated string |
@QRule(pred, 'key') | Uses a string key as the error message |
@QRule(pred, () => string) | Lazy function evaluated at rule-check time |
See also
- Validation —
@QRuleandcheckRules()API - Per-Class Configuration — override settings per model class
- Getting Started — global
QConfigsetup