Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 59 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@
- 自动审查代码变更
- 性能和安全建议
- 可通过参数禁用
- 🌏 中英双语
- 自动检测中文内容
- 🌏 双向翻译
- 支持中文翻译为英文(默认)
- 支持英文翻译为中文
- 可配置默认翻译方向
- 智能中英互译
- 保持格式规范
- 📋 测试建议
Expand Down Expand Up @@ -173,6 +175,10 @@ a line exceeds the recommended value of git.

### 翻译命令

翻译命令支持双向翻译,可以进行中译英或英译中。

#### 基本用法

使用翻译命令有三种方式:
```bash
# 方式1:指定文件路径
Expand All @@ -188,11 +194,32 @@ git-commit-helper translate /path/to/existing/file # 文件路径

命令会自动判断参数内容:如果是一个存在的文件路径则读取文件内容进行翻译,否则将参数内容作为文本进行翻译。

#### 翻译方向控制

默认情况下,翻译命令使用配置文件中设置的默认翻译方向(默认为中译英)。你可以通过以下方式控制翻译方向:

```bash
# 中译英(使用默认方向或显式指定)
git-commit-helper translate "这是中文内容"
git-commit-helper translate --to-english "这是中文内容"

# 英译中
git-commit-helper translate --to-chinese "This is English content"

# 设置默认翻译方向
git-commit-helper config --set-translate-direction to-english # 默认中译英
git-commit-helper config --set-translate-direction to-chinese # 默认英译中
```

支持的翻译方向值:
- `to-english` 或 `chinese-to-english` 或 `中译英`:中文翻译为英文
- `to-chinese` 或 `english-to-chinese` 或 `英译中`:英文翻译为中文

### 命令概览

| 命令 | 说明 | 示例 |
|------|------|------|
| config | 配置 AI 服务 | `git-commit-helper config [--set-only-chinese <true\|false>/--set-only-english <true\|false>]` |
| config | 配置 AI 服务 | `git-commit-helper config [--set-only-chinese <true\|false>/--set-only-english <true\|false>/--set-translate-direction <to-english\|to-chinese>]` |
| show | 显示当前配置 | `git-commit-helper show` |
| install | 安装 Git Hook | `git-commit-helper install [-f]` |
| ai add | 添加 AI 服务 | `git-commit-helper ai add` |
Expand All @@ -202,7 +229,7 @@ git-commit-helper translate /path/to/existing/file # 文件路径
| ai set-timeout | 设置请求超时 | `git-commit-helper ai set-timeout -s 30` |
| ai list | 列出所有服务 | `git-commit-helper ai list` |
| ai test | 测试指定服务 | `git-commit-helper ai test [-t "测试文本"]` |
| translate | 翻译内容 | `git-commit-helper translate [-f 文件] [-t 文本]` |
| translate | 翻译内容 | `git-commit-helper translate [-f 文件] [-t 文本] [--to-english\|--to-chinese]` |
| commit | 生成提交信息 | `git-commit-helper commit [-t 类型] [-m 描述] [-a] [--amend] [--no-review/--no-influence/--no-log/--only-chinese/--only-english] [--issues ISSUE...]` |
| ai-review | 管理 AI 代码审查 | `git-commit-helper ai-review [--enable/--disable/--status]` |

Expand All @@ -223,7 +250,18 @@ git-commit-helper translate /path/to/existing/file # 文件路径
```bash
# 配置
git-commit-helper config [选项]
--set-only-chinese <true|false> 设置默认是否只使用中文提交信息
--set-only-chinese <true|false> 设置默认是否只使用中文提交信息
--set-only-english <true|false> 设置默认是否只使用英文提交信息
--set-translate-direction <DIRECTION> 设置默认翻译方向
可选值: to-english(中译英), to-chinese(英译中)

# 翻译内容
git-commit-helper translate [选项] [内容]
-f, --file <FILE> 指定要翻译的文件路径
-t, --text <TEXT> 指定要翻译的文本内容
--to-english 翻译为英文(中译英)
--to-chinese 翻译为中文(英译中)
[内容] 直接提供要翻译的文本或文件路径(智能判断)

# 远程代码审查
git-commit-helper <URL>
Expand Down Expand Up @@ -258,6 +296,22 @@ git-commit-helper commit [选项]
示例:

```bash
# 翻译示例
# 使用默认翻译方向(默认为中译英)
git-commit-helper translate "这是一段中文内容"

# 显式指定中译英
git-commit-helper translate --to-english "这是一段中文内容"

# 英译中
git-commit-helper translate --to-chinese "This is English content"

# 设置默认翻译方向为中译英
git-commit-helper config --set-translate-direction to-english

# 设置默认翻译方向为英译中
git-commit-helper config --set-translate-direction to-chinese

# 生成提交信息
git-commit-helper commit

Expand Down
50 changes: 38 additions & 12 deletions src/ai_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ use copilot_client::CopilotClient;

#[async_trait]
pub trait AiService: Send + Sync {
async fn translate(&self, text: &str) -> anyhow::Result<String> {
async fn translate(&self, text: &str, direction: &crate::config::TranslateDirection) -> anyhow::Result<String> {
// 使用翻译的 prompt
let system_prompt = get_translation_prompt(text);
let system_prompt = get_translation_prompt(text, direction);
Ok(self.chat(&system_prompt, text).await?)
}

Expand Down Expand Up @@ -218,9 +218,12 @@ fn wrap_chinese_text(text: &str, max_width: usize) -> String {
result
}

fn get_translation_prompt(text: &str) -> String {
let prompt = format!(
r#"You are a professional translator. Please translate the following Chinese text to English.
fn get_translation_prompt(text: &str, direction: &crate::config::TranslateDirection) -> String {
use crate::config::TranslateDirection;

let prompt = match direction {
TranslateDirection::ChineseToEnglish => format!(
r#"You are a professional translator. Please translate the following Chinese text to English.
Important rules:
1. Keep all English content, numbers, and English punctuation unchanged
2. Do not translate any content inside English double quotes
Expand All @@ -237,7 +240,30 @@ fn get_translation_prompt(text: &str) -> String {

Text to translate:
{}"#,
wrap_chinese_text(text, 72));
wrap_chinese_text(text, 72)
),
TranslateDirection::EnglishToChinese => format!(
r#"You are a professional translator. Please translate the following English text to Chinese.
Important rules:
1. Keep all Chinese content, numbers, and Chinese punctuation unchanged
2. Do not translate any content inside quotes
3. Maintain the original text structure and formatting
4. Only return the Chinese translation, DO NOT include the original English text
5. Keep simple and concise, no need to rewrite or expand the content
6. Use appropriate Chinese punctuation marks

Example response format:
feat: 添加外部插件支持

1. 实现插件加载机制
2. 添加插件配置接口
3. 设置插件发现路径: "/plugins"

Text to translate:
{}"#,
text
),
};

debug!("生成的提示词:\n{}", prompt);
prompt
Expand Down Expand Up @@ -725,7 +751,7 @@ pub async fn create_translator(config: &Config) -> anyhow::Result<Box<dyn Transl
create_translator_for_service(service_config).await
}

pub async fn translate_with_fallback(config: &Config, text: &str) -> anyhow::Result<String> {
pub async fn translate_with_fallback(config: &Config, text: &str, direction: &crate::config::TranslateDirection) -> anyhow::Result<String> {
let mut tried_services = Vec::new();

// 如果已设置环境变量,直接返回原文
Expand All @@ -734,7 +760,7 @@ pub async fn translate_with_fallback(config: &Config, text: &str) -> anyhow::Res
}

debug!("尝试使用默认服务 {:?}", config.default_service);
if let Some(result) = try_translate(&config.default_service, config, text).await {
if let Some(result) = try_translate(&config.default_service, config, text, direction).await {
return result;
}
tried_services.push(config.default_service.clone());
Expand All @@ -745,15 +771,15 @@ pub async fn translate_with_fallback(config: &Config, text: &str) -> anyhow::Res
}

debug!("尝试使用备选服务 {:?}", service_config.service);
if let Some(result) = try_translate(&service_config.service, config, text).await {
if let Some(result) = try_translate(&service_config.service, config, text, direction).await {
return result;
}
tried_services.push(service_config.service.clone());
}

while let Some(service) = select_retry_service(config, &tried_services)? {
debug!("用户选择使用 {:?} 重试", service);
if let Some(result) = try_translate(&service, config, text).await {
if let Some(result) = try_translate(&service, config, text, direction).await {
return result;
}
tried_services.push(service);
Expand All @@ -762,12 +788,12 @@ pub async fn translate_with_fallback(config: &Config, text: &str) -> anyhow::Res
Err(anyhow::anyhow!("所有AI服务均失败"))
}

async fn try_translate(service: &AIService, config: &Config, text: &str) -> Option<anyhow::Result<String>> {
async fn try_translate(service: &AIService, config: &Config, text: &str, direction: &crate::config::TranslateDirection) -> Option<anyhow::Result<String>> {
let service_config = config.services.iter()
.find(|s| s.service == *service)?;

let translator = create_translator_for_service(service_config).await.ok()?;
match translator.translate(text).await {
match translator.translate(text, direction).await {
Ok(result) => Some(Ok(result)),
Err(e) => {
warn!("{:?} 服务翻译失败: {}", service, e);
Expand Down
2 changes: 1 addition & 1 deletion src/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -959,7 +959,7 @@ pub async fn generate_commit_suggestion(commit_types: &[String], user_descriptio
None => get_staged_diff()?
};

let message = translator.translate(&prompt).await?.to_string();
let message = translator.translate(&prompt, &config::TranslateDirection::ChineseToEnglish).await?.to_string();

// 移除各种 AI 返回的元信息标记
let message = message
Expand Down
20 changes: 18 additions & 2 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ pub struct Config {
pub only_chinese: bool, // 是否默认只使用中文
#[serde(default = "default_only_english")]
pub only_english: bool, // 是否默认只使用英文
#[serde(default = "default_translate_direction")]
pub translate_direction: TranslateDirection, // 默认翻译方向
}

// 添加默认值函数
Expand All @@ -37,6 +39,16 @@ fn default_only_english() -> bool {
false
}

fn default_translate_direction() -> TranslateDirection {
TranslateDirection::ChineseToEnglish
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub enum TranslateDirection {
ChineseToEnglish, // 中译英(默认)
EnglishToChinese, // 英译中
}

#[derive(Debug, Serialize, Deserialize, Clone, Default)]
pub struct GerritConfig {
pub username: Option<String>,
Expand Down Expand Up @@ -89,6 +101,7 @@ impl Config {
gerrit: None,
only_chinese: false, // 默认关闭
only_english: false, // 默认关闭
translate_direction: default_translate_direction(), // 默认中译英
}
}

Expand Down Expand Up @@ -293,6 +306,7 @@ impl Config {
gerrit: None,
only_chinese: false, // 默认关闭
only_english: false, // 默认关闭
translate_direction: default_translate_direction(), // 默认中译英
};

// 确保配置目录存在
Expand Down Expand Up @@ -322,9 +336,10 @@ impl Config {
gerrit: None,
only_chinese: false,
only_english: false,
translate_direction: default_translate_direction(),
};
let translator = ai_service::create_translator(&test_config).await?;
match translator.translate("这是一个测试消息,用于验证翻译功能是否正常。").await {
match translator.translate("这是一个测试消息,用于验证翻译功能是否正常。", &TranslateDirection::ChineseToEnglish).await {
Ok(result) => {
println!("\n测试结果:");
println!("原文: 这是一个测试消息,用于验证翻译功能是否正常。");
Expand Down Expand Up @@ -496,11 +511,12 @@ impl Config {
gerrit: None,
only_chinese: false,
only_english: false,
translate_direction: default_translate_direction(),
};
let translator = ai_service::create_translator(&test_config).await?;
let text = "这是一个测试消息,用于验证翻译功能是否正常。";
debug!("开始发送翻译请求");
match translator.translate(text).await {
match translator.translate(text, &TranslateDirection::ChineseToEnglish).await {
Ok(result) => {
debug!("收到翻译响应");
println!("\n测试结果:");
Expand Down
7 changes: 4 additions & 3 deletions src/git.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::commit::CommitMessage;
use crate::ai_service;
use crate::review;
use crate::config::{self, TranslateDirection};
use dialoguer::Confirm;
use log::{debug, info};
use std::path::Path;
Expand Down Expand Up @@ -57,14 +58,14 @@ pub async fn process_commit_msg(path: &Path, no_review: bool) -> anyhow::Result<

info!("开始翻译流程,默认使用 {:?} 服务", config.default_service);

// 翻译标题
let en_title = ai_service::translate_with_fallback(&config, &msg.title).await?;
// 翻译标题(中译英)
let en_title = ai_service::translate_with_fallback(&config, &msg.title, &TranslateDirection::ChineseToEnglish).await?;
let en_title = wrap_text(&en_title, MAX_LINE_LENGTH);
let original_title = msg.title.clone();

// 翻译正文(如果有的话)
let (en_body, cn_body) = if let Some(body) = &msg.body {
let en_body = ai_service::translate_with_fallback(&config, body).await?;
let en_body = ai_service::translate_with_fallback(&config, body, &TranslateDirection::ChineseToEnglish).await?;
(Some(wrap_text(&en_body, MAX_LINE_LENGTH)), Some(body.clone()))
} else {
(None, None)
Expand Down
Loading