feat: 添加DeepLX翻译服务支持,包含服务地址配置和令牌可选性检查#76
Conversation
Reviewer's GuideThis PR integrates DeepLX as a new translation backend by registering it alongside existing services, exposing a configurable endpoint and optional token in the UI, adjusting validation rules, and adding the actual translation logic module. ER diagram for DeepLX service configuration optionserDiagram
CONFIG {
string service
string deeplx
map token
map proxy
}
SERVICES {
string value
string label
}
CONFIG ||--o{ SERVICES : uses
CONFIG ||--|{ TOKEN : has
TOKEN {
string service
string token
}
Class diagram for DeepLX translation service integrationclassDiagram
class Config {
+string service
+string deeplx
+map token
+map proxy
+string from
+string to
}
class servicesType {
+Set machine
+Set AI
+Set useCustomUrl
+isUseCustomUrl(service)
}
class options {
+array services
+object defaultOption
}
class _service {
+deeplx
}
class deeplx {
+async deeplx(message)
}
Config "1" -- "*" servicesType : uses
Config "1" -- "*" options : uses
_service "1" -- "1" deeplx : registers
deeplx <|-- deeplx : implements
note for deeplx "Implements DeepLX translation logic with optional token and configurable URL"
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey @hu3rror - I've reviewed your changes - here's some feedback:
- Avoid the no-op
if (config.service === services.deeplx) {}incheckConfigby inverting the logic or using a guard clause to make the intent clearer. - DRY up the default DeepLX API URL by moving it into a single constant/shared config instead of duplicating it in both
option.tsandconstant.ts. - Leverage the new
servicesType.isUseCustomUrlhelper inMain.vueto control the DeepLX URL input visibility rather than a dedicatedshowDeepLXcomputed property.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Avoid the no-op `if (config.service === services.deeplx) {}` in `checkConfig` by inverting the logic or using a guard clause to make the intent clearer.
- DRY up the default DeepLX API URL by moving it into a single constant/shared config instead of duplicating it in both `option.ts` and `constant.ts`.
- Leverage the new `servicesType.isUseCustomUrl` helper in `Main.vue` to control the DeepLX URL input visibility rather than a dedicated `showDeepLX` computed property.
## Individual Comments
### Comment 1
<location> `entrypoints/service/deeplx.ts:7` </location>
<code_context>
+
+async function deeplx(message: any) {
+ // deeplx 不支持 zh-Hans,需要转换为 zh
+ let targetLang = config.to === 'zh-Hans' ? 'zh' : config.to;
+ let sourceLang = config.from === 'auto' ? 'auto' : config.from;
+
+ // 判断是否使用代理或自定义URL
</code_context>
<issue_to_address>
Language code conversion for zh-Hans may need to be more robust.
Consider handling other Chinese language variants (e.g., 'zh-CN', 'zh-Hant') to ensure broader compatibility and prevent failures.
</issue_to_address>
<suggested_fix>
<<<<<<< SEARCH
// deeplx 不支持 zh-Hans,需要转换为 zh
let targetLang = config.to === 'zh-Hans' ? 'zh' : config.to;
let sourceLang = config.from === 'auto' ? 'auto' : config.from;
=======
// deeplx 不支持部分中文变体,需要统一转换为 zh
function normalizeChineseLang(lang: string): string {
// 常见中文变体
const zhVariants = [
'zh-Hans', 'zh-CN', 'zh-SG', // 简体
'zh-Hant', 'zh-TW', 'zh-HK', 'zh-MO' // 繁体
];
if (zhVariants.includes(lang)) {
return 'zh';
}
return lang;
}
let targetLang = normalizeChineseLang(config.to);
let sourceLang = config.from === 'auto' ? 'auto' : config.from;
>>>>>>> REPLACE
</suggested_fix>
### Comment 2
<location> `entrypoints/service/deeplx.ts:34` </location>
<code_context>
+ });
+
+ if (resp.ok) {
+ let result = await resp.json();
+ // DeepLX 返回格式通常是 { code: 200, data: "translated text" }
+ if (result.code === 200) {
+ return result.data;
+ } else {
</code_context>
<issue_to_address>
No error handling for invalid JSON responses.
Wrap resp.json() in a try-catch block to handle invalid JSON and provide a clearer error message.
</issue_to_address>
<suggested_fix>
<<<<<<< SEARCH
if (resp.ok) {
let result = await resp.json();
// DeepLX 返回格式通常是 { code: 200, data: "translated text" }
if (result.code === 200) {
return result.data;
} else {
throw new Error(`DeepLX 翻译失败: ${result.message || '未知错误'}`);
}
} else {
console.log("DeepLX 翻译失败:", resp);
throw new Error(`DeepLX 翻译失败: ${resp.status} ${resp.statusText} body: ${await resp.text()}`);
}
}
=======
if (resp.ok) {
let result;
try {
result = await resp.json();
} catch (err) {
throw new Error(`DeepLX 返回了无效的 JSON 响应: ${err instanceof Error ? err.message : String(err)}`);
}
// DeepLX 返回格式通常是 { code: 200, data: "translated text" }
if (result.code === 200) {
return result.data;
} else {
throw new Error(`DeepLX 翻译失败: ${result.message || '未知错误'}`);
}
} else {
console.log("DeepLX 翻译失败:", resp);
throw new Error(`DeepLX 翻译失败: ${resp.status} ${resp.statusText} body: ${await resp.text()}`);
}
}
>>>>>>> REPLACE
</suggested_fix>
### Comment 3
<location> `entrypoints/service/deeplx.ts:42` </location>
<code_context>
+ throw new Error(`DeepLX 翻译失败: ${result.message || '未知错误'}`);
+ }
+ } else {
+ console.log("DeepLX 翻译失败:", resp);
+ throw new Error(`DeepLX 翻译失败: ${resp.status} ${resp.statusText} body: ${await resp.text()}`);
+ }
</code_context>
<issue_to_address>
Logging the entire Response object may not be informative.
Instead, log resp.status, resp.statusText, or the response body for clearer debugging information.
</issue_to_address>
<suggested_fix>
<<<<<<< SEARCH
console.log("DeepLX 翻译失败:", resp);
throw new Error(`DeepLX 翻译失败: ${resp.status} ${resp.statusText} body: ${await resp.text()}`);
=======
const errorBody = await resp.text();
console.log("DeepLX 翻译失败:", `status: ${resp.status}, statusText: ${resp.statusText}, body: ${errorBody}`);
throw new Error(`DeepLX 翻译失败: ${resp.status} ${resp.statusText} body: ${errorBody}`);
>>>>>>> REPLACE
</suggested_fix>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| // deeplx 不支持 zh-Hans,需要转换为 zh | ||
| let targetLang = config.to === 'zh-Hans' ? 'zh' : config.to; | ||
| let sourceLang = config.from === 'auto' ? 'auto' : config.from; |
There was a problem hiding this comment.
suggestion: Language code conversion for zh-Hans may need to be more robust.
Consider handling other Chinese language variants (e.g., 'zh-CN', 'zh-Hant') to ensure broader compatibility and prevent failures.
| // deeplx 不支持 zh-Hans,需要转换为 zh | |
| let targetLang = config.to === 'zh-Hans' ? 'zh' : config.to; | |
| let sourceLang = config.from === 'auto' ? 'auto' : config.from; | |
| // deeplx 不支持部分中文变体,需要统一转换为 zh | |
| function normalizeChineseLang(lang: string): string { | |
| // 常见中文变体 | |
| const zhVariants = [ | |
| 'zh-Hans', 'zh-CN', 'zh-SG', // 简体 | |
| 'zh-Hant', 'zh-TW', 'zh-HK', 'zh-MO' // 繁体 | |
| ]; | |
| if (zhVariants.includes(lang)) { | |
| return 'zh'; | |
| } | |
| return lang; | |
| } | |
| let targetLang = normalizeChineseLang(config.to); | |
| let sourceLang = config.from === 'auto' ? 'auto' : config.from; |
| if (resp.ok) { | ||
| let result = await resp.json(); | ||
| // DeepLX 返回格式通常是 { code: 200, data: "translated text" } | ||
| if (result.code === 200) { | ||
| return result.data; | ||
| } else { | ||
| throw new Error(`DeepLX 翻译失败: ${result.message || '未知错误'}`); | ||
| } | ||
| } else { | ||
| console.log("DeepLX 翻译失败:", resp); | ||
| throw new Error(`DeepLX 翻译失败: ${resp.status} ${resp.statusText} body: ${await resp.text()}`); | ||
| } | ||
| } |
There was a problem hiding this comment.
suggestion (bug_risk): No error handling for invalid JSON responses.
Wrap resp.json() in a try-catch block to handle invalid JSON and provide a clearer error message.
| if (resp.ok) { | |
| let result = await resp.json(); | |
| // DeepLX 返回格式通常是 { code: 200, data: "translated text" } | |
| if (result.code === 200) { | |
| return result.data; | |
| } else { | |
| throw new Error(`DeepLX 翻译失败: ${result.message || '未知错误'}`); | |
| } | |
| } else { | |
| console.log("DeepLX 翻译失败:", resp); | |
| throw new Error(`DeepLX 翻译失败: ${resp.status} ${resp.statusText} body: ${await resp.text()}`); | |
| } | |
| } | |
| if (resp.ok) { | |
| let result; | |
| try { | |
| result = await resp.json(); | |
| } catch (err) { | |
| throw new Error(`DeepLX 返回了无效的 JSON 响应: ${err instanceof Error ? err.message : String(err)}`); | |
| } | |
| // DeepLX 返回格式通常是 { code: 200, data: "translated text" } | |
| if (result.code === 200) { | |
| return result.data; | |
| } else { | |
| throw new Error(`DeepLX 翻译失败: ${result.message || '未知错误'}`); | |
| } | |
| } else { | |
| console.log("DeepLX 翻译失败:", resp); | |
| throw new Error(`DeepLX 翻译失败: ${resp.status} ${resp.statusText} body: ${await resp.text()}`); | |
| } | |
| } |
| console.log("DeepLX 翻译失败:", resp); | ||
| throw new Error(`DeepLX 翻译失败: ${resp.status} ${resp.statusText} body: ${await resp.text()}`); |
There was a problem hiding this comment.
suggestion: Logging the entire Response object may not be informative.
Instead, log resp.status, resp.statusText, or the response body for clearer debugging information.
| console.log("DeepLX 翻译失败:", resp); | |
| throw new Error(`DeepLX 翻译失败: ${resp.status} ${resp.statusText} body: ${await resp.text()}`); | |
| const errorBody = await resp.text(); | |
| console.log("DeepLX 翻译失败:", `status: ${resp.status}, statusText: ${resp.statusText}, body: ${errorBody}`); | |
| throw new Error(`DeepLX 翻译失败: ${resp.status} ${resp.statusText} body: ${errorBody}`); |
| let sourceLang = config.from === 'auto' ? 'auto' : config.from; | ||
|
|
||
| // 判断是否使用代理或自定义URL | ||
| let url: string = config.proxy[config.service] ? config.proxy[config.service] : config.deeplx || 'http://localhost:1188/translate'; |
There was a problem hiding this comment.
suggestion (code-quality): Avoid unneeded ternary statements (simplify-ternary)
| let url: string = config.proxy[config.service] ? config.proxy[config.service] : config.deeplx || 'http://localhost:1188/translate'; | |
| let url: string = config.proxy[config.service] || (config.deeplx || 'http://localhost:1188/translate'); |
Explanation
It is possible to simplify certain ternary statements into either use of an|| or !.This makes the code easier to read, since there is no conditional logic.
|
希望能尽快合并:) |
look like good! |
这 PR 引入了对 DeepLX 翻译服务的支持,能够利用本地或自托管的 DeepLX 实例进行翻译。
主要改动点:
新增 DeepLX 翻译服务选项:
entrypoints/utils/option.ts,components/Main.vue)可自定义的 DeepLX 服务地址:
http://localhost:1188/translate。components/Main.vue,entrypoints/utils/constant.ts,entrypoints/utils/option.ts)可选的 API 令牌支持:
entrypoints/service/deeplx.ts,entrypoints/utils/check.ts)DeepLX 翻译逻辑:
deeplx.ts模块entrypoints/service/deeplx.ts,entrypoints/service/_service.ts)Summary by Sourcery
Add support for the DeepLX translation service, including selectable service option, configurable API endpoint, and optional authentication token.
New Features:
Bug Fixes:
Enhancements: