diff --git a/src/apis/index.js b/src/apis/index.js index 7213c75..2e3f29f 100644 --- a/src/apis/index.js +++ b/src/apis/index.js @@ -114,7 +114,7 @@ export const apiTranslate = async ({ OPT_LANGS_SPECIAL[translator].get(fromLang) ?? OPT_LANGS_SPECIAL[translator].get("auto"); const to = OPT_LANGS_SPECIAL[translator].get(toLang); - if (!to) { + if (!text || !to) { console.log(`[trans] target lang: ${toLang} not support`); return [trText, isSame]; } diff --git a/src/common.js b/src/common.js index f9d0cbc..6a0c7d1 100644 --- a/src/common.js +++ b/src/common.js @@ -78,7 +78,10 @@ export async function showFab(translator) { ); } -export function showTransbox({ tranboxSetting = DEFAULT_TRANBOX_SETTING }) { +export function showTransbox({ + tranboxSetting = DEFAULT_TRANBOX_SETTING, + transApis, +}) { if (!tranboxSetting?.transOpen) { return; } @@ -99,7 +102,7 @@ export function showTransbox({ tranboxSetting = DEFAULT_TRANBOX_SETTING }) { ReactDOM.createRoot(shadowRootElement).render( - + ); diff --git a/src/config/i18n.js b/src/config/i18n.js index d88f079..849b591 100644 --- a/src/config/i18n.js +++ b/src/config/i18n.js @@ -623,12 +623,20 @@ export const I18N = { zh: `显示翻译框快捷键`, en: `Toggle Translate Box Shortcut`, }, - tanbtn_offset_x: { + tranbtn_offset_x: { zh: `翻译按钮偏移(X)`, en: `Translate Button Offset (X)`, }, - tanbtn_offset_y: { + tranbtn_offset_y: { zh: `翻译按钮偏移(Y)`, en: `Translate Button Offset (Y)`, }, + translated_text: { + zh: `译文`, + en: `Translated Text`, + }, + original_text: { + zh: `原文`, + en: `Original Text`, + }, }; diff --git a/src/libs/utils.js b/src/libs/utils.js index efdb1d8..4a0f9e5 100644 --- a/src/libs/utils.js +++ b/src/libs/utils.js @@ -223,3 +223,13 @@ export const matchInputStr = (str, sign) => { } return str.match(reg); }; + +/** + * 判断是否英文单词 + * @param {*} str + * @returns + */ +export const isValidWord = (str) => { + const regex = /^[a-zA-Z-]+$/; + return regex.test(str); +}; diff --git a/src/views/Options/Tranbox.js b/src/views/Options/Tranbox.js index b60ef30..e3da7ad 100644 --- a/src/views/Options/Tranbox.js +++ b/src/views/Options/Tranbox.js @@ -110,7 +110,7 @@ export default function Tranbox() { { + onChangeSize && onChangeSize(size); + }, [size, onChangeSize]); + + useEffect(() => { + onChangePosition && onChangePosition(position); + }, [position, onChangePosition]); + return ( +

{dictResult.simple_means?.word_name}

+

+ {Object.entries(dictResult.simple_means?.exchange || {}).map( + ([key, val]) => ( + {`${exchangeMap[key] || key}: ${val.join( + "," + )}; `} + ) + )} +

+

+ {Object.values(dictResult.simple_means?.tags || {}) + .map((vals) => vals.join(", ")) + .join(", ")} +

+ {dictResult.simple_means?.symbols?.map(({ ph_en, ph_am, parts }, idx) => ( +
+

{`英: [${ph_en}] 美: [${ph_am}]`}

+ {parts.map(({ part, means }, idx) => ( +

{`[${part}]: ${means.join("; ")}`}

+ ))} +
+ ))} +
+ ); +} + +function TranCont({ text, translator, fromLang, toLang, transApis }) { + const i18n = useI18n(); + const [trText, setTrText] = useState(""); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(""); + const [dictResult, setDictResult] = useState(null); + + useEffect(() => { + (async () => { + try { + setLoading(true); + setTrText(""); + setError(""); + setDictResult(null); + + const apis = { ...transApis, ...DEFAULT_TRANS_APIS }; + const apiSetting = apis[translator]; + const tranRes = await apiTranslate({ + text, + translator, + fromLang, + toLang, + apiSetting, + }); + setTrText(tranRes[0]); + + // 词典 + if (isValidWord(text) && toLang.startsWith("zh")) { + if (fromLang === "en" && translator === OPT_TRANS_BAIDU) { + setDictResult(tranRes[2]); + } else { + const dictRes = await apiTranslate({ + text, + translator: OPT_TRANS_BAIDU, + fromLang: "en", + toLang: "zh-CN", + apiSetting: apis[OPT_TRANS_BAIDU], + }); + setDictResult(dictRes[2].dict_result); + } + } + } catch (err) { + setError(err.message); + } finally { + setLoading(false); + } + })(); + }, [text, translator, fromLang, toLang, transApis]); + + return ( + <> + + + + + {loading && } + {error && {error}} + {dictResult && } + + ); +} + +function TranForm({ text, setText, tranboxSetting, transApis }) { const i18n = useI18n(); - const { - transOpen, - translator, - fromLang, - toLang, - tranboxShortcut, - btnOffsetX, - btnOffsetY, - } = tranboxSetting; + const [editMode, setEditMode] = useState(false); + const [editText, setEditText] = useState(""); + const [translator, setTranslator] = useState(tranboxSetting.translator); + const [fromLang, setFromLang] = useState(tranboxSetting.fromLang); + const [toLang, setToLang] = useState(tranboxSetting.toLang); + const inputRef = useRef(null); return ( @@ -37,7 +155,9 @@ function TranForm({ tranboxSetting }) { name="fromLang" value={fromLang} label={i18n("from_lang")} - // onChange={handleChange} + onChange={(e) => { + setFromLang(e.target.value); + }} > {OPT_LANGS_FROM.map(([lang, name]) => ( @@ -55,7 +175,9 @@ function TranForm({ tranboxSetting }) { name="toLang" value={toLang} label={i18n("to_lang")} - // onChange={handleChange} + onChange={(e) => { + setToLang(e.target.value); + }} > {OPT_LANGS_TO.map(([lang, name]) => ( @@ -73,7 +195,9 @@ function TranForm({ tranboxSetting }) { value={translator} name="translator" label={i18n("translate_service")} - // onChange={handleChange} + onChange={(e) => { + setTranslator(e.target.value); + }} > {OPT_TRANS_ALL.map((item) => ( @@ -84,20 +208,72 @@ function TranForm({ tranboxSetting }) { + + + { + setEditText(e.target.value); + }} + onClick={() => { + setEditMode(true); + setEditText(text); + const timer = setTimeout(() => { + clearTimeout(timer); + inputRef.current?.focus(); + }, 100); + }} + onBlur={() => { + setEditMode(false); + setText(editText.trim()); + }} + /> + + + ); } -export default function TranBox({ position, setShowBox, tranboxSetting }) { +export default function TranBox({ + text, + setText, + setShowBox, + tranboxSetting, + transApis, + boxSize, + setBoxSize, + boxPosition, + setBoxPosition, +}) { return ( } + onChangeSize={setBoxSize} + onChangePosition={setBoxPosition} > - + diff --git a/src/views/Selection/Tranbtn.js b/src/views/Selection/Tranbtn.js index e28ffa8..74a9bdc 100644 --- a/src/views/Selection/Tranbtn.js +++ b/src/views/Selection/Tranbtn.js @@ -6,6 +6,7 @@ export default function TranBtn({ onClick, position, tranboxSetting }) { position: "fixed", left: position.x + tranboxSetting.btnOffsetX, top: position.y + tranboxSetting.btnOffsetY, + zIndex: 2147483647, }} onClick={onClick} onMouseUp={(e) => { diff --git a/src/views/Selection/index.js b/src/views/Selection/index.js index 99835e5..edacd27 100644 --- a/src/views/Selection/index.js +++ b/src/views/Selection/index.js @@ -1,26 +1,38 @@ import { useState, useEffect } from "react"; import TranBtn from "./Tranbtn"; import TranBox from "./Tranbox"; +import { shortcutRegister } from "../../libs/shortcut"; -export default function Slection({ tranboxSetting }) { +export default function Slection({ tranboxSetting, transApis }) { const [showBox, setShowBox] = useState(false); const [showBtn, setShowBtn] = useState(false); + const [selectedText, setSelText] = useState(""); const [text, setText] = useState(""); const [position, setPosition] = useState({ x: 0, y: 0 }); - - console.log("tranboxSetting", tranboxSetting); + const [boxSize, setBoxSize] = useState({ w: 600, h: 400 }); + const [boxPosition, setBoxPosition] = useState({ + x: (window.innerWidth - 600) / 2, + y: (window.innerHeight - 400) / 2, + }); function handleMouseup(e) { - const text = window.getSelection()?.toString()?.trim() || ""; + const selectedText = window.getSelection()?.toString()?.trim() || ""; + if (!selectedText) { + setShowBtn(false); + return; + } + + setSelText(selectedText); + setShowBtn(true); setPosition({ x: e.clientX, y: e.clientY }); - setText(text); - setShowBtn(!!text); } const handleClick = (e) => { e.stopPropagation(); setShowBtn(false); - if (!!text) { + + setText(selectedText); + if (!showBox) { setShowBox(true); } }; @@ -32,12 +44,31 @@ export default function Slection({ tranboxSetting }) { }; }, []); + useEffect(() => { + const clearShortcut = shortcutRegister( + tranboxSetting.tranboxShortcut, + () => { + setShowBox((pre) => !pre); + } + ); + + return () => { + clearShortcut(); + }; + }, [tranboxSetting.tranboxShortcut, setShowBox]); + return ( <> {showBox && ( )}