如何在NestJS中本地化Swagger接口的@ApiQuery描述?
NestJS Swagger @ApiQuery 描述本地化方案
装饰器在类定义阶段执行,此时I18n服务尚未初始化,所以无法直接将动态翻译后的字符串传入@ApiQuery的description参数。以下是两种可行的解决方案:
方案一:生成多语言独立Swagger文档
通过创建不同语言版本的OpenAPI文档,让用户访问不同端点查看对应语言的接口描述:
定义带国际化键的自定义装饰器
用自定义装饰器存储翻译键,替代直接写入硬编码描述:import { ApiQuery, ApiQueryOptions } from '@nestjs/swagger'; export const ApiI18nQuery = (options: Omit<ApiQueryOptions, 'description'> & { i18nKey: string }) => { // 先传入翻译键作为临时描述,后续替换 return ApiQuery({ ...options, description: options.i18nKey }); };在接口中使用自定义装饰器
@Get() @ApiI18nQuery({ name: 'search', required: false, i18nKey: 'api.query.search' }) @ApiI18nQuery({ name: 'limit', required: false, type: Number, i18nKey: 'api.query.limit' }) getItems( @Query('search') search?: string, @Query('limit') limit?: number, ) { return this.carService.find({ search, limit }); }生成多语言文档并注册端点
借助transformDocument钩子,在生成文档时替换翻译键为对应语言的文本:import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; import { I18nService } from 'nestjs-i18n'; // 假设你用的是nestjs-i18n async function bootstrap() { const app = await NestFactory.create(AppModule); const i18nService = app.get(I18nService); // 生成英文文档 const enDoc = SwaggerModule.createDocument(app, new DocumentBuilder() .setTitle('API Documentation (English)') .build(), { transformDocument: (doc) => { replaceI18nDescriptions(doc, i18nService, 'en'); return doc; }, }); // 生成西班牙文文档 const esDoc = SwaggerModule.createDocument(app, new DocumentBuilder() .setTitle('Documentación de la API (Español)') .build(), { transformDocument: (doc) => { replaceI18nDescriptions(doc, i18nService, 'es'); return doc; }, }); // 注册两个Swagger UI端点 SwaggerModule.setup('api/docs/en', app, enDoc); SwaggerModule.setup('api/docs/es', app, esDoc); await app.listen(3000); } // 通用替换函数 function replaceI18nDescriptions(doc: any, i18nService: I18nService, lang: string) { Object.values(doc.paths).forEach(path => { Object.values(path).forEach((operation: any) => { operation.parameters?.forEach((param: any) => { if (param.in === 'query' && param.description) { param.description = i18nService.translate(param.description, { lang }); } }); }); }); }
方案二:Swagger UI内动态切换语言
通过自定义JS在Swagger UI页面添加语言切换控件,动态替换描述文本,无需生成多份文档:
使用带扩展字段的自定义装饰器
将翻译键存入OpenAPI的扩展字段,避免和临时描述混淆:import { ApiQuery, ApiQueryOptions } from '@nestjs/swagger'; export const ApiI18nQuery = (options: Omit<ApiQueryOptions, 'description'> & { i18nKey: string }) => { return ApiQuery({ ...options, description: options.i18nKey, 'x-i18n-key': options.i18nKey, // 存储到扩展字段 }); };在Swagger UI中注入自定义JS
在SwaggerModule.setup时添加语言切换逻辑:SwaggerModule.setup('api/docs', app, document, { customJs: ` // 定义翻译字典(可改为从外部JSON文件加载) const translations = { en: { 'api.query.search': 'Search term to filter items', 'api.query.limit': 'Number of items to return' }, es: { 'api.query.search': 'Término de búsqueda para filtrar elementos', 'api.query.limit': 'Número de elementos a devolver' } }; // 添加语言选择下拉框 const langSelect = document.createElement('select'); langSelect.className = 'lang-selector'; langSelect.innerHTML = '<option value="en">English</option><option value="es">Español</option>'; document.querySelector('.swagger-ui .topbar-wrapper').appendChild(langSelect); // 替换描述文本的函数 function updateDescriptions(lang) { document.querySelectorAll('.parameter__description').forEach(el => { const key = el.textContent.trim(); if (translations[lang][key]) { el.textContent = translations[lang][key]; } }); // 可扩展替换其他元素,如接口标题、摘要等 } // 初始化显示英文 updateDescriptions('en'); // 监听语言切换事件 langSelect.addEventListener('change', (e) => { updateDescriptions(e.target.value); }); `, customCss: ` /* 给语言选择框加样式 */ .lang-selector { margin-left: 1rem; padding: 0.3rem; border-radius: 4px; border: 1px solid #ccc; } ` });
如果你的翻译存储在外部JSON文件中,可以将translations改为通过fetch加载对应语言的JSON文件,避免硬编码。
内容的提问来源于stack exchange,提问作者Rashid Behbudov
相关产品推荐
相关产品推荐

