diff --git a/messages/de-DE.json b/messages/de-DE.json index 37df479..048fdfc 100644 --- a/messages/de-DE.json +++ b/messages/de-DE.json @@ -373,7 +373,8 @@ "success": "Textpaar zum Ordner hinzugefügt", "error": "Fehler beim Hinzufügen des Textpaars zum Ordner" }, - "autoSave": "Autom. Speichern" + "autoSave": "Autom. Speichern", + "customLanguage": "oder Sprache eingeben..." }, "dictionary": { "title": "Wörterbuch", diff --git a/messages/en-US.json b/messages/en-US.json index 48ee512..4a8ea3a 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -46,7 +46,7 @@ "unfavorite": "Unfavorite", "pleaseLogin": "Please login first" }, -"folder_id": { + "folder_id": { "unauthorized": "You are not the owner of this folder", "back": "Back", "textPairs": "Text Pairs", @@ -287,7 +287,7 @@ "favorites": "Favorites", "settings": "Settings" }, -"ocr": { + "ocr": { "title": "OCR Vocabulary Extractor", "description": "Upload vocabulary table screenshots from textbooks to extract word-definition pairs", "uploadSection": "Upload Image", @@ -400,6 +400,7 @@ "auto": "Auto", "generateIPA": "generate ipa", "translateInto": "translate into", + "customLanguage": "or type language...", "chinese": "Chinese", "english": "English", "french": "French", diff --git a/messages/fr-FR.json b/messages/fr-FR.json index 986b7b2..91668bf 100644 --- a/messages/fr-FR.json +++ b/messages/fr-FR.json @@ -402,7 +402,8 @@ "success": "Paire de texte ajoutée au dossier", "error": "Échec de l'ajout de la paire de texte au dossier" }, - "autoSave": "Sauvegarde automatique" + "autoSave": "Sauvegarde automatique", + "customLanguage": "ou tapez la langue..." }, "dictionary": { "title": "Dictionnaire", @@ -508,15 +509,6 @@ "view": "Voir" } }, - "follow": { - "follow": "Suivre", - "following": "Abonnements", - "followers": "Abonnés", - "followersOf": "Abonnés de {username}", - "followingOf": "Abonnements de {username}", - "noFollowers": "Pas encore d'abonnés", - "noFollowing": "Ne suit personne" - }, "follow": { "follow": "Suivre", "following": "Abonné", diff --git a/messages/it-IT.json b/messages/it-IT.json index 4b28255..861f9ad 100644 --- a/messages/it-IT.json +++ b/messages/it-IT.json @@ -402,7 +402,8 @@ "success": "Coppia di testo aggiunta alla cartella", "error": "Impossibile aggiungere coppia di testo alla cartella" }, - "autoSave": "Salvataggio Automatico" + "autoSave": "Salvataggio Automatico", + "customLanguage": "o digita lingua..." }, "dictionary": { "title": "Dizionario", @@ -508,15 +509,6 @@ "view": "Visualizza" } }, - "follow": { - "follow": "Segui", - "following": "Seguiti", - "followers": "Seguaci", - "followersOf": "Seguaci di {username}", - "followingOf": "Seguiti di {username}", - "noFollowers": "Nessun seguace ancora", - "noFollowing": "Non segui ancora nessuno" - }, "follow": { "follow": "Segui", "following": "Stai seguendo", diff --git a/messages/ja-JP.json b/messages/ja-JP.json index b7501ff..6721c04 100644 --- a/messages/ja-JP.json +++ b/messages/ja-JP.json @@ -411,7 +411,8 @@ "success": "テキストペアがフォルダーに追加されました", "error": "テキストペアをフォルダーに追加できませんでした" }, - "autoSave": "自動保存" + "autoSave": "自動保存", + "customLanguage": "または言語を入力..." }, "dictionary": { "title": "辞書", diff --git a/messages/ko-KR.json b/messages/ko-KR.json index 082ea17..6dde2d7 100644 --- a/messages/ko-KR.json +++ b/messages/ko-KR.json @@ -402,7 +402,8 @@ "success": "텍스트 쌍이 폴더에 추가됨", "error": "폴더에 텍스트 쌍 추가 실패" }, - "autoSave": "자동 저장" + "autoSave": "자동 저장", + "customLanguage": "또는 언어 입력..." }, "dictionary": { "title": "사전", @@ -508,15 +509,6 @@ "view": "보기" } }, - "follow": { - "follow": "팔로우", - "following": "팔로잉", - "followers": "팔로워", - "followersOf": "{username}의 팔로워", - "followingOf": "{username}의 팔로잉", - "noFollowers": "아직 팔로워가 없습니다", - "noFollowing": "아직 팔로잉하는 사람이 없습니다" - }, "follow": { "follow": "팔로우", "following": "팔로잉", diff --git a/messages/ug-CN.json b/messages/ug-CN.json index d4d5313..96776b2 100644 --- a/messages/ug-CN.json +++ b/messages/ug-CN.json @@ -402,7 +402,8 @@ "success": "تېكىست جۈپى قىسقۇچقا قوشۇلدى", "error": "تېكىست جۈپىنى قىسقۇچقا قوشۇش مەغلۇپ بولدى" }, - "autoSave": "ئاپتوماتىك ساقلاش" + "autoSave": "ئاپتوماتىك ساقلاش", + "customLanguage": "ياكى تىل تىل كىرۇڭ..." }, "dictionary": { "title": "لۇغەت", @@ -508,15 +509,6 @@ "view": "كۆرۈش" } }, - "follow": { - "follow": "ئەگىشىش", - "following": "ئەگىشىۋاتقانلار", - "followers": "ئەگەشكۈچىلەر", - "followersOf": "{username} نىڭ ئەگەشكۈچىلىرى", - "followingOf": "{username} نىڭ ئەگىشىۋاتقانلىرى", - "noFollowers": "تېخى ئەگەشكۈچى يوق", - "noFollowing": "تېخى ئەگىشىۋاتقان يوق" - }, "follow": { "follow": "ئەگىشىش", "following": "ئەگىشىۋاتىدۇ", diff --git a/messages/zh-CN.json b/messages/zh-CN.json index 19e4a6a..9a45ae4 100644 --- a/messages/zh-CN.json +++ b/messages/zh-CN.json @@ -424,7 +424,8 @@ "success": "文本对已添加到文件夹", "error": "添加文本对到文件夹失败" }, - "autoSave": "自动保存" + "autoSave": "自动保存", + "customLanguage": "或输入语言..." }, "dictionary": { "title": "词典", diff --git a/src/app/(features)/translator/page.tsx b/src/app/(features)/translator/page.tsx index 6737d1f..01dbf16 100644 --- a/src/app/(features)/translator/page.tsx +++ b/src/app/(features)/translator/page.tsx @@ -1,8 +1,8 @@ "use client"; -import { LightButton, PrimaryButton, - IconClick } from "@/design-system/base/button"; +import { LightButton, PrimaryButton, IconClick } from "@/design-system/base/button"; import { Select } from "@/design-system/base/select"; +import { Input } from "@/design-system/base/input"; import { Textarea } from "@/design-system/base/textarea"; import { IMAGES } from "@/config/images"; import { useAudioPlayer } from "@/hooks/useAudioPlayer"; @@ -46,6 +46,7 @@ export default function TranslatorPage() { const taref = useRef(null); const [sourceLanguage, setSourceLanguage] = useState("Auto"); const [targetLanguage, setTargetLanguage] = useState("Chinese"); + const [customTargetLanguage, setCustomTargetLanguage] = useState(""); const [translationResult, setTranslationResult] = useState(null); const [needIpa, setNeedIpa] = useState(true); const [processing, setProcessing] = useState(false); @@ -93,18 +94,18 @@ export default function TranslatorPage() { setProcessing(true); const sourceText = taref.current.value; + const effectiveTargetLanguage = customTargetLanguage.trim() || targetLanguage; // 判断是否需要强制重新翻译 - // 只有当源文本、源语言和目标语言都与上次相同时,才强制重新翻译 const forceRetranslate = lastTranslation?.sourceText === sourceText && lastTranslation?.sourceLanguage === sourceLanguage && - lastTranslation?.targetLanguage === targetLanguage; + lastTranslation?.targetLanguage === effectiveTargetLanguage; try { const result = await actionTranslateText({ sourceText, - targetLanguage, + targetLanguage: effectiveTargetLanguage, forceRetranslate, needIpa, sourceLanguage: sourceLanguage === "Auto" ? undefined : sourceLanguage, @@ -115,7 +116,7 @@ export default function TranslatorPage() { setLastTranslation({ sourceText, sourceLanguage, - targetLanguage, + targetLanguage: effectiveTargetLanguage, }); } else { toast.error(result.message || "翻译失败,请重试"); @@ -246,39 +247,43 @@ export default function TranslatorPage() {
{t("translateInto")} setTargetLanguage("Chinese")} + selected={!customTargetLanguage && targetLanguage === "Chinese"} + onClick={() => { + setTargetLanguage("Chinese"); + setCustomTargetLanguage(""); + }} className="shrink-0 hidden lg:inline-flex" > {t("chinese")} setTargetLanguage("English")} + selected={!customTargetLanguage && targetLanguage === "English"} + onClick={() => { + setTargetLanguage("English"); + setCustomTargetLanguage(""); + }} className="shrink-0 hidden lg:inline-flex" > {t("english")} setTargetLanguage("Japanese")} + selected={!customTargetLanguage && targetLanguage === "Japanese"} + onClick={() => { + setTargetLanguage("Japanese"); + setCustomTargetLanguage(""); + }} className="shrink-0 hidden xl:inline-flex" > {t("japanese")} - - {TARGET_LANGUAGES.map((lang) => ( - - ))} - + value={customTargetLanguage} + onChange={(e) => setCustomTargetLanguage(e.target.value)} + placeholder={t("customLanguage")} + className="w-auto min-w-[120px] shrink-0" + />