<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      升鮮寶生鮮配送供應(yīng)鏈管理系統(tǒng),輔助開發(fā)工具,《多語言自動翻譯與導(dǎo)出工具(WinForms版)》開發(fā)文檔 及 阿里云機器翻譯,數(shù)據(jù)庫Mysql .net 全部源代碼

       

      首先展示一下工具的界面

       

      image

       

       

       

       

       

      多語言自動翻譯與導(dǎo)出工具(WinForms版)開發(fā)文檔

      一、系統(tǒng)簡介

      本工具是一款用于自動翻譯多語言字段并導(dǎo)出國際化數(shù)據(jù)的桌面應(yīng)用,支持從 MySQL 數(shù)據(jù)庫讀取中文內(nèi)容,調(diào)用阿里云機器翻譯 API 自動生成 繁體中文 (zh-TW)、英文 (en-US)、日文 (ja-JP) 等多語言版本,并將結(jié)果同步回數(shù)據(jù)庫或?qū)С鰹?Excel 文件。

      二、功能結(jié)構(gòu)

      數(shù)據(jù)庫配置區(qū):輸入 MySQL 服務(wù)器地址、端口、數(shù)據(jù)庫名、用戶名、密碼,并可測試連接與保存配置。
      阿里云配置區(qū):輸入 AccessKeyId 與 AccessKeySecret,選擇需要翻譯的目標(biāo)語言(支持多選)。
      翻譯控制區(qū):一鍵開始多線程翻譯、支持中斷與進度顯示、自動限流與斷點緩存。
      導(dǎo)出區(qū):將數(shù)據(jù)庫中的多語言結(jié)果導(dǎo)出為 Excel 文件(支持自定義保存路徑與打開文件夾)。
      緩存機制:所有翻譯結(jié)果寫入本地 cache.json,下次啟動自動跳過已翻譯內(nèi)容。

      三、界面設(shè)計

      主界面包含兩個主要分組:數(shù)據(jù)庫配置區(qū)與阿里云配置區(qū)。前者用于設(shè)置 MySQL 連接信息,后者用于輸入阿里云 API 憑證、勾選目標(biāo)語言、啟動翻譯與導(dǎo)出操作。

      四、核心邏輯架構(gòu)

      系統(tǒng)包含 MainForm 主窗體、LangRecord 數(shù)據(jù)實體、TranslateWorker 線程池調(diào)度器、CacheManager 緩存管理器與 ExcelExporter 導(dǎo)出模塊。其中 MainForm 提供圖形界面與交互邏輯,TranslateWorker 負(fù)責(zé)并發(fā)任務(wù)分發(fā)。

      五、數(shù)據(jù)庫結(jié)構(gòu)

      sys_language 表字段包括表名、主鍵ID、字段名、字段值、語言等,主鍵為(table_name, table_id, field_name, language)。

      六、核心功能說明

      1. 數(shù)據(jù)庫連接測試:檢測服務(wù)器可用性并提示詳細(xì)錯誤。
      2. 翻譯邏輯:基于 AlibabaCloud.SDK.Alimt20181012 官方 SDK 調(diào)用阿里云機器翻譯服務(wù)。
      3. 只翻譯缺失語言:自動跳過已有翻譯值的字段,節(jié)省調(diào)用次數(shù)。
      4. Excel 導(dǎo)出:支持選擇保存路徑、防止 BigInt 精度丟失、自動樣式化輸出。
      5. 緩存機制:使用 cache.json 文件緩存已翻譯文本以避免重復(fù)調(diào)用。

      七、依賴庫

      MySql.Data 6.9.12 - MySQL 8.0 連接庫
      EPPlus 4.5.3.3 - Excel 導(dǎo)出
      AlibabaCloud.SDK.Alimt20181012 - 翻譯 SDK
      Newtonsoft.Json - JSON 緩存文件讀寫

      八、性能優(yōu)化

      使用多線程并發(fā)翻譯、自動限流機制與緩存避免重復(fù)調(diào)用,分頁查詢減少內(nèi)存壓力。

      九、常見問題

      400 錯誤請求:語言參數(shù)錯誤
      403 無權(quán)限:AccessKey 無效或未開通服務(wù)
      精度丟失:Excel 科學(xué)計數(shù)法,已通過字符串格式解決

      十、部署與運行

      1. 安裝依賴包(MySql.Data、EPPlus、AlibabaCloud.SDK.Alimt20181012 等)
      2. 編譯并運行程序。
      3. 填寫數(shù)據(jù)庫與阿里云配置,測試連接后開始翻譯。
      4. 翻譯完成后點擊“導(dǎo)出Excel”。

      十一、未來擴展方向

      可擴展支持更多語言、批量翻譯多個表、導(dǎo)入Excel回寫、集成DeepL等翻譯服務(wù)。

       

      主要的C#源代碼:

         

      using MySql.Data.MySqlClient;
      using Newtonsoft.Json;
      using OfficeOpenXml;
      using Org.BouncyCastle.Asn1.Cmp;
      using System;
      using System.Collections.Generic;
      using System.Diagnostics;
      using System.IO;
      using System.Linq;
      using System.Net;
      using System.Security.Cryptography;
      using System.Text;
      using System.Text.Json;
      using System.Threading;
      using System.Web.Script.Serialization;
      using System.Windows.Forms;
      using static System.Windows.Forms.VisualStyles.VisualStyleElement;
      
      namespace AliyunTranslator40
      {
          public partial class MainForm : Form
          {
              private string host = "", port = "3306", database = "", user = "", password = "";
              private string AccessKeyId = "", AccessKeySecret = "";
              private const string ConfigFile = "config.json";
              private const string CacheFile = "cache.json";
              private string ConnStr = "";
      
              private volatile bool stopRequested = false;
              private Dictionary<string, string> cache = new Dictionary<string, string>();
              private int total = 0, done = 0;
              private Semaphore sema = new Semaphore(4, 4);
              private Stopwatch sw = new Stopwatch();
      
              public MainForm()
              {
                  InitializeComponent();
                  LoadConfig();
              }
      
              #region 配置管理
              private void btnSaveDb_Click(object sender, EventArgs e)
              {
                  host = txtHost.Text.Trim();
                  port = txtPort.Text.Trim();
                  database = txtDb.Text.Trim();
                  user = txtUser.Text.Trim();
                  password = txtPwd.Text.Trim();
                  BuildConnStr();
                  SaveConfig();
                  Log("? 數(shù)據(jù)庫配置已保存。");
              }
      
              private void btnSaveKey_Click(object sender, EventArgs e)
              {
                  AccessKeyId = txtKeyId.Text.Trim();
                  AccessKeySecret = txtKeySecret.Text.Trim();
                  SaveConfig();
                  Log("? 阿里云密鑰已保存。");
              }
      
              private void BuildConnStr()
              {
                  ConnStr = $"Server={host};Port={port};Database={database};Uid={user};Pwd={password};Charset=utf8mb4;SslMode=None;";
              }
      
              private void LoadConfig()
              {
                  if (!File.Exists(ConfigFile)) return;
                  var js = new JavaScriptSerializer();
                  var cfg = js.Deserialize<Dictionary<string, string>>(File.ReadAllText(ConfigFile));
                  if (cfg == null) return;
      
                  host = cfg.ContainsKey("Host") ? cfg["Host"] : "";
                  port = cfg.ContainsKey("Port") ? cfg["Port"] : "3306";
                  database = cfg.ContainsKey("Database") ? cfg["Database"] : "";
                  user = cfg.ContainsKey("User") ? cfg["User"] : "";
                  password = cfg.ContainsKey("Password") ? cfg["Password"] : "";
                  AccessKeyId = cfg.ContainsKey("AccessKeyId") ? cfg["AccessKeyId"] : "";
                  AccessKeySecret = cfg.ContainsKey("AccessKeySecret") ? cfg["AccessKeySecret"] : "";
      
                  txtHost.Text = host;
                  txtPort.Text = port;
                  txtDb.Text = database;
                  txtUser.Text = user;
                  txtPwd.Text = password;
                  txtKeyId.Text = AccessKeyId;
                  txtKeySecret.Text = AccessKeySecret;
                  BuildConnStr();
                  Log("? 已加載配置。");
              }
      
              private void SaveConfig()
              {
                  var js = new JavaScriptSerializer();
                  var cfg = new Dictionary<string, string>
                  {
                      {"Host", host}, {"Port", port}, {"Database", database},
                      {"User", user}, {"Password", password},
                      {"AccessKeyId", AccessKeyId}, {"AccessKeySecret", AccessKeySecret}
                  };
                  File.WriteAllText(ConfigFile, js.Serialize(cfg));
              }
      
              #endregion
      
              #region 翻譯流程
              private void btnStart_Click(object sender, EventArgs e)
              {
                  stopRequested = false;
                  ThreadPool.QueueUserWorkItem(_ => RunTranslate());
              }
      
              private void btnStop_Click(object sender, EventArgs e)
              {
                  stopRequested = true;
                  Log("?? 已請求停止。");
              }
      
              private void RunTranslate()
              {
                  try
                  {
                      LoadCache();
                      List<LangRecord> list = new List<LangRecord>();
                      UpdateStatus("正在讀取數(shù)據(jù)...");
      
                      using (MySqlConnection conn = new MySqlConnection(ConnStr))
                      {
                          conn.Open();
                          var cmd = new MySqlCommand("SELECT table_name, table_id, field_name, field_value FROM sys_language WHERE language='zh-CN';", conn);
                          var reader = cmd.ExecuteReader();
                          while (reader.Read())
                          {
                              list.Add(new LangRecord
                              {
                                  TableName = reader["table_name"].ToString(),
                                  TableId = Convert.ToInt64(reader["table_id"]),
                                  FieldName = reader["field_name"].ToString(),
                                  FieldValue = reader["field_value"].ToString()
                              });
                          }
                          reader.Close();
                      }
      
                      total = list.Count;
                      done = 0;
                      sw.Restart();
                      UpdateStatus($"共 {total} 條數(shù)據(jù),開始翻譯...");
      
                      foreach (var rec in list)
                      {
                          if (stopRequested) break;
                          sema.WaitOne();
                          ThreadPool.QueueUserWorkItem(state => ProcessRecord(rec));
                      }
      
                      while (done < total && !stopRequested)
                          Thread.Sleep(500);
      
                      SaveCache();
                      ExportToExcel();
                      UpdateStatus("? 翻譯完成。");
                  }
                  catch (Exception ex)
                  {
                      Log("? 翻譯錯誤:" + ex.Message);
                  }
              }
      
              private void ProcessRecord(LangRecord rec)
              {
                  try
                  {
                      if (stopRequested) return;
                      string cn = rec.FieldValue.Trim();
                      if (chkEnUs.Checked && !HasTranslation(rec, "en-US"))
                          SaveTranslation(rec, "en-US", TranslateAliyun(cn, "zh", "en"));
                      if (chkZhTw.Checked && !HasTranslation(rec, "zh-TW"))
                          SaveTranslation(rec, "zh-TW", TranslateAliyun(cn, "zh", "zh-tw"));
      
                      if (chkJaJp.Checked && !HasTranslation(rec, "ja-JP"))
                          SaveTranslation(rec, "ja-JP", TranslateAliyun(cn, "zh", "ja"));
                  }
                  catch (Exception ex)
                  {
                      Log("?? 單條失敗: " + ex.Message);
                  }
                  finally
                  {
                      Interlocked.Increment(ref done);
                      UpdateProgress();
                      sema.Release();
                  }
              }
              #endregion
      
      
      
              #region 阿里云簽名翻譯
              private string TranslateAliyun(string text, string from, string to)
              {
                  if (string.IsNullOrWhiteSpace(text))
                      return text;
      
                  if (string.IsNullOrWhiteSpace(AccessKeyId) || string.IsNullOrWhiteSpace(AccessKeySecret))
                  {
                      Log("?? 阿里云AccessKey未配置");
                      return text;
                  }
      
                  try
                  {
                      string endpoint = "https://mt.aliyuncs.com";
                      string version = "2018-10-12";
                      string action = "TranslateGeneral";
      
                      // 構(gòu)建參數(shù)(按字母順序排序,這是阿里云的要求)
                      var parameters = new SortedDictionary<string, string>(StringComparer.Ordinal)
                      {
                          ["AccessKeyId"] = AccessKeyId,
                          ["Action"] = action,
                          ["Format"] = "JSON",
                          ["FormatType"] = "text",
                          ["Scene"] = "general",
                          ["SignatureMethod"] = "HMAC-SHA1",
                          ["SignatureNonce"] = Guid.NewGuid().ToString(),
                          ["SignatureVersion"] = "1.0",
                          ["SourceLanguage"] = from,
                          ["SourceText"] = text,
                          ["TargetLanguage"] = to,
                          ["Timestamp"] = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"),
                          ["Version"] = version
                      };
      
                      // 構(gòu)建查詢字符串
                      string queryString = BuildQueryString(parameters);
      
                      // 計算簽名
                      string signature = CalculateSignature("GET", parameters);
      
                      // 構(gòu)建最終URL
                      string finalUrl = $"{endpoint}/?{queryString}&Signature={Uri.EscapeDataString(signature)}";
      
                      return ExecuteTranslationRequest(finalUrl, text, from, to);
                  }
                  catch (Exception ex)
                  {
                      Log($"?? 翻譯異常: {ex.Message}");
                      return text;
                  }
              }
      
              /// <summary>
              /// 構(gòu)建查詢字符串(URL編碼)
              /// </summary>
              private string BuildQueryString(SortedDictionary<string, string> parameters)
              {
                  var encodedParams = parameters.Select(p =>
                      $"{Uri.EscapeDataString(p.Key)}={Uri.EscapeDataString(p.Value)}");
      
                  return string.Join("&", encodedParams);
              }
      
              /// <summary>
              /// 計算阿里云簽名
              /// </summary>
              private string CalculateSignature(string method, SortedDictionary<string, string> parameters)
              {
                  // 1. 構(gòu)建規(guī)范化查詢字符串
                  string canonicalizedQueryString = BuildQueryString(parameters);
      
                  // 2. 構(gòu)建待簽名字符串
                  string stringToSign = $"{method}&{Uri.EscapeDataString("/")}&{Uri.EscapeDataString(canonicalizedQueryString)}";
      
                  // 3. 計算HMAC-SHA1簽名
                  string key = $"{AccessKeySecret}&";
                  using (var hmac = new HMACSHA1(Encoding.UTF8.GetBytes(key)))
                  {
                      byte[] hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign));
                      return Convert.ToBase64String(hash);
                  }
              }
      
              /// <summary>
              /// 執(zhí)行翻譯請求并解析結(jié)果
              /// </summary>
              private string ExecuteTranslationRequest(string url, string originalText, string from, string to)
              {
                  HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                  request.Method = "GET";
                  request.Timeout = 15000; // 15秒超時
                  request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36";
      
                  using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                  using (Stream stream = response.GetResponseStream())
                  using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
                  {
                      string responseText = reader.ReadToEnd();
      
                      if (response.StatusCode != HttpStatusCode.OK)
                      {
                          Log($"?? API返回錯誤狀態(tài)碼: {(int)response.StatusCode}");
                          return originalText;
                      }
      
                      return ParseTranslationResult(responseText, originalText, from, to, JsonDocument.Parse(responseText));
                  }
              }
      
              /// <summary>
              /// 解析翻譯結(jié)果
              /// </summary>
              private string ParseTranslationResult(string jsonResponse, string originalText, string from, string to, JsonDocument doc)
              {
                  try
                  {
                      JsonElement root = doc.RootElement;
      
                      // 檢查是否有錯誤
                      if (root.TryGetProperty("Code", out JsonElement codeElement))
                      {
                          string errorCode = codeElement.GetString();
                          if (!string.IsNullOrEmpty(errorCode) && errorCode != "200")
                          {
                              string errorMessage = root.TryGetProperty("Message", out JsonElement messageElement)
                                  ? messageElement.GetString()
                                  : "未知錯誤";
                              Log($"?? 翻譯API錯誤: {errorCode} - {errorMessage}");
                              return originalText;
                          }
                      }
      
                      // 提取翻譯結(jié)果
                      if (root.TryGetProperty("Data", out JsonElement dataElement) &&
                          dataElement.TryGetProperty("Translated", out JsonElement translatedElement))
                      {
                          string translatedText = translatedElement.GetString();
                          if (!string.IsNullOrEmpty(translatedText))
                          {
                              Log($"?? [{from}->{to}] {originalText} => {translatedText}");
                              return translatedText;
                          }
                      }
      
                      Log($"?? 無法解析翻譯結(jié)果: {jsonResponse}");
                      return originalText;
                  }
                  catch (Newtonsoft.Json.JsonException ex)
                  {
                      Log($"?? JSON解析失敗: {ex.Message}");
                      return originalText;
                  }
              }
              #endregion
      
      
              #region 數(shù)據(jù)保存與導(dǎo)出
              private void SaveTranslation(LangRecord rec, string lang, string val)
              {
                  using (MySqlConnection conn = new MySqlConnection(ConnStr))
                  {
                      conn.Open();
                      string sql = "INSERT INTO sys_language (table_name, table_id, field_name, language, field_value) VALUES (@t,@id,@f,@lang,@val) ON DUPLICATE KEY UPDATE field_value=VALUES(field_value)";
                      MySqlCommand cmd = new MySqlCommand(sql, conn);
                      cmd.Parameters.AddWithValue("@t", rec.TableName);
                      cmd.Parameters.AddWithValue("@id", rec.TableId);
                      cmd.Parameters.AddWithValue("@f", rec.FieldName);
                      cmd.Parameters.AddWithValue("@lang", lang);
                      cmd.Parameters.AddWithValue("@val", val);
                      cmd.ExecuteNonQuery();
                  }
              }
      
              private void btnTestDb_Click(object sender, EventArgs e)
              {
                  try
                  {
                      // 獲取輸入
                      host = txtHost.Text.Trim();
                      port = txtPort.Text.Trim();
                      database = txtDb.Text.Trim();
                      user = txtUser.Text.Trim();
                      password = txtPwd.Text.Trim();
                      BuildConnStr();
      
                      // 檢查輸入有效性
                      if (string.IsNullOrEmpty(host) || string.IsNullOrEmpty(database) || string.IsNullOrEmpty(user))
                      {
                          MessageBox.Show("請輸入完整的數(shù)據(jù)庫連接信息(服務(wù)器、數(shù)據(jù)庫、用戶名)!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                          return;
                      }
      
                      // 顯示測試中狀態(tài)
                      lblStatus.Text = "狀態(tài): 正在連接數(shù)據(jù)庫...";
                      lblStatus.Refresh();
      
                      DateTime start = DateTime.Now;
      
                      using (var conn = new MySqlConnection(ConnStr))
                      {
                          conn.Open();
                          MySqlCommand cmd = new MySqlCommand("SELECT VERSION();", conn);
                          string version = Convert.ToString(cmd.ExecuteScalar());
                          TimeSpan elapsed = DateTime.Now - start;
      
                          MessageBox.Show(
                              $"? 數(shù)據(jù)庫連接成功!\n\n服務(wù)器: {host}\n數(shù)據(jù)庫: {database}\n版本: {version}\n耗時: {elapsed.TotalMilliseconds:F0} ms",
                              "連接成功",
                              MessageBoxButtons.OK,
                              MessageBoxIcon.Information
                          );
      
                          Log($"? 成功連接數(shù)據(jù)庫 [{database}] (版本: {version}),耗時 {elapsed.TotalMilliseconds:F0} ms");
                          lblStatus.Text = "狀態(tài): 數(shù)據(jù)庫連接成功 ?";
                      }
                  }
                  catch (MySqlException ex)
                  {
                      string msg;
                      switch (ex.Number)
                      {
                          case 1045: msg = "用戶名或密碼錯誤"; break;
                          case 1042: msg = "無法連接到指定主機"; break;
                          case 1049: msg = "數(shù)據(jù)庫不存在"; break;
                          default: msg = "MySQL 錯誤: " + ex.Message; break;
                      }
                      MessageBox.Show($"? 連接失敗: {msg}", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
                      Log("? 連接失敗: " + msg);
                      lblStatus.Text = "狀態(tài): 連接失敗 ?";
                  }
                  catch (Exception ex)
                  {
                      MessageBox.Show($"? 未知錯誤: {ex.Message}", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
                      Log("? 未知錯誤: " + ex.Message);
                      lblStatus.Text = "狀態(tài): 連接異常 ?";
                  }
              }
      
      
              private void btnExport_Click(object sender, EventArgs e)
              {
                  ExportToExcel();
              }
      
      
      
              private void ExportToExcel()
              {
                  try
                  {
                      UpdateStatus("正在準(zhǔn)備導(dǎo)出 Excel...");
      
                      // 1?? 彈出保存文件對話框
                      SaveFileDialog sfd = new SaveFileDialog();
                      sfd.Title = "選擇導(dǎo)出路徑";
                      sfd.Filter = "Excel 文件 (*.xlsx)|*.xlsx";
                      sfd.FileName = $"translate_result_{DateTime.Now:yyyyMMdd_HHmmss}.xlsx";
                      sfd.InitialDirectory = AppDomain.CurrentDomain.BaseDirectory;
      
                      if (sfd.ShowDialog() != DialogResult.OK)
                      {
                          Log("?? 用戶取消導(dǎo)出。");
                          UpdateStatus("已取消導(dǎo)出");
                          return;
                      }
      
                      string file = sfd.FileName;
                      Log("?? 導(dǎo)出路徑:" + file);
                      UpdateStatus("正在導(dǎo)出 Excel,請稍候...");
      
                      // 2?? 創(chuàng)建 Excel
                      using (var pkg = new OfficeOpenXml.ExcelPackage())
                      {
                          var ws = pkg.Workbook.Worksheets.Add("Translations");
      
                          // 表頭
                          string[] headers = { "表名", "主鍵ID", "字段名", "中文(zh-CN)", "繁體(zh-TW)", "英文(en-US)", "日文(ja-JP)" };
                          for (int i = 0; i < headers.Length; i++)
                          {
                              ws.Cells[1, i + 1].Value = headers[i];
                              ws.Cells[1, i + 1].Style.Font.Bold = true;
                              ws.Cells[1, i + 1].Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
                              ws.Cells[1, i + 1].Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.LightGray);
                              ws.Cells[1, i + 1].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
                          }
      
                          // 3?? 查詢數(shù)據(jù)并寫入
                          using (MySqlConnection conn = new MySqlConnection(ConnStr))
                          {
                              conn.Open();
                              string sql = @"
                          SELECT 
                              table_name, 
                              table_id, 
                              field_name,
                              MAX(CASE WHEN language='zh-CN' THEN field_value END) AS zhCN,
                              MAX(CASE WHEN language='zh-TW' THEN field_value END) AS zhTW,
                              MAX(CASE WHEN language='en-US' THEN field_value END) AS enUS,
                              MAX(CASE WHEN language='ja-JP' THEN field_value END) AS jaJP
                          FROM sys_language
                          GROUP BY table_name, table_id, field_name
                          ORDER BY table_name, table_id, field_name;";
      
                              MySqlCommand cmd = new MySqlCommand(sql, conn);
                              var reader = cmd.ExecuteReader();
                              int row = 2;
      
                              while (reader.Read())
                              {
                                  string tableName = Convert.ToString(reader["table_name"]);
                                  string tableId = Convert.ToString(reader["table_id"]);  // ?? BigInt → string
                                  string fieldName = Convert.ToString(reader["field_name"]);
      
                                  ws.Cells[row, 1].Value = tableName;
                                  ws.Cells[row, 2].Value = tableId;
                                  ws.Cells[row, 3].Value = fieldName;
                                  ws.Cells[row, 4].Value = Convert.ToString(reader["zhCN"]);
                                  ws.Cells[row, 5].Value = Convert.ToString(reader["zhTW"]);
                                  ws.Cells[row, 6].Value = Convert.ToString(reader["enUS"]);
                                  ws.Cells[row, 7].Value = Convert.ToString(reader["jaJP"]);
      
                                  // 設(shè)置 ID 列為文本格式(防止科學(xué)計數(shù)法)
                                  ws.Cells[row, 2].Style.Numberformat.Format = "@";
                                  row++;
                              }
                              reader.Close();
                          }
      
                          // 4?? 自動列寬 + 邊框
                          ws.Cells.AutoFitColumns();
                          var range = ws.Cells[1, 1, ws.Dimension.End.Row, ws.Dimension.End.Column];
                          range.Style.Border.Top.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
                          range.Style.Border.Left.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
                          range.Style.Border.Right.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
                          range.Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
      
                          // 5?? 保存文件
                          pkg.SaveAs(new FileInfo(file));
                      }
      
                      Log("? Excel 導(dǎo)出完成:" + file);
                      UpdateStatus("? Excel 導(dǎo)出完成");
      
                      MessageBox.Show($"? 導(dǎo)出成功!\n文件已保存至:\n{file}", "導(dǎo)出成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
      
                      // 6?? 詢問是否打開文件夾
                      if (MessageBox.Show("是否打開文件所在文件夾?", "完成", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                      {
                          try
                          {
                              System.Diagnostics.Process.Start("explorer.exe", "/select,\"" + file + "\"");
                          }
                          catch { }
                      }
                  }
                  catch (Exception ex)
                  {
                      Log("? 導(dǎo)出失敗: " + ex.Message);
                      MessageBox.Show("? 導(dǎo)出失敗: " + ex.Message, "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
                      UpdateStatus("? 導(dǎo)出失敗");
                  }
              }
      
      
      
              #endregion
      
              #region UI 控制
              private void UpdateProgress()
              {
                  if (InvokeRequired) { Invoke(new Action(UpdateProgress)); return; }
                  double pct = total > 0 ? done * 100.0 / total : 0;
                  progressBar.Value = (int)Math.Min(100, pct);
                  lblStatus.Text = $"進度: {pct:F1}% ({done}/{total})";
              }
      
              private void UpdateStatus(string msg)
              {
                  if (InvokeRequired) { Invoke(new Action<string>(UpdateStatus), msg); return; }
                  lblStatus.Text = "狀態(tài): " + msg;
              }
      
              private void Log(string msg)
              {
                  if (InvokeRequired) { Invoke(new Action<string>(Log), msg); return; }
                  txtLog.AppendText($"[{DateTime.Now:HH:mm:ss}] {msg}\r\n");
              }
      
              private void LoadCache()
              {
                  if (File.Exists(CacheFile))
                  {
                      var js = new JavaScriptSerializer();
                      cache = js.Deserialize<Dictionary<string, string>>(File.ReadAllText(CacheFile));
                      if (cache == null) cache = new Dictionary<string, string>();
                      Log($"?? 加載緩存:{cache.Count} 條");
                  }
              }
      
              private void SaveCache()
              {
                  var js = new JavaScriptSerializer();
                  File.WriteAllText(CacheFile, js.Serialize(cache));
                  Log($"?? 保存緩存:{cache.Count} 條");
              }
              #endregion
      
      
      
              private bool HasTranslation(LangRecord rec, string lang)
              {
                  try
                  {
                      using (MySqlConnection conn = new MySqlConnection(ConnStr))
                      {
                          conn.Open();
                          string sql = "SELECT COUNT(*) FROM sys_language WHERE table_name=@t AND table_id=@id AND field_name=@f AND language=@lang AND field_value IS NOT NULL AND field_value <> '';";
                          MySqlCommand cmd = new MySqlCommand(sql, conn);
                          cmd.Parameters.AddWithValue("@t", rec.TableName);
                          cmd.Parameters.AddWithValue("@id", rec.TableId);
                          cmd.Parameters.AddWithValue("@f", rec.FieldName);
                          cmd.Parameters.AddWithValue("@lang", lang);
                          object count = cmd.ExecuteScalar();
                          return Convert.ToInt32(count) > 0;
                      }
                  }
                  catch (Exception ex)
                  {
                      Log("?? 檢查翻譯狀態(tài)出錯:" + ex.Message);
                      return false;
                  }
              }
      
          }
      
          public class LangRecord
          {
              public string TableName;
              public long TableId;
              public string FieldName;
              public string FieldValue;
          }
      }

       升鮮寶多語言翻譯工具V1.0--使用幫助文檔

       

      多語言自動翻譯與導(dǎo)出工具 使用幫助文檔

      一、軟件簡介

      本軟件用于自動翻譯系統(tǒng)中 sys_language 表的多語言字段,支持將中文內(nèi)容批量翻譯為繁體中文、英文、日文,并自動寫入數(shù)據(jù)庫或?qū)С?Excel。適合用于多語言網(wǎng)站、供應(yīng)鏈管理系統(tǒng)、零售POS、多租戶SaaS 等項目中批量國際化場景。

      二、軟件界面說明

      主界面分為數(shù)據(jù)庫配置區(qū)、阿里云配置區(qū)、操作區(qū)和日志區(qū)。
      數(shù)據(jù)庫配置區(qū):輸入 MySQL 連接信息。
      阿里云配置區(qū):輸入 AccessKeyId 與 AccessKeySecret 并勾選翻譯目標(biāo)語言。
      操作區(qū):包含測試連接、保存配置、開始翻譯、停止和導(dǎo)出Excel按鈕。
      日志區(qū):顯示實時進度與狀態(tài)。

      三、安裝與運行

      系統(tǒng)要求:Windows 7/10/11,.NET Framework 4.0,MySQL 8.0。
      步驟:
      1. 啟動程序 MultiLangTranslator.exe。
      2. 輸入數(shù)據(jù)庫信息并點擊“測試連接”。
      3. 填寫阿里云 AccessKey 并勾選語言。
      4. 點擊“開始翻譯”執(zhí)行任務(wù)。
      5. 完成后點擊“導(dǎo)出Excel”生成文件。

      四、翻譯功能說明

      從 sys_language 表讀取中文(zh-CN)字段,通過阿里云 API 翻譯為 zh-TW、en-US、ja-JP。支持多線程并發(fā)、自動限流(429時降速)和緩存機制。只翻譯缺失語言功能可跳過已有翻譯記錄。

      五、Excel 導(dǎo)出功能

      點擊“導(dǎo)出Excel”后選擇保存路徑,生成包含中、繁、英、日的多語言對照表。
      BigInt 主鍵轉(zhuǎn)為字符串避免科學(xué)計數(shù)法問題。
      導(dǎo)出完成后可一鍵打開文件所在目錄。

      六、日志與進度

      日志區(qū)實時顯示連接信息、翻譯進度和錯誤提示。
      狀態(tài)欄顯示當(dāng)前任務(wù)階段:連接中、翻譯中、導(dǎo)出中、完成。

      七、配置文件

      配置文件 config.json 自動保存數(shù)據(jù)庫和阿里云憑證。
      {
        'Host': '127.0.0.1',
        'Port': '3306',
        'Database': 'sxbscm',
        'User': 'root',
        'Password': '123456',
        'AccessKeyId': 'your_key',
        'AccessKeySecret': 'your_secret'
      }

      八、常見問題

      連接失敗:檢查數(shù)據(jù)庫網(wǎng)絡(luò)或密碼。
      400錯誤請求:檢查翻譯參數(shù)語言代碼。
      429限流:阿里云請求過多,系統(tǒng)會自動降低并發(fā)。
      Excel精度丟失:程序已將BigInt強制為字符串。

      九、安全提示

      妥善保管 AccessKeyId 與 AccessKeySecret。
      建議使用權(quán)限受限的阿里云子賬號。
      程序僅調(diào)用阿里云翻譯接口,不上傳數(shù)據(jù)庫內(nèi)容。

      十、版本更新

      v1.0:初版發(fā)布,支持中/繁/英/日翻譯與導(dǎo)出。
      v1.1(規(guī)劃):新增進度條、DeepL支持、任務(wù)暫停恢復(fù)。

      十一、聯(lián)系與定制

      如需擴展功能(新增語言、支持DeepL或Google翻譯、企業(yè)私有部署),請聯(lián)系系統(tǒng)開發(fā)團隊(升鮮寶 余東升  微信:sxbscm2012) 進行二次定制。

      posted @ 2025-10-17 00:50  升鮮寶供應(yīng)鏈管理系統(tǒng)  閱讀(28)  評論(0)    收藏  舉報
      主站蜘蛛池模板: av大片在线无码免费| 国产精品揄拍一区二区久久| 国产精品福利在线观看无码卡一| 欧美一区二区三区性视频| 午夜福利院一区二区三区| 偷拍专区一区二区三区| 伊人精品无码av一区二区三区| 免费av深夜在线观看| 真人无码作爱免费视频| 麻豆aⅴ精品无码一区二区| 四虎永久免费精品视频| 久久月本道色综合久久| 亚洲 一区二区 在线| 色吊丝免费av一区二区| 久久精品国产99国产精品严洲| 少妇人妻互换不带套| 日夜啪啪一区二区三区| 亚洲国产午夜精品理论片| 国产视频一区二区三区视频| 欧美色丁香| 成人国产av精品免费网| 视频免费完整版在线播放| 久久久无码精品午夜| 久久99精品久久久久麻豆| 欧美日韩精品久久久免费观看| 人人爽人人爽人人片a免费| 最新精品国偷自产在线美女足| 日本一区二区中文字幕久久| 伊在人间香蕉最新视频| 人妻少妇偷人精品免费看| 久久超碰色中文字幕超清| 精品中文人妻在线不卡| 午夜大尺度福利视频一区| 丝袜人妻一区二区三区网站| 国产在线无码精品无码| www射我里面在线观看| 国产精品不卡一区二区久久| 中文字幕制服国产精品| 农村老熟妇乱子伦视频| 饥渴少妇高潮正在播放| yw尤物av无码国产在线观看|