From 9d31ccb5ea70182b1c56793b90b9682ae6707a90 Mon Sep 17 00:00:00 2001 From: icarus Date: Fri, 22 Aug 2025 19:18:24 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E7=BF=BB=E8=AF=91):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E8=AF=BB=E5=8F=96=E5=8A=9F=E8=83=BD=E5=B9=B6?= =?UTF-8?q?=E6=94=B9=E8=BF=9B=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加对文本文件的支持并优化文件处理流程 改进错误提示信息,包括文件过大和读取失败的场景 --- src/renderer/src/i18n/locales/zh-cn.json | 7 +++ .../src/pages/translate/TranslatePage.tsx | 45 +++++++++++++++---- src/renderer/src/utils/file.ts | 9 ++++ 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index 743c1d7621..425c7ef996 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -3737,6 +3737,13 @@ "exchange": { "label": "交换源语言与目标语言" }, + "files": { + "error": { + "too_large": "文件过大 (0 ~ 5MB)", + "unknown": "读取文件内容失败" + }, + "reading": "读取文件内容中..." + }, "history": { "clear": "清空历史", "clear_description": "清空历史将删除所有翻译历史记录,是否继续?", diff --git a/src/renderer/src/pages/translate/TranslatePage.tsx b/src/renderer/src/pages/translate/TranslatePage.tsx index c63fdd74e2..c7413e6782 100644 --- a/src/renderer/src/pages/translate/TranslatePage.tsx +++ b/src/renderer/src/pages/translate/TranslatePage.tsx @@ -20,6 +20,7 @@ import { setTranslating as setTranslatingAction } from '@renderer/store/runtime' import { setTranslatedContent as setTranslatedContentAction } from '@renderer/store/translate' import { type AutoDetectionMethod, + isImageFile, isSupportedOcrFile, type Model, type TranslateHistory, @@ -33,6 +34,7 @@ import { detectLanguage, determineTargetLanguage } from '@renderer/utils/translate' +import { imageExts, MB, textExts } from '@shared/config/constant' import { Button, Flex, FloatButton, Popover, Tooltip, Typography } from 'antd' import TextArea, { TextAreaRef } from 'antd/es/input/TextArea' import { isEmpty, throttle } from 'lodash' @@ -57,7 +59,7 @@ const TranslatePage: FC = () => { const { translateModel, setTranslateModel } = useDefaultModel() const { prompt, getLanguageByLangcode } = useTranslate() const { shikiMarkdownIt } = useCodeStyle() - const { onSelectFile, selecting } = useFiles() + const { onSelectFile, selecting } = useFiles({ extensions: [...imageExts, ...textExts] }) const { ocr } = useOcr() // states @@ -442,19 +444,46 @@ const TranslatePage: FC = () => { if (!file) { return } - if (isSupportedOcrFile(file)) { - window.message.loading({ content: t('ocr.processing'), key: 'translate_ocr_processing', duration: 0 }) - const ocrResult = await ocr(file) - setText(ocrResult.text) + + // extensible + const shouldOCR = isImageFile(file) + + if (shouldOCR) { + if (isSupportedOcrFile(file)) { + window.message.loading({ content: t('ocr.processing'), key: 'translate_ocr_processing', duration: 0 }) + try { + const ocrResult = await ocr(file) + setText(ocrResult.text) + } catch (e) { + logger.error('Failed to ocr.', e as Error) + window.message.error(t('ocr.error.unknown') + ': ' + formatErrorMessage(e)) + } + } else { + // @ts-expect-error all situations covered. just for robustness + window.message.error(t('ocr.file.not_supported', { type: file.type })) + } } else { - window.message.error(t('ocr.file.not_supported', { type: file.type })) + // the threshold may be too large + if (file.size > 5 * MB) { + window.message.error(t('translate.files.error.too_large')) + } else { + window.message.loading({ content: t('translate.files.reading'), key: 'translate_files_reading', duration: 0 }) + try { + const result = await window.api.fs.readText(file.path) + setText(result) + } catch (e) { + logger.error('Failed to read text file.', e as Error) + window.message.error(t('translate.files.error.unknown') + ': ' + formatErrorMessage(e)) + } + } } } catch (e) { - logger.error('Failed to select file and ocr.', e as Error) - window.message.error(t('ocr.error.unknown') + ' ' + formatErrorMessage(e)) + logger.error('Unknown error when selecting file.', e as Error) + window.message.error(t('translate.files.error.unknown') + ': ' + formatErrorMessage(e)) } finally { setIsProcessing(false) window.message.destroy('translate_ocr_processing') + window.message.destroy('translate_files_reading') } }, [ocr, onSelectFile, selecting, t]) diff --git a/src/renderer/src/utils/file.ts b/src/renderer/src/utils/file.ts index 6218e3f5c1..051bf321fb 100644 --- a/src/renderer/src/utils/file.ts +++ b/src/renderer/src/utils/file.ts @@ -57,6 +57,15 @@ export function removeSpecialCharactersForFileName(str: string): string { .trim() } +/** + * 检查文件是否为支持的类型。 + * 支持的文件类型包括: + * 1. 文件扩展名在supportExts集合中的文件 + * 2. 文本文件 + * @param {string} filePath 文件路径 + * @param {Set} supportExts 支持的文件扩展名集合 + * @returns {Promise} 如果文件类型受支持返回true,否则返回false + */ export async function isSupportedFile(filePath: string, supportExts: Set): Promise { try { if (supportExts.has(getFileExtension(filePath))) {