feat: support bing dict
This commit is contained in:
@@ -3,6 +3,7 @@ import { fetchData } from "../libs/fetch";
|
||||
import {
|
||||
URL_CACHE_TRAN,
|
||||
URL_CACHE_DELANG,
|
||||
URL_CACHE_BINGDICT,
|
||||
KV_SALT_SYNC,
|
||||
OPT_LANGS_TO_SPEC,
|
||||
OPT_LANGS_SPEC_DEFAULT,
|
||||
@@ -107,6 +108,60 @@ export const apiMicrosoftLangdetect = async (text) => {
|
||||
return "";
|
||||
};
|
||||
|
||||
/**
|
||||
* Microsoft词典
|
||||
* @param {*} text
|
||||
* @returns
|
||||
*/
|
||||
export const apiMicrosoftDict = async (text) => {
|
||||
const cacheOpts = { text };
|
||||
const cacheInput = `${URL_CACHE_BINGDICT}?${queryString.stringify(cacheOpts)}`;
|
||||
const cache = await getHttpCachePolyfill(cacheInput);
|
||||
if (cache) {
|
||||
return cache;
|
||||
}
|
||||
|
||||
const host = "https://cn.bing.com";
|
||||
const url = `${host}/dict/search?q=${text}`;
|
||||
const str = await fetchData(url, {}, { useCache: false });
|
||||
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(str, "text/html");
|
||||
|
||||
const word = doc.querySelector("#headword > h1").textContent.trim();
|
||||
if (!word) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const trs = [];
|
||||
doc.querySelectorAll("div.qdef > ul > li").forEach(($li) => {
|
||||
const pos = $li.querySelector(".pos")?.textContent?.trim();
|
||||
const def = $li.querySelector(".def")?.textContent?.trim();
|
||||
trs.push({ pos, def });
|
||||
});
|
||||
|
||||
const aus = [];
|
||||
const $audioUS = doc.querySelector("#bigaud_us");
|
||||
const $audioUK = doc.querySelector("#bigaud_uk");
|
||||
if ($audioUS) {
|
||||
const audioUS = host + $audioUS?.dataset?.mp3link;
|
||||
const $phoneticUS = $audioUS.parentElement?.previousElementSibling;
|
||||
const phoneticUS = $phoneticUS?.textContent?.trim();
|
||||
aus.push({ key: "US", audio: audioUS, phonetic: phoneticUS });
|
||||
}
|
||||
if ($audioUK) {
|
||||
const audioUK = host + $audioUK?.dataset?.mp3link;
|
||||
const $phoneticUK = $audioUK.parentElement?.previousElementSibling;
|
||||
const phoneticUK = $phoneticUK?.textContent?.trim();
|
||||
aus.push({ key: "UK", audio: audioUK, phonetic: phoneticUK });
|
||||
}
|
||||
|
||||
const res = { word, trs, aus };
|
||||
putHttpCachePolyfill(cacheInput, null, res);
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
/**
|
||||
* 百度语言识别
|
||||
* @param {*} text
|
||||
|
||||
@@ -14,8 +14,9 @@ export const INPUT_PLACE_KEY = "{{key}}"; // 占位符
|
||||
export const INPUT_PLACE_MODEL = "{{model}}"; // 占位符
|
||||
|
||||
export const OPT_DICT_BAIDU = "Baidu";
|
||||
export const OPT_DICT_BING = "Bing";
|
||||
export const OPT_DICT_YOUDAO = "Youdao";
|
||||
export const OPT_DICT_ALL = [OPT_DICT_BAIDU, OPT_DICT_YOUDAO];
|
||||
export const OPT_DICT_ALL = [OPT_DICT_BING, OPT_DICT_YOUDAO];
|
||||
export const OPT_DICT_MAP = new Set(OPT_DICT_ALL);
|
||||
|
||||
export const OPT_SUG_BAIDU = "Baidu";
|
||||
|
||||
@@ -2,6 +2,7 @@ import { APP_LCNAME } from "./app";
|
||||
|
||||
export const URL_CACHE_TRAN = `https://${APP_LCNAME}/translate`;
|
||||
export const URL_CACHE_DELANG = `https://${APP_LCNAME}/detectlang`;
|
||||
export const URL_CACHE_BINGDICT = `https://${APP_LCNAME}/bingdict`;
|
||||
|
||||
export const URL_KISS_WORKER = "https://github.com/fishjar/kiss-worker";
|
||||
export const URL_KISS_PROXY = "https://github.com/fishjar/kiss-proxy";
|
||||
|
||||
@@ -22,6 +22,7 @@ import { apiTranslate } from "../../apis";
|
||||
import { OPT_TRANS_BAIDU, PHONIC_MAP } from "../../config";
|
||||
import { useConfirm } from "../../hooks/Confirm";
|
||||
import { useSetting } from "../../hooks/Setting";
|
||||
import { DICT_MAP } from "../Selection/DictMap";
|
||||
|
||||
function FavAccordion({ word, index }) {
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
@@ -55,6 +56,7 @@ function FavAccordion({ word, index }) {
|
||||
export default function FavWords() {
|
||||
const i18n = useI18n();
|
||||
const { favList, wordList, mergeWords, clearWords } = useFavWords();
|
||||
const { setting } = useSetting();
|
||||
const confirm = useConfirm();
|
||||
|
||||
const handleImport = (data) => {
|
||||
@@ -80,41 +82,22 @@ export default function FavWords() {
|
||||
};
|
||||
|
||||
const handleTranslation = async () => {
|
||||
const { enDict } = setting?.tranboxSetting;
|
||||
const dict = DICT_MAP[enDict];
|
||||
if (!dict) return "";
|
||||
|
||||
const tranList = [];
|
||||
for (const text of wordList) {
|
||||
for (const word of wordList) {
|
||||
try {
|
||||
// todo: 修复
|
||||
const dictRes = await apiTranslate({
|
||||
text,
|
||||
translator: OPT_TRANS_BAIDU,
|
||||
fromLang: "en",
|
||||
toLang: "zh-CN",
|
||||
});
|
||||
if (dictRes[2]?.type === 1) {
|
||||
tranList.push(JSON.parse(dictRes[2].result));
|
||||
}
|
||||
const data = await dict.apiFn(word);
|
||||
const tran = dict.toText(data);
|
||||
tranList.push([word, tran].join("\n"));
|
||||
} catch (err) {
|
||||
// skip
|
||||
}
|
||||
}
|
||||
|
||||
return tranList
|
||||
.map((dictResult) =>
|
||||
[
|
||||
`## ${dictResult.src}`,
|
||||
dictResult.voice
|
||||
?.map(Object.entries)
|
||||
.map((item) => item[0])
|
||||
.map(([key, val]) => `${PHONIC_MAP[key]?.[0] || key} ${val}`)
|
||||
.join(" "),
|
||||
dictResult.content[0].mean
|
||||
.map(({ pre, cont }) => {
|
||||
return ` - ${pre ? `[${pre}] ` : ""}${Object.keys(cont).join("; ")}`;
|
||||
})
|
||||
.join("\n"),
|
||||
].join("\n\n")
|
||||
)
|
||||
.join("\n\n");
|
||||
return tranList.join("\n\n");
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import VolumeUpIcon from "@mui/icons-material/VolumeUp";
|
||||
import { useTextAudio } from "../../hooks/Audio";
|
||||
import { useAudio } from "../../hooks/Audio";
|
||||
|
||||
export default function AudioBtn({ text, lan = "uk" }) {
|
||||
const { error, ready, playing, onPlay } = useTextAudio(text, lan);
|
||||
export default function AudioBtn({ src }) {
|
||||
const { error, ready, playing, onPlay } = useAudio(src);
|
||||
|
||||
if (error || !ready) {
|
||||
return (
|
||||
|
||||
@@ -1,90 +1,28 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { useState, useEffect, useMemo } from "react";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import FavBtn from "./FavBtn";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import AudioBtn from "./AudioBtn";
|
||||
import CircularProgress from "@mui/material/CircularProgress";
|
||||
import Divider from "@mui/material/Divider";
|
||||
import Alert from "@mui/material/Alert";
|
||||
import { OPT_DICT_BAIDU, OPT_DICT_YOUDAO, PHONIC_MAP } from "../../config";
|
||||
import CopyBtn from "./CopyBtn";
|
||||
import { useAsyncNow } from "../../hooks/Fetch";
|
||||
import { apiYoudaoDict } from "../../apis";
|
||||
import { DICT_MAP } from "./DictMap";
|
||||
|
||||
function DictBaidu({ text, setCopyText }) {
|
||||
// useEffect(() => {
|
||||
// if (!data) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// const copyText = [
|
||||
// data.src,
|
||||
// data.voice
|
||||
// ?.map(Object.entries)
|
||||
// .map((item) => item[0])
|
||||
// .map(([key, val]) => `${PHONIC_MAP[key]?.[0] || key} ${val}`)
|
||||
// .join(" "),
|
||||
// data.content[0].mean
|
||||
// .map(({ pre, cont }) => {
|
||||
// return `${pre ? `[${pre}] ` : ""}${Object.keys(cont).join("; ")}`;
|
||||
// })
|
||||
// .join("\n"),
|
||||
// ].join("\n");
|
||||
|
||||
// setCopyText(copyText);
|
||||
// }, [data, setCopyText]);
|
||||
|
||||
return <Typography>baidu dict not supported yet</Typography>;
|
||||
|
||||
{
|
||||
/* {dictResult && (
|
||||
<Typography component="div">
|
||||
<Typography component="div">
|
||||
{dictResult.voice
|
||||
?.map(Object.entries)
|
||||
.map((item) => item[0])
|
||||
.map(([key, val]) => (
|
||||
<Typography
|
||||
component="div"
|
||||
key={key}
|
||||
style={{ display: "inline-block" }}
|
||||
>
|
||||
<Typography component="span">{`${PHONIC_MAP[key]?.[0] || key} ${val}`}</Typography>
|
||||
<AudioBtn text={dictResult.src} lan={PHONIC_MAP[key]?.[1]} />
|
||||
</Typography>
|
||||
))}
|
||||
</Typography>
|
||||
|
||||
<Typography component="ul">
|
||||
{dictResult.content[0].mean.map(({ pre, cont }, idx) => (
|
||||
<Typography component="li" key={idx}>
|
||||
{pre && `[${pre}] `}
|
||||
{Object.keys(cont).join("; ")}
|
||||
</Typography>
|
||||
))}
|
||||
</Typography>
|
||||
</Typography>
|
||||
)} */
|
||||
}
|
||||
}
|
||||
|
||||
function DictYoudao({ text, setCopyText }) {
|
||||
const { loading, error, data } = useAsyncNow(apiYoudaoDict, text);
|
||||
function DictBody({ text, setCopyText, dict }) {
|
||||
const { loading, error, data } = useAsyncNow(dict.apiFn, text);
|
||||
|
||||
useEffect(() => {
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
const copyText = [
|
||||
text,
|
||||
data?.ec?.word?.trs
|
||||
?.map(({ pos, tran }) => `${pos ? `[${pos}] ` : ""}${tran}`)
|
||||
.join("\n"),
|
||||
].join("\n");
|
||||
|
||||
const copyText = [text, dict.toText(data)].join("\n");
|
||||
setCopyText(copyText);
|
||||
}, [data, setCopyText]);
|
||||
}, [data, text, dict, setCopyText]);
|
||||
|
||||
const uiAudio = useMemo(() => dict.uiAudio(data), [data, dict]);
|
||||
const uiTrans = useMemo(() => dict.uiTrans(data), [data, dict]);
|
||||
|
||||
if (loading) {
|
||||
return <CircularProgress size={16} />;
|
||||
@@ -95,30 +33,20 @@ function DictYoudao({ text, setCopyText }) {
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return;
|
||||
return <Typography>Empty result</Typography>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Typography component="div">
|
||||
<Typography component="ul">
|
||||
{data?.ec?.word?.trs?.map(({ pos, tran }, idx) => (
|
||||
<Typography component="li" key={idx}>
|
||||
{pos && `[${pos}] `}
|
||||
{tran}
|
||||
</Typography>
|
||||
))}
|
||||
</Typography>
|
||||
{uiAudio}
|
||||
{uiTrans}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
export default function DictCont({ text, enDict }) {
|
||||
const [copyText, setCopyText] = useState(text);
|
||||
|
||||
const dictMap = {
|
||||
[OPT_DICT_BAIDU]: <DictBaidu text={text} setCopyText={setCopyText} />,
|
||||
[OPT_DICT_YOUDAO]: <DictYoudao text={text} setCopyText={setCopyText} />,
|
||||
};
|
||||
const dict = DICT_MAP[enDict];
|
||||
|
||||
return (
|
||||
<Stack spacing={1}>
|
||||
@@ -136,7 +64,7 @@ export default function DictCont({ text, enDict }) {
|
||||
|
||||
<Divider />
|
||||
|
||||
{dictMap[enDict] || <Typography>Dict not support</Typography>}
|
||||
{dict && <DictBody text={text} setCopyText={setCopyText} dict={dict} />}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
56
src/views/Selection/DictMap.js
Normal file
56
src/views/Selection/DictMap.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import Typography from "@mui/material/Typography";
|
||||
import AudioBtn from "./AudioBtn";
|
||||
import { OPT_DICT_BING, OPT_DICT_YOUDAO } from "../../config";
|
||||
import { apiMicrosoftDict, apiYoudaoDict } from "../../apis";
|
||||
|
||||
export const DICT_MAP = {
|
||||
[OPT_DICT_BING]: {
|
||||
apiFn: apiMicrosoftDict,
|
||||
toText: (data) =>
|
||||
data.trs
|
||||
?.map(({ pos, def }) => `${pos ? `[${pos}] ` : ""}${def}`)
|
||||
.join("\n"),
|
||||
uiAudio: (data) => (
|
||||
<Typography component="div">
|
||||
{data?.aus.map(({ key, audio, phonetic }) => (
|
||||
<Typography
|
||||
component="div"
|
||||
key={key}
|
||||
style={{ display: "inline-block" }}
|
||||
>
|
||||
<Typography component="span">{phonetic}</Typography>
|
||||
<AudioBtn src={audio} />
|
||||
</Typography>
|
||||
))}
|
||||
</Typography>
|
||||
),
|
||||
uiTrans: (data) => (
|
||||
<Typography component="ul">
|
||||
{data?.trs?.map(({ pos, def }, idx) => (
|
||||
<Typography component="li" key={idx}>
|
||||
{pos && `[${pos}] `}
|
||||
{def}
|
||||
</Typography>
|
||||
))}
|
||||
</Typography>
|
||||
),
|
||||
},
|
||||
[OPT_DICT_YOUDAO]: {
|
||||
apiFn: apiYoudaoDict,
|
||||
toText: (data) =>
|
||||
data?.ec?.word?.trs
|
||||
?.map(({ pos, tran }) => `${pos ? `[${pos}] ` : ""}${tran}`)
|
||||
.join("\n"),
|
||||
uiAudio: () => null,
|
||||
uiTrans: (data) => (
|
||||
<Typography component="ul">
|
||||
{data?.ec?.word?.trs?.map(({ pos, tran }, idx) => (
|
||||
<Typography component="li" key={idx}>
|
||||
{pos && `[${pos}] `}
|
||||
{tran}
|
||||
</Typography>
|
||||
))}
|
||||
</Typography>
|
||||
),
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user