NestJS结合Sequelize如何实现LocalizedColumn装饰器简化多语言字段定义
自定义@LocalizedColumn装饰器实现方案
前置准备
首先确认你项目中已安装以下依赖:
- sequelize-typescript
- @nestjs/swagger
- lodash
同时你已定义好语言映射配置Locals,示例参考:
// src/constants/locale.constant.ts export const Locals = { ar: 'Ar', en: 'En' } as const; // 支持的语言列表 export const SUPPORTED_LOCALES = Object.keys(Locals) as Array<keyof typeof Locals>;
装饰器实现代码
import { Column, DataType } from 'sequelize-typescript'; import { ApiProperty } from '@nestjs/swagger'; import * as _ from 'lodash'; import { Locals, SUPPORTED_LOCALES } from 'src/constants/locale.constant'; export function LocalizedColumn(columnOptions: { type: DataType, allowNull?: boolean } & Record<string, any> = {}) { return function (target: any, propertyKey: string) { // 生成所有语言对应的物理字段名列表 const localeColumns: string[] = SUPPORTED_LOCALES.map(locale => { const suffix = Locals[locale]; return `${propertyKey}${suffix}`; }); // 动态给每个语言的物理字段添加@Column和@ApiProperty装饰器 localeColumns.forEach((columnName, index) => { const locale = SUPPORTED_LOCALES[index]; // 注册物理字段 Column({ ...columnOptions, // 可选:自定义数据库字段名蛇形命名,不需要可删除 field: _.snakeCase(columnName) })(target, columnName); // 注册Swagger文档注解,不需要可删除本段 ApiProperty({ type: columnOptions.type, required: !columnOptions.allowNull, description: `${propertyKey}(${locale})` })(target, columnName); }); // 给原属性注册虚拟字段逻辑 Column({ type: DataType.VIRTUAL(columnOptions.type, localeColumns), get() { const currentLocale = (this as any).$local || 'ar'; const suffix = Locals[currentLocale as keyof typeof Locals]; return this[`${propertyKey}${suffix}`]; }, set(value: any) { const currentLocale = (this as any).$local || 'ar'; const suffix = Locals[currentLocale as keyof typeof Locals]; this[`${propertyKey}${suffix}`] = value; } })(target, propertyKey); } }
使用方式
在模型中直接注解即可,和你预期的用法完全一致:
import { ApiProperty } from '@nestjs/swagger'; import { DataType, Model } from 'sequelize-typescript'; import { LocalizedColumn } from 'src/decorators/localized-column.decorator'; export class YourModel extends Model { @ApiProperty({ type: String }) @LocalizedColumn({ type: DataType.STRING, allowNull: false }) name: string; @ApiProperty({ type: String }) @LocalizedColumn({ type: DataType.STRING }) address: string; }
注意事项
- 需要确保请求处理流程中,会把当前用户的语言标识挂载到模型实例的
$local属性上,你可以选择在请求中间件、全局拦截器或者service层赋值;如果不想挂载到实例上,也可以修改装饰器的get/set逻辑,从cls-hooked的全局请求上下文里取当前语言,使用起来更灵活。 - 后续新增语言只需要修改
Locals常量添加映射即可,不需要改动其他逻辑。 - 如果不需要生成多语言字段的Swagger文档,直接删除装饰器中
ApiProperty相关的代码即可。
内容的提问来源于stack exchange,提问作者zain khatib
相关产品推荐
相关产品推荐

