"use client"; import { LightButton, PrimaryButton } from "@/components/ui/buttons"; import { IconClick } from "@/components/ui/buttons"; import { IMAGES } from "@/config/images"; import { useAudioPlayer } from "@/hooks/useAudioPlayer"; import { useTranslations } from "next-intl"; import { useRef, useState } from "react"; import { actionTranslateText } from "@/modules/translator/translator-action"; import { toast } from "sonner"; import { getTTSUrl, TTS_SUPPORTED_LANGUAGES } from "@/lib/bigmodel/tts"; import { TSharedTranslationResult } from "@/shared/translator-type"; export default function TranslatorPage() { const t = useTranslations("translator"); const taref = useRef(null); const [targetLanguage, setTargetLanguage] = useState("Chinese"); const [translationResult, setTranslationResult] = useState(null); const [needIpa, setNeedIpa] = useState(true); const [processing, setProcessing] = useState(false); const [lastTranslation, setLastTranslation] = useState<{ sourceText: string; targetLanguage: string; } | null>(null); const { load, play } = useAudioPlayer(); const lastTTS = useRef({ text: "", url: "", }); const tts = async (text: string, locale: string) => { if (lastTTS.current.text !== text) { try { // Map language name to TTS format let theLanguage = locale.toLowerCase().replace(/[^a-z]/g, '').replace(/^./, match => match.toUpperCase()); // Check if language is in TTS supported list const supportedLanguages: TTS_SUPPORTED_LANGUAGES[] = [ "Auto", "Chinese", "English", "German", "Italian", "Portuguese", "Spanish", "Japanese", "Korean", "French", "Russian" ]; if (!supportedLanguages.includes(theLanguage as TTS_SUPPORTED_LANGUAGES)) { theLanguage = "Auto"; } const url = await getTTSUrl(text, theLanguage as TTS_SUPPORTED_LANGUAGES); await load(url); await play(); lastTTS.current.text = text; lastTTS.current.url = url; } catch (error) { toast.error("Failed to generate audio"); } } }; const translate = async () => { if (!taref.current || processing) return; setProcessing(true); const sourceText = taref.current.value; // 判断是否需要强制重新翻译 // 只有当源文本和目标语言都与上次相同时,才强制重新翻译 const forceRetranslate = lastTranslation?.sourceText === sourceText && lastTranslation?.targetLanguage === targetLanguage; try { const result = await actionTranslateText({ sourceText, targetLanguage, forceRetranslate, needIpa, }); if (result.success && result.data) { setTranslationResult(result.data); setLastTranslation({ sourceText, targetLanguage, }); } else { toast.error(result.message || "翻译失败,请重试"); } } catch (error) { toast.error("翻译失败,请重试"); console.error("翻译错误:", error); } finally { setProcessing(false); } }; return (
{/* TCard Component */}
{/* Card Component - Left Side */}
{/* ICard1 Component */}
{translationResult?.sourceIpa || ""}
{ await navigator.clipboard.writeText( taref.current?.value || "", ); }} > { const t = taref.current?.value; if (!t) return; tts(t, translationResult?.sourceLanguage || ""); }} >
{t("detectLanguage")} setNeedIpa((prev) => !prev)} > {t("generateIPA")}
{/* Card Component - Right Side */}
{/* ICard2 Component */}
{translationResult?.translatedText || ""}
{translationResult?.targetIpa || ""}
{ await navigator.clipboard.writeText(translationResult?.translatedText || ""); }} > { if (!translationResult) return; tts( translationResult.translatedText, translationResult.targetLanguage, ); }} >
{t("translateInto")} setTargetLanguage("Chinese")} > {t("chinese")} setTargetLanguage("English")} > {t("english")} setTargetLanguage("Italian")} > {t("italian")} { const newLang = prompt(t("enterLanguage")); if (newLang) { setTargetLanguage(newLang); } }} > {t("other")}
{/* TranslateButton Component */}
{t("translate")}
); }