fix: api hooks
This commit is contained in:
@@ -214,10 +214,9 @@ export const apiTranslate = async ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { apiType, apiSlug, useBatchFetch } = apiSetting;
|
const { apiType, apiSlug, useBatchFetch } = apiSetting;
|
||||||
const from =
|
const langMap = OPT_LANGS_SPECIAL[apiType];
|
||||||
OPT_LANGS_SPECIAL[apiType].get(fromLang) ??
|
const from = langMap.get(fromLang) ?? langMap.get("auto");
|
||||||
OPT_LANGS_SPECIAL[apiType].get("auto");
|
const to = langMap.get(toLang);
|
||||||
const to = OPT_LANGS_SPECIAL[apiType].get(toLang);
|
|
||||||
if (!to) {
|
if (!to) {
|
||||||
kissLog(`target lang: ${toLang} not support`);
|
kissLog(`target lang: ${toLang} not support`);
|
||||||
return ["", false];
|
return ["", false];
|
||||||
@@ -249,6 +248,9 @@ export const apiTranslate = async ({
|
|||||||
const queue = getBatchQueue({
|
const queue = getBatchQueue({
|
||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
|
fromLang,
|
||||||
|
toLang,
|
||||||
|
langMap,
|
||||||
docInfo,
|
docInfo,
|
||||||
apiSetting,
|
apiSetting,
|
||||||
usePool,
|
usePool,
|
||||||
@@ -257,22 +259,32 @@ export const apiTranslate = async ({
|
|||||||
const tranlation = await queue.addTask({ text });
|
const tranlation = await queue.addTask({ text });
|
||||||
if (Array.isArray(tranlation)) {
|
if (Array.isArray(tranlation)) {
|
||||||
[trText, srLang = ""] = tranlation;
|
[trText, srLang = ""] = tranlation;
|
||||||
|
} else if (typeof tranlation === "string") {
|
||||||
|
trText = tranlation;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const translations = await handleTranslate({
|
const translations = await handleTranslate({
|
||||||
texts: [text],
|
texts: [text],
|
||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
|
fromLang,
|
||||||
|
toLang,
|
||||||
|
langMap,
|
||||||
docInfo,
|
docInfo,
|
||||||
apiSetting,
|
apiSetting,
|
||||||
usePool,
|
usePool,
|
||||||
});
|
});
|
||||||
if (Array.isArray(translations?.[0])) {
|
if (Array.isArray(translations)) {
|
||||||
[trText, srLang = ""] = translations[0];
|
if (Array.isArray(translations[0])) {
|
||||||
|
[trText, srLang = ""] = translations[0];
|
||||||
|
} else {
|
||||||
|
[trText, srLang = ""] = translations;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isSame = srLang && (to.includes(srLang) || srLang.includes(to));
|
// const isSame = srLang && (to.includes(srLang) || srLang.includes(to));
|
||||||
|
const isSame = srLang && srLang.slice(0, 2) === to.slice(0, 2);
|
||||||
|
|
||||||
// 插入缓存
|
// 插入缓存
|
||||||
if (useCache && trText) {
|
if (useCache && trText) {
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ const parseAIRes = (raw) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const genGoogle = ({ texts, from, to, url, key }) => {
|
const genGoogle = ({ texts, from, to, url, key }) => {
|
||||||
const params = {
|
const params = queryString.stringify({
|
||||||
client: "gtx",
|
client: "gtx",
|
||||||
dt: "t",
|
dt: "t",
|
||||||
dj: 1,
|
dj: 1,
|
||||||
@@ -119,52 +119,42 @@ const genGoogle = ({ texts, from, to, url, key }) => {
|
|||||||
sl: from,
|
sl: from,
|
||||||
tl: to,
|
tl: to,
|
||||||
q: texts.join(" "),
|
q: texts.join(" "),
|
||||||
};
|
});
|
||||||
const input = `${url}?${queryString.stringify(params)}`;
|
url = `${url}?${params}`;
|
||||||
const init = {
|
const headers = {
|
||||||
headers: {
|
"Content-type": "application/json",
|
||||||
"Content-type": "application/json",
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
if (key) {
|
if (key) {
|
||||||
init.headers.Authorization = `Bearer ${key}`;
|
headers.Authorization = `Bearer ${key}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return [input, init];
|
return { url, headers, method: "GET" };
|
||||||
};
|
};
|
||||||
|
|
||||||
const genGoogle2 = ({ texts, from, to, url, key }) => {
|
const genGoogle2 = ({ texts, from, to, url, key }) => {
|
||||||
const body = JSON.stringify([[texts, from, to], "wt_lib"]);
|
const data = [[texts, from, to], "wt_lib"];
|
||||||
const init = {
|
const headers = {
|
||||||
method: "POST",
|
"Content-Type": "application/json+protobuf",
|
||||||
headers: {
|
"X-Goog-API-Key": key,
|
||||||
"Content-Type": "application/json+protobuf",
|
|
||||||
"X-Goog-API-Key": key,
|
|
||||||
},
|
|
||||||
body,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return [url, init];
|
return { url, data, headers };
|
||||||
};
|
};
|
||||||
|
|
||||||
const genMicrosoft = async ({ texts, from, to }) => {
|
const genMicrosoft = ({ texts, from, to, token }) => {
|
||||||
const [token] = await msAuth();
|
const params = queryString.stringify({
|
||||||
const params = {
|
|
||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
"api-version": "3.0",
|
"api-version": "3.0",
|
||||||
|
});
|
||||||
|
const url = `https://api-edge.cognitive.microsofttranslator.com/translate?${params}`;
|
||||||
|
const headers = {
|
||||||
|
"Content-type": "application/json",
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
};
|
};
|
||||||
const input = `https://api-edge.cognitive.microsofttranslator.com/translate?${queryString.stringify(params)}`;
|
const data = texts.map((text) => ({ Text: text }));
|
||||||
const init = {
|
|
||||||
headers: {
|
|
||||||
"Content-type": "application/json",
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify(texts.map((text) => ({ Text: text }))),
|
|
||||||
};
|
|
||||||
|
|
||||||
return [input, init];
|
return { url, data, headers };
|
||||||
};
|
};
|
||||||
|
|
||||||
const genDeepl = ({ texts, from, to, url, key }) => {
|
const genDeepl = ({ texts, from, to, url, key }) => {
|
||||||
@@ -174,16 +164,12 @@ const genDeepl = ({ texts, from, to, url, key }) => {
|
|||||||
source_lang: from,
|
source_lang: from,
|
||||||
// split_sentences: "0",
|
// split_sentences: "0",
|
||||||
};
|
};
|
||||||
const init = {
|
const headers = {
|
||||||
headers: {
|
"Content-type": "application/json",
|
||||||
"Content-type": "application/json",
|
Authorization: `DeepL-Auth-Key ${key}`,
|
||||||
Authorization: `DeepL-Auth-Key ${key}`,
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return [url, init];
|
return { url, data, headers };
|
||||||
};
|
};
|
||||||
|
|
||||||
const genDeeplX = ({ texts, from, to, url, key }) => {
|
const genDeeplX = ({ texts, from, to, url, key }) => {
|
||||||
@@ -193,18 +179,14 @@ const genDeeplX = ({ texts, from, to, url, key }) => {
|
|||||||
source_lang: from,
|
source_lang: from,
|
||||||
};
|
};
|
||||||
|
|
||||||
const init = {
|
const headers = {
|
||||||
headers: {
|
"Content-type": "application/json",
|
||||||
"Content-type": "application/json",
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
};
|
};
|
||||||
if (key) {
|
if (key) {
|
||||||
init.headers.Authorization = `Bearer ${key}`;
|
headers.Authorization = `Bearer ${key}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return [url, init];
|
return { url, data, headers };
|
||||||
};
|
};
|
||||||
|
|
||||||
const genNiuTrans = ({ texts, from, to, url, key, dictNo, memoryNo }) => {
|
const genNiuTrans = ({ texts, from, to, url, key, dictNo, memoryNo }) => {
|
||||||
@@ -217,15 +199,11 @@ const genNiuTrans = ({ texts, from, to, url, key, dictNo, memoryNo }) => {
|
|||||||
memoryNo,
|
memoryNo,
|
||||||
};
|
};
|
||||||
|
|
||||||
const init = {
|
const headers = {
|
||||||
headers: {
|
"Content-type": "application/json",
|
||||||
"Content-type": "application/json",
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return [url, init];
|
return { url, data, headers };
|
||||||
};
|
};
|
||||||
|
|
||||||
const genTencent = ({ texts, from, to }) => {
|
const genTencent = ({ texts, from, to }) => {
|
||||||
@@ -246,19 +224,15 @@ const genTencent = ({ texts, from, to }) => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const input = "https://transmart.qq.com/api/imt";
|
const url = "https://transmart.qq.com/api/imt";
|
||||||
const init = {
|
const headers = {
|
||||||
headers: {
|
"Content-Type": "application/json",
|
||||||
"Content-Type": "application/json",
|
"user-agent":
|
||||||
"user-agent":
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36",
|
||||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36",
|
referer: "https://transmart.qq.com/zh-CN/index",
|
||||||
referer: "https://transmart.qq.com/zh-CN/index",
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return [input, init];
|
return { url, data, headers };
|
||||||
};
|
};
|
||||||
|
|
||||||
const genVolcengine = ({ texts, from, to }) => {
|
const genVolcengine = ({ texts, from, to }) => {
|
||||||
@@ -268,22 +242,15 @@ const genVolcengine = ({ texts, from, to }) => {
|
|||||||
text: texts.join(" "),
|
text: texts.join(" "),
|
||||||
};
|
};
|
||||||
|
|
||||||
const input = "https://translate.volcengine.com/crx/translate/v1";
|
const url = "https://translate.volcengine.com/crx/translate/v1";
|
||||||
const init = {
|
const headers = {
|
||||||
headers: {
|
"Content-type": "application/json",
|
||||||
"Content-type": "application/json",
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return [input, init];
|
return { url, data, headers };
|
||||||
};
|
};
|
||||||
|
|
||||||
const genOpenAI = ({
|
const genOpenAI = ({
|
||||||
texts,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
url,
|
url,
|
||||||
key,
|
key,
|
||||||
systemPrompt,
|
systemPrompt,
|
||||||
@@ -291,16 +258,8 @@ const genOpenAI = ({
|
|||||||
model,
|
model,
|
||||||
temperature,
|
temperature,
|
||||||
maxTokens,
|
maxTokens,
|
||||||
customHeader,
|
|
||||||
customBody,
|
|
||||||
docInfo,
|
|
||||||
hisMsgs,
|
hisMsgs,
|
||||||
}) => {
|
}) => {
|
||||||
systemPrompt = genSystemPrompt({ systemPrompt, from, to });
|
|
||||||
userPrompt = genUserPrompt({ userPrompt, from, to, texts, docInfo });
|
|
||||||
customHeader = parseJsonObj(customHeader);
|
|
||||||
customBody = parseJsonObj(customBody);
|
|
||||||
|
|
||||||
const userMsg = {
|
const userMsg = {
|
||||||
role: "user",
|
role: "user",
|
||||||
content: userPrompt,
|
content: userPrompt,
|
||||||
@@ -317,27 +276,18 @@ const genOpenAI = ({
|
|||||||
],
|
],
|
||||||
temperature,
|
temperature,
|
||||||
max_completion_tokens: maxTokens,
|
max_completion_tokens: maxTokens,
|
||||||
...customBody,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const init = {
|
const headers = {
|
||||||
headers: {
|
"Content-type": "application/json",
|
||||||
"Content-type": "application/json",
|
Authorization: `Bearer ${key}`, // OpenAI
|
||||||
Authorization: `Bearer ${key}`, // OpenAI
|
// "api-key": key, // Azure OpenAI
|
||||||
"api-key": key, // Azure OpenAI
|
|
||||||
...customHeader,
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return [url, init, userMsg];
|
return { url, data, headers, userMsg };
|
||||||
};
|
};
|
||||||
|
|
||||||
const genGemini = ({
|
const genGemini = ({
|
||||||
texts,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
url,
|
url,
|
||||||
key,
|
key,
|
||||||
systemPrompt,
|
systemPrompt,
|
||||||
@@ -345,18 +295,11 @@ const genGemini = ({
|
|||||||
model,
|
model,
|
||||||
temperature,
|
temperature,
|
||||||
maxTokens,
|
maxTokens,
|
||||||
customHeader,
|
|
||||||
customBody,
|
|
||||||
docInfo,
|
|
||||||
hisMsgs,
|
hisMsgs,
|
||||||
}) => {
|
}) => {
|
||||||
url = url
|
url = url
|
||||||
.replaceAll(INPUT_PLACE_MODEL, model)
|
.replaceAll(INPUT_PLACE_MODEL, model)
|
||||||
.replaceAll(INPUT_PLACE_KEY, key);
|
.replaceAll(INPUT_PLACE_KEY, key);
|
||||||
systemPrompt = genSystemPrompt({ systemPrompt, from, to });
|
|
||||||
userPrompt = genUserPrompt({ userPrompt, from, to, texts, docInfo });
|
|
||||||
customHeader = parseJsonObj(customHeader);
|
|
||||||
customBody = parseJsonObj(customBody);
|
|
||||||
|
|
||||||
const userMsg = { role: "user", parts: [{ text: userPrompt }] };
|
const userMsg = { role: "user", parts: [{ text: userPrompt }] };
|
||||||
const data = {
|
const data = {
|
||||||
@@ -393,25 +336,15 @@ const genGemini = ({
|
|||||||
threshold: "BLOCK_NONE",
|
threshold: "BLOCK_NONE",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
...customBody,
|
};
|
||||||
|
const headers = {
|
||||||
|
"Content-type": "application/json",
|
||||||
};
|
};
|
||||||
|
|
||||||
const init = {
|
return { url, data, headers, userMsg };
|
||||||
headers: {
|
|
||||||
"Content-type": "application/json",
|
|
||||||
...customHeader,
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
};
|
|
||||||
|
|
||||||
return [url, init, userMsg];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const genGemini2 = ({
|
const genGemini2 = ({
|
||||||
texts,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
url,
|
url,
|
||||||
key,
|
key,
|
||||||
systemPrompt,
|
systemPrompt,
|
||||||
@@ -419,16 +352,8 @@ const genGemini2 = ({
|
|||||||
model,
|
model,
|
||||||
temperature,
|
temperature,
|
||||||
maxTokens,
|
maxTokens,
|
||||||
customHeader,
|
|
||||||
customBody,
|
|
||||||
docInfo,
|
|
||||||
hisMsgs,
|
hisMsgs,
|
||||||
}) => {
|
}) => {
|
||||||
systemPrompt = genSystemPrompt({ systemPrompt, from, to });
|
|
||||||
userPrompt = genUserPrompt({ userPrompt, from, to, texts, docInfo });
|
|
||||||
customHeader = parseJsonObj(customHeader);
|
|
||||||
customBody = parseJsonObj(customBody);
|
|
||||||
|
|
||||||
const userMsg = {
|
const userMsg = {
|
||||||
role: "user",
|
role: "user",
|
||||||
content: userPrompt,
|
content: userPrompt,
|
||||||
@@ -445,26 +370,17 @@ const genGemini2 = ({
|
|||||||
],
|
],
|
||||||
temperature,
|
temperature,
|
||||||
max_tokens: maxTokens,
|
max_tokens: maxTokens,
|
||||||
...customBody,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const init = {
|
const headers = {
|
||||||
headers: {
|
"Content-type": "application/json",
|
||||||
"Content-type": "application/json",
|
Authorization: `Bearer ${key}`,
|
||||||
Authorization: `Bearer ${key}`,
|
|
||||||
...customHeader,
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return [url, init, userMsg];
|
return { url, data, headers, userMsg };
|
||||||
};
|
};
|
||||||
|
|
||||||
const genClaude = ({
|
const genClaude = ({
|
||||||
texts,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
url,
|
url,
|
||||||
key,
|
key,
|
||||||
systemPrompt,
|
systemPrompt,
|
||||||
@@ -472,16 +388,8 @@ const genClaude = ({
|
|||||||
model,
|
model,
|
||||||
temperature,
|
temperature,
|
||||||
maxTokens,
|
maxTokens,
|
||||||
customHeader,
|
|
||||||
customBody,
|
|
||||||
docInfo,
|
|
||||||
hisMsgs,
|
hisMsgs,
|
||||||
}) => {
|
}) => {
|
||||||
systemPrompt = genSystemPrompt({ systemPrompt, from, to });
|
|
||||||
userPrompt = genUserPrompt({ userPrompt, from, to, texts, docInfo });
|
|
||||||
customHeader = parseJsonObj(customHeader);
|
|
||||||
customBody = parseJsonObj(customBody);
|
|
||||||
|
|
||||||
const userMsg = {
|
const userMsg = {
|
||||||
role: "user",
|
role: "user",
|
||||||
content: userPrompt,
|
content: userPrompt,
|
||||||
@@ -492,28 +400,19 @@ const genClaude = ({
|
|||||||
messages: [...hisMsgs, userMsg],
|
messages: [...hisMsgs, userMsg],
|
||||||
temperature,
|
temperature,
|
||||||
max_tokens: maxTokens,
|
max_tokens: maxTokens,
|
||||||
...customBody,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const init = {
|
const headers = {
|
||||||
headers: {
|
"Content-type": "application/json",
|
||||||
"Content-type": "application/json",
|
"anthropic-version": "2023-06-01",
|
||||||
"anthropic-version": "2023-06-01",
|
"anthropic-dangerous-direct-browser-access": "true",
|
||||||
"anthropic-dangerous-direct-browser-access": "true",
|
"x-api-key": key,
|
||||||
"x-api-key": key,
|
|
||||||
...customHeader,
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return [url, init, userMsg];
|
return { url, data, headers, userMsg };
|
||||||
};
|
};
|
||||||
|
|
||||||
const genOpenRouter = ({
|
const genOpenRouter = ({
|
||||||
texts,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
url,
|
url,
|
||||||
key,
|
key,
|
||||||
systemPrompt,
|
systemPrompt,
|
||||||
@@ -521,16 +420,8 @@ const genOpenRouter = ({
|
|||||||
model,
|
model,
|
||||||
temperature,
|
temperature,
|
||||||
maxTokens,
|
maxTokens,
|
||||||
customHeader,
|
|
||||||
customBody,
|
|
||||||
docInfo,
|
|
||||||
hisMsgs,
|
hisMsgs,
|
||||||
}) => {
|
}) => {
|
||||||
systemPrompt = genSystemPrompt({ systemPrompt, from, to });
|
|
||||||
userPrompt = genUserPrompt({ userPrompt, from, to, texts, docInfo });
|
|
||||||
customHeader = parseJsonObj(customHeader);
|
|
||||||
customBody = parseJsonObj(customBody);
|
|
||||||
|
|
||||||
const userMsg = {
|
const userMsg = {
|
||||||
role: "user",
|
role: "user",
|
||||||
content: userPrompt,
|
content: userPrompt,
|
||||||
@@ -547,26 +438,17 @@ const genOpenRouter = ({
|
|||||||
],
|
],
|
||||||
temperature,
|
temperature,
|
||||||
max_tokens: maxTokens,
|
max_tokens: maxTokens,
|
||||||
...customBody,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const init = {
|
const headers = {
|
||||||
headers: {
|
"Content-type": "application/json",
|
||||||
"Content-type": "application/json",
|
Authorization: `Bearer ${key}`,
|
||||||
Authorization: `Bearer ${key}`,
|
|
||||||
...customHeader,
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return [url, init, userMsg];
|
return { url, data, headers, userMsg };
|
||||||
};
|
};
|
||||||
|
|
||||||
const genOllama = ({
|
const genOllama = ({
|
||||||
texts,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
think,
|
think,
|
||||||
url,
|
url,
|
||||||
key,
|
key,
|
||||||
@@ -575,16 +457,8 @@ const genOllama = ({
|
|||||||
model,
|
model,
|
||||||
temperature,
|
temperature,
|
||||||
maxTokens,
|
maxTokens,
|
||||||
customHeader,
|
|
||||||
customBody,
|
|
||||||
docInfo,
|
|
||||||
hisMsgs,
|
hisMsgs,
|
||||||
}) => {
|
}) => {
|
||||||
systemPrompt = genSystemPrompt({ systemPrompt, from, to });
|
|
||||||
userPrompt = genUserPrompt({ userPrompt, from, to, texts, docInfo });
|
|
||||||
customHeader = parseJsonObj(customHeader);
|
|
||||||
customBody = parseJsonObj(customBody);
|
|
||||||
|
|
||||||
const userMsg = {
|
const userMsg = {
|
||||||
role: "user",
|
role: "user",
|
||||||
content: userPrompt,
|
content: userPrompt,
|
||||||
@@ -603,22 +477,16 @@ const genOllama = ({
|
|||||||
max_tokens: maxTokens,
|
max_tokens: maxTokens,
|
||||||
think,
|
think,
|
||||||
stream: false,
|
stream: false,
|
||||||
...customBody,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const init = {
|
const headers = {
|
||||||
headers: {
|
"Content-type": "application/json",
|
||||||
"Content-type": "application/json",
|
|
||||||
...customHeader,
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
};
|
};
|
||||||
if (key) {
|
if (key) {
|
||||||
init.headers.Authorization = `Bearer ${key}`;
|
headers.Authorization = `Bearer ${key}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return [url, init, userMsg];
|
return { url, data, headers, userMsg };
|
||||||
};
|
};
|
||||||
|
|
||||||
const genCloudflareAI = ({ texts, from, to, url, key }) => {
|
const genCloudflareAI = ({ texts, from, to, url, key }) => {
|
||||||
@@ -628,52 +496,65 @@ const genCloudflareAI = ({ texts, from, to, url, key }) => {
|
|||||||
target_lang: to,
|
target_lang: to,
|
||||||
};
|
};
|
||||||
|
|
||||||
const init = {
|
const headers = {
|
||||||
headers: {
|
"Content-type": "application/json",
|
||||||
"Content-type": "application/json",
|
Authorization: `Bearer ${key}`,
|
||||||
Authorization: `Bearer ${key}`,
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return [url, init];
|
return { url, data, headers };
|
||||||
};
|
};
|
||||||
|
|
||||||
const genCustom = ({
|
const genCustom = ({ texts, from, to, url, key }) => {
|
||||||
texts,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
url,
|
|
||||||
key,
|
|
||||||
reqHook,
|
|
||||||
docInfo,
|
|
||||||
hisMsgs,
|
|
||||||
}) => {
|
|
||||||
if (reqHook?.trim()) {
|
|
||||||
interpreter.run(`exports.reqHook = ${reqHook}`);
|
|
||||||
return interpreter.exports.reqHook({
|
|
||||||
texts,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
url,
|
|
||||||
key,
|
|
||||||
docInfo,
|
|
||||||
hisMsgs,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = { texts, from, to };
|
const data = { texts, from, to };
|
||||||
const init = {
|
const headers = {
|
||||||
headers: {
|
"Content-type": "application/json",
|
||||||
"Content-type": "application/json",
|
Authorization: `Bearer ${key}`,
|
||||||
Authorization: `Bearer ${key}`,
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return [url, init];
|
return { url, data, headers };
|
||||||
|
};
|
||||||
|
|
||||||
|
const genReqFuncs = {
|
||||||
|
[OPT_TRANS_GOOGLE]: genGoogle,
|
||||||
|
[OPT_TRANS_GOOGLE_2]: genGoogle2,
|
||||||
|
[OPT_TRANS_MICROSOFT]: genMicrosoft,
|
||||||
|
[OPT_TRANS_DEEPL]: genDeepl,
|
||||||
|
[OPT_TRANS_DEEPLFREE]: genDeeplFree,
|
||||||
|
[OPT_TRANS_DEEPLX]: genDeeplX,
|
||||||
|
[OPT_TRANS_NIUTRANS]: genNiuTrans,
|
||||||
|
[OPT_TRANS_BAIDU]: genBaidu,
|
||||||
|
[OPT_TRANS_TENCENT]: genTencent,
|
||||||
|
[OPT_TRANS_VOLCENGINE]: genVolcengine,
|
||||||
|
[OPT_TRANS_OPENAI]: genOpenAI,
|
||||||
|
[OPT_TRANS_GEMINI]: genGemini,
|
||||||
|
[OPT_TRANS_GEMINI_2]: genGemini2,
|
||||||
|
[OPT_TRANS_CLAUDE]: genClaude,
|
||||||
|
[OPT_TRANS_CLOUDFLAREAI]: genCloudflareAI,
|
||||||
|
[OPT_TRANS_OLLAMA]: genOllama,
|
||||||
|
[OPT_TRANS_OPENROUTER]: genOpenRouter,
|
||||||
|
[OPT_TRANS_CUSTOMIZE]: genCustom,
|
||||||
|
};
|
||||||
|
|
||||||
|
const genInit = ({
|
||||||
|
url = "",
|
||||||
|
data = null,
|
||||||
|
headers = {},
|
||||||
|
userMsg = null,
|
||||||
|
method = "POST",
|
||||||
|
}) => {
|
||||||
|
if (!url) {
|
||||||
|
throw new Error("genInit: url is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
const init = {
|
||||||
|
method,
|
||||||
|
headers,
|
||||||
|
};
|
||||||
|
if (method !== "GET" && method !== "HEAD" && data) {
|
||||||
|
Object.assign(init, { body: JSON.stringify(data) });
|
||||||
|
}
|
||||||
|
|
||||||
|
return [url, init, userMsg];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -681,66 +562,70 @@ const genCustom = ({
|
|||||||
* @param {*}
|
* @param {*}
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const genTransReq = ({ apiType, apiSlug, ...args }) => {
|
export const genTransReq = async ({ reqHook, resHook, ...args }) => {
|
||||||
switch (apiType) {
|
const {
|
||||||
case OPT_TRANS_DEEPL:
|
apiType,
|
||||||
case OPT_TRANS_OPENAI:
|
apiSlug,
|
||||||
case OPT_TRANS_GEMINI:
|
key,
|
||||||
case OPT_TRANS_GEMINI_2:
|
systemPrompt,
|
||||||
case OPT_TRANS_CLAUDE:
|
userPrompt,
|
||||||
case OPT_TRANS_CLOUDFLAREAI:
|
from,
|
||||||
case OPT_TRANS_OLLAMA:
|
to,
|
||||||
case OPT_TRANS_OPENROUTER:
|
texts,
|
||||||
case OPT_TRANS_NIUTRANS:
|
docInfo,
|
||||||
case OPT_TRANS_CUSTOMIZE:
|
customHeader,
|
||||||
args.key = keyPick(apiSlug, args.key, keyMap);
|
customBody,
|
||||||
break;
|
} = args;
|
||||||
case OPT_TRANS_DEEPLX:
|
|
||||||
args.url = keyPick(apiSlug, args.url, urlMap);
|
if (API_SPE_TYPES.mulkeys.has(apiType)) {
|
||||||
break;
|
args.key = keyPick(apiSlug, key, keyMap);
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (apiType) {
|
if (apiType === OPT_TRANS_DEEPLX) {
|
||||||
case OPT_TRANS_GOOGLE:
|
args.url = keyPick(apiSlug, args.url, urlMap);
|
||||||
return genGoogle(args);
|
|
||||||
case OPT_TRANS_GOOGLE_2:
|
|
||||||
return genGoogle2(args);
|
|
||||||
case OPT_TRANS_MICROSOFT:
|
|
||||||
return genMicrosoft(args);
|
|
||||||
case OPT_TRANS_DEEPL:
|
|
||||||
return genDeepl(args);
|
|
||||||
case OPT_TRANS_DEEPLFREE:
|
|
||||||
return genDeeplFree(args);
|
|
||||||
case OPT_TRANS_DEEPLX:
|
|
||||||
return genDeeplX(args);
|
|
||||||
case OPT_TRANS_NIUTRANS:
|
|
||||||
return genNiuTrans(args);
|
|
||||||
case OPT_TRANS_BAIDU:
|
|
||||||
return genBaidu(args);
|
|
||||||
case OPT_TRANS_TENCENT:
|
|
||||||
return genTencent(args);
|
|
||||||
case OPT_TRANS_VOLCENGINE:
|
|
||||||
return genVolcengine(args);
|
|
||||||
case OPT_TRANS_OPENAI:
|
|
||||||
return genOpenAI(args);
|
|
||||||
case OPT_TRANS_GEMINI:
|
|
||||||
return genGemini(args);
|
|
||||||
case OPT_TRANS_GEMINI_2:
|
|
||||||
return genGemini2(args);
|
|
||||||
case OPT_TRANS_CLAUDE:
|
|
||||||
return genClaude(args);
|
|
||||||
case OPT_TRANS_CLOUDFLAREAI:
|
|
||||||
return genCloudflareAI(args);
|
|
||||||
case OPT_TRANS_OLLAMA:
|
|
||||||
return genOllama(args);
|
|
||||||
case OPT_TRANS_OPENROUTER:
|
|
||||||
return genOpenRouter(args);
|
|
||||||
case OPT_TRANS_CUSTOMIZE:
|
|
||||||
return genCustom(args);
|
|
||||||
default:
|
|
||||||
throw new Error(`[trans] ${apiType} not support`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (API_SPE_TYPES.ai.has(apiType)) {
|
||||||
|
args.systemPrompt = genSystemPrompt({ systemPrompt, from, to });
|
||||||
|
args.userPrompt = genUserPrompt({ userPrompt, from, to, texts, docInfo });
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
url = "",
|
||||||
|
data = null,
|
||||||
|
headers = {},
|
||||||
|
userMsg = null,
|
||||||
|
method = "POST",
|
||||||
|
} = genReqFuncs[apiType](args);
|
||||||
|
|
||||||
|
// 合并用户自定义headers和body
|
||||||
|
if (customHeader?.trim()) {
|
||||||
|
Object.assign(headers, parseJsonObj(customHeader));
|
||||||
|
}
|
||||||
|
if (customBody?.trim()) {
|
||||||
|
Object.assign(data, parseJsonObj(customBody));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行 request hook
|
||||||
|
if (reqHook?.trim()) {
|
||||||
|
try {
|
||||||
|
interpreter.run(`exports.reqHook = ${reqHook}`);
|
||||||
|
const hookResult = await interpreter.exports.reqHook(args, {
|
||||||
|
url,
|
||||||
|
data,
|
||||||
|
headers,
|
||||||
|
userMsg,
|
||||||
|
method,
|
||||||
|
});
|
||||||
|
if (hookResult && hookResult.url) {
|
||||||
|
return genInit(hookResult);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
kissLog("run req hook", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return genInit({ url, data, headers, userMsg, method });
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -749,10 +634,48 @@ export const genTransReq = ({ apiType, apiSlug, ...args }) => {
|
|||||||
* @param {*} param3
|
* @param {*} param3
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const parseTransRes = (
|
export const parseTransRes = async (
|
||||||
res,
|
res,
|
||||||
{ texts, from, to, resHook, thinkIgnore, history, userMsg, apiType }
|
{
|
||||||
|
texts,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
fromLang,
|
||||||
|
toLang,
|
||||||
|
langMap,
|
||||||
|
resHook,
|
||||||
|
thinkIgnore,
|
||||||
|
history,
|
||||||
|
userMsg,
|
||||||
|
apiType,
|
||||||
|
}
|
||||||
) => {
|
) => {
|
||||||
|
// 执行 response hook
|
||||||
|
if (resHook?.trim()) {
|
||||||
|
try {
|
||||||
|
interpreter.run(`exports.resHook = ${resHook}`);
|
||||||
|
const hookResult = await interpreter.exports.resHook({
|
||||||
|
apiType,
|
||||||
|
userMsg,
|
||||||
|
res,
|
||||||
|
texts,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
fromLang,
|
||||||
|
toLang,
|
||||||
|
langMap,
|
||||||
|
});
|
||||||
|
if (hookResult && Array.isArray(hookResult.translations)) {
|
||||||
|
if (history && userMsg && hookResult.modelMsg) {
|
||||||
|
history.add(userMsg, hookResult.modelMsg);
|
||||||
|
}
|
||||||
|
return hookResult.translations;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
kissLog("run res hook", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let modelMsg = "";
|
let modelMsg = "";
|
||||||
|
|
||||||
switch (apiType) {
|
switch (apiType) {
|
||||||
@@ -832,7 +755,9 @@ export const parseTransRes = (
|
|||||||
case OPT_TRANS_OLLAMA:
|
case OPT_TRANS_OLLAMA:
|
||||||
modelMsg = res?.choices?.[0]?.message;
|
modelMsg = res?.choices?.[0]?.message;
|
||||||
|
|
||||||
const deepModels = thinkIgnore.split(",").filter((model) => model.trim());
|
const deepModels = thinkIgnore
|
||||||
|
.split(",")
|
||||||
|
.filter((model) => model?.trim());
|
||||||
if (deepModels.some((model) => res?.model?.startsWith(model))) {
|
if (deepModels.some((model) => res?.model?.startsWith(model))) {
|
||||||
modelMsg?.content.replace(/<think>[\s\S]*<\/think>/i, "");
|
modelMsg?.content.replace(/<think>[\s\S]*<\/think>/i, "");
|
||||||
}
|
}
|
||||||
@@ -845,23 +770,7 @@ export const parseTransRes = (
|
|||||||
}
|
}
|
||||||
return parseAIRes(modelMsg?.content);
|
return parseAIRes(modelMsg?.content);
|
||||||
case OPT_TRANS_CUSTOMIZE:
|
case OPT_TRANS_CUSTOMIZE:
|
||||||
if (resHook?.trim()) {
|
return res?.map((item) => [item.text, item.src]);
|
||||||
interpreter.run(`exports.resHook = ${resHook}`);
|
|
||||||
if (history) {
|
|
||||||
const [translations, modelMsg] = interpreter.exports.resHook({
|
|
||||||
res,
|
|
||||||
texts,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
});
|
|
||||||
userMsg && modelMsg && history.add(userMsg, modelMsg);
|
|
||||||
return translations;
|
|
||||||
} else {
|
|
||||||
return interpreter.exports.resHook({ res, texts, from, to });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return res?.map((item) => [item.text, item.src]);
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -877,6 +786,9 @@ export const handleTranslate = async ({
|
|||||||
texts,
|
texts,
|
||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
|
fromLang,
|
||||||
|
toLang,
|
||||||
|
langMap,
|
||||||
docInfo,
|
docInfo,
|
||||||
apiSetting,
|
apiSetting,
|
||||||
usePool,
|
usePool,
|
||||||
@@ -897,12 +809,21 @@ export const handleTranslate = async ({
|
|||||||
hisMsgs = history.getAll();
|
hisMsgs = history.getAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let token = "";
|
||||||
|
if (apiType === OPT_TRANS_MICROSOFT) {
|
||||||
|
[token] = await msAuth();
|
||||||
|
}
|
||||||
|
|
||||||
const [input, init, userMsg] = await genTransReq({
|
const [input, init, userMsg] = await genTransReq({
|
||||||
texts,
|
texts,
|
||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
|
fromLang,
|
||||||
|
toLang,
|
||||||
|
langMap,
|
||||||
docInfo,
|
docInfo,
|
||||||
hisMsgs,
|
hisMsgs,
|
||||||
|
token,
|
||||||
...apiSetting,
|
...apiSetting,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -921,6 +842,9 @@ export const handleTranslate = async ({
|
|||||||
texts,
|
texts,
|
||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
|
fromLang,
|
||||||
|
toLang,
|
||||||
|
langMap,
|
||||||
history,
|
history,
|
||||||
userMsg,
|
userMsg,
|
||||||
...apiSetting,
|
...apiSetting,
|
||||||
|
|||||||
@@ -350,6 +350,18 @@ Output: {"translations":[{"id":1,"text":"一个<b>React</b>组件","sourceLangua
|
|||||||
|
|
||||||
Fail-safe: On any error, return {"translations":[]}.`;
|
Fail-safe: On any error, return {"translations":[]}.`;
|
||||||
|
|
||||||
|
const defaultRequestHook = `async (args, { url, data, headers, userMsg, method } = {}) => {
|
||||||
|
console.log("request hook args:", args);
|
||||||
|
// return { url, data, headers, userMsg, method };
|
||||||
|
}`;
|
||||||
|
|
||||||
|
const defaultResponseHook = `async ({ res, ...args }) => {
|
||||||
|
console.log("reaponse hook args:", res, args);
|
||||||
|
// const translations = [["你好", "zh"]];
|
||||||
|
// const modelMsg = "";
|
||||||
|
// return { translations, modelMsg };
|
||||||
|
}`;
|
||||||
|
|
||||||
// 翻译接口默认参数
|
// 翻译接口默认参数
|
||||||
const defaultApi = {
|
const defaultApi = {
|
||||||
apiSlug: "", // 唯一标识
|
apiSlug: "", // 唯一标识
|
||||||
@@ -473,16 +485,8 @@ const defaultApiOpts = {
|
|||||||
[OPT_TRANS_CUSTOMIZE]: {
|
[OPT_TRANS_CUSTOMIZE]: {
|
||||||
...defaultApi,
|
...defaultApi,
|
||||||
url: "https://translate.googleapis.com/translate_a/single?client=gtx&dj=1&dt=t&ie=UTF-8&q={{text}}&sl=en&tl=zh-CN",
|
url: "https://translate.googleapis.com/translate_a/single?client=gtx&dj=1&dt=t&ie=UTF-8&q={{text}}&sl=en&tl=zh-CN",
|
||||||
reqHook: `// Request Hook
|
reqHook: defaultRequestHook,
|
||||||
(text, from, to, url, key) => [url, {
|
resHook: defaultResponseHook,
|
||||||
headers: {
|
|
||||||
"Content-type": "application/json",
|
|
||||||
},
|
|
||||||
method: "GET",
|
|
||||||
body: null,
|
|
||||||
}]`,
|
|
||||||
resHook: `// Response Hook
|
|
||||||
(res, text, from, to) => [res.sentences.map((item) => item.trans).join(" "), to === res.src]`,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -136,6 +136,52 @@ https://translate.googleapis.com/translate_a/single?client=gtx&dj=1&dt=t&ie=UTF-
|
|||||||
${customApiLangs}
|
${customApiLangs}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const requestHookHelperZH = `1、第一个参数包含如下字段:'texts', 'from', 'to', 'url', 'key', 'model', 'systemPrompt', ...
|
||||||
|
2、返回值必须是包含以下字段的对象: 'url', 'data', 'headers', 'userMsg', 'method'
|
||||||
|
3、如返回空值,则hook函数不会产生任何效果。
|
||||||
|
|
||||||
|
// 示例
|
||||||
|
async (args, { url, data, headers, userMsg, method } = {}) => {
|
||||||
|
console.log("request hook args:", args);
|
||||||
|
return { url, data, headers, userMsg, method };
|
||||||
|
}`;
|
||||||
|
|
||||||
|
const requestHookHelperEN = `1. The first parameter contains the following fields: 'texts', 'from', 'to', 'url', 'key', 'model', 'systemPrompt', ...
|
||||||
|
2. The return value must be an object containing the following fields: 'url', 'data', 'headers', 'userMsg', 'method'
|
||||||
|
3. If a null value is returned, the hook function will have no effect.
|
||||||
|
|
||||||
|
// Example
|
||||||
|
async (args, { url, data, headers, userMsg, method } = {}) => {
|
||||||
|
console.log("request hook args:", args);
|
||||||
|
return { url, data, headers, userMsg, method };
|
||||||
|
}`;
|
||||||
|
|
||||||
|
const responsetHookHelperZH = `1、第一个参数包含如下字段:'res', ...
|
||||||
|
2、返回值必须是包含以下字段的对象: 'translations', 'modelMsg'
|
||||||
|
('translations' 应为一个二维数组,表示 [译文,源语言] 的列表)
|
||||||
|
3、如返回空值,则hook函数不会产生任何效果。
|
||||||
|
|
||||||
|
// 示例
|
||||||
|
async ({ res, ...args }) => {
|
||||||
|
console.log("reaponse hook args:", res, args);
|
||||||
|
const translations = [["你好", "zh"]];
|
||||||
|
const modelMsg = "";
|
||||||
|
return { translations, modelMsg };
|
||||||
|
}`;
|
||||||
|
|
||||||
|
const responsetHookHelperEN = `1. The first parameter contains the following fields: 'res', ...
|
||||||
|
2. The return value must be an object containing the following fields: 'translations', 'modelMsg'
|
||||||
|
('translations' should be a two-dimensional array representing a list of [translation, source language]).
|
||||||
|
3. If a null value is returned, the hook function will have no effect.
|
||||||
|
|
||||||
|
// Example
|
||||||
|
async ({ res, ...args }) => {
|
||||||
|
console.log("reaponse hook args:", res, args);
|
||||||
|
const translations = [["你好", "zh"]];
|
||||||
|
const modelMsg = "";
|
||||||
|
return { translations, modelMsg };
|
||||||
|
}`;
|
||||||
|
|
||||||
export const I18N = {
|
export const I18N = {
|
||||||
app_name: {
|
app_name: {
|
||||||
zh: `简约翻译`,
|
zh: `简约翻译`,
|
||||||
@@ -152,6 +198,16 @@ export const I18N = {
|
|||||||
en: customApiHelpEN,
|
en: customApiHelpEN,
|
||||||
zh_TW: customApiHelpZH,
|
zh_TW: customApiHelpZH,
|
||||||
},
|
},
|
||||||
|
request_hook_helper: {
|
||||||
|
zh: requestHookHelperZH,
|
||||||
|
en: requestHookHelperEN,
|
||||||
|
zh_TW: requestHookHelperZH,
|
||||||
|
},
|
||||||
|
response_hook_helper: {
|
||||||
|
zh: responsetHookHelperZH,
|
||||||
|
en: responsetHookHelperEN,
|
||||||
|
zh_TW: responsetHookHelperZH,
|
||||||
|
},
|
||||||
translate_alt: {
|
translate_alt: {
|
||||||
zh: `翻译`,
|
zh: `翻译`,
|
||||||
en: `Translate`,
|
en: `Translate`,
|
||||||
@@ -613,9 +669,9 @@ export const I18N = {
|
|||||||
zh_TW: `選擇器節點樣式`,
|
zh_TW: `選擇器節點樣式`,
|
||||||
},
|
},
|
||||||
selector_style_helper: {
|
selector_style_helper: {
|
||||||
zh: `开启翻译时注入,关闭翻译时不会移除。`,
|
zh: `开启翻译时注入。`,
|
||||||
en: `It is injected when translation is turned on and will not be removed when translation is turned off.`,
|
en: `It is injected when translation is turned on.`,
|
||||||
zh_TW: `在開啟翻譯時注入,關閉翻譯時不會移除。`,
|
zh_TW: `在開啟翻譯時注入。`,
|
||||||
},
|
},
|
||||||
selector_parent_style: {
|
selector_parent_style: {
|
||||||
zh: `选择器父节点样式`,
|
zh: `选择器父节点样式`,
|
||||||
@@ -1213,9 +1269,9 @@ export const I18N = {
|
|||||||
zh_TW: `翻譯開始 Hook`,
|
zh_TW: `翻譯開始 Hook`,
|
||||||
},
|
},
|
||||||
translate_start_hook_helper: {
|
translate_start_hook_helper: {
|
||||||
zh: `翻译前时运行,入参为: 翻译节点列表。`,
|
zh: `翻译前时运行,入参为: ({hostNode, parentNode, nodes})`,
|
||||||
en: `Run before translation, input parameters are: translation node list.`,
|
en: `Run before translation, input parameters are: ({hostNode, parentNode, nodes})`,
|
||||||
zh_TW: `翻譯前時運行,入參為: 翻譯節點清單。`,
|
zh_TW: `翻譯前時運行,入參為: ({hostNode, parentNode, nodes})`,
|
||||||
},
|
},
|
||||||
translate_end_hook: {
|
translate_end_hook: {
|
||||||
zh: `翻译完成钩子函数`,
|
zh: `翻译完成钩子函数`,
|
||||||
@@ -1223,9 +1279,9 @@ export const I18N = {
|
|||||||
zh_TW: `翻譯完成 Hook`,
|
zh_TW: `翻譯完成 Hook`,
|
||||||
},
|
},
|
||||||
translate_end_hook_helper: {
|
translate_end_hook_helper: {
|
||||||
zh: `翻译完成时运行,入参为: 翻译节点列表。`,
|
zh: `翻译完成时运行,入参为: ({hostNode, parentNode, nodes, wrapperNode, innerNode})`,
|
||||||
en: `Run when translation is complete, input parameters are: translation node list.`,
|
en: `Run when translation is complete, input parameters are: ({hostNode, parentNode, nodes, wrapperNode, innerNode})`,
|
||||||
zh_TW: `翻譯完成時運行,入參為: 翻譯節點清單。`,
|
zh_TW: `翻譯完成時運行,入參為: ({hostNode, parentNode, nodes, wrapperNode, innerNode})`,
|
||||||
},
|
},
|
||||||
translate_remove_hook: {
|
translate_remove_hook: {
|
||||||
zh: `翻译移除钩子函数`,
|
zh: `翻译移除钩子函数`,
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ export const DEFAULT_SELECTOR =
|
|||||||
"h1, h2, h3, h4, h5, h6, li, p, dd, blockquote, figcaption, label, legend";
|
"h1, h2, h3, h4, h5, h6, li, p, dd, blockquote, figcaption, label, legend";
|
||||||
export const DEFAULT_IGNORE_SELECTOR =
|
export const DEFAULT_IGNORE_SELECTOR =
|
||||||
"button, code, footer, form, header, mark, nav, pre";
|
"button, code, footer, form, header, mark, nav, pre";
|
||||||
export const DEFAULT_KEEP_SELECTOR = `code, img, svg, pre`;
|
export const DEFAULT_KEEP_SELECTOR = `code, img, svg, pre, a:has(code)`;
|
||||||
export const DEFAULT_RULE = {
|
export const DEFAULT_RULE = {
|
||||||
pattern: "", // 匹配网址
|
pattern: "", // 匹配网址
|
||||||
selector: "", // 选择器
|
selector: "", // 选择器
|
||||||
|
|||||||
@@ -70,6 +70,9 @@ const BatchQueue = (
|
|||||||
try {
|
try {
|
||||||
const payloads = tasksToProcess.map((item) => item.payload);
|
const payloads = tasksToProcess.map((item) => item.payload);
|
||||||
const responses = await sendBatchRequest(payloads);
|
const responses = await sendBatchRequest(payloads);
|
||||||
|
if (!Array.isArray(responses)) {
|
||||||
|
throw new Error("responses format error");
|
||||||
|
}
|
||||||
|
|
||||||
tasksToProcess.forEach((taskItem, index) => {
|
tasksToProcess.forEach((taskItem, index) => {
|
||||||
const response = responses[index];
|
const response = responses[index];
|
||||||
|
|||||||
@@ -62,10 +62,11 @@ async function trySetObj(key, obj) {
|
|||||||
|
|
||||||
async function getObj(key) {
|
async function getObj(key) {
|
||||||
const val = await get(key);
|
const val = await get(key);
|
||||||
|
if (val === null || val === undefined) return null;
|
||||||
try {
|
try {
|
||||||
return JSON.parse(val);
|
return JSON.parse(val);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
kissLog("parse json: ", key);
|
kissLog("parse json in storage err: ", key);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -255,6 +255,7 @@ export class Translator {
|
|||||||
#setting; // 设置选项
|
#setting; // 设置选项
|
||||||
#rule; // 规则
|
#rule; // 规则
|
||||||
#isInitialized = false; // 初始化状态
|
#isInitialized = false; // 初始化状态
|
||||||
|
#isJsInjected = false; // 注入用户JS
|
||||||
#mouseHoverEnabled = false; // 鼠标悬停翻译
|
#mouseHoverEnabled = false; // 鼠标悬停翻译
|
||||||
#enabled = false; // 全局默认状态
|
#enabled = false; // 全局默认状态
|
||||||
#runId = 0; // 用于中止过期的异步请求
|
#runId = 0; // 用于中止过期的异步请求
|
||||||
@@ -1248,6 +1249,11 @@ export class Translator {
|
|||||||
|
|
||||||
// 注入JS/CSS
|
// 注入JS/CSS
|
||||||
#initInjector() {
|
#initInjector() {
|
||||||
|
if (this.#isJsInjected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.#isJsInjected = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { injectJs, injectCss } = this.#rule;
|
const { injectJs, injectCss } = this.#rule;
|
||||||
if (isExt) {
|
if (isExt) {
|
||||||
@@ -1258,7 +1264,7 @@ export class Translator {
|
|||||||
injectCss && injectInternalCss(injectCss);
|
injectCss && injectInternalCss(injectCss);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
kissLog("inject js");
|
kissLog("inject js", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import { apiTranslate } from "../../apis";
|
|||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import { limitNumber, limitFloat } from "../../libs/utils";
|
import { limitNumber, limitFloat } from "../../libs/utils";
|
||||||
import ReusableAutocomplete from "./ReusableAutocomplete";
|
import ReusableAutocomplete from "./ReusableAutocomplete";
|
||||||
|
import ShowMoreButton from "./ShowMoreButton";
|
||||||
import {
|
import {
|
||||||
OPT_TRANS_DEEPLX,
|
OPT_TRANS_DEEPLX,
|
||||||
OPT_TRANS_OLLAMA,
|
OPT_TRANS_OLLAMA,
|
||||||
@@ -115,6 +116,7 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
|
|||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
const [formData, setFormData] = useState({});
|
const [formData, setFormData] = useState({});
|
||||||
const [isModified, setIsModified] = useState(false);
|
const [isModified, setIsModified] = useState(false);
|
||||||
|
const [showMore, setShowMore] = useState(false);
|
||||||
const confirm = useConfirm();
|
const confirm = useConfirm();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -282,7 +284,7 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
|
|||||||
<>
|
<>
|
||||||
<Box>
|
<Box>
|
||||||
<Grid container spacing={2} columns={12}>
|
<Grid container spacing={2} columns={12}>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
{/* todo: 改成 ReusableAutocomplete 可选择和填写模型 */}
|
{/* todo: 改成 ReusableAutocomplete 可选择和填写模型 */}
|
||||||
<TextField
|
<TextField
|
||||||
size="small"
|
size="small"
|
||||||
@@ -293,7 +295,7 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<ReusableAutocomplete
|
<ReusableAutocomplete
|
||||||
freeSolo
|
freeSolo
|
||||||
size="small"
|
size="small"
|
||||||
@@ -305,7 +307,7 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
size="small"
|
size="small"
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -316,7 +318,7 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
size="small"
|
size="small"
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -327,7 +329,7 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}></Grid>
|
<Grid item xs={12} sm={12} md={6} lg={3}></Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@@ -393,27 +395,6 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Box> */}
|
</Box> */}
|
||||||
|
|
||||||
<TextField
|
|
||||||
size="small"
|
|
||||||
label={i18n("custom_header")}
|
|
||||||
name="customHeader"
|
|
||||||
value={customHeader}
|
|
||||||
onChange={handleChange}
|
|
||||||
multiline
|
|
||||||
maxRows={10}
|
|
||||||
helperText={i18n("custom_header_help")}
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
size="small"
|
|
||||||
label={i18n("custom_body")}
|
|
||||||
name="customBody"
|
|
||||||
value={customBody}
|
|
||||||
onChange={handleChange}
|
|
||||||
multiline
|
|
||||||
maxRows={10}
|
|
||||||
helperText={i18n("custom_body_help")}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -469,6 +450,14 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
multiline
|
multiline
|
||||||
maxRows={10}
|
maxRows={10}
|
||||||
|
FormHelperTextProps={{
|
||||||
|
component: "div",
|
||||||
|
}}
|
||||||
|
helperText={
|
||||||
|
<Box component="pre" sx={{ overflowX: "auto" }}>
|
||||||
|
{i18n("request_hook_helper")}
|
||||||
|
</Box>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
size="small"
|
size="small"
|
||||||
@@ -478,6 +467,14 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
multiline
|
multiline
|
||||||
maxRows={10}
|
maxRows={10}
|
||||||
|
FormHelperTextProps={{
|
||||||
|
component: "div",
|
||||||
|
}}
|
||||||
|
helperText={
|
||||||
|
<Box component="pre" sx={{ overflowX: "auto" }}>
|
||||||
|
{i18n("response_hook_helper")}
|
||||||
|
</Box>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -485,7 +482,7 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
|
|||||||
{API_SPE_TYPES.batch.has(api.apiType) && (
|
{API_SPE_TYPES.batch.has(api.apiType) && (
|
||||||
<Box>
|
<Box>
|
||||||
<Grid container spacing={2} columns={12}>
|
<Grid container spacing={2} columns={12}>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -499,7 +496,7 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
|
|||||||
<MenuItem value={true}>{i18n("enable")}</MenuItem>
|
<MenuItem value={true}>{i18n("enable")}</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
size="small"
|
size="small"
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -510,7 +507,7 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
size="small"
|
size="small"
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -521,7 +518,7 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
size="small"
|
size="small"
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -540,7 +537,7 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
|
|||||||
<>
|
<>
|
||||||
<Box>
|
<Box>
|
||||||
<Grid container spacing={2} columns={12}>
|
<Grid container spacing={2} columns={12}>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
{" "}
|
{" "}
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
@@ -555,7 +552,7 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
|
|||||||
<MenuItem value={true}>{i18n("enable")}</MenuItem>
|
<MenuItem value={true}>{i18n("enable")}</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
{" "}
|
{" "}
|
||||||
<TextField
|
<TextField
|
||||||
size="small"
|
size="small"
|
||||||
@@ -574,7 +571,7 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
|
|||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Grid container spacing={2} columns={12}>
|
<Grid container spacing={2} columns={12}>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
size="small"
|
size="small"
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -585,7 +582,7 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
size="small"
|
size="small"
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -596,7 +593,7 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
size="small"
|
size="small"
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -607,10 +604,74 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}></Grid>
|
<Grid item xs={12} sm={12} md={6} lg={3}></Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
{showMore && (
|
||||||
|
<>
|
||||||
|
<TextField
|
||||||
|
size="small"
|
||||||
|
label={i18n("custom_header")}
|
||||||
|
name="customHeader"
|
||||||
|
value={customHeader}
|
||||||
|
onChange={handleChange}
|
||||||
|
multiline
|
||||||
|
maxRows={10}
|
||||||
|
helperText={i18n("custom_header_help")}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
size="small"
|
||||||
|
label={i18n("custom_body")}
|
||||||
|
name="customBody"
|
||||||
|
value={customBody}
|
||||||
|
onChange={handleChange}
|
||||||
|
multiline
|
||||||
|
maxRows={10}
|
||||||
|
helperText={i18n("custom_body_help")}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{apiType !== OPT_TRANS_CUSTOMIZE && (
|
||||||
|
<>
|
||||||
|
<TextField
|
||||||
|
size="small"
|
||||||
|
label={"Request Hook"}
|
||||||
|
name="reqHook"
|
||||||
|
value={reqHook}
|
||||||
|
onChange={handleChange}
|
||||||
|
multiline
|
||||||
|
maxRows={10}
|
||||||
|
FormHelperTextProps={{
|
||||||
|
component: "div",
|
||||||
|
}}
|
||||||
|
helperText={
|
||||||
|
<Box component="pre" sx={{ overflowX: "auto" }}>
|
||||||
|
{i18n("request_hook_helper")}
|
||||||
|
</Box>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
size="small"
|
||||||
|
label={"Response Hook"}
|
||||||
|
name="resHook"
|
||||||
|
value={resHook}
|
||||||
|
onChange={handleChange}
|
||||||
|
multiline
|
||||||
|
maxRows={10}
|
||||||
|
FormHelperTextProps={{
|
||||||
|
component: "div",
|
||||||
|
}}
|
||||||
|
helperText={
|
||||||
|
<Box component="pre" sx={{ overflowX: "auto" }}>
|
||||||
|
{i18n("response_hook_helper")}
|
||||||
|
</Box>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
<Stack
|
<Stack
|
||||||
direction="row"
|
direction="row"
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
@@ -652,9 +713,11 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
|
|||||||
}
|
}
|
||||||
label={i18n("is_disabled")}
|
label={i18n("is_disabled")}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<ShowMoreButton showMore={showMore} onChange={setShowMore} />
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
{apiType === OPT_TRANS_CUSTOMIZE && <pre>{i18n("custom_api_help")}</pre>}
|
{/* {apiType === OPT_TRANS_CUSTOMIZE && <pre>{i18n("custom_api_help")}</pre>} */}
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import Accordion from "@mui/material/Accordion";
|
|||||||
import AccordionSummary from "@mui/material/AccordionSummary";
|
import AccordionSummary from "@mui/material/AccordionSummary";
|
||||||
import AccordionDetails from "@mui/material/AccordionDetails";
|
import AccordionDetails from "@mui/material/AccordionDetails";
|
||||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||||
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
|
|
||||||
import { useRules } from "../../hooks/Rules";
|
import { useRules } from "../../hooks/Rules";
|
||||||
import MenuItem from "@mui/material/MenuItem";
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
import Grid from "@mui/material/Grid";
|
import Grid from "@mui/material/Grid";
|
||||||
@@ -62,6 +61,7 @@ import CancelIcon from "@mui/icons-material/Cancel";
|
|||||||
import SaveIcon from "@mui/icons-material/Save";
|
import SaveIcon from "@mui/icons-material/Save";
|
||||||
import { kissLog } from "../../libs/log";
|
import { kissLog } from "../../libs/log";
|
||||||
import { useApiList } from "../../hooks/Api";
|
import { useApiList } from "../../hooks/Api";
|
||||||
|
import ShowMoreButton from "./ShowMoreButton";
|
||||||
|
|
||||||
function RuleFields({ rule, rules, setShow, setKeyword }) {
|
function RuleFields({ rule, rules, setShow, setKeyword }) {
|
||||||
const initFormValues = useMemo(
|
const initFormValues = useMemo(
|
||||||
@@ -209,30 +209,6 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
);
|
);
|
||||||
|
|
||||||
const ShowMoreButton = showMore ? (
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
variant="text"
|
|
||||||
onClick={() => {
|
|
||||||
setShowMore(false);
|
|
||||||
}}
|
|
||||||
startIcon={<ExpandLessIcon />}
|
|
||||||
>
|
|
||||||
{i18n("less")}
|
|
||||||
</Button>
|
|
||||||
) : (
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
variant="text"
|
|
||||||
onClick={() => {
|
|
||||||
setShowMore(true);
|
|
||||||
}}
|
|
||||||
startIcon={<ExpandMoreIcon />}
|
|
||||||
>
|
|
||||||
{i18n("more")}
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<Stack spacing={2}>
|
<Stack spacing={2}>
|
||||||
@@ -293,7 +269,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Grid container spacing={2} columns={12}>
|
<Grid container spacing={2} columns={12}>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
size="small"
|
size="small"
|
||||||
@@ -309,7 +285,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
<MenuItem value={"false"}>{i18n("default_disabled")}</MenuItem>
|
<MenuItem value={"false"}>{i18n("default_disabled")}</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
size="small"
|
size="small"
|
||||||
@@ -325,7 +301,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
size="small"
|
size="small"
|
||||||
@@ -341,7 +317,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
size="small"
|
size="small"
|
||||||
@@ -358,7 +334,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
size="small"
|
size="small"
|
||||||
@@ -374,7 +350,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
size="small"
|
size="small"
|
||||||
@@ -390,7 +366,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
size="small"
|
size="small"
|
||||||
@@ -406,7 +382,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
<MenuItem value={"font"}>{`<font>`}</MenuItem>
|
<MenuItem value={"font"}>{`<font>`}</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
size="small"
|
size="small"
|
||||||
@@ -423,7 +399,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
size="small"
|
size="small"
|
||||||
@@ -442,7 +418,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
))}
|
))}
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
size="small"
|
size="small"
|
||||||
@@ -461,7 +437,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
))}
|
))}
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
size="small"
|
size="small"
|
||||||
@@ -480,7 +456,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
))}
|
))}
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
{/* <Grid item xs={12} sm={6} md={6} lg={3}>
|
{/* <Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
size="small"
|
size="small"
|
||||||
@@ -500,7 +476,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
</TextField>
|
</TextField>
|
||||||
</Grid> */}
|
</Grid> */}
|
||||||
|
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
size="small"
|
size="small"
|
||||||
@@ -521,7 +497,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Grid container spacing={2} columns={12}>
|
<Grid container spacing={2} columns={12}>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
size="small"
|
size="small"
|
||||||
@@ -540,7 +516,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
))}
|
))}
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
size="small"
|
size="small"
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -714,7 +690,6 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
{i18n("delete")}
|
{i18n("delete")}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{ShowMoreButton}
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
@@ -742,9 +717,9 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
>
|
>
|
||||||
{i18n("restore_default")}
|
{i18n("restore_default")}
|
||||||
</Button>
|
</Button>
|
||||||
{ShowMoreButton}
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
<ShowMoreButton showMore={showMore} onChange={setShowMore} />
|
||||||
</Stack>
|
</Stack>
|
||||||
) : (
|
) : (
|
||||||
// 添加
|
// 添加
|
||||||
@@ -765,7 +740,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
>
|
>
|
||||||
{i18n("cancel")}
|
{i18n("cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
{ShowMoreButton}
|
<ShowMoreButton showMore={showMore} onChange={setShowMore} />
|
||||||
</Stack>
|
</Stack>
|
||||||
))}
|
))}
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -1078,7 +1053,7 @@ function SubRulesEdit({ subList, addSub, updateDataCache }) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subList.find((item) => item.url === url)) {
|
if (subList.some((item) => item.url === url)) {
|
||||||
setInputError(i18n("error_duplicate_values"));
|
setInputError(i18n("error_duplicate_values"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ export default function Settings() {
|
|||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Grid container spacing={2} columns={12}>
|
<Grid container spacing={2} columns={12}>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -166,7 +166,7 @@ export default function Settings() {
|
|||||||
))}
|
))}
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -180,7 +180,7 @@ export default function Settings() {
|
|||||||
<MenuItem value={false}>{i18n("disable")}</MenuItem>
|
<MenuItem value={false}>{i18n("disable")}</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -196,7 +196,7 @@ export default function Settings() {
|
|||||||
<MenuItem value={true}>{i18n("hide")}</MenuItem>
|
<MenuItem value={true}>{i18n("hide")}</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -210,7 +210,7 @@ export default function Settings() {
|
|||||||
<MenuItem value={1}>{i18n("fab_click_translate")}</MenuItem>
|
<MenuItem value={1}>{i18n("fab_click_translate")}</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
size="small"
|
size="small"
|
||||||
@@ -221,7 +221,7 @@ export default function Settings() {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
size="small"
|
size="small"
|
||||||
@@ -232,7 +232,7 @@ export default function Settings() {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
size="small"
|
size="small"
|
||||||
@@ -243,7 +243,7 @@ export default function Settings() {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
size="small"
|
size="small"
|
||||||
@@ -254,7 +254,7 @@ export default function Settings() {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
fullWidth
|
fullWidth
|
||||||
size="small"
|
size="small"
|
||||||
@@ -265,7 +265,7 @@ export default function Settings() {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -282,7 +282,7 @@ export default function Settings() {
|
|||||||
))}
|
))}
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -297,7 +297,7 @@ export default function Settings() {
|
|||||||
<MenuItem value={2}>{i18n("secondary_context_menus")}</MenuItem>
|
<MenuItem value={2}>{i18n("secondary_context_menus")}</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -353,25 +353,25 @@ export default function Settings() {
|
|||||||
<>
|
<>
|
||||||
<Box>
|
<Box>
|
||||||
<Grid container spacing={2} columns={12}>
|
<Grid container spacing={2} columns={12}>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<ShortcutItem
|
<ShortcutItem
|
||||||
action={OPT_SHORTCUT_TRANSLATE}
|
action={OPT_SHORTCUT_TRANSLATE}
|
||||||
label={i18n("toggle_translate_shortcut")}
|
label={i18n("toggle_translate_shortcut")}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<ShortcutItem
|
<ShortcutItem
|
||||||
action={OPT_SHORTCUT_STYLE}
|
action={OPT_SHORTCUT_STYLE}
|
||||||
label={i18n("toggle_style_shortcut")}
|
label={i18n("toggle_style_shortcut")}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<ShortcutItem
|
<ShortcutItem
|
||||||
action={OPT_SHORTCUT_POPUP}
|
action={OPT_SHORTCUT_POPUP}
|
||||||
label={i18n("toggle_popup_shortcut")}
|
label={i18n("toggle_popup_shortcut")}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} sm={6} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<ShortcutItem
|
<ShortcutItem
|
||||||
action={OPT_SHORTCUT_SETTING}
|
action={OPT_SHORTCUT_SETTING}
|
||||||
label={i18n("open_setting_shortcut")}
|
label={i18n("open_setting_shortcut")}
|
||||||
|
|||||||
35
src/views/Options/ShowMoreButton.js
Normal file
35
src/views/Options/ShowMoreButton.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||||
|
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
|
||||||
|
import Button from "@mui/material/Button";
|
||||||
|
import { useI18n } from "../../hooks/I18n";
|
||||||
|
|
||||||
|
export default function ShowMoreButton({ onChange, showMore }) {
|
||||||
|
const i18n = useI18n();
|
||||||
|
const handleClick = () => {
|
||||||
|
onChange((prev) => !prev);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (showMore) {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
variant="text"
|
||||||
|
onClick={handleClick}
|
||||||
|
startIcon={<ExpandLessIcon />}
|
||||||
|
>
|
||||||
|
{i18n("less")}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
variant="text"
|
||||||
|
onClick={handleClick}
|
||||||
|
startIcon={<ExpandMoreIcon />}
|
||||||
|
>
|
||||||
|
{i18n("more")}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user