diff --git a/src/config/api.js b/src/config/api.js index 1d30682..ad5dfdb 100644 --- a/src/config/api.js +++ b/src/config/api.js @@ -63,6 +63,9 @@ export const OPT_LANGDETECTOR_ALL = [ OPT_TRANS_TENCENT, ]; +export const OPT_DICT_ALL = [OPT_TRANS_BAIDU]; +export const OPT_DICT_MAP = new Set(OPT_DICT_ALL); + // 翻译引擎特殊集合 export const API_SPE_TYPES = { // 内置翻译 diff --git a/src/config/i18n.js b/src/config/i18n.js index 9447de1..f764c39 100644 --- a/src/config/i18n.js +++ b/src/config/i18n.js @@ -1513,4 +1513,14 @@ export const I18N = { en: `Placeholder tags`, zh_TW: `佔位標`, }, + detected_lang: { + zh: `语言检测`, + en: `Language detection`, + zh_TW: `語言偵測`, + }, + detected_result: { + zh: `检测结果`, + en: `Detect result`, + zh_TW: `檢測結果`, + }, }; diff --git a/src/config/setting.js b/src/config/setting.js index e4d52e0..bb04580 100644 --- a/src/config/setting.js +++ b/src/config/setting.js @@ -88,7 +88,7 @@ export const DEFAULT_TRANBOX_SETTING = { simpleStyle: false, // 是否简洁界面 followSelection: false, // 翻译框是否跟随选中文本 triggerMode: OPT_TRANBOX_TRIGGER_CLICK, // 触发翻译方式 - extStyles: "", // 附加样式 + // extStyles: "", // 附加样式 enDict: OPT_DICT_BAIDU, // 英文词典 }; diff --git a/src/views/Options/Navigator.js b/src/views/Options/Navigator.js index bcdf36a..0e40946 100644 --- a/src/views/Options/Navigator.js +++ b/src/views/Options/Navigator.js @@ -14,7 +14,7 @@ import ApiIcon from "@mui/icons-material/Api"; import InputIcon from "@mui/icons-material/Input"; import SelectAllIcon from "@mui/icons-material/SelectAll"; import EventNoteIcon from "@mui/icons-material/EventNote"; -import MouseIcon from '@mui/icons-material/Mouse'; +import MouseIcon from "@mui/icons-material/Mouse"; function LinkItem({ label, url, icon }) { const match = useMatch(url); @@ -77,6 +77,12 @@ export default function Navigator(props) { url: "/words", icon: , }, + { + id: "playground", + label: "Playground", + url: "/playground", + icon: , + }, { id: "about", label: i18n("about"), url: "/about", icon: }, ]; return ( diff --git a/src/views/Options/Playground.js b/src/views/Options/Playground.js new file mode 100644 index 0000000..90207bf --- /dev/null +++ b/src/views/Options/Playground.js @@ -0,0 +1,28 @@ +import { useState } from "react"; +import TranForm from "../Selection/TranForm"; +import { DEFAULT_SETTING, DEFAULT_TRANBOX_SETTING } from "../../config"; +import { useSetting } from "../../hooks/Setting"; + +export default function Playgound() { + const [text, setText] = useState(""); + const { setting } = useSetting(); + const { transApis, langDetector, tranboxSetting } = + setting || DEFAULT_SETTING; + const { apiSlugs, fromLang, toLang, toLang2, enDict } = + tranboxSetting || DEFAULT_TRANBOX_SETTING; + return ( + + ); +} diff --git a/src/views/Options/Tranbox.js b/src/views/Options/Tranbox.js index 1e2ddd6..6a322fa 100644 --- a/src/views/Options/Tranbox.js +++ b/src/views/Options/Tranbox.js @@ -10,6 +10,7 @@ import { OPT_TRANBOX_TRIGGER_CLICK, OPT_TRANBOX_TRIGGER_ALL, OPT_DICT_BAIDU, + OPT_DICT_ALL, } from "../../config"; import ShortcutInput from "./ShortcutInput"; import FormControlLabel from "@mui/material/FormControlLabel"; @@ -65,7 +66,7 @@ export default function Tranbox() { simpleStyle = false, followSelection = false, triggerMode = OPT_TRANBOX_TRIGGER_CLICK, - extStyles = "", + // extStyles = "", enDict = OPT_DICT_BAIDU, } = tranboxSetting; @@ -153,7 +154,8 @@ export default function Tranbox() { helperText={i18n("to_lang2_helper")} onChange={handleChange} > - {[["none", "None"], ...OPT_LANGS_TO].map(([lang, name]) => ( + {i18n("disable")} + {OPT_LANGS_TO.map(([lang, name]) => ( {name} @@ -172,7 +174,11 @@ export default function Tranbox() { onChange={handleChange} > {i18n("disable")} - {OPT_DICT_BAIDU} + {OPT_DICT_ALL.map((item) => ( + + {item} + + ))} @@ -305,7 +311,7 @@ export default function Tranbox() { - + /> */} ); diff --git a/src/views/Options/index.js b/src/views/Options/index.js index a167713..02d5ba6 100644 --- a/src/views/Options/index.js +++ b/src/views/Options/index.js @@ -21,6 +21,7 @@ import Apis from "./Apis"; import InputSetting from "./InputSetting"; import Tranbox from "./Tranbox"; import FavWords from "./FavWords"; +import Playgound from "./Playground"; import MouseHoverSetting from "./MouseHover"; import Loading from "../../hooks/Loading"; @@ -111,6 +112,7 @@ export default function Options() { } /> } /> } /> + } /> } /> diff --git a/src/views/Popup/index.js b/src/views/Popup/index.js index 9576a5c..3c8153e 100644 --- a/src/views/Popup/index.js +++ b/src/views/Popup/index.js @@ -312,20 +312,6 @@ export default function Popup({ setShowPopup, translator }) { label={i18n("shadowroot_alt")} /> - - - } - label={i18n("transonly_alt")} - /> - + + + } + label={i18n("transonly_alt")} + /> + { + useEffect(() => { if (!dictResult) { - return text; + return; } - return [ + const copyText = [ dictResult.src, dictResult.voice ?.map(Object.entries) @@ -63,29 +63,22 @@ export default function DictCont({ text }) { }) .join("\n"), ].join("\n"); - }, [text, dictResult]); + + setCopyText(copyText); + }, [dictResult, setCopyText]); if (loading) { return ; } - return ( - - {text && ( - - - {dictResult?.src || text} - - - - - - - )} + if (error) { + return {error}; + } - {error && {error}} + return baidu: {text}; - {dictResult && ( + { + /* {dictResult && ( {dictResult.voice @@ -112,7 +105,32 @@ export default function DictCont({ text }) { ))} + )} */ + } +} + +export default function DictCont({ text, enDict }) { + const [copyText, setCopyText] = useState(text); + + const dictMap = { + [OPT_TRANS_BAIDU]: , + }; + + return ( + + {text && ( + + + {text} + + + + + + )} + + {dictMap[enDict] || Dict not support} ); } diff --git a/src/views/Selection/SugCont.js b/src/views/Selection/SugCont.js index b64ddd8..1afe01f 100644 --- a/src/views/Selection/SugCont.js +++ b/src/views/Selection/SugCont.js @@ -21,7 +21,7 @@ export default function SugCont({ text }) { } return ( - + {sugs.map(({ k, v }) => ( {k} diff --git a/src/views/Selection/TranBox.js b/src/views/Selection/TranBox.js index 28ac672..996fe4b 100644 --- a/src/views/Selection/TranBox.js +++ b/src/views/Selection/TranBox.js @@ -2,13 +2,9 @@ import { SettingProvider } from "../../hooks/Setting"; import ThemeProvider from "../../hooks/Theme"; import DraggableResizable from "./DraggableResizable"; import Stack from "@mui/material/Stack"; -import TextField from "@mui/material/TextField"; -import MenuItem from "@mui/material/MenuItem"; -import Grid from "@mui/material/Grid"; import Box from "@mui/material/Box"; import Divider from "@mui/material/Divider"; import IconButton from "@mui/material/IconButton"; -import DoneIcon from "@mui/icons-material/Done"; import DragIndicatorIcon from "@mui/icons-material/DragIndicator"; import UnfoldLessIcon from "@mui/icons-material/UnfoldLess"; import UnfoldMoreIcon from "@mui/icons-material/UnfoldMore"; @@ -19,14 +15,9 @@ import LockOpenIcon from "@mui/icons-material/LockOpen"; import CloseIcon from "@mui/icons-material/Close"; import Typography from "@mui/material/Typography"; import { useI18n } from "../../hooks/I18n"; -import { OPT_LANGS_FROM, OPT_LANGS_TO } from "../../config"; -import { useState, useRef, useMemo } from "react"; -import TranCont from "./TranCont"; -import DictCont from "./DictCont"; -import SugCont from "./SugCont"; -import CopyBtn from "./CopyBtn"; -import { isValidWord } from "../../libs/utils"; +import { useState } from "react"; import { isMobile } from "../../libs/mobile"; +import TranForm from "./TranForm.js"; function Header({ setShowPopup, @@ -46,7 +37,6 @@ function Header({ return ( e.stopPropagation()} onTouchEnd={(e) => e.stopPropagation()} > @@ -120,188 +110,11 @@ function Header({ ); } -function TranForm({ - text, - setText, - tranboxSetting, - transApis, - simpleStyle, - langDetector, - enDict, -}) { - const i18n = useI18n(); - - const [editMode, setEditMode] = useState(false); - const [editText, setEditText] = useState(""); - const [apiSlug, setApiSlug] = useState(tranboxSetting.apiSlug); - const [fromLang, setFromLang] = useState(tranboxSetting.fromLang); - const [toLang, setToLang] = useState(tranboxSetting.toLang); - const inputRef = useRef(null); - - const optApis = useMemo( - () => - transApis - .filter((api) => !api.isDisabled) - .map((api) => ({ - key: api.apiSlug, - name: api.apiName || api.apiSlug, - })), - [transApis] - ); - - return ( - - {!simpleStyle && ( - <> - - - - { - setFromLang(e.target.value); - }} - > - {OPT_LANGS_FROM.map(([lang, name]) => ( - - {name} - - ))} - - - - { - setToLang(e.target.value); - }} - > - {OPT_LANGS_TO.map(([lang, name]) => ( - - {name} - - ))} - - - - { - setApiSlug(e.target.value); - }} - > - {optApis.map(({ key, name }) => ( - - {name} - - ))} - - - - - - - { - setEditText(e.target.value); - }} - onFocus={() => { - setEditMode(true); - setEditText(text); - }} - onBlur={() => { - setEditMode(false); - setText(editText.trim()); - }} - InputProps={{ - endAdornment: ( - - {editMode ? ( - { - e.stopPropagation(); - }} - > - - - ) : ( - - )} - - ), - }} - /> - - - )} - - {(!simpleStyle || - !isValidWord(text) || - !toLang.startsWith("zh") || - enDict === "-") && ( - - )} - - {enDict !== "-" && isValidWord(text) && ( - <> - - - - )} - - ); -} - export default function TranBox({ text, setText, setShowBox, - tranboxSetting, + tranboxSetting: { apiSlugs, fromLang, toLang, toLang2 }, transApis, boxSize, setBoxSize, @@ -313,7 +126,7 @@ export default function TranBox({ setHideClickAway, followSelection, setFollowSelection, - extStyles, + extStyles = "", langDetector, enDict, }) { @@ -343,15 +156,20 @@ export default function TranBox({ onMouseEnter={() => setMouseHover(true)} onMouseLeave={() => setMouseHover(false)} > - + + + diff --git a/src/views/Selection/TranCont.js b/src/views/Selection/TranCont.js index fef744c..c1ab854 100644 --- a/src/views/Selection/TranCont.js +++ b/src/views/Selection/TranCont.js @@ -3,31 +3,32 @@ import Box from "@mui/material/Box"; import CircularProgress from "@mui/material/CircularProgress"; import Stack from "@mui/material/Stack"; import { useI18n } from "../../hooks/I18n"; -import { DEFAULT_API_SETTING } from "../../config"; -import { useEffect, useState } from "react"; +import { useEffect, useState, useMemo } from "react"; import { apiTranslate } from "../../apis"; import CopyBtn from "./CopyBtn"; import Typography from "@mui/material/Typography"; import Alert from "@mui/material/Alert"; -import { tryDetectLang } from "../../libs/detect"; export default function TranCont({ text, - apiSlug, fromLang, toLang, - toLang2 = "en", + apiSlug, transApis, simpleStyle = false, - langDetector, }) { const i18n = useI18n(); const [trText, setTrText] = useState(""); - const [loading, setLoading] = useState(true); + const [loading, setLoading] = useState(false); const [error, setError] = useState(""); + const apiSetting = useMemo( + () => transApis.find((api) => api.apiSlug === apiSlug), + [transApis, apiSlug] + ); + useEffect(() => { - if (!text?.trim()) { + if (!text?.trim() || !apiSetting) { return; } @@ -37,24 +38,13 @@ export default function TranCont({ setTrText(""); setError(""); - let to = toLang; - if (fromLang === "auto" && toLang !== toLang2 && toLang2 !== "none") { - const detectLang = await tryDetectLang(text, "true", langDetector); - if (detectLang === toLang) { - to = toLang2; - } - } - - const apiSetting = - transApis.find((api) => api.apiSlug === apiSlug) || - DEFAULT_API_SETTING; const [trText] = await apiTranslate({ text, - apiSlug, fromLang, - toLang: to, + toLang, apiSetting, }); + setTrText(trText); } catch (err) { setError(err.message); @@ -62,11 +52,11 @@ export default function TranCont({ setLoading(false); } })(); - }, [text, apiSlug, fromLang, toLang, toLang2, transApis, langDetector]); + }, [text, fromLang, toLang, apiSetting]); if (simpleStyle) { return ( - + {error ? ( {error} ) : loading ? ( @@ -79,10 +69,10 @@ export default function TranCont({ } return ( - + { + if (!text.trim()) { + setDeLang(""); + return; + } + + (async () => { + try { + setDeLoading(true); + const deLang = await tryDetectLang(text, langDetector); + if (deLang) { + setDeLang(deLang); + } + } catch (err) { + kissLog("tranbox: detect lang", err); + } finally { + setDeLoading(false); + } + })(); + }, [text, langDetector, setDeLang, setDeLoading]); + + // todo: 语言变化后,realToLang引发二次翻译请求 + const realToLang = useMemo(() => { + if ( + fromLang === "auto" && + toLang !== toLang2 && + toLang2 !== "-" && + deLang === toLang + ) { + return toLang2; + } + + return toLang; + }, [fromLang, toLang, toLang2, deLang]); + + const optApis = useMemo( + () => + transApis + .filter((api) => !api.isDisabled) + .map((api) => ({ + key: api.apiSlug, + name: api.apiName || api.apiSlug, + })), + [transApis] + ); + + const isWord = useMemo(() => isValidWord(text), [text]); + + return ( + + {!simpleStyle && ( + <> + + + + { + setApiSlugs(e.target.value); + }} + > + {optApis.map(({ key, name }) => ( + + {name} + + ))} + + + + { + setFromLang(e.target.value); + }} + > + {OPT_LANGS_FROM.map(([lang, name]) => ( + + {name} + + ))} + + + + { + setToLang(e.target.value); + }} + > + {OPT_LANGS_TO.map(([lang, name]) => ( + + {name} + + ))} + + + + + + {isPlaygound && ( + + + + { + setEnDict(e.target.value); + }} + > + {i18n("disable")} + {OPT_DICT_ALL.map((item) => ( + + {item} + + ))} + + + + { + setLangDetector(e.target.value); + }} + > + {i18n("disable")} + {OPT_LANGDETECTOR_ALL.map((item) => ( + + {item} + + ))} + + + + + ) : null, + }} + /> + + + + )} + + + { + setEditText(e.target.value); + }} + onFocus={() => { + setEditMode(true); + }} + onBlur={() => { + setEditMode(false); + setText(editText.trim()); + }} + InputProps={{ + endAdornment: ( + + {editMode ? ( + { + e.stopPropagation(); + }} + > + + + ) : ( + + )} + + ), + }} + /> + + + )} + + {apiSlugs.map((slug) => ( + + ))} + + {isWord && OPT_DICT_MAP.has(enDict) && ( + <> + + + + )} + + ); +} diff --git a/src/views/Selection/index.js b/src/views/Selection/index.js index b32feba..5eb6ee7 100644 --- a/src/views/Selection/index.js +++ b/src/views/Selection/index.js @@ -30,7 +30,7 @@ export default function Slection({ followSelection: initFollowMouse = false, tranboxShortcut = DEFAULT_TRANBOX_SHORTCUT, triggerMode = OPT_TRANBOX_TRIGGER_CLICK, - extStyles, + // extStyles, btnOffsetX, btnOffsetY, boxOffsetX = 0, @@ -236,7 +236,7 @@ export default function Slection({ setHideClickAway={setHideClickAway} followSelection={followSelection} setFollowSelection={setFollowSelection} - extStyles={extStyles} + // extStyles={extStyles} langDetector={langDetector} enDict={enDict} />