/** * 字段装饰器 i18n 翻译使用示例 * * 本示例演示如何使用 fieldI18n 选项通过 i18n key 进行多语言转换 * * 注意:此示例文件仅供参考,展示如何使用 fieldI18n 选项。 * 如果使用 TypeScript 5+ 的新装饰器语法,需要确保 tsconfig.json 中 * "experimentalDecorators" 设置为 true。 */ /** * 在应用启动时(如 app.module.ts 或 main.ts)配置 i18n 翻译函数 * * @example * // app.module.ts * import { setI18nTranslate } from '@your-lib/core'; * *@Module({ * imports: [ * ConfigModule.forRoot(), * I18nModule.forRoot({ * fallbackLanguage: 'en', * loader: TranslationsLoader({ * config: { * defaultLanguage: 'zh', * languages: ['zh', 'en'], * types: ['validation', 'field'], * }, * }), * }), * ], * providers: [AppService], * }) * export class AppModule implements OnModuleInit { * constructor(private readonly i18n: I18nService) {} * * async onModuleInit() { * // 设置全局 i18n 翻译函数 * setI18nTranslate((key, options) => this.i18n.translate(key, options)); * } * } */ /** * 翻译文件结构示例 (src/i18n/zh.json): * * { * "field": { * "user": { * "username": "用户名", * "email": "邮箱", * "phone": "手机号", * "role": "角色", * "status": "状态", * "description": "个人简介" * }, * "product": { * "name": "产品名称", * "price": "价格", * "stock": "库存", * "status": "产品状态" * } * }, * "field.value": { * "user.role": { * "user": "普通用户", * "admin": "管理员", * "vip": "VIP用户" * }, * "user.status": { * "active": "正常", * "inactive": "未激活", * "suspended": "已暂停" * } * } * } * * 翻译文件结构示例 (src/i18n/en.json): * * { * "field": { * "user": { * "username": "Username", * "email": "Email", * "phone": "Phone Number", * "role": "Role", * "status": "Status", * "description": "Bio" * }, * "product": { * "name": "Product Name", * "price": "Price", * "stock": "Stock", * "status": "Product Status" * } * }, * "field.value": { * "user.role": { * "user": "User", * "admin": "Administrator", * "vip": "VIP User" * }, * "user.status": { * "active": "Active", * "inactive": "Inactive", * "suspended": "Suspended" * } * } * } */ /** * 用户 DTO - 使用 i18n key */ export declare class CreateUserDto { username: string; email: string; phone?: string; description?: string; emailVerified?: boolean; } /** * 产品 DTO - 使用 i18n key */ export declare class CreateProductDto { name: string; price: number; stock: number; } declare enum UserRole { USER = "user", ADMIN = "admin", VIP = "vip" } declare enum UserStatus { ACTIVE = "active", INACTIVE = "inactive", SUSPENDED = "suspended" } /** * 用户更新 DTO - 枚举字段使用 i18n */ export declare class UpdateUserDto { role: UserRole; status: UserStatus; } /** * 验证错误过滤器示例 * * @example * import { getValidationMetadata, getFieldLabelForValidation } from '@your-lib/core'; * * @Catch(ValidationError) * export class ValidationErrorFilter implements ExceptionFilter { * catch(exception: ValidationError, host: ArgumentsHost) { * const ctx = host.switchToHttp(); * const response = ctx.getResponse(); * const request = ctx.getRequest(); * const language = request.headers['accept-language'] || 'zh'; * * const errors = exception.errors.map(error => { * const metadata = getValidationMetadata(error.target.constructor, error.property); * const fieldLabel = getFieldLabelForValidation(metadata, language); * * // 如果 fieldLabel 是 i18n key,需要翻译 * const displayLabel = fieldLabel.includes('.') * ? this.i18n.translate(fieldLabel, { lang: language }) * : fieldLabel; * * return { * field: error.property, * fieldLabel: displayLabel, * constraints: error.constraints, * }; * }); * * response.status(400).json({ * statusCode: 400, * message: 'Validation failed', * errors, * }); * } * } */ /** * 审计日志服务示例 * * @example * import { getAuditMetadata } from '@your-lib/core'; * * @Injectable() * export class AuditService { * constructor(private readonly i18n: I18nService) {} * * async logFieldChange( * entity: any, * field: string, * oldValue: any, * newValue: any, * language: string = 'zh', * ) { * const metadata = getAuditMetadata(entity.constructor, field); * * // 翻译字段标签 * let fieldLabel = metadata?.label || field; * if (typeof fieldLabel === 'string' && fieldLabel.includes('.')) { * fieldLabel = await this.i18n.translate(fieldLabel, { lang: language }); * } else if (typeof fieldLabel === 'object') { * fieldLabel = fieldLabel[language] || fieldLabel.zh || fieldLabel.en; * } * * // 翻译枚举值 * const valueLabels = metadata?.valueLabels; * const displayOldValue = valueLabels?.[oldValue] * ? await this.translateValueLabel(valueLabels[oldValue], language) * : oldValue; * const displayNewValue = valueLabels?.[newValue] * ? await this.translateValueLabel(valueLabels[newValue], language) * : newValue; * * return { * fieldLabel, * oldValue, * newValue, * displayOldValue, * displayNewValue, * }; * } * * private async translateValueLabel( * label: string | { [lang: string]: string }, * language: string, * ): Promise { * if (typeof label === 'string' && label.includes('.')) { * return await this.i18n.translate(label, { lang: language }); * } * if (typeof label === 'object') { * return label[language] || label.zh || label.en || ''; * } * return label; * } * } */ /** * 场景 1: 纯 i18n key 方式(推荐) * * 优点: * - 翻译集中管理,易于维护 * - 支持动态切换语言 * - 翻译可以复用 * - 适合大型项目和国际化需求 * * 缺点: * - 需要额外的翻译文件配置 * - 增加了一定的复杂度 */ export declare class PureI18nDto { username: string; } /** * 场景 2: 纯多语言对象方式 * * 优点: * - 简单直接,无需额外配置 * - 适合小型项目或固定语言场景 * - 翻译就在代码中,查看方便 * * 缺点: * - 翻译分散在各个 DTO 中,难以统一管理 * - 不易于动态切换语言 * - 翻译无法复用 */ export declare class PureLabelDto { username: string; } /** * 场景 3: 混合方式(fieldLabel 优先) * * 优点: * - 灵活性最高 * - 可以为特定字段覆盖 i18n 翻译 * * 缺点: * - 可能造成混淆 * - 建议统一使用一种方式 */ export declare class MixedDto { username: string; } export declare class RegisterUserDto { username: string; email: string; password: string; phone?: string; agreeTerms?: boolean; } export {};