diff --git a/src/app/(translate)/json-translate/client.tsx b/src/app/(translate)/json-translate/client.tsx index 4bc1fb3..9113c78 100644 --- a/src/app/(translate)/json-translate/client.tsx +++ b/src/app/(translate)/json-translate/client.tsx @@ -95,6 +95,7 @@ const ClientPage = () => { }; const testDeeplxTranslation = async () => { + setIsLoading(true); try { const testTranslation = await translateText({ text: "Hello world", @@ -108,32 +109,40 @@ const ClientPage = () => { return true; } catch (error) { return false; + } finally { + setIsLoading(false); } }; - const handleTranslate = async () => { - // Reset Output - setJsonOutput(""); - - // Check Input + const validateInputs = async () => { if ((translationMethod === "deepl" && !apiKeyDeepl) || (translationMethod === "google" && !apiKeyGoogleTranslate) || (translationMethod === "azure" && !apiKeyAzure)) { message.error("Google/DeepL/Azure 翻译方法中,API Key 不能为空。没有 API 的话,可以使用 DeepLX 免费翻译。"); return; } - if (!jsonInput) { - message.error("JSON Input 不能为空"); - return; - } if (translationMethod === "deeplx") { const isDeeplxWorking = await testDeeplxTranslation(); if (!isDeeplxWorking) { message.error("当前 Deeplx 节点有问题,请切换其他翻译模式"); - setTranslationMethod("google"); // 默认切换到 Google 翻译,可以根据需要调整 - return; + setTranslationMethod("google"); // 默认切换到 Google 翻译 + return false; } } + return true; + }; + + const handleTranslate = async () => { + // Reset Output + setJsonOutput(""); + + if (!jsonInput) { + message.error("JSON Input 不能为空"); + return; + } + + if (!(await validateInputs())) return; + let jsonObject; try { jsonObject = preprocessJson(jsonInput); diff --git a/src/app/(translate)/sublabel-translator/client.tsx b/src/app/(translate)/sublabel-translator/client.tsx index bfcd0cc..de03243 100644 --- a/src/app/(translate)/sublabel-translator/client.tsx +++ b/src/app/(translate)/sublabel-translator/client.tsx @@ -25,9 +25,8 @@ const ClientPage = () => { const [translatedText, setTranslatedText] = useState(""); const [translateInProgress, setTranslateInProgress] = useState(false); const [translationMode, setTranslationMode] = useState("single"); - const [startTime, setStartTime] = useState(null); - const [runningTime, setRunningTime] = useState(0); const [isClient, setIsClient] = useState(false); + const [progressPercent, setProgressPercent] = useState(0); useEffect(() => { const loadFromLocalStorage = (key: string, setState: (value: string) => void) => { @@ -63,21 +62,6 @@ const ClientPage = () => { } }, [translationMethod, apiKeyDeepl, apiKeyGoogleTranslate, apiKeyAzure, apiRegionAzure, sourceLanguage, targetLanguage, isClient]); - useEffect(() => { - let timer: NodeJS.Timeout | null = null; - if (translateInProgress && startTime) { - timer = setInterval(() => { - setRunningTime((Date.now() - startTime) / 1000); - }, 1000); - } else if (timer) { - clearInterval(timer); - setRunningTime(0); - } - return () => { - if (timer) clearInterval(timer); - }; - }, [translateInProgress, startTime]); - const handleFileUpload = (file: File) => { setFile(file); const reader = new FileReader(); @@ -125,29 +109,6 @@ const ClientPage = () => { } }; - const translateTextUsingMethod = async (text: string) => { - return await translateText({ - text, - translationMethod, - targetLanguage, - sourceLanguage, - apiKey: translationMethod === "deepl" ? apiKeyDeepl : translationMethod === "google" ? apiKeyGoogleTranslate : apiKeyAzure, - apiRegion: translationMethod === "azure" && apiRegionAzure ? apiRegionAzure : "eastasia", - }); - }; - - const testDeeplxTranslation = async () => { - try { - const testTranslation = await translateTextUsingMethod("Hello world"); - if (!testTranslation) { - throw new Error("测试翻译失败"); - } - return true; - } catch (error) { - return false; - } - }; - const filterContentLines = (lines: string[]) => { const contentLines: string[] = []; const contentIndices: number[] = []; @@ -165,15 +126,31 @@ const ClientPage = () => { return { contentLines, contentIndices }; }; - const validateInputs = async () => { - if (sourceLanguage === targetLanguage) { - message.error("源语言和目标语言不能相同"); + const testDeeplxTranslation = async () => { + setTranslateInProgress(true); + setProgressPercent(10); + try { + const testTranslation = await translateText({ + text: "Hello world", + translationMethod: "deeplx", + targetLanguage, + sourceLanguage, + }); + if (!testTranslation) { + throw new Error("测试翻译失败"); + } + return true; + } catch (error) { return false; + } finally { + setTranslateInProgress(false); } + }; - if (translationMethod !== "deeplx" && !apiKeyDeepl && !apiKeyGoogleTranslate && !apiKeyAzure) { - message.error("请设置 API Key"); - return false; + const validateInputs = async () => { + if ((translationMethod === "deepl" && !apiKeyDeepl) || (translationMethod === "google" && !apiKeyGoogleTranslate) || (translationMethod === "azure" && !apiKeyAzure)) { + message.error("Google/DeepL/Azure 翻译方法中,API Key 不能为空。没有 API 的话,可以使用 DeepLX 免费翻译。"); + return; } if (translationMethod === "deeplx") { @@ -188,7 +165,9 @@ const ClientPage = () => { return true; }; - const performTranslation = async (sourceText: string, fileName?: string) => { + const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + + const performTranslation = async (sourceText: string, fileName?: string, fileIndex?: number, totalFiles?: number) => { const lines = sourceText.split("\n"); const { contentLines, contentIndices } = filterContentLines(lines); @@ -196,9 +175,19 @@ const ClientPage = () => { const chunks = splitTextIntoChunks(contentLines.join("\n"), 3000); const translatedLines: string[] = []; - for (const chunk of chunks) { - const translatedContent = await translateTextUsingMethod(chunk); + for (let i = 0; i < chunks.length; i++) { + const chunk = chunks[i]; + const translatedContent = await translateText({ + text: chunk, + translationMethod, + targetLanguage, + sourceLanguage, + apiKey: translationMethod === "deepl" ? apiKeyDeepl : translationMethod === "google" ? apiKeyGoogleTranslate : apiKeyAzure, + apiRegion: translationMethod === "azure" && apiRegionAzure ? apiRegionAzure : "eastasia", + }); translatedLines.push(translatedContent); + setProgressPercent((((fileIndex ? fileIndex : 0) + i / chunks.length) / (totalFiles ? totalFiles : 1)) * 100); + await delay(1500); // 限速1500毫秒 } const finalTranslatedLines = translatedLines.join("\n").split("\n"); @@ -223,8 +212,6 @@ const ClientPage = () => { } } catch (error) { message.error("翻译过程中发生错误"); - } finally { - setTranslateInProgress(false); } }; @@ -232,9 +219,10 @@ const ClientPage = () => { if (!(await validateInputs())) return; setTranslateInProgress(true); - setStartTime(Date.now()); + setProgressPercent(0); await performTranslation(sourceText); + setTranslateInProgress(false); }; const handleMultipleTranslate = async () => { @@ -246,20 +234,22 @@ const ClientPage = () => { } setTranslateInProgress(true); - setStartTime(Date.now()); + setProgressPercent(0); - for (const currentFile of multipleFiles) { + for (let i = 0; i < multipleFiles.length; i++) { + const currentFile = multipleFiles[i]; const reader = new FileReader(); await new Promise((resolve) => { reader.onload = async (e) => { const text = (e.target?.result as string).replace(/\r\n/g, "\n"); - await performTranslation(text, currentFile.name); + await performTranslation(text, currentFile.name, i, multipleFiles.length); resolve(); }; reader.readAsText(currentFile); }); } + setTranslateInProgress(false); message.success("翻译完成,已自动下载所有翻译后的字幕文件"); }; @@ -368,7 +358,7 @@ const ClientPage = () => { {translateInProgress && ( - `${Math.floor(runningTime)}s`} style={{ fontSize: "60px" }} /> + )} {translationMode === "single" && translatedText && ( diff --git a/src/app/components/translateText.tsx b/src/app/components/translateText.tsx index 402668f..f11b047 100644 --- a/src/app/components/translateText.tsx +++ b/src/app/components/translateText.tsx @@ -86,7 +86,7 @@ export const translateText = async ({ text, translationMethod, targetLanguage, s return data.data; } case "azure": { - const url = `https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=${targetLanguage}`; + const url = `https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=${targetLanguage}&from=${sourceLanguage}`; const response = await fetch(url, { method: "POST", headers: {