【AI工具】CS文件控件文本翻译器:使用火山引擎API翻译C#文件中的控件显示文本

在研究一个俄语界面的程序,为了把界面的俄语翻译为中文,让AI写个html 程序能够使用火山引擎API把csharp UI文件中控件的text属性从俄语翻译为中文。(提示词需要根据效果进行调整)。

这是一个C# (.cs) 文件控件文本翻译器。它的主要作用是读取用户上传的C#源代码文件,利用火山引擎大模型API,将代码中面向用户的界面文本(例如按钮文字、标签内容、消息框提示等)从俄语翻译成中文,同时保持原始代码的结构和语法不变。


功能分解

  1. 用户界面 (UI) 与交互 (UX):

  • 现代化设计

    :页面采用了渐变背景、圆角、阴影等现代CSS样式,提供了美观且专业的视觉体验。

  • 响应式布局

    :通过 @media 查询,界面能够适应不同尺寸的屏幕(如桌面和手机),保证了在小屏幕设备上的可用性。

  • 清晰的流程引导

    :界面被划分为API配置、翻译配置、文件上传、进度显示和结果下载等几个逻辑区域,引导用户按步骤完成操作。

  • 配置区域:

    • API配置

      :用户需要输入自己的火山引擎API信息,包括:

      API Key (Bearer Token)

      :用于身份验证,输入框为密码类型以保护密钥。

      模型名称

      :允许用户自定义调用的AI模型,并提供了一个默认值。

      API端点

      :指定API请求的URL,同样提供了默认值。

    • 翻译配置

      :用户可以精细化控制翻译过程:

      自定义提示词 (Prompt)

      :提供了一个强大的文本框,用户可以编辑给AI的指令。默认提示词非常专业,明确要求AI扮演C#本地化专家,只翻译俄语字符串,并保持代码结构、格式不变,还给出了翻译示例。

      批次大小 (Batch Size)

      :允许用户选择每次发送给API的文本块大小(以字符为单位)。这是为了处理大文件,避免超出API单次请求的长度限制。

      输出文件名

      :用户可以指定翻译后下载的文件的名称。

  • 文件处理:

    • 文件上传

      :提供一个样式精美的按钮来选择本地的 .cs 文件。

    • 文件信息显示

      :选择文件后,页面会立即显示该文件的名称、大小和最后修改日期,提供即时反馈。

    • 智能命名

      :如果用户没有指定输出文件名,程序会自动根据上传的文件名生成一个(例如 MyForm.cs 会变成 MyForm_translated.cs)。

    • 客户端读取

      :文件内容完全在用户的浏览器中通过 FileReader API进行读取,不会上传到任何中间服务器,保证了代码的私密性。

  • 核心翻译逻辑 (JavaScript):

    • 分批处理 (Batching)

      startTranslation 函数会将整个C#文件内容根据设定的“批次大小”切割成多个小文本块。

    • 异步API调用

      :程序会循环遍历每一个文本块,使用 async/await 和 fetch 函数,逐个调用火山引擎API进行翻译。

    • 实时进度反馈

      :在翻译过程中:

      一个进度条会实时更新,显示总体完成百分比。

      旁边的文本会提示当前正在处理哪个批次(如 “正在翻译第 2/10 个批次...”)。

      下方的**日志控制台 (Log Container)**会实时打印详细的操作日志,包括文件读取、分批情况、每个批次的翻译成功或失败信息,并用不同颜色(信息、成功、错误)加以区分,便于追踪和调试。

    • 健壮的错误处理

      API调用部分有详细的错误捕获机制,如果API返回错误,会在日志中明确提示失败原因。

      即使某个批次翻译失败,程序也会将该批次的原文保留,然后继续处理下一个批次,确保最终能生成一个完整的文件,而不是中途中断。

    • 结果整合与下载

      :所有批次处理完毕后,程序会将翻译后的(或翻译失败保留的原文)文本块重新组合成一个完整的代码文件内容。然后显示“下载”按钮,用户点击后即可将结果保存到本地。

    总结

    总而言之,这是一个纯前端、功能强大且用户体验良好的开发者工具。它通过调用外部AI服务,解决了C#代码本地化过程中繁琐的文本翻译工作,实现了以下几个关键点:

    • 自动化

      :将手动翻译代码中字符串的工作自动化。

    • 智能化

      :利用大模型的能力进行高质量、符合上下文的翻译。

    • 安全性

      :代码文件仅在用户本地浏览器处理,不经过第三方服务器。

    • 高可用性

      :通过分批处理和错误处理机制,保证了对大文件处理的稳定性和可靠性。

    • 用户友好

      :界面直观,提供实时反馈,让复杂的过程变得透明可控。

    <!DOCTYPE html><html lang="zh-CN"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>CS文件控件文本翻译器</title>    <!-- 修复:移除了CryptoJS库,因为Bearer认证不需要它 -->    <style>        * {            margin: 0;            padding: 0;            box-sizing: border-box;        }
            body {            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);            min-height: 100vh;            padding: 20px;        }
            .container {            max-width: 1200px;            margin: 0 auto;            background: white;            border-radius: 20px;            box-shadow: 0 20px 40px rgba(0,0,0,0.1);            overflow: hidden;        }
            .header {            background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);            color: white;            padding: 30px;            text-align: center;        }
            .header h1 {            font-size: 2.5em;            margin-bottom: 10px;            text-shadow: 0 2px 4px rgba(0,0,0,0.3);        }
            .header p {            font-size: 1.1em;            opacity: 0.9;        }
            .main-content {            padding: 40px;        }
            .config-section {            background: #f8f9ff;            padding: 25px;            border-radius: 15px;            margin-bottom: 30px;            border-left: 5px solid #4facfe;        }
            .config-section h3 {            color: #333;            margin-bottom: 20px;            font-size: 1.3em;        }
            .form-group {            margin-bottom: 20px;        }
            .form-group label {            display: block;            margin-bottom: 8px;            font-weight: 600;            color: #555;        }
            .form-group input, .form-group textarea, .form-group select {            width: 100%;            padding: 12px;            border: 2px solid #e1e5e9;            border-radius: 8px;            font-size: 14px;            transition: border-color 0.3s ease;        }
            .form-group input:focus, .form-group textarea:focus, .form-group select:focus {            outline: none;            border-color: #4facfe;            box-shadow: 0 0 0 3px rgba(79, 172, 254, 0.1);        }
            .form-group textarea {            resize: vertical;            min-height: 100px;        }
            .form-row {            display: grid;            grid-template-columns: 1fr 1fr;            gap: 20px;        }
            .file-upload {            position: relative;            display: inline-block;            width: 100%;        }
            .file-upload input[type=file] {            position: absolute;            left: -9999px;        }
            .file-upload-label {            display: block;            padding: 15px;            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);            color: white;            text-align: center;            border-radius: 8px;            cursor: pointer;            transition: transform 0.3s ease;        }
            .file-upload-label:hover {            transform: translateY(-2px);        }
            .btn {            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);            color: white;            padding: 15px 30px;            border: none;            border-radius: 8px;            font-size: 16px;            font-weight: 600;            cursor: pointer;            transition: all 0.3s ease;            text-transform: uppercase;            letter-spacing: 1px;        }
            .btn:hover {            transform: translateY(-2px);            box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3);        }
            .btn:disabled {            opacity: 0.6;            cursor: not-allowed;            transform: none;        }
            .progress-container {            margin-top: 20px;            padding: 20px;            background: #f8f9ff;            border-radius: 10px;            border-left: 5px solid #4facfe;        }
            .progress-bar {            width: 100%;            height: 20px;            background: #e1e5e9;            border-radius: 10px;            overflow: hidden;            margin-bottom: 15px;        }
            .progress-fill {            height: 100%;            background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);            width: 0%;            transition: width 0.3s ease;        }
            .log-container {            background: #1e1e1e;            color: #00ff00;            padding: 20px;            border-radius: 10px;            max-height: 300px;            overflow-y: auto;            font-family: 'Courier New', monospace;            font-size: 14px;            line-height: 1.4;        }
            .log-entry {            margin-bottom: 5px;        }
            .log-entry.error {            color: #ff6b6b;        }
            .log-entry.success {            color: #51cf66;        }
            .log-entry.info {            color: #74c0fc;        }
            .result-section {            margin-top: 30px;            padding: 25px;            background: #f8f9ff;            border-radius: 15px;            border-left: 5px solid #51cf66;        }
            .download-btn {            background: linear-gradient(135deg, #51cf66 0%, #40c057 100%);            margin-top: 15px;        }
            .download-btn:hover {            box-shadow: 0 10px 20px rgba(81, 207, 102, 0.3);        }
            @media (max-width: 768px) {            .form-row {                grid-template-columns: 1fr;            }            .header h1 {                font-size: 2em;            }            .main-content {                padding: 20px;            }        }    </style></head><body>    <div class="container">        <div class="header">            <h1>🔧 CS文件控件文本翻译器</h1>            <p>使用火山引擎API翻译C#文件中的控件显示文本</p>        </div>
            <div class="main-content">            <!-- API配置区域 -->            <div class="config-section">                <h3>🔑 API配置 (API Configuration)</h3>                 <!-- 修复:恢复为单个API Key输入框,移除Secret Key -->                <div class="form-group">                    <label for="apiKey">API Key (Bearer Token):</label>                    <input type="password" id="apiKey" placeholder="请输入火山方舟API Key">                </div>                <!-- 新增:模型名称输入框,使其更灵活 -->                <div class="form-group">                    <label for="modelName">模型名称 (Model Name):</label>                    <input type="text" id="modelName" value="deepseek-v3-1-250821">                </div>                <div class="form-group">                    <label for="endpoint">API端点 (Endpoint):</label>                    <!-- 修复:移除value开头的空格 -->                    <input type="url" id="endpoint" placeholder="https://ark.cn-beijing.volces.com/api/v3/chat/completions" value="https://ark.cn-beijing.volces.com/api/v3/chat/completions">                </div>            </div>
                <!-- 翻译配置区域 -->            <div class="config-section">                <h3>⚙️ 翻译配置 (Translation Settings)</h3>                <div class="form-group">                    <label for="customPrompt">自定义提示词 (Custom Prompt):</label>                    <textarea id="customPrompt" placeholder="请输入自定义提示词,用于指导AI如何翻译控件文本">你是一个专业的C#界面本地化翻译专家。请将以下C#代码中的控件俄语文本(如按钮文字、标签文本、消息框内容等)翻译为中文,保持代码结构不变,只翻译用户界面显示的文本内容。
    翻译要求:1. 只翻译字符串字面量中的俄语文本内容2. 保持所有代码语法、结构、变量名、方法名完全不变3. 保持缩进和格式不变4. 专业术语要准确,符合中文软件界面习惯5. 不要添加额外的注释或说明
    示例:原文:this.btnHello.Text = "Привет";译文:this.btnHello.Text = "你好";;</textarea>                </div>                <div class="form-row">                    <div class="form-group">                        <label for="batchSize">批次大小 (Batch Size):</label>                        <select id="batchSize">                            <option value="1000">1000字符</option>                            <option value="2000" selected>2000字符</option>                            <option value="3000">3000字符</option>                            <option value="5000">5000字符</option>                        </select>                    </div>                    <div class="form-group">                        <label for="outputFileName">输出文件名 (Output Filename):</label>                        <input type="text" id="outputFileName" placeholder="translated_file.cs" value="">                    </div>                </div>            </div>
                <!-- 文件上传区域 -->            <div class="config-section">                <h3>📁 文件上传 (File Upload)</h3>                <div class="form-group">                    <div class="file-upload">                        <input type="file" id="csFile" accept=".cs" />                        <label for="csFile" class="file-upload-label">                            📎 选择CS文件 (Select CS File)                        </label>                    </div>                    <div id="fileInfo" style="margin-top: 10px; color: #666;"></div>                </div>            </div>
                <!-- 操作按钮 -->            <div style="text-align: center; margin: 30px 0;">                <button class="btn" id="translateBtn" onclick="startTranslation()">                    🚀 开始翻译 (Start Translation)                </button>            </div>
                <!-- 进度显示区域 -->            <div id="progressContainer" class="progress-container" style="display: none;">                <h3>📊 翻译进度 (Translation Progress)</h3>                <div class="progress-bar">                    <div class="progress-fill" id="progressFill"></div>                </div>                <div id="progressText">准备中... (Preparing...)</div>
                    <div class="log-container" id="logContainer">                    <div class="log-entry info">系统初始化完成 (System initialized)</div>                </div>            </div>
                <!-- 结果区域 -->            <div id="resultSection" class="result-section" style="display: none;">                <h3>✅ 翻译完成 (Translation Complete)</h3>                <p>翻译已完成,点击下载按钮获取翻译后的文件。</p>                <button class="btn download-btn" id="downloadBtn" onclick="downloadResult()">                    💾 下载翻译文件 (Download Translated File)                </button>            </div>        </div>    </div>
        <script>        let translatedContent = '';        let currentFile = null;
            document.getElementById('csFile').addEventListener('change', function(e) {            const file = e.target.files[0];            const fileInfo = document.getElementById('fileInfo');            if (file) {                currentFile = file;                fileInfo.innerHTML = `                    <strong>已选择文件:</strong> ${file.name}<br>                    <strong>文件大小:</strong> ${(file.size / 1024).toFixed(2)} KB<br>                    <strong>最后修改:</strong> ${new Date(file.lastModified).toLocaleString()}                `;                const outputFileName = document.getElementById('outputFileName');                if (!outputFileName.value) {                    const baseName = file.name.replace('.cs', '');                    outputFileName.value = `${baseName}_translated.cs`;                }            } else {                currentFile = null;                fileInfo.innerHTML = '';            }        });
            function addLog(message, type = 'info') {            const logContainer = document.getElementById('logContainer');            const logEntry = document.createElement('div');            logEntry.className = `log-entry ${type}`;            logEntry.innerHTML = `[${new Date().toLocaleTimeString()}] ${message}`;            logContainer.appendChild(logEntry);            logContainer.scrollTop = logContainer.scrollHeight;        }
            function updateProgress(percent, text) {            document.getElementById('progressFill').style.width = `${percent}%`;            document.getElementById('progressText').textContent = text;        }
            // 修复:根据curl示例重写API调用函数        async function callVolcanoAPI(text, prompt) {            const apiKey = document.getElementById('apiKey').value;            const endpoint = document.getElementById('endpoint').value.trim();            const modelName = document.getElementById('modelName').value.trim();
                if (!apiKey) {                throw new Error('请输入API Key');            }            if (!endpoint) {                throw new Error('请输入API端点URL');            }             if (!modelName) {                throw new Error('请输入模型名称');            }
                // 1. 构造请求体 (Body) - 完全匹配curl示例            const requestBody = {                model: modelName,                messages: [                    { role: 'system', content: prompt },                    { role: 'user', content: text }                ]            };
                // 2. 构造请求头 (Headers) - 完全匹配curl示例            const headers = {                'Content-Type': 'application/json',                'Authorization': `Bearer ${apiKey}`            };
                // 3. 发送API请求            const response = await fetch(endpoint, {                method: 'POST',                headers: headers,                body: JSON.stringify(requestBody)            });
                // 4. 处理响应            if (!response.ok) {                const errorText = await response.text();                let errorData;                try {                    errorData = JSON.parse(errorText);                } catch(e) {                    errorData = { message: errorText || '未知错误' };                }                throw new Error(`API调用失败: ${response.status} - ${errorData.message || errorData.error?.message || '无法解析错误信息'}`);            }
                const data = await response.json();             if (data.error) {                throw new Error(`API返回错误: ${data.error.message}`);            }            // 提取API返回的文本            return data.choices?.[0]?.message?.content || text;        }
            function splitTextIntoBatches(text, batchSize) {            const batches = [];            let currentBatch = '';            const lines = text.split('\n');
                for (const line of lines) {                if (currentBatch.length + line.length + 1 > batchSize && currentBatch.length > 0) {                    batches.push(currentBatch);                    currentBatch = line + '\n';                } else {                    currentBatch += line + '\n';                }            }
                if (currentBatch.trim()) {                batches.push(currentBatch);            }
                return batches;        }
            async function startTranslation() {            if (!currentFile) {                alert('请先选择一个CS文件');                return;            }
                const apiKey = document.getElementById('apiKey').value;            if (!apiKey) {                alert('请输入API Key');                return;            }
                const translateBtn = document.getElementById('translateBtn');            const progressContainer = document.getElementById('progressContainer');            const resultSection = document.getElementById('resultSection');
                translateBtn.disabled = true;            progressContainer.style.display = 'block';            resultSection.style.display = 'none';            translatedContent = '';            document.getElementById('logContainer').innerHTML = '';            addLog('系统初始化完成 (System initialized)', 'info');
                try {                addLog('开始读取文件... (Reading file...)', 'info');
                    const fileContent = await new Promise((resolve, reject) => {                    const reader = new FileReader();                    reader.onload = e => resolve(e.target.result);                    reader.onerror = reject;                    reader.readAsText(currentFile, 'utf-8');                });
                    addLog(`文件读取完成,大小: ${fileContent.length} 字符`, 'success');
                    const batchSize = parseInt(document.getElementById('batchSize').value);                const customPrompt = document.getElementById('customPrompt').value;
                    const batches = splitTextIntoBatches(fileContent, batchSize);                addLog(`文件已分割为 ${batches.length} 个批次`, 'info');
                    let translatedBatches = [];                for (let i = 0; i < batches.length; i++) {                    const batch = batches[i];                    const progress = ((i + 1) / batches.length) * 100;
                        updateProgress(progress, `正在翻译第 ${i + 1}/${batches.length} 个批次...`);                    addLog(`开始翻译批次 ${i + 1}/${batches.length}`, 'info');
                        try {                        // 启用真实API调用                        const translatedBatch = await callVolcanoAPI(batch, customPrompt);                        translatedBatches.push(translatedBatch);                        addLog(`批次 ${i + 1} 翻译完成`, 'success');                    } catch (error) {                        addLog(`批次 ${i + 1} 翻译失败: ${error.message}`, 'error');                        translatedBatches.push(batch);                    }                }
                    translatedContent = translatedBatches.join('');                updateProgress(100, '翻译完成!');                addLog('所有批次翻译完成,准备下载...', 'success');
                    resultSection.style.display = 'block';
                } catch (error) {                addLog(`翻译过程中发生错误: ${error.message}`, 'error');                alert(`翻译失败: ${error.message}`);            } finally {                translateBtn.disabled = false;            }        }
            function downloadResult() {            if (!translatedContent) {                alert('没有可下载的内容');                return;            }
                const outputFileName = document.getElementById('outputFileName').value || 'translated_file.cs';
                const blob = new Blob([translatedContent], { type: 'text/plain;charset=utf-8' });            const url = URL.createObjectURL(blob);
                const a = document.createElement('a');            a.href = url;            a.download = outputFileName;            document.body.appendChild(a);            a.click();            document.body.removeChild(a);
                URL.revokeObjectURL(url);
                addLog(`文件已下载: ${outputFileName}`, 'success');        }    </script></body></html>
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值