Skip to content

Commit

Permalink
feat: optimize translation progress bar and add translation delay
Browse files Browse the repository at this point in the history
  • Loading branch information
rockbenben committed Jun 14, 2024
1 parent a8b8c99 commit 1049156
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 68 deletions.
31 changes: 20 additions & 11 deletions src/app/(translate)/json-translate/client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ const ClientPage = () => {
};

const testDeeplxTranslation = async () => {
setIsLoading(true);
try {
const testTranslation = await translateText({
text: "Hello world",
Expand All @@ -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);
Expand Down
102 changes: 46 additions & 56 deletions src/app/(translate)/sublabel-translator/client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@ const ClientPage = () => {
const [translatedText, setTranslatedText] = useState<string>("");
const [translateInProgress, setTranslateInProgress] = useState(false);
const [translationMode, setTranslationMode] = useState("single");
const [startTime, setStartTime] = useState<number | null>(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) => {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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[] = [];
Expand All @@ -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") {
Expand All @@ -188,17 +165,29 @@ 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);

try {
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");
Expand All @@ -223,18 +212,17 @@ const ClientPage = () => {
}
} catch (error) {
message.error("翻译过程中发生错误");
} finally {
setTranslateInProgress(false);
}
};

const handleTranslate = async () => {
if (!(await validateInputs())) return;

setTranslateInProgress(true);
setStartTime(Date.now());
setProgressPercent(0);

await performTranslation(sourceText);
setTranslateInProgress(false);
};

const handleMultipleTranslate = async () => {
Expand All @@ -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<void>((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("翻译完成,已自动下载所有翻译后的字幕文件");
};

Expand Down Expand Up @@ -368,7 +358,7 @@ const ClientPage = () => {
</Flex>
{translateInProgress && (
<Modal title="翻译中" open={translateInProgress} footer={null} closable={false}>
<Progress type="circle" percent={100} format={() => `${Math.floor(runningTime)}s`} style={{ fontSize: "60px" }} />
<Progress type="circle" percent={Math.round(progressPercent * 100) / 100} style={{ fontSize: "60px" }} />
</Modal>
)}
{translationMode === "single" && translatedText && (
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/translateText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down

0 comments on commit 1049156

Please sign in to comment.