feat: AI 引擎提示词三语化 + 语言下拉框母语名称

- engine.ts: CUSTOM_RULE_SYSTEM_PROMPT / DEEP_REVIEW_SYSTEM_PROMPT 从硬编码中文改为三语模板(zh-CN/en/ja);parseJsonResponse 错误消息改用 t() 本地化;用户消息标签按语言本地化
- setupView.ts: 删除未使用的 getLanguageLabel / languageLabel;语言下拉选项文本固定为母语名称(中文(简体)/English/日本語),不再随界面语言翻译
This commit is contained in:
范智鹏
2026-07-26 22:59:48 +08:00
parent ff32ecf5c2
commit 6d29f304e3
2 changed files with 90 additions and 26 deletions
+86 -12
View File
@@ -9,7 +9,7 @@ import type {
TranslatedDiagnostic,
AIFinding,
} from './schema';
import { t } from '../i18n/messages';
import { t, getLanguage } from '../i18n/messages';
function buildCustomRulePrompt(rules: CustomRule[]): string {
return rules.map(r =>
@@ -61,7 +61,7 @@ function parseJsonResponse(raw: string): object {
const start = trimmed.indexOf('{');
const end = trimmed.lastIndexOf('}');
if (start === -1 || end === -1) {
throw new Error(`响应中未找到 JSON。原始响应(前200字符):${trimmed.slice(0, 200)}`);
throw new Error(t('engine.jsonNotFound', { 0: trimmed.slice(0, 200) }));
}
let jsonStr = trimmed.substring(start, end + 1);
try {
@@ -71,29 +71,103 @@ function parseJsonResponse(raw: string): object {
try {
return JSON.parse(jsonStr);
} catch {
throw new Error(`JSON 解析失败。原始响应(前200字符):${jsonStr.slice(0, 200)}`);
throw new Error(t('engine.jsonParseFail', { 0: jsonStr.slice(0, 200) }));
}
}
}
const CUSTOM_RULE_SYSTEM_PROMPT = `你是代码规则审查员,只评估以下自定义规则是否被违反。
function buildCustomRuleSystemPrompt(): string {
const lang = getLanguage();
if (lang === 'ja') {
return `あなたはコードルールレビュアーです。以下のカスタムルールに違反しているかどうかのみを評価してください。
意味を理解し、テキストの一致ではなく判断してください。
JSONのみを出力、形式:
{ "customRuleResults": [{ "ruleId": "ルールID", "line": 行番号, "severity": "error|warning|info", "message": "違反の説明" }] }
ルールに違反していない場合は空の配列を返してください。
出力言語:ja`;
}
if (lang === 'en') {
return `You are a code rule reviewer. Only evaluate whether the following custom rules are violated.
Understand semantics, not text matching.
Output JSON only, format:
{ "customRuleResults": [{ "ruleId": "rule id", "line": line number, "severity": "error|warning|info", "message": "violation description" }] }
If no rules are violated, return an empty array.
Output language: en`;
}
return `你是代码规则审查员,只评估以下自定义规则是否被违反。
理解语义而非文本匹配。
仅输出 JSON,格式:
{ "customRuleResults": [{ "ruleId": "规则ID", "line": 行号, "severity": "error|warning|info", "message": "触发描述" }] }
如果没有违反任何规则,返回空数组。`;
如果没有违反任何规则,返回空数组。
const DEEP_REVIEW_SYSTEM_PROMPT = `你是资深代码审查专家,完成两个任务:
输出语言:zh-CN`;
}
function buildDeepReviewSystemPrompt(): string {
const lang = getLanguage();
if (lang === 'ja') {
return `あなたはシニアコードレビュー専門家です。2つのタスクを実行してください:
1. 英語の静的解析結果を出力言語に翻訳し、修正提案を追加する
2. コードを詳細にレビューし、静的解析でカバーされていない問題を発見する
重点分野:セキュリティ脆弱性、論理エラー、パフォーマンス問題、設計欠陥
静的解析ですでに報告された問題を重複しないでください。
JSONのみを出力。文字列内の二重引用符は \\" でエスケープしてください。
形式:
{
"translatedDiagnostics": [{ "originalRuleId": "元のID", "translatedMessage": "翻訳メッセージ", "translatedSuggestion": "提案", "codeDiff": "任意" }],
"findings": [{ "ruleId": "kebab-case", "severity": "error|warning|info", "category": "bug|performance|security|style|design", "title": "タイトル", "description": "説明", "suggestion": "提案", "codeDiff": "任意", "line": 行番号 }]
}
出力言語:ja`;
}
if (lang === 'en') {
return `You are a senior code review expert. Complete two tasks:
1. Translate English static analysis results into the output language and add fix suggestions
2. Deeply review the code to find issues not covered by static analysis
Focus on: security vulnerabilities, logic errors, performance issues, design flaws
Do not duplicate issues already reported by static analysis.
Output JSON only. Double quotes in strings must be escaped with \\".
Format:
{
"translatedDiagnostics": [{ "originalRuleId": "original id", "translatedMessage": "translated message", "translatedSuggestion": "suggestion", "codeDiff": "optional" }],
"findings": [{ "ruleId": "kebab-case", "severity": "error|warning|info", "category": "bug|performance|security|style|design", "title": "title", "description": "description", "suggestion": "suggestion", "codeDiff": "optional", "line": line number }]
}
Output language: en`;
}
return `你是资深代码审查专家,完成两个任务:
1. 将英文静态分析结果翻译为输出语言,并补充修复建议
2. 深度审查代码,发现静态分析未覆盖的问题
重点:安全漏洞、逻辑错误、性能问题、设计缺陷
不要重复静态分析已报告的问题。
仅输出 JSON,字符串中的双引号必须用 \" 转义。
仅输出 JSON,字符串中的双引号必须用 \\" 转义。
格式:
{
"translatedDiagnostics": [{ "originalRuleId": "原始ID", "translatedMessage": "翻译", "translatedSuggestion": "建议", "codeDiff": "可选" }],
"findings": [{ "ruleId": "kebab-case", "severity": "error|warning|info", "category": "bug|performance|security|style|design", "title": "标题", "description": "描述", "suggestion": "建议", "codeDiff": "可选", "line": 行号 }]
}`;
}
输出语言:zh-CN`;
}
function buildUserPromptCustomRules(customRules: CustomRule[], numberedCode: string): string {
const lang = getLanguage();
const label = lang === 'ja' ? 'カスタムルール' : lang === 'en' ? 'Custom Rules' : '自定义规则';
const codeLabel = lang === 'ja' ? 'コード(行番号付き)' : lang === 'en' ? 'Code (with line numbers)' : '代码(带行号)';
return `## ${label}\n${buildCustomRulePrompt(customRules)}\n\n## ${codeLabel}\n${numberedCode}`;
}
function buildUserPromptDeepReview(numberedCode: string, staticDiagnostics: LinterDiagnostic[]): string {
const lang = getLanguage();
const codeLabel = lang === 'ja' ? 'コード(行番号付き)' : lang === 'en' ? 'Code (with line numbers)' : '代码(带行号)';
const resultLabel = lang === 'ja' ? '静的解析結果' : lang === 'en' ? 'Static Analysis Results' : '静态分析结果(英文)';
return `## ${codeLabel}\n${numberedCode}\n\n## ${resultLabel}\n${buildLinterDiagnosticsPrompt(staticDiagnostics)}`;
}
export async function runAIReview(
context: vscode.ExtensionContext,
@@ -141,15 +215,15 @@ export async function runAIReview(
const requestA =
customRules.length > 0
? provider.chat(
CUSTOM_RULE_SYSTEM_PROMPT,
`## 自定义规则\n${buildCustomRulePrompt(customRules)}\n\n## 代码(带行号)\n${numberedCode}`,
buildCustomRuleSystemPrompt(),
buildUserPromptCustomRules(customRules, numberedCode),
options
)
: Promise.resolve('{}');
const requestB = provider.chat(
`${DEEP_REVIEW_SYSTEM_PROMPT}\n输出语言:${getAIOutputLanguage()}`,
`## 代码(带行号)\n${numberedCode}\n\n## 静态分析结果(英文)\n${buildLinterDiagnosticsPrompt(staticDiagnostics)}`,
buildDeepReviewSystemPrompt(),
buildUserPromptDeepReview(numberedCode, staticDiagnostics),
options
);
+4 -14
View File
@@ -13,16 +13,7 @@ import { TxtConverter } from '../rules/converters/txt-converter';
import { ExcelConverter } from '../rules/converters/excel-converter';
import { DocxConverter } from '../rules/converters/docx-converter';
import { PptxConverter } from '../rules/converters/pptx-converter';
import { t, onLanguageChange, Language } from '../i18n/messages';
function getLanguageLabel(lang: string): string {
switch (lang) {
case 'zh-CN': return t('lang.zhCN');
case 'en': return t('lang.en');
case 'ja': return t('lang.ja');
default: return lang;
}
}
import { t, onLanguageChange } from '../i18n/messages';
export class SetupViewProvider implements vscode.WebviewViewProvider {
private _view?: vscode.WebviewView;
@@ -146,7 +137,6 @@ export class SetupViewProvider implements vscode.WebviewViewProvider {
baseUrl: baseUrlConfigured ? config.baseUrl : '',
baseUrlConfigured,
language: config.outputLanguage,
languageLabel: getLanguageLabel(config.outputLanguage),
apiKeyConfigured,
},
providers: getAllProviderMeta(),
@@ -599,9 +589,9 @@ input::placeholder { color: var(--vscode-input-placeholderForeground, var(--vsco
<div class="field">
<label class="field-label">${t('setup.outputLangHint')}</label>
<select id="languageSelect" onchange="postMsg('setLanguage', this.value)">
<option value="zh-CN"${config.outputLanguage === 'zh-CN' ? ' selected' : ''}>${t('lang.zhCN')}</option>
<option value="en"${config.outputLanguage === 'en' ? ' selected' : ''}>${t('lang.en')}</option>
<option value="ja"${config.outputLanguage === 'ja' ? ' selected' : ''}>${t('lang.ja')}</option>
<option value="zh-CN"${config.outputLanguage === 'zh-CN' ? ' selected' : ''}>中文(简体)</option>
<option value="en"${config.outputLanguage === 'en' ? ' selected' : ''}>English</option>
<option value="ja"${config.outputLanguage === 'ja' ? ' selected' : ''}>日本語</option>
</select>
</div>
</div>