You need to sign in or sign up before continuing.
Commit 5e14298e authored by mingyard's avatar mingyard

feat:翻译:列表和功能

parent 1f953a2c
......@@ -7,6 +7,7 @@
],
"words": [
"activerecords",
"DEEPL",
"dotenv",
"healthz",
"hset",
......
......@@ -10,6 +10,7 @@ import { SystemController } from './controller/system.controller';
import { UserModule } from './controller/user/user.module';
import { AuthModule } from './controller/auth/auth.module';
import { RedisModule } from '@nestjs-modules/ioredis';
import { TranslateModule } from './controller/translate/translate.module';
@Module({
imports: [
......@@ -28,6 +29,7 @@ import { RedisModule } from '@nestjs-modules/ioredis';
}),
UserModule,
AuthModule,
TranslateModule,
],
controllers: [SystemController],
})
......
export const DEEPL_SOURCE_LANGUAGES = [
{ key: 'AR', language: 'Arabic', name: '阿拉伯语' },
{ key: 'BG', language: 'Bulgarian', name: '保加利亚语' },
{ key: 'CS', language: 'Czech', name: '捷克语' },
{ key: 'DA', language: 'Danish', name: '丹麦语' },
{ key: 'DE', language: 'German', name: '德语' },
{ key: 'EL', language: 'Greek', name: '希腊语' },
{ key: 'EN', language: 'English', name: '英语' },
{ key: 'ES', language: 'Spanish', name: '西班牙语' },
{ key: 'ET', language: 'Estonian', name: '爱沙尼亚语' },
{ key: 'FI', language: 'Finnish', name: '芬兰语' },
{ key: 'FR', language: 'French', name: '法语' },
{ key: 'HU', language: 'Hungarian', name: '匈牙利语' },
{ key: 'ID', language: 'Indonesian', name: '印度尼西亚语' },
{ key: 'IT', language: 'Italian', name: '意大利语' },
{ key: 'JA', language: 'Japanese', name: '日语' },
{ key: 'KO', language: 'Korean', name: '韩语' },
{ key: 'LT', language: 'Lithuanian', name: '立陶宛语' },
{ key: 'LV', language: 'Latvian', name: '拉脱维亚语' },
{ key: 'NB', language: 'Norwegian Bokmål', name: '挪威语' },
{ key: 'NL', language: 'Dutch', name: '荷兰语' },
{ key: 'PL', language: 'Polish', name: '波兰语' },
{ key: 'PT', language: 'Portuguese', name: '葡萄牙语' },
{ key: 'RO', language: 'Romanian', name: '罗马尼亚语' },
{ key: 'RU', language: 'Russian', name: '俄语' },
{ key: 'SK', language: 'Slovak', name: '斯洛伐克语' },
{ key: 'SL', language: 'Slovenian', name: '斯洛文尼亚语' },
{ key: 'SV', language: 'Swedish', name: '瑞典语' },
{ key: 'TR', language: 'Turkish', name: '土耳其语' },
{ key: 'UK', language: 'Ukrainian', name: '乌克兰语' },
{ key: 'ZH', language: 'Chinese', name: '中文' },
];
export const DEEPL_TARGET_LANGUAGES = [
{ key: 'AR', language: 'Arabic', name: '阿拉伯语' },
{ key: 'BG', language: 'Bulgarian', name: '保加利亚语' },
{ key: 'CS', language: 'Czech', name: '捷克语' },
{ key: 'DA', language: 'Danish', name: '丹麦语' },
{ key: 'DE', language: 'German', name: '德语' },
{ key: 'EL', language: 'Greek', name: '希腊语' },
{ key: 'EN', language: 'English', name: '英语' },
// { key: 'EN-GB', language: 'English (British)', name: '英语(英式)' },
// { key: 'EN-US', language: 'English (American)', name: '英语(美式)' },
{ key: 'ES', language: 'Spanish', name: '西班牙语' },
{ key: 'ET', language: 'Estonian', name: '爱沙尼亚语' },
{ key: 'FI', language: 'Finnish', name: '芬兰语' },
{ key: 'FR', language: 'French', name: '法语' },
{ key: 'HU', language: 'Hungarian', name: '匈牙利语' },
{ key: 'ID', language: 'Indonesian', name: '印度尼西亚语' },
{ key: 'IT', language: 'Italian', name: '意大利语' },
{ key: 'JA', language: 'Japanese', name: '日语' },
{ key: 'KO', language: 'Korean', name: '韩语' },
{ key: 'LT', language: 'Lithuanian', name: '立陶宛语' },
{ key: 'LV', language: 'Latvian', name: '拉脱维亚语' },
{ key: 'NB', language: 'Norwegian Bokmål', name: '挪威语' },
{ key: 'NL', language: 'Dutch', name: '荷兰语' },
{ key: 'PL', language: 'Polish', name: '波兰语' },
{ key: 'PT', language: 'Portuguese', name: '葡萄牙语' },
{ key: 'RO', language: 'Romanian', name: '罗马尼亚语' },
{ key: 'RU', language: 'Russian', name: '俄语' },
{ key: 'SK', language: 'Slovak', name: '斯洛伐克语' },
{ key: 'SL', language: 'Slovenian', name: '斯洛文尼亚语' },
{ key: 'SV', language: 'Swedish', name: '瑞典语' },
{ key: 'TR', language: 'Turkish', name: '土耳其语' },
{ key: 'UK', language: 'Ukrainian', name: '乌克兰语' },
{ key: 'ZH', language: 'Chinese', name: '中文' },
// { key: 'ZH-HANS', language: 'Chinese (simplified)', name: '中文(简体)' },
// { key: 'ZH-HANT', language: 'Chinese (traditional)', name: '中文(繁体)' },
];
// 支持的语言
export enum SupportLanguages {
AR = 'AR',
BG = 'BG',
CS = 'CS',
DA = 'DA',
DE = 'DE',
EL = 'EL',
EN = 'EN',
ES = 'ES',
ET = 'ET',
FI = 'FI',
FR = 'FR',
HU = 'HU',
ID = 'ID',
IT = 'IT',
JA = 'JA',
KO = 'KO',
LT = 'LT',
LV = 'LV',
NB = 'NB',
NL = 'NL',
PL = 'PL',
PT = 'PT',
RO = 'RO',
RU = 'RU',
SK = 'SK',
SL = 'SL',
SV = 'SV',
TR = 'TR',
UK = 'UK',
ZH = 'ZH',
}
import { env } from './env';
export interface DeeplConfig {
endpoint: string;
secret: string;
}
export const deepl: DeeplConfig = {
endpoint: env.DEEPL_ENDPOINT ?? 'https://api-free.deepl.com',
secret: env.DEEPL_SECRET ?? '',
};
import { app } from './app';
import { cache } from './cache';
import { database } from './database';
import { deepl } from './deepl';
export const config = {
...app,
cache,
database,
deepl,
};
import { SupportLanguages } from '@/common/utils/constants';
import { ApiProperty } from '@nestjs/swagger';
import { Expose } from 'class-transformer';
import { IsEnum, IsNotEmpty, IsString } from 'class-validator';
export class TranslateReqDto {
@ApiProperty({
description: '目标语言',
enum: SupportLanguages,
example: SupportLanguages.AR,
})
@Expose()
@IsNotEmpty()
@IsEnum(SupportLanguages)
target: SupportLanguages;
@ApiProperty({
description: '待翻译文本',
type: String,
example: '待翻译文本',
})
@Expose()
@IsNotEmpty()
@IsString()
text: string;
}
import { ApiProperty } from '@nestjs/swagger';
import { Expose } from 'class-transformer';
export class TranslateResDto {
@ApiProperty({
description: '要翻译的文本',
type: 'string',
example: '要翻译的文本',
})
@Expose()
text: string;
@ApiProperty({
description: '源语言',
type: 'string',
example: 'EN',
})
@Expose()
source: string;
}
import { Test, TestingModule } from '@nestjs/testing';
import { TranslateController } from './translate.controller';
import { TranslateService } from './translate.service';
describe('TranslateController', () => {
let controller: TranslateController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [TranslateController],
providers: [TranslateService],
}).compile();
controller = module.get<TranslateController>(TranslateController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
import { Body, Controller, Get, Post } from '@nestjs/common';
import { TranslateService } from './translate.service';
import { Auth } from '@/common/decorators/auth.decorator';
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
import { TranslateReqDto } from './dto/req/translateReq.dto';
import { TranslateResDto } from './dto/res/translateRes.dto';
@ApiTags('translate')
@Controller('translate')
export class TranslateController {
constructor(private readonly translateService: TranslateService) {}
// 获取翻译支持的语言
@Get('languages')
@ApiOperation({ summary: '获取翻译支持的语言' })
@ApiResponse({
status: 200,
description: '成功返回支持的语言列表',
example: {
source: [{ key: 'AR', language: 'Arabic', name: '阿拉伯语' }],
target: [{ key: 'AR', language: 'Arabic', name: '阿拉伯语' }],
},
})
@Auth()
async getLanguages(): Promise<{ source: object[]; target: object[] }> {
return await this.translateService.getLanguages();
}
// 翻译文本
@Post('text')
@ApiOperation({ summary: '翻译文本' })
@ApiResponse({
status: 200,
description: '成功返回翻译结果',
example: {
source: 'EN',
text: '要翻译的文本',
},
})
@Auth()
async translateText(
@Body() translateDto: TranslateReqDto,
): Promise<TranslateResDto> {
return await this.translateService.translateText(translateDto);
}
}
import { Module } from '@nestjs/common';
import { TranslateService } from './translate.service';
import { TranslateController } from './translate.controller';
import { AuthGuard } from '../auth/auth.guard';
import { AuthModule } from '../auth/auth.module';
import { UserModule } from '../user/user.module'; // 导入 UserModule
@Module({
imports: [AuthModule, UserModule], // 添加 UserModule 到 imports 数组
controllers: [TranslateController],
providers: [TranslateService, AuthGuard],
})
export class TranslateModule {}
import { Test, TestingModule } from '@nestjs/testing';
import { TranslateService } from './translate.service';
describe('TranslateService', () => {
let service: TranslateService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [TranslateService],
}).compile();
service = module.get<TranslateService>(TranslateService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
import {
DEEPL_SOURCE_LANGUAGES,
DEEPL_TARGET_LANGUAGES,
} from '@/common/utils/constants';
import { Injectable } from '@nestjs/common';
import { TranslateReqDto } from './dto/req/translateReq.dto';
import { TranslateResDto } from './dto/res/translateRes.dto';
import { axiosPostRequest } from '@/common/utils/requests/request';
import { config } from '@/config';
import { BadRequestError } from '@/common/exception/badRequest/BadRequestError';
@Injectable()
export class TranslateService {
constructor() {}
// 获取翻译支持的语言
async getLanguages(): Promise<{ source: object[]; target: object[] }> {
return {
source: DEEPL_SOURCE_LANGUAGES,
target: DEEPL_TARGET_LANGUAGES,
};
}
// 翻译文本
async translateText(translateDto: TranslateReqDto): Promise<TranslateResDto> {
const result = await axiosPostRequest(
`${config.deepl.endpoint}/v2/translate`,
{
text: [translateDto.text],
target_lang: translateDto.target,
},
{
headers: {
'Content-Type': 'application/json',
Authorization: `DeepL-Auth-Key ${config.deepl.secret}`,
},
},
);
const { translations } = result?.data;
if (!translations?.length) {
throw BadRequestError.default('翻译失败');
}
const [{ detected_source_language: source, text }] = translations;
return { source, text };
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment