Compare commits
93 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e1dfa35c6c | ||
|
|
73f80692d3 | ||
|
|
42c7dae495 | ||
|
|
b2a1309caa | ||
|
|
94bf5f9580 | ||
|
|
704ebdc9d7 | ||
|
|
165da4e559 | ||
|
|
d3e3b484bf | ||
|
|
192f8faa5b | ||
|
|
579d5cb0a3 | ||
|
|
07fca5b9af | ||
|
|
866a63ab6c | ||
|
|
97b4935bc4 | ||
|
|
30129abef3 | ||
|
|
24d904b32c | ||
|
|
5f0ce57ead | ||
|
|
51f58d095a | ||
|
|
d22e3838c4 | ||
|
|
adbb421b7b | ||
|
|
eaa47af269 | ||
|
|
a6cb5544f8 | ||
|
|
9e91faa660 | ||
|
|
8636fadc72 | ||
|
|
0621957592 | ||
|
|
8ec06b0c84 | ||
|
|
d47f8d7ee9 | ||
|
|
24f8959525 | ||
|
|
983740578b | ||
|
|
b5f79ed7cd | ||
|
|
bbb0e79d4e | ||
|
|
471dc05897 | ||
|
|
7a772d2459 | ||
|
|
1d92421960 | ||
|
|
aeaaf429d7 | ||
|
|
84432e98ae | ||
|
|
77c6102de7 | ||
|
|
ab5dd82169 | ||
|
|
23e7b69dc5 | ||
|
|
3dc8f393f2 | ||
|
|
8a2144f263 | ||
|
|
c1c59caa10 | ||
|
|
d27ebd90b6 | ||
|
|
467745c1e9 | ||
|
|
537378a038 | ||
|
|
4b5ed30e5b | ||
|
|
52b7f6a225 | ||
|
|
f31675d8a2 | ||
|
|
dd46a8450c | ||
|
|
b0843f7d66 | ||
|
|
daadc0195c | ||
|
|
298dec6957 | ||
|
|
bf39d85dfa | ||
|
|
30a9de25a8 | ||
|
|
af1ecf0bd4 | ||
|
|
fe55a2cd3c | ||
|
|
5a33d4e57e | ||
|
|
7f46a9023c | ||
|
|
dfd943b621 | ||
|
|
7007d0d922 | ||
|
|
601678500d | ||
|
|
9bfb504381 | ||
|
|
8a03b0cf15 | ||
|
|
11ba89de0a | ||
|
|
bac7f62eea | ||
|
|
eef90ea02b | ||
|
|
0650df534a | ||
|
|
9ef8c8b823 | ||
|
|
d7e08da0b2 | ||
|
|
ef361e0798 | ||
|
|
6855332092 | ||
|
|
121d523e02 | ||
|
|
42a375c4c7 | ||
|
|
a1dd705d97 | ||
|
|
71f90b36ca | ||
|
|
37facdc3c1 | ||
|
|
66b4f547ff | ||
|
|
d27b9c7f2d | ||
|
|
278ff9c6bc | ||
|
|
d6fe1ce9d7 | ||
|
|
0bfa5256b8 | ||
|
|
72ccfc8aec | ||
|
|
d117c5dc10 | ||
|
|
9312783f44 | ||
|
|
e5b16ebfd3 | ||
|
|
5d1d65c2d3 | ||
|
|
9ca1309cec | ||
|
|
a03afc05f5 | ||
|
|
0198963584 | ||
|
|
58e745d967 | ||
|
|
377e347d68 | ||
|
|
bac0704d3d | ||
|
|
d2ff46edf6 | ||
|
|
f908372b4e |
2
.env
2
.env
@@ -2,7 +2,7 @@ GENERATE_SOURCEMAP=false
|
|||||||
|
|
||||||
REACT_APP_NAME=KISS Translator
|
REACT_APP_NAME=KISS Translator
|
||||||
REACT_APP_NAME_CN=简约翻译
|
REACT_APP_NAME_CN=简约翻译
|
||||||
REACT_APP_VERSION=1.8.9
|
REACT_APP_VERSION=1.9.0
|
||||||
|
|
||||||
REACT_APP_HOMEPAGE=https://github.com/fishjar/kiss-translator
|
REACT_APP_HOMEPAGE=https://github.com/fishjar/kiss-translator
|
||||||
|
|
||||||
|
|||||||
29
.github/workflows/release.yml
vendored
29
.github/workflows/release.yml
vendored
@@ -7,28 +7,28 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: pnpm/action-setup@v2
|
- uses: pnpm/action-setup@v4
|
||||||
with:
|
with:
|
||||||
version: 8.7.6
|
version: latest
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: "18.17.0"
|
node-version: latest
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
- run: pnpm install
|
- run: pnpm install
|
||||||
- run: pnpm build
|
- run: pnpm build
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: build-artifacts
|
name: build-artifacts
|
||||||
path: build
|
path: build
|
||||||
deploy-web:
|
deploy-web:
|
||||||
needs: build
|
needs: build
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/download-artifact@v3
|
- uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: build-artifacts
|
name: build-artifacts
|
||||||
path: build
|
path: build
|
||||||
@@ -37,7 +37,8 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
folder: build/web
|
folder: build/web
|
||||||
create-release:
|
create-release:
|
||||||
runs-on: ubuntu-22.04
|
needs: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
outputs:
|
||||||
upload_url: ${{ steps.create-release.outputs.upload_url }}
|
upload_url: ${{ steps.create-release.outputs.upload_url }}
|
||||||
steps:
|
steps:
|
||||||
@@ -55,10 +56,10 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
client: ["chrome", "edge", "firefox", "userscript"]
|
client: ["chrome", "edge", "firefox", "userscript"]
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/download-artifact@v3
|
- uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: build-artifacts
|
name: build-artifacts
|
||||||
path: build
|
path: build
|
||||||
|
|||||||
4
.prettierignore
Normal file
4
.prettierignore
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
node_modules
|
||||||
|
build
|
||||||
|
public
|
||||||
|
package.json
|
||||||
24
.prettierrc
Normal file
24
.prettierrc
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"arrowParens": "always",
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"endOfLine": "lf",
|
||||||
|
"htmlWhitespaceSensitivity": "css",
|
||||||
|
"insertPragma": false,
|
||||||
|
"singleAttributePerLine": false,
|
||||||
|
"bracketSameLine": false,
|
||||||
|
"jsxBracketSameLine": false,
|
||||||
|
"jsxSingleQuote": false,
|
||||||
|
"printWidth": 80,
|
||||||
|
"proseWrap": "preserve",
|
||||||
|
"quoteProps": "as-needed",
|
||||||
|
"requirePragma": false,
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": false,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"useTabs": false,
|
||||||
|
"embeddedLanguageFormatting": "auto",
|
||||||
|
"vueIndentScriptAndStyle": false,
|
||||||
|
"experimentalTernaries": false,
|
||||||
|
"parser": "babel"
|
||||||
|
}
|
||||||
@@ -92,6 +92,7 @@ const userscriptWebpack = (config, env) => {
|
|||||||
// @grant GM.info
|
// @grant GM.info
|
||||||
// @grant unsafeWindow
|
// @grant unsafeWindow
|
||||||
// @connect translate.googleapis.com
|
// @connect translate.googleapis.com
|
||||||
|
// @connect translate-pa.googleapis.com
|
||||||
// @connect api-edge.cognitive.microsofttranslator.com
|
// @connect api-edge.cognitive.microsofttranslator.com
|
||||||
// @connect edge.microsoft.com
|
// @connect edge.microsoft.com
|
||||||
// @connect api-free.deepl.com
|
// @connect api-free.deepl.com
|
||||||
@@ -108,12 +109,10 @@ const userscriptWebpack = (config, env) => {
|
|||||||
// @connect dav.jianguoyun.com
|
// @connect dav.jianguoyun.com
|
||||||
// @connect fanyi.baidu.com
|
// @connect fanyi.baidu.com
|
||||||
// @connect transmart.qq.com
|
// @connect transmart.qq.com
|
||||||
// @connect localhost:3000
|
// @connect niutrans.com
|
||||||
// @connect 127.0.0.1:3000
|
// @connect translate.volcengine.com
|
||||||
// @connect localhost:1188
|
// @connect localhost
|
||||||
// @connect 127.0.0.1:1188
|
// @connect 127.0.0.1
|
||||||
// @connect localhost:11434
|
|
||||||
// @connect 127.0.0.1:11434
|
|
||||||
// @run-at document-end
|
// @run-at document-end
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
|
|
||||||
|
|||||||
13
package.json
13
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "kiss-translator",
|
"name": "kiss-translator",
|
||||||
"description": "A minimalist bilingual translation Extension & Greasemonkey Script",
|
"description": "A minimalist bilingual translation Extension & Greasemonkey Script",
|
||||||
"version": "1.8.9",
|
"version": "1.9.0",
|
||||||
"author": "Gabe<yugang2002@gmail.com>",
|
"author": "Gabe<yugang2002@gmail.com>",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
"react-markdown": "^8.0.7",
|
"react-markdown": "^8.0.7",
|
||||||
"react-router-dom": "^6.16.0",
|
"react-router-dom": "^6.16.0",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
|
"sval": "^0.5.2",
|
||||||
"webdav": "^5.3.0",
|
"webdav": "^5.3.0",
|
||||||
"webextension-polyfill": "^0.10.0"
|
"webextension-polyfill": "^0.10.0"
|
||||||
},
|
},
|
||||||
@@ -25,13 +26,15 @@
|
|||||||
"start:userscript": "REACT_APP_CLIENT=userscript react-app-rewired start",
|
"start:userscript": "REACT_APP_CLIENT=userscript react-app-rewired start",
|
||||||
"build:chrome": "rm -rf build/chrome && BUILD_PATH=./build/chrome REACT_APP_CLIENT=chrome react-app-rewired build && rm build/chrome/content.html",
|
"build:chrome": "rm -rf build/chrome && BUILD_PATH=./build/chrome REACT_APP_CLIENT=chrome react-app-rewired build && rm build/chrome/content.html",
|
||||||
"build:edge": "rm -rf build/edge && cp -r build/chrome build/edge",
|
"build:edge": "rm -rf build/edge && cp -r build/chrome build/edge",
|
||||||
|
"build:thunderbird": "rm -rf build/thunderbird && BUILD_PATH=./build/thunderbird REACT_APP_CLIENT=thunderbird react-app-rewired build && rm build/thunderbird/content.html && cp ./build/thunderbird/manifest.thunderbird.json ./build/thunderbird/manifest.json && rm build/*/manifest.thunderbird.json",
|
||||||
"build:firefox": "rm -rf build/firefox && cp -r build/chrome build/firefox && cat ./build/firefox/manifest.firefox.json > ./build/firefox/manifest.json && rm build/*/manifest.firefox.json",
|
"build:firefox": "rm -rf build/firefox && cp -r build/chrome build/firefox && cat ./build/firefox/manifest.firefox.json > ./build/firefox/manifest.json && rm build/*/manifest.firefox.json",
|
||||||
"build:web": "rm -rf build/web && BUILD_PATH=./build/web REACT_APP_CLIENT=userscript react-app-rewired build",
|
"build:web": "rm -rf build/web && BUILD_PATH=./build/web REACT_APP_CLIENT=userscript react-app-rewired build",
|
||||||
"build:userscript-ios": "file1=build/web/kiss-translator.user.js file2=build/web/kiss-translator-ios-safari.user.js && cp $file1 $file2 && sed -i 's|// @grant unsafeWindow|// @inject-into content|g' $file2",
|
"build:userscript-ios": "file1=build/web/kiss-translator.user.js file2=build/web/kiss-translator-ios-safari.user.js && cp $file1 $file2 && sed -i 's|// @grant unsafeWindow|// @inject-into content|g' $file2",
|
||||||
"build:userscript": "rm -rf build/userscript && mkdir build/userscript && cp build/web/*.user.js build/userscript/",
|
"build:userscript": "rm -rf build/userscript && mkdir build/userscript && cp build/web/*.user.js build/userscript/",
|
||||||
"build:rules": "babel-node src/rules.js",
|
"build:rules": "babel-node src/rules.js",
|
||||||
"build": "pnpm build:chrome && pnpm build:edge && pnpm build:firefox && pnpm build:web && pnpm build:userscript-ios && pnpm build:userscript && pnpm build:rules",
|
"build": "pnpm format && pnpm build:chrome && pnpm build:edge && pnpm build:thunderbird && pnpm build:firefox && pnpm build:web && pnpm build:userscript-ios && pnpm build:userscript && pnpm build:rules",
|
||||||
"pack": "cd build && zip -r chrome.zip chrome && zip -r edge.zip edge && cd firefox && zip -r ../firefox.zip .",
|
"zip": "cd build && zip -r chrome.zip chrome && zip -r edge.zip edge && (cd firefox && zip -r ../firefox.zip .) && (cd thunderbird && zip -r ../thunderbird.zip .)",
|
||||||
|
"format": "prettier --write \"**/*.{js,json,html}\"",
|
||||||
"test": "react-app-rewired test",
|
"test": "react-app-rewired test",
|
||||||
"eject": "react-scripts eject"
|
"eject": "react-scripts eject"
|
||||||
},
|
},
|
||||||
@@ -43,7 +46,8 @@
|
|||||||
"globals": {
|
"globals": {
|
||||||
"GM": true,
|
"GM": true,
|
||||||
"unsafeWindow": true,
|
"unsafeWindow": true,
|
||||||
"globalThis": true
|
"globalThis": true,
|
||||||
|
"messenger": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
@@ -63,6 +67,7 @@
|
|||||||
"@babel/node": "^7.22.19",
|
"@babel/node": "^7.22.19",
|
||||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||||
"@babel/preset-env": "^7.22.20",
|
"@babel/preset-env": "^7.22.20",
|
||||||
|
"prettier": "3.6.2",
|
||||||
"react-app-rewired": "^2.2.1"
|
"react-app-rewired": "^2.2.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12138
pnpm-lock.yaml
generated
12138
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
// (() => {
|
// (() => {
|
||||||
// var shadow = document.querySelector("#shadow1");
|
// var shadow = document.querySelector("#shadow1");
|
||||||
// var root = shadow.attachShadow({ mode: "open" });
|
// var root = shadow.attachShadow({ mode: "open" });
|
||||||
@@ -54,8 +54,8 @@
|
|||||||
// }, 1000);
|
// }, 1000);
|
||||||
|
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
var el = document.querySelector("h2>p>span");
|
var el = document.querySelector('h2>p>span');
|
||||||
el.innerText = "hello world";
|
el.innerText = 'hello world';
|
||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@@ -105,28 +105,26 @@
|
|||||||
<br />
|
<br />
|
||||||
<div id="content">
|
<div id="content">
|
||||||
<p>You need to enable JavaScript to run <span>this app.</span></p>
|
<p>You need to enable JavaScript to run <span>this app.</span></p>
|
||||||
The <span>embargo</span> has just lifted to confirm that AmpereOne is
|
The <span>embargo</span> has just lifted to confirm that AmpereOne is coming to
|
||||||
coming to Google Cloud with the C3A instances.
|
Google Cloud with the C3A instances.
|
||||||
<br />
|
<br />
|
||||||
But these upcoming instances for now are only in private preview form.
|
But these upcoming instances for now are only in private preview form.
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
Needless to say I also haven't had any AmpereOne access to check out the
|
Needless to say I also haven't had any AmpereOne access to check out the
|
||||||
performance and power efficiency of these new Arm server processors from
|
performance and power efficiency of these new Arm server processors from Ampere
|
||||||
Ampere Computing.
|
Computing.
|
||||||
<br />
|
<br />
|
||||||
</div>
|
</div>
|
||||||
<h2>
|
<h2>
|
||||||
<p>
|
<p>
|
||||||
<span
|
<span>React is a JavaScript library for building user interfaces.</span>
|
||||||
>React is a JavaScript library for building user interfaces.</span
|
|
||||||
>
|
|
||||||
</p>
|
</p>
|
||||||
</h2>
|
</h2>
|
||||||
<hr />
|
<hr />
|
||||||
<input id="input1" style="width: 80%;" />
|
<input id="input1" style="width: 80%" />
|
||||||
<hr />
|
<hr />
|
||||||
<textarea id="textarea1" style="width: 80%;">test</textarea>
|
<textarea id="textarea1" style="width: 80%">test</textarea>
|
||||||
<hr />
|
<hr />
|
||||||
<div id="addtitle"></div>
|
<div id="addtitle"></div>
|
||||||
<h2>Shadow 1</h2>
|
<h2>Shadow 1</h2>
|
||||||
@@ -166,15 +164,47 @@
|
|||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<h2>
|
<h2>
|
||||||
React Server Components (or RSC) is a new application architecture
|
React Server Components (or RSC) is a new application architecture designed by the
|
||||||
designed by the React team.
|
React team.
|
||||||
</h2>
|
</h2>
|
||||||
<iframe
|
<iframe
|
||||||
id="iframe1"
|
id="iframe1"
|
||||||
width="800px"
|
width="800px"
|
||||||
height="600px"
|
height="600px"
|
||||||
src="http://localhost:3000/index.html"
|
src="http://localhost:3000/index.html"></iframe>
|
||||||
></iframe>
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<h2>We’ve first shared our research on RSC in an introductory talk and an RFC.</h2>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
@@ -208,52 +238,10 @@
|
|||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<h2>
|
<h2>
|
||||||
We’ve first shared our research on RSC in an introductory talk and an
|
To recap them, we are introducing a new kind of component—Server Components—that
|
||||||
RFC.
|
run ahead of time and are excluded from your JavaScript bundle.
|
||||||
</h2>
|
</h2>
|
||||||
<br />
|
<iframe id="iframe2" width="800px" height="600px" src="https://react.dev/"></iframe>
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<h2>
|
|
||||||
To recap them, we are introducing a new kind of component—Server
|
|
||||||
Components—that run ahead of time and are excluded from your JavaScript
|
|
||||||
bundle.
|
|
||||||
</h2>
|
|
||||||
<iframe
|
|
||||||
id="iframe2"
|
|
||||||
width="800px"
|
|
||||||
height="600px"
|
|
||||||
src="https://react.dev/"
|
|
||||||
></iframe>
|
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
@@ -288,15 +276,14 @@
|
|||||||
<br />
|
<br />
|
||||||
<div class="cont cont1">
|
<div class="cont cont1">
|
||||||
<h2>
|
<h2>
|
||||||
Server Components can run during the build, letting you read from the
|
Server Components can run during the build, letting you read from the filesystem
|
||||||
filesystem or fetch static content.
|
or fetch static content.
|
||||||
</h2>
|
</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
They can also run on the server, letting you access your data layer
|
They can also run on the server, letting you access your data layer without
|
||||||
without having to build an API. You can pass data by props from
|
having to build an API. You can pass data by props from Server Components to
|
||||||
Server Components to the interactive Client Components in the
|
the interactive Client Components in the browser.
|
||||||
browser.
|
|
||||||
</li>
|
</li>
|
||||||
<li>以声明式编写 UI,可以让你的代码更加可靠,且方便调试。</li>
|
<li>以声明式编写 UI,可以让你的代码更加可靠,且方便调试。</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -315,14 +302,14 @@
|
|||||||
<br />
|
<br />
|
||||||
<div class="cont cont2">
|
<div class="cont cont2">
|
||||||
<h2>
|
<h2>
|
||||||
Since our last update, we have merged the React Server Components RFC
|
Since our last update, we have merged the React Server Components RFC to ratify
|
||||||
to ratify the proposal.
|
the proposal.
|
||||||
</h2>
|
</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
RSC combines the simple “request/response” mental model of
|
RSC combines the simple “request/response” mental model of server-centric
|
||||||
server-centric Multi-Page Apps with the seamless interactivity of
|
Multi-Page Apps with the seamless interactivity of client-centric Single-Page
|
||||||
client-centric Single-Page Apps, giving you the best of both worlds.
|
Apps, giving you the best of both worlds.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
React 使创建交互式 UI
|
React 使创建交互式 UI
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"name": "__MSG_app_name__",
|
"name": "__MSG_app_name__",
|
||||||
"description": "__MSG_app_description__",
|
"description": "__MSG_app_description__",
|
||||||
"version": "1.8.9",
|
"version": "1.9.0",
|
||||||
"default_locale": "en",
|
"default_locale": "en",
|
||||||
"author": "Gabe<yugang2002@gmail.com>",
|
"author": "Gabe<yugang2002@gmail.com>",
|
||||||
"homepage_url": "https://github.com/fishjar/kiss-translator",
|
"homepage_url": "https://github.com/fishjar/kiss-translator",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"manifest_version": 3,
|
"manifest_version": 3,
|
||||||
"name": "__MSG_app_name__",
|
"name": "__MSG_app_name__",
|
||||||
"description": "__MSG_app_description__",
|
"description": "__MSG_app_description__",
|
||||||
"version": "1.8.9",
|
"version": "1.9.0",
|
||||||
"default_locale": "en",
|
"default_locale": "en",
|
||||||
"author": "Gabe<yugang2002@gmail.com>",
|
"author": "Gabe<yugang2002@gmail.com>",
|
||||||
"homepage_url": "https://github.com/fishjar/kiss-translator",
|
"homepage_url": "https://github.com/fishjar/kiss-translator",
|
||||||
@@ -45,12 +45,7 @@
|
|||||||
"description": "__MSG_open_options__"
|
"description": "__MSG_open_options__"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"permissions": [
|
"permissions": ["storage", "contextMenus", "scripting", "declarativeNetRequest"],
|
||||||
"storage",
|
|
||||||
"contextMenus",
|
|
||||||
"scripting",
|
|
||||||
"declarativeNetRequest"
|
|
||||||
],
|
|
||||||
"host_permissions": ["<all_urls>"],
|
"host_permissions": ["<all_urls>"],
|
||||||
"icons": {
|
"icons": {
|
||||||
"16": "images/logo16.png",
|
"16": "images/logo16.png",
|
||||||
|
|||||||
78
public/manifest.thunderbird.json
Normal file
78
public/manifest.thunderbird.json
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
{
|
||||||
|
"manifest_version": 2,
|
||||||
|
"name": "__MSG_app_name__",
|
||||||
|
"description": "__MSG_app_description__",
|
||||||
|
"version": "1.9.0",
|
||||||
|
"default_locale": "en",
|
||||||
|
"author": "Gabe<yugang2002@gmail.com>",
|
||||||
|
"homepage_url": "https://github.com/fishjar/kiss-translator",
|
||||||
|
"browser_specific_settings": {
|
||||||
|
"gecko": {
|
||||||
|
"id": "yugang2002@gmail.com",
|
||||||
|
"strict_min_version": "78.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"background": {
|
||||||
|
"scripts": ["background.js"]
|
||||||
|
},
|
||||||
|
"content_scripts": [
|
||||||
|
{
|
||||||
|
"js": ["content.js"],
|
||||||
|
"matches": ["<all_urls>"],
|
||||||
|
"all_frames": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"commands": {
|
||||||
|
"_execute_browser_action": {
|
||||||
|
"suggested_key": {
|
||||||
|
"default": "Alt+K"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"toggleTranslate": {
|
||||||
|
"suggested_key": {
|
||||||
|
"default": "Alt+Q"
|
||||||
|
},
|
||||||
|
"description": "__MSG_toggle_translate__"
|
||||||
|
},
|
||||||
|
"openTranbox": {
|
||||||
|
"suggested_key": {
|
||||||
|
"default": "Alt+S"
|
||||||
|
},
|
||||||
|
"description": "__MSG_open_tranbox__"
|
||||||
|
},
|
||||||
|
"toggleStyle": {
|
||||||
|
"suggested_key": {
|
||||||
|
"default": "Alt+C"
|
||||||
|
},
|
||||||
|
"description": "__MSG_toggle_style__"
|
||||||
|
},
|
||||||
|
"openOptions": {
|
||||||
|
"description": "__MSG_open_options__"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"permissions": [
|
||||||
|
"<all_urls>",
|
||||||
|
"storage",
|
||||||
|
"menus",
|
||||||
|
"messagesModify",
|
||||||
|
"scripting",
|
||||||
|
"declarativeNetRequest"
|
||||||
|
],
|
||||||
|
"icons": {
|
||||||
|
"16": "images/logo16.png",
|
||||||
|
"32": "images/logo32.png",
|
||||||
|
"48": "images/logo48.png",
|
||||||
|
"128": "images/logo128.png"
|
||||||
|
},
|
||||||
|
"browser_action": {
|
||||||
|
"default_icon": {
|
||||||
|
"128": "images/logo128.png"
|
||||||
|
},
|
||||||
|
"default_title": "__MSG_app_name__",
|
||||||
|
"default_popup": "popup.html"
|
||||||
|
},
|
||||||
|
"options_ui": {
|
||||||
|
"page": "options.html",
|
||||||
|
"open_in_tab": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ import queryString from "query-string";
|
|||||||
import { fetchData } from "../libs/fetch";
|
import { fetchData } from "../libs/fetch";
|
||||||
import {
|
import {
|
||||||
OPT_TRANS_GOOGLE,
|
OPT_TRANS_GOOGLE,
|
||||||
|
OPT_TRANS_GOOGLE_2,
|
||||||
OPT_TRANS_MICROSOFT,
|
OPT_TRANS_MICROSOFT,
|
||||||
OPT_TRANS_DEEPL,
|
OPT_TRANS_DEEPL,
|
||||||
OPT_TRANS_DEEPLFREE,
|
OPT_TRANS_DEEPLFREE,
|
||||||
@@ -9,10 +10,13 @@ import {
|
|||||||
OPT_TRANS_NIUTRANS,
|
OPT_TRANS_NIUTRANS,
|
||||||
OPT_TRANS_BAIDU,
|
OPT_TRANS_BAIDU,
|
||||||
OPT_TRANS_TENCENT,
|
OPT_TRANS_TENCENT,
|
||||||
|
OPT_TRANS_VOLCENGINE,
|
||||||
OPT_TRANS_OPENAI,
|
OPT_TRANS_OPENAI,
|
||||||
OPT_TRANS_OPENAI_2,
|
OPT_TRANS_OPENAI_2,
|
||||||
OPT_TRANS_OPENAI_3,
|
OPT_TRANS_OPENAI_3,
|
||||||
OPT_TRANS_GEMINI,
|
OPT_TRANS_GEMINI,
|
||||||
|
OPT_TRANS_GEMINI_2,
|
||||||
|
OPT_TRANS_CLAUDE,
|
||||||
OPT_TRANS_CLOUDFLAREAI,
|
OPT_TRANS_CLOUDFLAREAI,
|
||||||
OPT_TRANS_OLLAMA,
|
OPT_TRANS_OLLAMA,
|
||||||
OPT_TRANS_OLLAMA_2,
|
OPT_TRANS_OLLAMA_2,
|
||||||
@@ -24,6 +28,8 @@ import {
|
|||||||
OPT_TRANS_CUSTOMIZE_5,
|
OPT_TRANS_CUSTOMIZE_5,
|
||||||
URL_CACHE_TRAN,
|
URL_CACHE_TRAN,
|
||||||
KV_SALT_SYNC,
|
KV_SALT_SYNC,
|
||||||
|
URL_GOOGLE_TRAN,
|
||||||
|
URL_MICROSOFT_LANGDETECT,
|
||||||
URL_BAIDU_LANGDETECT,
|
URL_BAIDU_LANGDETECT,
|
||||||
URL_BAIDU_SUGGEST,
|
URL_BAIDU_SUGGEST,
|
||||||
URL_BAIDU_TTS,
|
URL_BAIDU_TTS,
|
||||||
@@ -31,8 +37,12 @@ import {
|
|||||||
URL_TENCENT_TRANSMART,
|
URL_TENCENT_TRANSMART,
|
||||||
OPT_LANGS_TENCENT,
|
OPT_LANGS_TENCENT,
|
||||||
OPT_LANGS_SPECIAL,
|
OPT_LANGS_SPECIAL,
|
||||||
|
OPT_LANGS_MICROSOFT,
|
||||||
} from "../config";
|
} from "../config";
|
||||||
import { sha256 } from "../libs/utils";
|
import { sha256 } from "../libs/utils";
|
||||||
|
import interpreter from "../libs/interpreter";
|
||||||
|
import { msAuth } from "../libs/auth";
|
||||||
|
import { kissLog } from "../libs/log";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步数据
|
* 同步数据
|
||||||
@@ -58,6 +68,52 @@ export const apiSyncData = async (url, key, data) =>
|
|||||||
*/
|
*/
|
||||||
export const apiFetch = (url) => fetchData(url);
|
export const apiFetch = (url) => fetchData(url);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Google语言识别
|
||||||
|
* @param {*} text
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const apiGoogleLangdetect = async (text) => {
|
||||||
|
const params = {
|
||||||
|
client: "gtx",
|
||||||
|
dt: "t",
|
||||||
|
dj: 1,
|
||||||
|
ie: "UTF-8",
|
||||||
|
sl: "auto",
|
||||||
|
tl: "zh-CN",
|
||||||
|
q: text,
|
||||||
|
};
|
||||||
|
const input = `${URL_GOOGLE_TRAN}?${queryString.stringify(params)}`;
|
||||||
|
const res = await fetchData(input, {
|
||||||
|
headers: {
|
||||||
|
"Content-type": "application/json",
|
||||||
|
},
|
||||||
|
useCache: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.src;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Microsoft语言识别
|
||||||
|
* @param {*} text
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const apiMicrosoftLangdetect = async (text) => {
|
||||||
|
const [token] = await msAuth();
|
||||||
|
const res = await fetchData(URL_MICROSOFT_LANGDETECT, {
|
||||||
|
headers: {
|
||||||
|
"Content-type": "application/json",
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify([{ Text: text }]),
|
||||||
|
useCache: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return OPT_LANGS_MICROSOFT.get(res[0].language) ?? res[0].language;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 百度语言识别
|
* 百度语言识别
|
||||||
* @param {*} text
|
* @param {*} text
|
||||||
@@ -171,7 +227,7 @@ export const apiTranslate = async ({
|
|||||||
OPT_LANGS_SPECIAL[translator].get("auto");
|
OPT_LANGS_SPECIAL[translator].get("auto");
|
||||||
const to = OPT_LANGS_SPECIAL[translator].get(toLang);
|
const to = OPT_LANGS_SPECIAL[translator].get(toLang);
|
||||||
if (!to) {
|
if (!to) {
|
||||||
console.log(`[trans] target lang: ${toLang} not support`);
|
kissLog(`target lang: ${toLang} not support`, "translate");
|
||||||
return [trText, isSame];
|
return [trText, isSame];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,6 +263,10 @@ export const apiTranslate = async ({
|
|||||||
trText = res.sentences.map((item) => item.trans).join(" ");
|
trText = res.sentences.map((item) => item.trans).join(" ");
|
||||||
isSame = to === res.src;
|
isSame = to === res.src;
|
||||||
break;
|
break;
|
||||||
|
case OPT_TRANS_GOOGLE_2:
|
||||||
|
trText = res?.[0]?.[0] || "";
|
||||||
|
isSame = to === res.src;
|
||||||
|
break;
|
||||||
case OPT_TRANS_MICROSOFT:
|
case OPT_TRANS_MICROSOFT:
|
||||||
trText = res
|
trText = res
|
||||||
.map((item) => item.translations.map((item) => item.text).join(" "))
|
.map((item) => item.translations.map((item) => item.text).join(" "))
|
||||||
@@ -245,12 +305,17 @@ export const apiTranslate = async ({
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OPT_TRANS_TENCENT:
|
case OPT_TRANS_TENCENT:
|
||||||
trText = res.auto_translation;
|
trText = res?.auto_translation?.[0];
|
||||||
isSame = text === trText;
|
isSame = text === trText;
|
||||||
break;
|
break;
|
||||||
|
case OPT_TRANS_VOLCENGINE:
|
||||||
|
trText = res?.translation || "";
|
||||||
|
isSame = to === res?.detected_language;
|
||||||
|
break;
|
||||||
case OPT_TRANS_OPENAI:
|
case OPT_TRANS_OPENAI:
|
||||||
case OPT_TRANS_OPENAI_2:
|
case OPT_TRANS_OPENAI_2:
|
||||||
case OPT_TRANS_OPENAI_3:
|
case OPT_TRANS_OPENAI_3:
|
||||||
|
case OPT_TRANS_GEMINI_2:
|
||||||
trText = res?.choices?.map((item) => item.message.content).join(" ");
|
trText = res?.choices?.map((item) => item.message.content).join(" ");
|
||||||
isSame = text === trText;
|
isSame = text === trText;
|
||||||
break;
|
break;
|
||||||
@@ -260,6 +325,10 @@ export const apiTranslate = async ({
|
|||||||
.join(" ");
|
.join(" ");
|
||||||
isSame = text === trText;
|
isSame = text === trText;
|
||||||
break;
|
break;
|
||||||
|
case OPT_TRANS_CLAUDE:
|
||||||
|
trText = res?.content?.map((item) => item.text).join(" ");
|
||||||
|
isSame = text === trText;
|
||||||
|
break;
|
||||||
case OPT_TRANS_CLOUDFLAREAI:
|
case OPT_TRANS_CLOUDFLAREAI:
|
||||||
trText = res?.result?.translated_text;
|
trText = res?.result?.translated_text;
|
||||||
isSame = text === trText;
|
isSame = text === trText;
|
||||||
@@ -267,7 +336,13 @@ export const apiTranslate = async ({
|
|||||||
case OPT_TRANS_OLLAMA:
|
case OPT_TRANS_OLLAMA:
|
||||||
case OPT_TRANS_OLLAMA_2:
|
case OPT_TRANS_OLLAMA_2:
|
||||||
case OPT_TRANS_OLLAMA_3:
|
case OPT_TRANS_OLLAMA_3:
|
||||||
trText = res?.response;
|
const { thinkIgnore = "" } = apiSetting;
|
||||||
|
const deepModels = thinkIgnore.split(",").filter((model) => model.trim());
|
||||||
|
if (deepModels.some((model) => res?.model?.startsWith(model))) {
|
||||||
|
trText = res?.response.replace(/<think>[\s\S]*<\/think>/i, "");
|
||||||
|
} else {
|
||||||
|
trText = res?.response;
|
||||||
|
}
|
||||||
isSame = text === trText;
|
isSame = text === trText;
|
||||||
break;
|
break;
|
||||||
case OPT_TRANS_CUSTOMIZE:
|
case OPT_TRANS_CUSTOMIZE:
|
||||||
@@ -275,27 +350,14 @@ export const apiTranslate = async ({
|
|||||||
case OPT_TRANS_CUSTOMIZE_3:
|
case OPT_TRANS_CUSTOMIZE_3:
|
||||||
case OPT_TRANS_CUSTOMIZE_4:
|
case OPT_TRANS_CUSTOMIZE_4:
|
||||||
case OPT_TRANS_CUSTOMIZE_5:
|
case OPT_TRANS_CUSTOMIZE_5:
|
||||||
trText = res.text;
|
const { resHook } = apiSetting;
|
||||||
isSame = to === res.from;
|
if (resHook?.trim()) {
|
||||||
|
interpreter.run(`exports.resHook = ${resHook}`);
|
||||||
const { customOption } = apiSetting;
|
[trText, isSame] = interpreter.exports.resHook(res, text, from, to);
|
||||||
if (customOption?.trim()) {
|
} else {
|
||||||
try {
|
trText = res.text;
|
||||||
const opt = JSON.parse(customOption);
|
isSame = to === res.from;
|
||||||
const textPattern = opt.resPattern?.text;
|
|
||||||
const fromPattern = opt.resPattern?.from;
|
|
||||||
if (textPattern) {
|
|
||||||
trText = textPattern.split(".").reduce((pre, cur) => pre[cur], res);
|
|
||||||
}
|
|
||||||
if (fromPattern) {
|
|
||||||
isSame =
|
|
||||||
to === fromPattern.split(".").reduce((pre, cur) => pre[cur], res);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
throw new Error(`custom option parse err: ${err}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import {
|
import {
|
||||||
OPT_TRANS_GOOGLE,
|
OPT_TRANS_GOOGLE,
|
||||||
|
OPT_TRANS_GOOGLE_2,
|
||||||
OPT_TRANS_MICROSOFT,
|
OPT_TRANS_MICROSOFT,
|
||||||
OPT_TRANS_DEEPL,
|
OPT_TRANS_DEEPL,
|
||||||
OPT_TRANS_DEEPLFREE,
|
OPT_TRANS_DEEPLFREE,
|
||||||
@@ -8,10 +9,13 @@ import {
|
|||||||
OPT_TRANS_NIUTRANS,
|
OPT_TRANS_NIUTRANS,
|
||||||
OPT_TRANS_BAIDU,
|
OPT_TRANS_BAIDU,
|
||||||
OPT_TRANS_TENCENT,
|
OPT_TRANS_TENCENT,
|
||||||
|
OPT_TRANS_VOLCENGINE,
|
||||||
OPT_TRANS_OPENAI,
|
OPT_TRANS_OPENAI,
|
||||||
OPT_TRANS_OPENAI_2,
|
OPT_TRANS_OPENAI_2,
|
||||||
OPT_TRANS_OPENAI_3,
|
OPT_TRANS_OPENAI_3,
|
||||||
OPT_TRANS_GEMINI,
|
OPT_TRANS_GEMINI,
|
||||||
|
OPT_TRANS_GEMINI_2,
|
||||||
|
OPT_TRANS_CLAUDE,
|
||||||
OPT_TRANS_CLOUDFLAREAI,
|
OPT_TRANS_CLOUDFLAREAI,
|
||||||
OPT_TRANS_OLLAMA,
|
OPT_TRANS_OLLAMA,
|
||||||
OPT_TRANS_OLLAMA_2,
|
OPT_TRANS_OLLAMA_2,
|
||||||
@@ -23,15 +27,18 @@ import {
|
|||||||
OPT_TRANS_CUSTOMIZE_5,
|
OPT_TRANS_CUSTOMIZE_5,
|
||||||
URL_MICROSOFT_TRAN,
|
URL_MICROSOFT_TRAN,
|
||||||
URL_TENCENT_TRANSMART,
|
URL_TENCENT_TRANSMART,
|
||||||
|
URL_VOLCENGINE_TRAN,
|
||||||
INPUT_PLACE_URL,
|
INPUT_PLACE_URL,
|
||||||
INPUT_PLACE_FROM,
|
INPUT_PLACE_FROM,
|
||||||
INPUT_PLACE_TO,
|
INPUT_PLACE_TO,
|
||||||
INPUT_PLACE_TEXT,
|
INPUT_PLACE_TEXT,
|
||||||
INPUT_PLACE_KEY,
|
INPUT_PLACE_KEY,
|
||||||
|
INPUT_PLACE_MODEL,
|
||||||
} from "../config";
|
} from "../config";
|
||||||
import { msAuth } from "../libs/auth";
|
import { msAuth } from "../libs/auth";
|
||||||
import { genDeeplFree } from "./deepl";
|
import { genDeeplFree } from "./deepl";
|
||||||
import { genBaidu } from "./baidu";
|
import { genBaidu } from "./baidu";
|
||||||
|
import interpreter from "../libs/interpreter";
|
||||||
|
|
||||||
const keyMap = new Map();
|
const keyMap = new Map();
|
||||||
const urlMap = new Map();
|
const urlMap = new Map();
|
||||||
@@ -77,6 +84,20 @@ const genGoogle = ({ text, from, to, url, key }) => {
|
|||||||
return [input, init];
|
return [input, init];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const genGoogle2 = ({ text, from, to, url, key }) => {
|
||||||
|
const body = JSON.stringify([[[text], from, to], "wt_lib"]);
|
||||||
|
const init = {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json+protobuf",
|
||||||
|
"X-Goog-API-Key": key,
|
||||||
|
},
|
||||||
|
body,
|
||||||
|
};
|
||||||
|
|
||||||
|
return [url, init];
|
||||||
|
};
|
||||||
|
|
||||||
const genMicrosoft = async ({ text, from, to }) => {
|
const genMicrosoft = async ({ text, from, to }) => {
|
||||||
const [token] = await msAuth();
|
const [token] = await msAuth();
|
||||||
const params = {
|
const params = {
|
||||||
@@ -161,10 +182,14 @@ const genNiuTrans = ({ text, from, to, url, key, dictNo, memoryNo }) => {
|
|||||||
const genTencent = ({ text, from, to }) => {
|
const genTencent = ({ text, from, to }) => {
|
||||||
const data = {
|
const data = {
|
||||||
header: {
|
header: {
|
||||||
fn: "auto_translation_block",
|
fn: "auto_translation",
|
||||||
|
client_key:
|
||||||
|
"browser-chrome-110.0.0-Mac OS-df4bd4c5-a65d-44b2-a40f-42f34f3535f2-1677486696487",
|
||||||
},
|
},
|
||||||
|
type: "plain",
|
||||||
|
model_category: "normal",
|
||||||
source: {
|
source: {
|
||||||
text_block: text,
|
text_list: [text],
|
||||||
lang: from,
|
lang: from,
|
||||||
},
|
},
|
||||||
target: {
|
target: {
|
||||||
@@ -175,6 +200,9 @@ const genTencent = ({ text, from, to }) => {
|
|||||||
const init = {
|
const init = {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
"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",
|
||||||
|
referer: "https://transmart.qq.com/zh-CN/index",
|
||||||
},
|
},
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
@@ -183,25 +211,63 @@ const genTencent = ({ text, from, to }) => {
|
|||||||
return [URL_TENCENT_TRANSMART, init];
|
return [URL_TENCENT_TRANSMART, init];
|
||||||
};
|
};
|
||||||
|
|
||||||
const genOpenAI = ({ text, from, to, url, key, prompt, model }) => {
|
const genVolcengine = ({ text, from, to }) => {
|
||||||
prompt = prompt
|
const data = {
|
||||||
|
source_language: from,
|
||||||
|
target_language: to,
|
||||||
|
text: text,
|
||||||
|
};
|
||||||
|
|
||||||
|
const init = {
|
||||||
|
headers: {
|
||||||
|
"Content-type": "application/json",
|
||||||
|
},
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
};
|
||||||
|
|
||||||
|
return [URL_VOLCENGINE_TRAN, init];
|
||||||
|
};
|
||||||
|
|
||||||
|
const genOpenAI = ({
|
||||||
|
text,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
url,
|
||||||
|
key,
|
||||||
|
systemPrompt,
|
||||||
|
userPrompt,
|
||||||
|
model,
|
||||||
|
temperature,
|
||||||
|
maxTokens,
|
||||||
|
}) => {
|
||||||
|
// 兼容历史上作为systemPrompt的prompt,如果prompt中不包含带翻译文本,则添加文本到prompt末尾
|
||||||
|
// if (!prompt.includes(INPUT_PLACE_TEXT)) {
|
||||||
|
// prompt += `\nSource Text: ${INPUT_PLACE_TEXT}`;
|
||||||
|
// }
|
||||||
|
systemPrompt = systemPrompt
|
||||||
.replaceAll(INPUT_PLACE_FROM, from)
|
.replaceAll(INPUT_PLACE_FROM, from)
|
||||||
.replaceAll(INPUT_PLACE_TO, to);
|
.replaceAll(INPUT_PLACE_TO, to)
|
||||||
|
.replaceAll(INPUT_PLACE_TEXT, text);
|
||||||
|
userPrompt = userPrompt
|
||||||
|
.replaceAll(INPUT_PLACE_FROM, from)
|
||||||
|
.replaceAll(INPUT_PLACE_TO, to)
|
||||||
|
.replaceAll(INPUT_PLACE_TEXT, text);
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
model,
|
model,
|
||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
role: "system",
|
role: "system",
|
||||||
content: prompt,
|
content: systemPrompt,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
role: "user",
|
role: "user",
|
||||||
content: text,
|
content: userPrompt,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
temperature: 0,
|
temperature,
|
||||||
max_tokens: 256,
|
max_tokens: maxTokens,
|
||||||
};
|
};
|
||||||
|
|
||||||
const init = {
|
const init = {
|
||||||
@@ -217,26 +283,50 @@ const genOpenAI = ({ text, from, to, url, key, prompt, model }) => {
|
|||||||
return [url, init];
|
return [url, init];
|
||||||
};
|
};
|
||||||
|
|
||||||
const genGemini = ({ text, from, to, url, key, prompt, model }) => {
|
const genGemini = ({
|
||||||
prompt = prompt
|
text,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
url,
|
||||||
|
key,
|
||||||
|
systemPrompt,
|
||||||
|
userPrompt,
|
||||||
|
model,
|
||||||
|
temperature,
|
||||||
|
maxTokens,
|
||||||
|
}) => {
|
||||||
|
url = url
|
||||||
|
.replaceAll(INPUT_PLACE_MODEL, model)
|
||||||
|
.replaceAll(INPUT_PLACE_KEY, key);
|
||||||
|
systemPrompt = systemPrompt
|
||||||
|
.replaceAll(INPUT_PLACE_FROM, from)
|
||||||
|
.replaceAll(INPUT_PLACE_TO, to)
|
||||||
|
.replaceAll(INPUT_PLACE_TEXT, text);
|
||||||
|
userPrompt = userPrompt
|
||||||
.replaceAll(INPUT_PLACE_FROM, from)
|
.replaceAll(INPUT_PLACE_FROM, from)
|
||||||
.replaceAll(INPUT_PLACE_TO, to)
|
.replaceAll(INPUT_PLACE_TO, to)
|
||||||
.replaceAll(INPUT_PLACE_TEXT, text);
|
.replaceAll(INPUT_PLACE_TEXT, text);
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
contents: [
|
system_instruction: {
|
||||||
{
|
parts: {
|
||||||
// role: "user",
|
text: systemPrompt,
|
||||||
parts: [
|
|
||||||
{
|
|
||||||
text: prompt,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
],
|
},
|
||||||
|
contents: {
|
||||||
|
role: "user",
|
||||||
|
parts: {
|
||||||
|
text: userPrompt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
generationConfig: {
|
||||||
|
maxOutputTokens: maxTokens,
|
||||||
|
temperature,
|
||||||
|
// topP: 0.8,
|
||||||
|
// topK: 10,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const input = `${url}/${model}:generateContent?key=${key}`;
|
|
||||||
const init = {
|
const init = {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-type": "application/json",
|
"Content-type": "application/json",
|
||||||
@@ -245,18 +335,130 @@ const genGemini = ({ text, from, to, url, key, prompt, model }) => {
|
|||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
};
|
};
|
||||||
|
|
||||||
return [input, init];
|
return [url, init];
|
||||||
};
|
};
|
||||||
|
|
||||||
const genOllama = ({ text, from, to, url, key, prompt, model }) => {
|
const genGemini2 = ({
|
||||||
prompt = prompt
|
text,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
url,
|
||||||
|
key,
|
||||||
|
systemPrompt,
|
||||||
|
userPrompt,
|
||||||
|
model,
|
||||||
|
temperature,
|
||||||
|
reasoningEffort,
|
||||||
|
}) => {
|
||||||
|
systemPrompt = systemPrompt
|
||||||
|
.replaceAll(INPUT_PLACE_FROM, from)
|
||||||
|
.replaceAll(INPUT_PLACE_TO, to)
|
||||||
|
.replaceAll(INPUT_PLACE_TEXT, text);
|
||||||
|
userPrompt = userPrompt
|
||||||
.replaceAll(INPUT_PLACE_FROM, from)
|
.replaceAll(INPUT_PLACE_FROM, from)
|
||||||
.replaceAll(INPUT_PLACE_TO, to)
|
.replaceAll(INPUT_PLACE_TO, to)
|
||||||
.replaceAll(INPUT_PLACE_TEXT, text);
|
.replaceAll(INPUT_PLACE_TEXT, text);
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
model,
|
model,
|
||||||
prompt,
|
reasoning_effort: reasoningEffort,
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
role: "system",
|
||||||
|
content: systemPrompt,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: "user",
|
||||||
|
content: userPrompt,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
temperature,
|
||||||
|
};
|
||||||
|
|
||||||
|
const init = {
|
||||||
|
headers: {
|
||||||
|
"Content-type": "application/json",
|
||||||
|
Authorization: `Bearer ${key}`,
|
||||||
|
},
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
};
|
||||||
|
|
||||||
|
return [url, init];
|
||||||
|
};
|
||||||
|
|
||||||
|
const genClaude = ({
|
||||||
|
text,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
url,
|
||||||
|
key,
|
||||||
|
systemPrompt,
|
||||||
|
userPrompt,
|
||||||
|
model,
|
||||||
|
temperature,
|
||||||
|
maxTokens,
|
||||||
|
}) => {
|
||||||
|
systemPrompt = systemPrompt
|
||||||
|
.replaceAll(INPUT_PLACE_FROM, from)
|
||||||
|
.replaceAll(INPUT_PLACE_TO, to)
|
||||||
|
.replaceAll(INPUT_PLACE_TEXT, text);
|
||||||
|
userPrompt = userPrompt
|
||||||
|
.replaceAll(INPUT_PLACE_FROM, from)
|
||||||
|
.replaceAll(INPUT_PLACE_TO, to)
|
||||||
|
.replaceAll(INPUT_PLACE_TEXT, text);
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
model,
|
||||||
|
system: systemPrompt,
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
role: "user",
|
||||||
|
content: userPrompt,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
temperature,
|
||||||
|
max_tokens: maxTokens,
|
||||||
|
};
|
||||||
|
|
||||||
|
const init = {
|
||||||
|
headers: {
|
||||||
|
"Content-type": "application/json",
|
||||||
|
"anthropic-version": "2023-06-01",
|
||||||
|
"x-api-key": key,
|
||||||
|
},
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
};
|
||||||
|
|
||||||
|
return [url, init];
|
||||||
|
};
|
||||||
|
|
||||||
|
const genOllama = ({
|
||||||
|
text,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
think,
|
||||||
|
url,
|
||||||
|
key,
|
||||||
|
systemPrompt,
|
||||||
|
userPrompt,
|
||||||
|
model,
|
||||||
|
}) => {
|
||||||
|
systemPrompt = systemPrompt
|
||||||
|
.replaceAll(INPUT_PLACE_FROM, from)
|
||||||
|
.replaceAll(INPUT_PLACE_TO, to)
|
||||||
|
.replaceAll(INPUT_PLACE_TEXT, text);
|
||||||
|
userPrompt = userPrompt
|
||||||
|
.replaceAll(INPUT_PLACE_FROM, from)
|
||||||
|
.replaceAll(INPUT_PLACE_TO, to)
|
||||||
|
.replaceAll(INPUT_PLACE_TEXT, text);
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
model,
|
||||||
|
system: systemPrompt,
|
||||||
|
prompt: userPrompt,
|
||||||
|
think: think,
|
||||||
stream: false,
|
stream: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -293,20 +495,27 @@ const genCloudflareAI = ({ text, from, to, url, key }) => {
|
|||||||
return [url, init];
|
return [url, init];
|
||||||
};
|
};
|
||||||
|
|
||||||
const genCustom = ({ text, from, to, url, key, customOption }) => {
|
const genCustom = ({ text, from, to, url, key, reqHook }) => {
|
||||||
const replaceInput = (str) =>
|
url = url
|
||||||
str
|
.replaceAll(INPUT_PLACE_URL, url)
|
||||||
.replaceAll(INPUT_PLACE_URL, url)
|
.replaceAll(INPUT_PLACE_FROM, from)
|
||||||
.replaceAll(INPUT_PLACE_FROM, from)
|
.replaceAll(INPUT_PLACE_TO, to)
|
||||||
.replaceAll(INPUT_PLACE_TO, to)
|
.replaceAll(INPUT_PLACE_TEXT, text)
|
||||||
.replaceAll(INPUT_PLACE_TEXT, text.replaceAll(`"`, `\n`))
|
.replaceAll(INPUT_PLACE_KEY, key);
|
||||||
.replaceAll(INPUT_PLACE_KEY, key);
|
let init = {};
|
||||||
|
|
||||||
|
if (reqHook?.trim()) {
|
||||||
|
interpreter.run(`exports.reqHook = ${reqHook}`);
|
||||||
|
[url, init] = interpreter.exports.reqHook(text, from, to, url, key);
|
||||||
|
return [url, init];
|
||||||
|
}
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
text,
|
text,
|
||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
};
|
};
|
||||||
const init = {
|
init = {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-type": "application/json",
|
"Content-type": "application/json",
|
||||||
},
|
},
|
||||||
@@ -316,23 +525,6 @@ const genCustom = ({ text, from, to, url, key, customOption }) => {
|
|||||||
if (key) {
|
if (key) {
|
||||||
init.headers.Authorization = `Bearer ${key}`;
|
init.headers.Authorization = `Bearer ${key}`;
|
||||||
}
|
}
|
||||||
url = replaceInput(url);
|
|
||||||
|
|
||||||
if (customOption?.trim()) {
|
|
||||||
try {
|
|
||||||
const opt = JSON.parse(replaceInput(customOption));
|
|
||||||
opt.url && (url = opt.url);
|
|
||||||
opt.headers && (init.headers = opt.headers);
|
|
||||||
opt.method && (init.method = opt.method);
|
|
||||||
if (init.method === "GET") {
|
|
||||||
delete init.body;
|
|
||||||
} else {
|
|
||||||
opt.body && (init.body = JSON.stringify(opt.body));
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
throw new Error(`custom option parse err: ${err}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [url, init];
|
return [url, init];
|
||||||
};
|
};
|
||||||
@@ -351,11 +543,18 @@ export const genTransReq = ({ translator, text, from, to }, apiSetting) => {
|
|||||||
case OPT_TRANS_OPENAI_2:
|
case OPT_TRANS_OPENAI_2:
|
||||||
case OPT_TRANS_OPENAI_3:
|
case OPT_TRANS_OPENAI_3:
|
||||||
case OPT_TRANS_GEMINI:
|
case OPT_TRANS_GEMINI:
|
||||||
|
case OPT_TRANS_GEMINI_2:
|
||||||
|
case OPT_TRANS_CLAUDE:
|
||||||
case OPT_TRANS_CLOUDFLAREAI:
|
case OPT_TRANS_CLOUDFLAREAI:
|
||||||
case OPT_TRANS_OLLAMA:
|
case OPT_TRANS_OLLAMA:
|
||||||
case OPT_TRANS_OLLAMA_2:
|
case OPT_TRANS_OLLAMA_2:
|
||||||
case OPT_TRANS_OLLAMA_3:
|
case OPT_TRANS_OLLAMA_3:
|
||||||
case OPT_TRANS_NIUTRANS:
|
case OPT_TRANS_NIUTRANS:
|
||||||
|
case OPT_TRANS_CUSTOMIZE:
|
||||||
|
case OPT_TRANS_CUSTOMIZE_2:
|
||||||
|
case OPT_TRANS_CUSTOMIZE_3:
|
||||||
|
case OPT_TRANS_CUSTOMIZE_4:
|
||||||
|
case OPT_TRANS_CUSTOMIZE_5:
|
||||||
args.key = keyPick(translator, args.key, keyMap);
|
args.key = keyPick(translator, args.key, keyMap);
|
||||||
break;
|
break;
|
||||||
case OPT_TRANS_DEEPLX:
|
case OPT_TRANS_DEEPLX:
|
||||||
@@ -367,6 +566,8 @@ export const genTransReq = ({ translator, text, from, to }, apiSetting) => {
|
|||||||
switch (translator) {
|
switch (translator) {
|
||||||
case OPT_TRANS_GOOGLE:
|
case OPT_TRANS_GOOGLE:
|
||||||
return genGoogle(args);
|
return genGoogle(args);
|
||||||
|
case OPT_TRANS_GOOGLE_2:
|
||||||
|
return genGoogle2(args);
|
||||||
case OPT_TRANS_MICROSOFT:
|
case OPT_TRANS_MICROSOFT:
|
||||||
return genMicrosoft(args);
|
return genMicrosoft(args);
|
||||||
case OPT_TRANS_DEEPL:
|
case OPT_TRANS_DEEPL:
|
||||||
@@ -381,12 +582,18 @@ export const genTransReq = ({ translator, text, from, to }, apiSetting) => {
|
|||||||
return genBaidu(args);
|
return genBaidu(args);
|
||||||
case OPT_TRANS_TENCENT:
|
case OPT_TRANS_TENCENT:
|
||||||
return genTencent(args);
|
return genTencent(args);
|
||||||
|
case OPT_TRANS_VOLCENGINE:
|
||||||
|
return genVolcengine(args);
|
||||||
case OPT_TRANS_OPENAI:
|
case OPT_TRANS_OPENAI:
|
||||||
case OPT_TRANS_OPENAI_2:
|
case OPT_TRANS_OPENAI_2:
|
||||||
case OPT_TRANS_OPENAI_3:
|
case OPT_TRANS_OPENAI_3:
|
||||||
return genOpenAI(args);
|
return genOpenAI(args);
|
||||||
case OPT_TRANS_GEMINI:
|
case OPT_TRANS_GEMINI:
|
||||||
return genGemini(args);
|
return genGemini(args);
|
||||||
|
case OPT_TRANS_GEMINI_2:
|
||||||
|
return genGemini2(args);
|
||||||
|
case OPT_TRANS_CLAUDE:
|
||||||
|
return genClaude(args);
|
||||||
case OPT_TRANS_CLOUDFLAREAI:
|
case OPT_TRANS_CLOUDFLAREAI:
|
||||||
return genCloudflareAI(args);
|
return genCloudflareAI(args);
|
||||||
case OPT_TRANS_OLLAMA:
|
case OPT_TRANS_OLLAMA:
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
CMD_TOGGLE_STYLE,
|
CMD_TOGGLE_STYLE,
|
||||||
CMD_OPEN_OPTIONS,
|
CMD_OPEN_OPTIONS,
|
||||||
CMD_OPEN_TRANBOX,
|
CMD_OPEN_TRANBOX,
|
||||||
|
CLIENT_THUNDERBIRD,
|
||||||
} from "./config";
|
} from "./config";
|
||||||
import { getSettingWithDefault, tryInitDefaultData } from "./libs/storage";
|
import { getSettingWithDefault, tryInitDefaultData } from "./libs/storage";
|
||||||
import { trySyncSettingAndRules } from "./libs/sync";
|
import { trySyncSettingAndRules } from "./libs/sync";
|
||||||
@@ -44,7 +45,7 @@ const REMOVE_HEADERS = [
|
|||||||
async function addContextMenus(contextMenuType = 1) {
|
async function addContextMenus(contextMenuType = 1) {
|
||||||
// 添加前先删除,避免重复ID的错误
|
// 添加前先删除,避免重复ID的错误
|
||||||
try {
|
try {
|
||||||
await browser.contextMenus.removeAll();
|
await browser.menus.removeAll();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
@@ -123,12 +124,26 @@ async function updateCspRules(csplist = DEFAULT_CSPLIST.join(",\n")) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册邮件显示脚本
|
||||||
|
*/
|
||||||
|
async function registerMsgDisplayScript() {
|
||||||
|
await messenger.messageDisplayScripts.register({
|
||||||
|
js: [{ file: "/content.js" }],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 插件安装
|
* 插件安装
|
||||||
*/
|
*/
|
||||||
browser.runtime.onInstalled.addListener(() => {
|
browser.runtime.onInstalled.addListener(() => {
|
||||||
tryInitDefaultData();
|
tryInitDefaultData();
|
||||||
|
|
||||||
|
//在thunderbird中注册脚本
|
||||||
|
if (process.env.REACT_APP_CLIENT === CLIENT_THUNDERBIRD) {
|
||||||
|
registerMsgDisplayScript();
|
||||||
|
}
|
||||||
|
|
||||||
// 右键菜单
|
// 右键菜单
|
||||||
addContextMenus();
|
addContextMenus();
|
||||||
|
|
||||||
@@ -151,6 +166,11 @@ browser.runtime.onStartup.addListener(async () => {
|
|||||||
tryClearCaches();
|
tryClearCaches();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//在thunderbird中注册脚本
|
||||||
|
if (process.env.REACT_APP_CLIENT === CLIENT_THUNDERBIRD) {
|
||||||
|
registerMsgDisplayScript();
|
||||||
|
}
|
||||||
|
|
||||||
// 右键菜单
|
// 右键菜单
|
||||||
// firefox重启后菜单会消失,故重复添加
|
// firefox重启后菜单会消失,故重复添加
|
||||||
addContextMenus(contextMenuType);
|
addContextMenus(contextMenuType);
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ function runtimeListener(translator) {
|
|||||||
default:
|
default:
|
||||||
return { error: `message action is unavailable: ${action}` };
|
return { error: `message action is unavailable: ${action}` };
|
||||||
}
|
}
|
||||||
return { data: translator.rule };
|
return { rule: translator.rule, setting: translator.setting };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,14 +135,18 @@ async function showFab(translator) {
|
|||||||
* @param {*} param0
|
* @param {*} param0
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function showTransbox({
|
function showTransbox(
|
||||||
contextMenuType,
|
{
|
||||||
tranboxSetting = DEFAULT_TRANBOX_SETTING,
|
contextMenuType,
|
||||||
transApis,
|
tranboxSetting = DEFAULT_TRANBOX_SETTING,
|
||||||
darkMode,
|
transApis,
|
||||||
uiLang,
|
darkMode,
|
||||||
}) {
|
uiLang,
|
||||||
if (!tranboxSetting?.transOpen) {
|
langDetector,
|
||||||
|
},
|
||||||
|
{ transSelected }
|
||||||
|
) {
|
||||||
|
if (transSelected === "false") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,6 +176,7 @@ function showTransbox({
|
|||||||
tranboxSetting={tranboxSetting}
|
tranboxSetting={tranboxSetting}
|
||||||
transApis={transApis}
|
transApis={transApis}
|
||||||
uiLang={uiLang}
|
uiLang={uiLang}
|
||||||
|
langDetector={langDetector}
|
||||||
/>
|
/>
|
||||||
</CacheProvider>
|
</CacheProvider>
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
@@ -249,7 +254,7 @@ export async function run(isUserscript = false) {
|
|||||||
inputTranslate(setting);
|
inputTranslate(setting);
|
||||||
|
|
||||||
// 划词翻译
|
// 划词翻译
|
||||||
showTransbox(setting);
|
showTransbox(setting, rule);
|
||||||
|
|
||||||
// 浮球按钮
|
// 浮球按钮
|
||||||
await showFab(translator);
|
await showFab(translator);
|
||||||
|
|||||||
@@ -42,7 +42,23 @@ const customApiLangs = `["en", "English - English"],
|
|||||||
["vi", "Vietnamese - Tiếng Việt"],
|
["vi", "Vietnamese - Tiếng Việt"],
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const customDefaultOption = `{
|
const hookExample = `// URL
|
||||||
|
https://translate.googleapis.com/translate_a/single?client=gtx&dj=1&dt=t&ie=UTF-8&q={{text}}&sl=en&tl=zh-CN
|
||||||
|
|
||||||
|
// Request Hook
|
||||||
|
(text, from, to, url, key) => [url, {
|
||||||
|
headers: {
|
||||||
|
"Content-type": "application/json",
|
||||||
|
},
|
||||||
|
method: "GET",
|
||||||
|
body: null,
|
||||||
|
}]
|
||||||
|
|
||||||
|
// Response Hook
|
||||||
|
(res, text, from, to) => [res.sentences.map((item) => item.trans).join(" "), to === res.src]`;
|
||||||
|
|
||||||
|
const customApiHelpZH = `// 请求数据默认格式
|
||||||
|
{
|
||||||
"url": "{{url}}",
|
"url": "{{url}}",
|
||||||
"method": "POST",
|
"method": "POST",
|
||||||
"headers": {
|
"headers": {
|
||||||
@@ -50,18 +66,12 @@ const customDefaultOption = `{
|
|||||||
"Authorization": "Bearer {{key}}"
|
"Authorization": "Bearer {{key}}"
|
||||||
},
|
},
|
||||||
"body": {
|
"body": {
|
||||||
"text": "{{text}}",
|
"text": "{{text}}", // 待翻译文字
|
||||||
"from": "{{from}}",
|
"from": "{{from}}", // 文字的语言(可能为空)
|
||||||
"to": "{{to}}"
|
"to": "{{to}}", // 目标语言
|
||||||
},
|
},
|
||||||
"resPattern": {
|
}
|
||||||
"text": "text",
|
|
||||||
"from": "from"
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
|
|
||||||
const customApiHelpZH = `// 自定义选项范例
|
|
||||||
${customDefaultOption}
|
|
||||||
|
|
||||||
// 返回数据默认格式
|
// 返回数据默认格式
|
||||||
{
|
{
|
||||||
@@ -70,20 +80,43 @@ ${customDefaultOption}
|
|||||||
to: "", // 目标语言(可选)
|
to: "", // 目标语言(可选)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Hook 范例
|
||||||
|
${hookExample}
|
||||||
|
|
||||||
|
|
||||||
// 支持的语言代码如下
|
// 支持的语言代码如下
|
||||||
${customApiLangs}
|
${customApiLangs}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const customApiHelpEN = `// Example of custom options
|
const customApiHelpEN = `// Default request
|
||||||
${customDefaultOption}
|
{
|
||||||
|
"url": "{{url}}",
|
||||||
|
"method": "POST",
|
||||||
|
"headers": {
|
||||||
|
"Content-type": "application/json",
|
||||||
|
"Authorization": "Bearer {{key}}"
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"text": "{{text}}", // Text to be translated
|
||||||
|
"from": "{{from}}", // The language of the text (may be empty)
|
||||||
|
"to": "{{to}}", // Target language
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
// Return data default format
|
|
||||||
|
// Default response
|
||||||
{
|
{
|
||||||
text: "", // translated text
|
text: "", // translated text
|
||||||
from: "", // Recognized source language
|
from: "", // Recognized source language
|
||||||
to: "", // Target language (optional)
|
to: "", // Target language (optional)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Hook Example
|
||||||
|
${hookExample}
|
||||||
|
|
||||||
|
|
||||||
// The supported language codes are as follows
|
// The supported language codes are as follows
|
||||||
${customApiLangs}
|
${customApiLangs}
|
||||||
`;
|
`;
|
||||||
@@ -153,6 +186,22 @@ export const I18N = {
|
|||||||
zh: `最大并发请求数量 (1-100)`,
|
zh: `最大并发请求数量 (1-100)`,
|
||||||
en: `Maximum Number Of Concurrent Requests (1-100)`,
|
en: `Maximum Number Of Concurrent Requests (1-100)`,
|
||||||
},
|
},
|
||||||
|
if_think: {
|
||||||
|
zh: `启用或禁用模型的深度思考能力`,
|
||||||
|
en: `Enable or disable the model’s thinking behavior `,
|
||||||
|
},
|
||||||
|
think: {
|
||||||
|
zh: `启用深度思考`,
|
||||||
|
en: `enable thinking`,
|
||||||
|
},
|
||||||
|
nothink: {
|
||||||
|
zh: `禁用深度思考`,
|
||||||
|
en: `disable thinking`,
|
||||||
|
},
|
||||||
|
think_ignore: {
|
||||||
|
zh: `忽略以下模型的<think>输出,逗号(,)分割,当模型支持思考但ollama不支持时需要填写本参数`,
|
||||||
|
en: `Ignore the <think> block for the following models, comma (,) separated`,
|
||||||
|
},
|
||||||
fetch_interval: {
|
fetch_interval: {
|
||||||
zh: `每次请求间隔时间 (0-5000ms)`,
|
zh: `每次请求间隔时间 (0-5000ms)`,
|
||||||
en: `Time Between Requests (0-5000ms)`,
|
en: `Time Between Requests (0-5000ms)`,
|
||||||
@@ -161,6 +210,10 @@ export const I18N = {
|
|||||||
zh: `重新翻译间隔时间 (100-5000ms)`,
|
zh: `重新翻译间隔时间 (100-5000ms)`,
|
||||||
en: `Retranslation Interval (100-5000ms)`,
|
en: `Retranslation Interval (100-5000ms)`,
|
||||||
},
|
},
|
||||||
|
http_timeout: {
|
||||||
|
zh: `请求超时时间 (5000-30000ms)`,
|
||||||
|
en: `Request Timeout Time (5000-30000ms)`,
|
||||||
|
},
|
||||||
min_translate_length: {
|
min_translate_length: {
|
||||||
zh: `最小翻译字符数 (1-100)`,
|
zh: `最小翻译字符数 (1-100)`,
|
||||||
en: `Minimum number Of Translated Characters (1-100)`,
|
en: `Minimum number Of Translated Characters (1-100)`,
|
||||||
@@ -394,8 +447,8 @@ export const I18N = {
|
|||||||
en: `Keep unchanged selector`,
|
en: `Keep unchanged selector`,
|
||||||
},
|
},
|
||||||
keep_selector_helper: {
|
keep_selector_helper: {
|
||||||
zh: `1、遵循CSS选择器语法。2、子元素选择器用“>>>”隔开。`,
|
zh: `1、遵循CSS选择器语法。`,
|
||||||
en: `1. Follow CSS selector syntax. 2. Sub-element selectors are separated by ">>>".`,
|
en: `1. Follow CSS selector syntax.`,
|
||||||
},
|
},
|
||||||
terms: {
|
terms: {
|
||||||
zh: `专业术语`,
|
zh: `专业术语`,
|
||||||
@@ -623,7 +676,7 @@ export const I18N = {
|
|||||||
},
|
},
|
||||||
use_simple_style: {
|
use_simple_style: {
|
||||||
zh: `使用简洁界面`,
|
zh: `使用简洁界面`,
|
||||||
en: `Click outside to close the pop-up window`,
|
en: `Use a simple interface`,
|
||||||
},
|
},
|
||||||
show: {
|
show: {
|
||||||
zh: `显示`,
|
zh: `显示`,
|
||||||
@@ -821,6 +874,10 @@ export const I18N = {
|
|||||||
zh: `更多`,
|
zh: `更多`,
|
||||||
en: `More`,
|
en: `More`,
|
||||||
},
|
},
|
||||||
|
less: {
|
||||||
|
zh: `更少`,
|
||||||
|
en: `Less`,
|
||||||
|
},
|
||||||
fixer_selector: {
|
fixer_selector: {
|
||||||
zh: `网页修复选择器`,
|
zh: `网页修复选择器`,
|
||||||
en: `Fixer Selector`,
|
en: `Fixer Selector`,
|
||||||
@@ -873,4 +930,44 @@ export const I18N = {
|
|||||||
zh: `翻译框跟随选中文本`,
|
zh: `翻译框跟随选中文本`,
|
||||||
en: `Transbox Follow Selection`,
|
en: `Transbox Follow Selection`,
|
||||||
},
|
},
|
||||||
|
translate_start_hook: {
|
||||||
|
zh: `翻译开始钩子函数`,
|
||||||
|
en: `Translate Start Hook`,
|
||||||
|
},
|
||||||
|
translate_start_hook_helper: {
|
||||||
|
zh: `翻译开始时运行,入参为: 翻译节点,原文文本。`,
|
||||||
|
en: `Run when translation starts, the input parameters are: translation node, original text.`,
|
||||||
|
},
|
||||||
|
translate_end_hook: {
|
||||||
|
zh: `翻译完成钩子函数`,
|
||||||
|
en: `Translate End Hook`,
|
||||||
|
},
|
||||||
|
translate_end_hook_helper: {
|
||||||
|
zh: `翻译完成时运行,入参为: 翻译节点,原文文本,译文文本,保留元素。`,
|
||||||
|
en: `Run when the translation is completed, the input parameters are: translation node, original text, translation text, retained elements.`,
|
||||||
|
},
|
||||||
|
translate_remove_hook: {
|
||||||
|
zh: `翻译移除钩子函数`,
|
||||||
|
en: `Translate Removed Hook`,
|
||||||
|
},
|
||||||
|
translate_remove_hook_helper: {
|
||||||
|
zh: `翻译移除时运行,入参为: 翻译节点。`,
|
||||||
|
en: `Run when translation is removed, the input parameters are: translation node.`,
|
||||||
|
},
|
||||||
|
english_dict: {
|
||||||
|
zh: `英文词典`,
|
||||||
|
en: `English Dictionary`,
|
||||||
|
},
|
||||||
|
api_name: {
|
||||||
|
zh: `接口名称`,
|
||||||
|
en: `API Name`,
|
||||||
|
},
|
||||||
|
is_disabled: {
|
||||||
|
zh: `是否禁用`,
|
||||||
|
en: `Is Disabled`,
|
||||||
|
},
|
||||||
|
translate_selected: {
|
||||||
|
zh: `是否启用划词翻译`,
|
||||||
|
en: `If translate selected`,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -39,7 +39,13 @@ export const CLIENT_CHROME = "chrome";
|
|||||||
export const CLIENT_EDGE = "edge";
|
export const CLIENT_EDGE = "edge";
|
||||||
export const CLIENT_FIREFOX = "firefox";
|
export const CLIENT_FIREFOX = "firefox";
|
||||||
export const CLIENT_USERSCRIPT = "userscript";
|
export const CLIENT_USERSCRIPT = "userscript";
|
||||||
export const CLIENT_EXTS = [CLIENT_CHROME, CLIENT_EDGE, CLIENT_FIREFOX];
|
export const CLIENT_THUNDERBIRD = "thunderbird";
|
||||||
|
export const CLIENT_EXTS = [
|
||||||
|
CLIENT_CHROME,
|
||||||
|
CLIENT_EDGE,
|
||||||
|
CLIENT_FIREFOX,
|
||||||
|
CLIENT_THUNDERBIRD,
|
||||||
|
];
|
||||||
|
|
||||||
export const KV_RULES_KEY = "kiss-rules.json";
|
export const KV_RULES_KEY = "kiss-rules.json";
|
||||||
export const KV_WORDS_KEY = "kiss-words.json";
|
export const KV_WORDS_KEY = "kiss-words.json";
|
||||||
@@ -78,9 +84,20 @@ export const URL_RAW_PREFIX =
|
|||||||
"https://raw.githubusercontent.com/fishjar/kiss-translator/master";
|
"https://raw.githubusercontent.com/fishjar/kiss-translator/master";
|
||||||
|
|
||||||
export const URL_CACHE_TRAN = `https://${APP_LCNAME}/translate`;
|
export const URL_CACHE_TRAN = `https://${APP_LCNAME}/translate`;
|
||||||
|
|
||||||
|
// api.cognitive.microsofttranslator.com
|
||||||
export const URL_MICROSOFT_TRAN =
|
export const URL_MICROSOFT_TRAN =
|
||||||
"https://api-edge.cognitive.microsofttranslator.com/translate";
|
"https://api-edge.cognitive.microsofttranslator.com/translate";
|
||||||
export const URL_MICROSOFT_AUTH = "https://edge.microsoft.com/translate/auth";
|
export const URL_MICROSOFT_AUTH = "https://edge.microsoft.com/translate/auth";
|
||||||
|
export const URL_MICROSOFT_LANGDETECT =
|
||||||
|
"https://api-edge.cognitive.microsofttranslator.com/detect?api-version=3.0";
|
||||||
|
|
||||||
|
export const URL_GOOGLE_TRAN =
|
||||||
|
"https://translate.googleapis.com/translate_a/single";
|
||||||
|
export const URL_GOOGLE_TRAN2 =
|
||||||
|
"https://translate-pa.googleapis.com/v1/translateHtml";
|
||||||
|
export const DEFAULT_GOOGLE_API_KEY = "AIzaSyATBXajvzQLTDHEQbcpq0Ihe0vWDHmO520";
|
||||||
|
|
||||||
export const URL_BAIDU_LANGDETECT = "https://fanyi.baidu.com/langdetect";
|
export const URL_BAIDU_LANGDETECT = "https://fanyi.baidu.com/langdetect";
|
||||||
export const URL_BAIDU_SUGGEST = "https://fanyi.baidu.com/sug";
|
export const URL_BAIDU_SUGGEST = "https://fanyi.baidu.com/sug";
|
||||||
export const URL_BAIDU_TTS = "https://fanyi.baidu.com/gettts";
|
export const URL_BAIDU_TTS = "https://fanyi.baidu.com/gettts";
|
||||||
@@ -89,13 +106,18 @@ export const URL_BAIDU_TRANSAPI = "https://fanyi.baidu.com/transapi";
|
|||||||
export const URL_BAIDU_TRANSAPI_V2 = "https://fanyi.baidu.com/v2transapi";
|
export const URL_BAIDU_TRANSAPI_V2 = "https://fanyi.baidu.com/v2transapi";
|
||||||
export const URL_DEEPLFREE_TRAN = "https://www2.deepl.com/jsonrpc";
|
export const URL_DEEPLFREE_TRAN = "https://www2.deepl.com/jsonrpc";
|
||||||
export const URL_TENCENT_TRANSMART = "https://transmart.qq.com/api/imt";
|
export const URL_TENCENT_TRANSMART = "https://transmart.qq.com/api/imt";
|
||||||
|
export const URL_VOLCENGINE_TRAN =
|
||||||
|
"https://translate.volcengine.com/crx/translate/v1";
|
||||||
export const URL_NIUTRANS_REG =
|
export const URL_NIUTRANS_REG =
|
||||||
"https://niutrans.com/login?active=3&userSource=kiss-translator";
|
"https://niutrans.com/login?active=3&userSource=kiss-translator";
|
||||||
|
|
||||||
export const DEFAULT_USER_AGENT =
|
export const DEFAULT_USER_AGENT =
|
||||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36";
|
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36";
|
||||||
|
|
||||||
|
export const OPT_DICT_BAIDU = "Baidu";
|
||||||
|
|
||||||
export const OPT_TRANS_GOOGLE = "Google";
|
export const OPT_TRANS_GOOGLE = "Google";
|
||||||
|
export const OPT_TRANS_GOOGLE_2 = "Google2";
|
||||||
export const OPT_TRANS_MICROSOFT = "Microsoft";
|
export const OPT_TRANS_MICROSOFT = "Microsoft";
|
||||||
export const OPT_TRANS_DEEPL = "DeepL";
|
export const OPT_TRANS_DEEPL = "DeepL";
|
||||||
export const OPT_TRANS_DEEPLX = "DeepLX";
|
export const OPT_TRANS_DEEPLX = "DeepLX";
|
||||||
@@ -103,10 +125,13 @@ export const OPT_TRANS_DEEPLFREE = "DeepLFree";
|
|||||||
export const OPT_TRANS_NIUTRANS = "NiuTrans";
|
export const OPT_TRANS_NIUTRANS = "NiuTrans";
|
||||||
export const OPT_TRANS_BAIDU = "Baidu";
|
export const OPT_TRANS_BAIDU = "Baidu";
|
||||||
export const OPT_TRANS_TENCENT = "Tencent";
|
export const OPT_TRANS_TENCENT = "Tencent";
|
||||||
|
export const OPT_TRANS_VOLCENGINE = "Volcengine";
|
||||||
export const OPT_TRANS_OPENAI = "OpenAI";
|
export const OPT_TRANS_OPENAI = "OpenAI";
|
||||||
export const OPT_TRANS_OPENAI_2 = "OpenAI2";
|
export const OPT_TRANS_OPENAI_2 = "OpenAI2";
|
||||||
export const OPT_TRANS_OPENAI_3 = "OpenAI3";
|
export const OPT_TRANS_OPENAI_3 = "OpenAI3";
|
||||||
export const OPT_TRANS_GEMINI = "Gemini";
|
export const OPT_TRANS_GEMINI = "Gemini";
|
||||||
|
export const OPT_TRANS_GEMINI_2 = "Gemini2";
|
||||||
|
export const OPT_TRANS_CLAUDE = "Claude";
|
||||||
export const OPT_TRANS_CLOUDFLAREAI = "CloudflareAI";
|
export const OPT_TRANS_CLOUDFLAREAI = "CloudflareAI";
|
||||||
export const OPT_TRANS_OLLAMA = "Ollama";
|
export const OPT_TRANS_OLLAMA = "Ollama";
|
||||||
export const OPT_TRANS_OLLAMA_2 = "Ollama2";
|
export const OPT_TRANS_OLLAMA_2 = "Ollama2";
|
||||||
@@ -118,9 +143,11 @@ export const OPT_TRANS_CUSTOMIZE_4 = "Custom4";
|
|||||||
export const OPT_TRANS_CUSTOMIZE_5 = "Custom5";
|
export const OPT_TRANS_CUSTOMIZE_5 = "Custom5";
|
||||||
export const OPT_TRANS_ALL = [
|
export const OPT_TRANS_ALL = [
|
||||||
OPT_TRANS_GOOGLE,
|
OPT_TRANS_GOOGLE,
|
||||||
|
OPT_TRANS_GOOGLE_2,
|
||||||
OPT_TRANS_MICROSOFT,
|
OPT_TRANS_MICROSOFT,
|
||||||
OPT_TRANS_BAIDU,
|
OPT_TRANS_BAIDU,
|
||||||
OPT_TRANS_TENCENT,
|
OPT_TRANS_TENCENT,
|
||||||
|
OPT_TRANS_VOLCENGINE,
|
||||||
OPT_TRANS_DEEPL,
|
OPT_TRANS_DEEPL,
|
||||||
OPT_TRANS_DEEPLFREE,
|
OPT_TRANS_DEEPLFREE,
|
||||||
OPT_TRANS_DEEPLX,
|
OPT_TRANS_DEEPLX,
|
||||||
@@ -129,6 +156,8 @@ export const OPT_TRANS_ALL = [
|
|||||||
OPT_TRANS_OPENAI_2,
|
OPT_TRANS_OPENAI_2,
|
||||||
OPT_TRANS_OPENAI_3,
|
OPT_TRANS_OPENAI_3,
|
||||||
OPT_TRANS_GEMINI,
|
OPT_TRANS_GEMINI,
|
||||||
|
OPT_TRANS_GEMINI_2,
|
||||||
|
OPT_TRANS_CLAUDE,
|
||||||
OPT_TRANS_CLOUDFLAREAI,
|
OPT_TRANS_CLOUDFLAREAI,
|
||||||
OPT_TRANS_OLLAMA,
|
OPT_TRANS_OLLAMA,
|
||||||
OPT_TRANS_OLLAMA_2,
|
OPT_TRANS_OLLAMA_2,
|
||||||
@@ -140,6 +169,13 @@ export const OPT_TRANS_ALL = [
|
|||||||
OPT_TRANS_CUSTOMIZE_5,
|
OPT_TRANS_CUSTOMIZE_5,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const OPT_LANGDETECTOR_ALL = [
|
||||||
|
OPT_TRANS_GOOGLE,
|
||||||
|
OPT_TRANS_MICROSOFT,
|
||||||
|
OPT_TRANS_BAIDU,
|
||||||
|
OPT_TRANS_TENCENT,
|
||||||
|
];
|
||||||
|
|
||||||
export const OPT_LANGS_TO = [
|
export const OPT_LANGS_TO = [
|
||||||
["en", "English - English"],
|
["en", "English - English"],
|
||||||
["zh-CN", "Simplified Chinese - 简体中文"],
|
["zh-CN", "Simplified Chinese - 简体中文"],
|
||||||
@@ -182,6 +218,7 @@ export const OPT_LANGS_TO = [
|
|||||||
export const OPT_LANGS_FROM = [["auto", "Auto-detect"], ...OPT_LANGS_TO];
|
export const OPT_LANGS_FROM = [["auto", "Auto-detect"], ...OPT_LANGS_TO];
|
||||||
export const OPT_LANGS_SPECIAL = {
|
export const OPT_LANGS_SPECIAL = {
|
||||||
[OPT_TRANS_GOOGLE]: new Map(OPT_LANGS_FROM.map(([key]) => [key, key])),
|
[OPT_TRANS_GOOGLE]: new Map(OPT_LANGS_FROM.map(([key]) => [key, key])),
|
||||||
|
[OPT_TRANS_GOOGLE_2]: new Map(OPT_LANGS_FROM.map(([key]) => [key, key])),
|
||||||
[OPT_TRANS_MICROSOFT]: new Map([
|
[OPT_TRANS_MICROSOFT]: new Map([
|
||||||
...OPT_LANGS_FROM.map(([key]) => [key, key]),
|
...OPT_LANGS_FROM.map(([key]) => [key, key]),
|
||||||
["auto", ""],
|
["auto", ""],
|
||||||
@@ -202,7 +239,7 @@ export const OPT_LANGS_SPECIAL = {
|
|||||||
]),
|
]),
|
||||||
[OPT_TRANS_DEEPLX]: new Map([
|
[OPT_TRANS_DEEPLX]: new Map([
|
||||||
...OPT_LANGS_FROM.map(([key]) => [key, key.toUpperCase()]),
|
...OPT_LANGS_FROM.map(([key]) => [key, key.toUpperCase()]),
|
||||||
["auto", ""],
|
["auto", "auto"],
|
||||||
["zh-CN", "ZH"],
|
["zh-CN", "ZH"],
|
||||||
["zh-TW", "ZH"],
|
["zh-TW", "ZH"],
|
||||||
]),
|
]),
|
||||||
@@ -212,6 +249,12 @@ export const OPT_LANGS_SPECIAL = {
|
|||||||
["zh-CN", "zh"],
|
["zh-CN", "zh"],
|
||||||
["zh-TW", "cht"],
|
["zh-TW", "cht"],
|
||||||
]),
|
]),
|
||||||
|
[OPT_TRANS_VOLCENGINE]: new Map([
|
||||||
|
...OPT_LANGS_FROM.map(([key]) => [key, key]),
|
||||||
|
["auto", "auto"],
|
||||||
|
["zh-CN", "zh"],
|
||||||
|
["zh-TW", "zh-Hant"],
|
||||||
|
]),
|
||||||
[OPT_TRANS_BAIDU]: new Map([
|
[OPT_TRANS_BAIDU]: new Map([
|
||||||
...OPT_LANGS_FROM.map(([key]) => [key, key]),
|
...OPT_LANGS_FROM.map(([key]) => [key, key]),
|
||||||
["zh-CN", "zh"],
|
["zh-CN", "zh"],
|
||||||
@@ -273,6 +316,12 @@ export const OPT_LANGS_SPECIAL = {
|
|||||||
[OPT_TRANS_GEMINI]: new Map(
|
[OPT_TRANS_GEMINI]: new Map(
|
||||||
OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]])
|
OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]])
|
||||||
),
|
),
|
||||||
|
[OPT_TRANS_GEMINI_2]: new Map(
|
||||||
|
OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]])
|
||||||
|
),
|
||||||
|
[OPT_TRANS_CLAUDE]: new Map(
|
||||||
|
OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]])
|
||||||
|
),
|
||||||
[OPT_TRANS_OLLAMA]: new Map(
|
[OPT_TRANS_OLLAMA]: new Map(
|
||||||
OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]])
|
OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]])
|
||||||
),
|
),
|
||||||
@@ -318,6 +367,12 @@ export const OPT_LANGS_SPECIAL = {
|
|||||||
]),
|
]),
|
||||||
};
|
};
|
||||||
export const OPT_LANGS_LIST = OPT_LANGS_TO.map(([lang]) => lang);
|
export const OPT_LANGS_LIST = OPT_LANGS_TO.map(([lang]) => lang);
|
||||||
|
export const OPT_LANGS_MICROSOFT = new Map(
|
||||||
|
Array.from(OPT_LANGS_SPECIAL[OPT_TRANS_MICROSOFT].entries()).map(([k, v]) => [
|
||||||
|
v,
|
||||||
|
k,
|
||||||
|
])
|
||||||
|
);
|
||||||
export const OPT_LANGS_BAIDU = new Map(
|
export const OPT_LANGS_BAIDU = new Map(
|
||||||
Array.from(OPT_LANGS_SPECIAL[OPT_TRANS_BAIDU].entries()).map(([k, v]) => [
|
Array.from(OPT_LANGS_SPECIAL[OPT_TRANS_BAIDU].entries()).map(([k, v]) => [
|
||||||
v,
|
v,
|
||||||
@@ -384,6 +439,7 @@ export const INPUT_PLACE_FROM = "{{from}}"; // 占位符
|
|||||||
export const INPUT_PLACE_TO = "{{to}}"; // 占位符
|
export const INPUT_PLACE_TO = "{{to}}"; // 占位符
|
||||||
export const INPUT_PLACE_TEXT = "{{text}}"; // 占位符
|
export const INPUT_PLACE_TEXT = "{{text}}"; // 占位符
|
||||||
export const INPUT_PLACE_KEY = "{{key}}"; // 占位符
|
export const INPUT_PLACE_KEY = "{{key}}"; // 占位符
|
||||||
|
export const INPUT_PLACE_MODEL = "{{model}}"; // 占位符
|
||||||
|
|
||||||
export const DEFAULT_COLOR = "#209CEE"; // 默认高亮背景色/线条颜色
|
export const DEFAULT_COLOR = "#209CEE"; // 默认高亮背景色/线条颜色
|
||||||
|
|
||||||
@@ -412,10 +468,14 @@ export const GLOBLA_RULE = {
|
|||||||
transTiming: OPT_TIMING_PAGESCROLL, // 翻译时机/鼠标悬停翻译
|
transTiming: OPT_TIMING_PAGESCROLL, // 翻译时机/鼠标悬停翻译
|
||||||
transTag: DEFAULT_TRANS_TAG, // 译文元素标签
|
transTag: DEFAULT_TRANS_TAG, // 译文元素标签
|
||||||
transTitle: "false", // 是否同时翻译页面标题
|
transTitle: "false", // 是否同时翻译页面标题
|
||||||
|
transSelected: "true", // 是否启用划词翻译
|
||||||
detectRemote: "false", // 是否使用远程语言检测
|
detectRemote: "false", // 是否使用远程语言检测
|
||||||
skipLangs: [], // 不翻译的语言
|
skipLangs: [], // 不翻译的语言
|
||||||
fixerSelector: "", // 修复函数选择器
|
fixerSelector: "", // 修复函数选择器
|
||||||
fixerFunc: "-", // 修复函数
|
fixerFunc: "-", // 修复函数
|
||||||
|
transStartHook: "", // 钩子函数
|
||||||
|
transEndHook: "", // 钩子函数
|
||||||
|
transRemoveHook: "", // 钩子函数
|
||||||
};
|
};
|
||||||
|
|
||||||
// 输入框翻译
|
// 输入框翻译
|
||||||
@@ -447,7 +507,7 @@ export const OPT_TRANBOX_TRIGGER_ALL = [
|
|||||||
];
|
];
|
||||||
export const DEFAULT_TRANBOX_SHORTCUT = ["AltLeft", "KeyS"];
|
export const DEFAULT_TRANBOX_SHORTCUT = ["AltLeft", "KeyS"];
|
||||||
export const DEFAULT_TRANBOX_SETTING = {
|
export const DEFAULT_TRANBOX_SETTING = {
|
||||||
transOpen: true,
|
// transOpen: true, // 是否启用划词翻译(作废,移至rule)
|
||||||
translator: OPT_TRANS_MICROSOFT,
|
translator: OPT_TRANS_MICROSOFT,
|
||||||
fromLang: "auto",
|
fromLang: "auto",
|
||||||
toLang: "zh-CN",
|
toLang: "zh-CN",
|
||||||
@@ -463,6 +523,7 @@ export const DEFAULT_TRANBOX_SETTING = {
|
|||||||
followSelection: false, // 翻译框是否跟随选中文本
|
followSelection: false, // 翻译框是否跟随选中文本
|
||||||
triggerMode: OPT_TRANBOX_TRIGGER_CLICK, // 触发翻译方式
|
triggerMode: OPT_TRANBOX_TRIGGER_CLICK, // 触发翻译方式
|
||||||
extStyles: "", // 附加样式
|
extStyles: "", // 附加样式
|
||||||
|
enDict: OPT_DICT_BAIDU, // 英文词典
|
||||||
};
|
};
|
||||||
|
|
||||||
// 订阅列表
|
// 订阅列表
|
||||||
@@ -481,64 +542,120 @@ export const DEFAULT_SUBRULES_LIST = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const DEFAULT_HTTP_TIMEOUT = 5000; // 调用超时时间
|
||||||
|
|
||||||
// 翻译接口
|
// 翻译接口
|
||||||
const defaultCustomApi = {
|
const defaultCustomApi = {
|
||||||
url: "",
|
url: "",
|
||||||
key: "",
|
key: "",
|
||||||
customOption: "",
|
customOption: "", // (作废)
|
||||||
|
reqHook: "", // request 钩子函数
|
||||||
|
resHook: "", // response 钩子函数
|
||||||
fetchLimit: DEFAULT_FETCH_LIMIT,
|
fetchLimit: DEFAULT_FETCH_LIMIT,
|
||||||
fetchInterval: DEFAULT_FETCH_INTERVAL,
|
fetchInterval: DEFAULT_FETCH_INTERVAL,
|
||||||
|
apiName: "",
|
||||||
|
isDisabled: false,
|
||||||
|
httpTimeout: DEFAULT_HTTP_TIMEOUT,
|
||||||
};
|
};
|
||||||
const defaultOpenaiApi = {
|
const defaultOpenaiApi = {
|
||||||
url: "https://api.openai.com/v1/chat/completions",
|
url: "https://api.openai.com/v1/chat/completions",
|
||||||
key: "",
|
key: "",
|
||||||
model: "gpt-4",
|
model: "gpt-4",
|
||||||
prompt: `You will be provided with a sentence in ${INPUT_PLACE_FROM}, and your task is to translate it into ${INPUT_PLACE_TO}.`,
|
systemPrompt: `You are a professional, authentic machine translation engine.`,
|
||||||
|
userPrompt: `Translate the following source text from ${INPUT_PLACE_FROM} to ${INPUT_PLACE_TO}. Output translation directly without any additional text.\n\nSource Text: ${INPUT_PLACE_TEXT}\n\nTranslated Text:`,
|
||||||
|
temperature: 0,
|
||||||
|
maxTokens: 256,
|
||||||
fetchLimit: 1,
|
fetchLimit: 1,
|
||||||
fetchInterval: 500,
|
fetchInterval: 500,
|
||||||
|
apiName: "",
|
||||||
|
isDisabled: false,
|
||||||
|
httpTimeout: DEFAULT_HTTP_TIMEOUT * 2,
|
||||||
};
|
};
|
||||||
const defaultOllamaApi = {
|
const defaultOllamaApi = {
|
||||||
url: "http://localhost:11434/api/generate",
|
url: "http://localhost:11434/api/generate",
|
||||||
key: "",
|
key: "",
|
||||||
model: "llama3",
|
model: "llama3.1",
|
||||||
prompt: `Translate the following text from ${INPUT_PLACE_FROM} to ${INPUT_PLACE_TO}:\n\n${INPUT_PLACE_TEXT}`,
|
systemPrompt: `You are a professional, authentic machine translation engine.`,
|
||||||
|
userPrompt: `Translate the following source text from ${INPUT_PLACE_FROM} to ${INPUT_PLACE_TO}. Output translation directly without any additional text.\n\nSource Text: ${INPUT_PLACE_TEXT}\n\nTranslated Text:`,
|
||||||
|
think: false,
|
||||||
|
thinkIgnore: `qwen3,deepseek-r1`,
|
||||||
fetchLimit: 1,
|
fetchLimit: 1,
|
||||||
fetchInterval: 500,
|
fetchInterval: 500,
|
||||||
|
apiName: "",
|
||||||
|
isDisabled: false,
|
||||||
|
httpTimeout: DEFAULT_HTTP_TIMEOUT * 2,
|
||||||
};
|
};
|
||||||
export const DEFAULT_TRANS_APIS = {
|
export const DEFAULT_TRANS_APIS = {
|
||||||
[OPT_TRANS_GOOGLE]: {
|
[OPT_TRANS_GOOGLE]: {
|
||||||
url: "https://translate.googleapis.com/translate_a/single",
|
url: URL_GOOGLE_TRAN,
|
||||||
key: "",
|
key: "",
|
||||||
fetchLimit: DEFAULT_FETCH_LIMIT, // 最大任务数量
|
fetchLimit: DEFAULT_FETCH_LIMIT, // 最大任务数量
|
||||||
fetchInterval: DEFAULT_FETCH_INTERVAL, // 任务间隔时间
|
fetchInterval: DEFAULT_FETCH_INTERVAL, // 任务间隔时间
|
||||||
|
apiName: OPT_TRANS_GOOGLE, // 接口自定义名称
|
||||||
|
isDisabled: false, // 是否禁用
|
||||||
|
httpTimeout: DEFAULT_HTTP_TIMEOUT, // 超时时间
|
||||||
|
},
|
||||||
|
[OPT_TRANS_GOOGLE_2]: {
|
||||||
|
url: URL_GOOGLE_TRAN2,
|
||||||
|
key: DEFAULT_GOOGLE_API_KEY,
|
||||||
|
fetchLimit: DEFAULT_FETCH_LIMIT,
|
||||||
|
fetchInterval: DEFAULT_FETCH_INTERVAL,
|
||||||
|
apiName: OPT_TRANS_GOOGLE_2,
|
||||||
|
isDisabled: false,
|
||||||
|
httpTimeout: DEFAULT_HTTP_TIMEOUT,
|
||||||
},
|
},
|
||||||
[OPT_TRANS_MICROSOFT]: {
|
[OPT_TRANS_MICROSOFT]: {
|
||||||
fetchLimit: DEFAULT_FETCH_LIMIT,
|
fetchLimit: DEFAULT_FETCH_LIMIT,
|
||||||
fetchInterval: DEFAULT_FETCH_INTERVAL,
|
fetchInterval: DEFAULT_FETCH_INTERVAL,
|
||||||
|
apiName: OPT_TRANS_MICROSOFT,
|
||||||
|
isDisabled: false,
|
||||||
|
httpTimeout: DEFAULT_HTTP_TIMEOUT,
|
||||||
},
|
},
|
||||||
[OPT_TRANS_BAIDU]: {
|
[OPT_TRANS_BAIDU]: {
|
||||||
fetchLimit: DEFAULT_FETCH_LIMIT,
|
fetchLimit: DEFAULT_FETCH_LIMIT,
|
||||||
fetchInterval: DEFAULT_FETCH_INTERVAL,
|
fetchInterval: DEFAULT_FETCH_INTERVAL,
|
||||||
|
apiName: OPT_TRANS_BAIDU,
|
||||||
|
isDisabled: false,
|
||||||
|
httpTimeout: DEFAULT_HTTP_TIMEOUT,
|
||||||
},
|
},
|
||||||
[OPT_TRANS_TENCENT]: {
|
[OPT_TRANS_TENCENT]: {
|
||||||
fetchLimit: DEFAULT_FETCH_LIMIT,
|
fetchLimit: DEFAULT_FETCH_LIMIT,
|
||||||
fetchInterval: DEFAULT_FETCH_INTERVAL,
|
fetchInterval: DEFAULT_FETCH_INTERVAL,
|
||||||
|
apiName: OPT_TRANS_TENCENT,
|
||||||
|
isDisabled: false,
|
||||||
|
httpTimeout: DEFAULT_HTTP_TIMEOUT,
|
||||||
|
},
|
||||||
|
[OPT_TRANS_VOLCENGINE]: {
|
||||||
|
fetchLimit: DEFAULT_FETCH_LIMIT,
|
||||||
|
fetchInterval: DEFAULT_FETCH_INTERVAL,
|
||||||
|
apiName: OPT_TRANS_VOLCENGINE,
|
||||||
|
isDisabled: false,
|
||||||
|
httpTimeout: DEFAULT_HTTP_TIMEOUT,
|
||||||
},
|
},
|
||||||
[OPT_TRANS_DEEPL]: {
|
[OPT_TRANS_DEEPL]: {
|
||||||
url: "https://api-free.deepl.com/v2/translate",
|
url: "https://api-free.deepl.com/v2/translate",
|
||||||
key: "",
|
key: "",
|
||||||
fetchLimit: 1,
|
fetchLimit: 1,
|
||||||
fetchInterval: 500,
|
fetchInterval: 500,
|
||||||
|
apiName: OPT_TRANS_DEEPL,
|
||||||
|
isDisabled: false,
|
||||||
|
httpTimeout: DEFAULT_HTTP_TIMEOUT,
|
||||||
},
|
},
|
||||||
[OPT_TRANS_DEEPLFREE]: {
|
[OPT_TRANS_DEEPLFREE]: {
|
||||||
fetchLimit: 1,
|
fetchLimit: 1,
|
||||||
fetchInterval: 500,
|
fetchInterval: 500,
|
||||||
|
apiName: OPT_TRANS_DEEPLFREE,
|
||||||
|
isDisabled: false,
|
||||||
|
httpTimeout: DEFAULT_HTTP_TIMEOUT,
|
||||||
},
|
},
|
||||||
[OPT_TRANS_DEEPLX]: {
|
[OPT_TRANS_DEEPLX]: {
|
||||||
url: "http://localhost:1188/translate",
|
url: "http://localhost:1188/translate",
|
||||||
key: "",
|
key: "",
|
||||||
fetchLimit: 1,
|
fetchLimit: 1,
|
||||||
fetchInterval: 500,
|
fetchInterval: 500,
|
||||||
|
apiName: OPT_TRANS_DEEPLX,
|
||||||
|
isDisabled: false,
|
||||||
|
httpTimeout: DEFAULT_HTTP_TIMEOUT,
|
||||||
},
|
},
|
||||||
[OPT_TRANS_NIUTRANS]: {
|
[OPT_TRANS_NIUTRANS]: {
|
||||||
url: "https://api.niutrans.com/NiuTransServer/translation",
|
url: "https://api.niutrans.com/NiuTransServer/translation",
|
||||||
@@ -547,23 +664,63 @@ export const DEFAULT_TRANS_APIS = {
|
|||||||
memoryNo: "",
|
memoryNo: "",
|
||||||
fetchLimit: DEFAULT_FETCH_LIMIT,
|
fetchLimit: DEFAULT_FETCH_LIMIT,
|
||||||
fetchInterval: DEFAULT_FETCH_INTERVAL,
|
fetchInterval: DEFAULT_FETCH_INTERVAL,
|
||||||
|
apiName: OPT_TRANS_NIUTRANS,
|
||||||
|
isDisabled: false,
|
||||||
|
httpTimeout: DEFAULT_HTTP_TIMEOUT,
|
||||||
},
|
},
|
||||||
[OPT_TRANS_OPENAI]: defaultOpenaiApi,
|
[OPT_TRANS_OPENAI]: defaultOpenaiApi,
|
||||||
[OPT_TRANS_OPENAI_2]: defaultOpenaiApi,
|
[OPT_TRANS_OPENAI_2]: defaultOpenaiApi,
|
||||||
[OPT_TRANS_OPENAI_3]: defaultOpenaiApi,
|
[OPT_TRANS_OPENAI_3]: defaultOpenaiApi,
|
||||||
[OPT_TRANS_GEMINI]: {
|
[OPT_TRANS_GEMINI]: {
|
||||||
url: "https://generativelanguage.googleapis.com/v1/models",
|
url: `https://generativelanguage.googleapis.com/v1/models/${INPUT_PLACE_MODEL}:generateContent?key=${INPUT_PLACE_KEY}`,
|
||||||
key: "",
|
key: "",
|
||||||
model: "gemini-pro",
|
model: "gemini-2.5-flash",
|
||||||
prompt: `Translate the following text from ${INPUT_PLACE_FROM} to ${INPUT_PLACE_TO}:\n\n${INPUT_PLACE_TEXT}`,
|
systemPrompt: `You are a professional, authentic machine translation engine.`,
|
||||||
|
userPrompt: `Translate the following source text from ${INPUT_PLACE_FROM} to ${INPUT_PLACE_TO}. Output translation directly without any additional text.\n\nSource Text: ${INPUT_PLACE_TEXT}\n\nTranslated Text:`,
|
||||||
|
temperature: 0,
|
||||||
|
maxTokens: 2048,
|
||||||
fetchLimit: 1,
|
fetchLimit: 1,
|
||||||
fetchInterval: 500,
|
fetchInterval: 500,
|
||||||
|
apiName: OPT_TRANS_GEMINI,
|
||||||
|
isDisabled: false,
|
||||||
|
httpTimeout: DEFAULT_HTTP_TIMEOUT * 2,
|
||||||
|
},
|
||||||
|
[OPT_TRANS_GEMINI_2]: {
|
||||||
|
url: `https://generativelanguage.googleapis.com/v1beta/openai/chat/completions`,
|
||||||
|
key: "",
|
||||||
|
model: "gemini-2.0-flash",
|
||||||
|
systemPrompt: `You are a professional, authentic machine translation engine.`,
|
||||||
|
userPrompt: `Translate the following source text from ${INPUT_PLACE_FROM} to ${INPUT_PLACE_TO}. Output translation directly without any additional text.\n\nSource Text: ${INPUT_PLACE_TEXT}\n\nTranslated Text:`,
|
||||||
|
temperature: 0,
|
||||||
|
reasoningEffort: "low",
|
||||||
|
fetchLimit: 1,
|
||||||
|
fetchInterval: 500,
|
||||||
|
apiName: OPT_TRANS_GEMINI_2,
|
||||||
|
isDisabled: false,
|
||||||
|
httpTimeout: DEFAULT_HTTP_TIMEOUT * 2,
|
||||||
|
},
|
||||||
|
[OPT_TRANS_CLAUDE]: {
|
||||||
|
url: "https://api.anthropic.com/v1/messages",
|
||||||
|
key: "",
|
||||||
|
model: "claude-3-haiku-20240307",
|
||||||
|
systemPrompt: `You are a professional, authentic machine translation engine.`,
|
||||||
|
userPrompt: `Translate the following source text from ${INPUT_PLACE_FROM} to ${INPUT_PLACE_TO}. Output translation directly without any additional text.\n\nSource Text: ${INPUT_PLACE_TEXT}\n\nTranslated Text:`,
|
||||||
|
temperature: 0,
|
||||||
|
maxTokens: 1024,
|
||||||
|
fetchLimit: 1,
|
||||||
|
fetchInterval: 500,
|
||||||
|
apiName: OPT_TRANS_CLAUDE,
|
||||||
|
isDisabled: false,
|
||||||
|
httpTimeout: DEFAULT_HTTP_TIMEOUT * 2,
|
||||||
},
|
},
|
||||||
[OPT_TRANS_CLOUDFLAREAI]: {
|
[OPT_TRANS_CLOUDFLAREAI]: {
|
||||||
url: "https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/ai/run/@cf/meta/m2m100-1.2b",
|
url: "https://api.cloudflare.com/client/v4/accounts/{{ACCOUNT_ID}}/ai/run/@cf/meta/m2m100-1.2b",
|
||||||
key: "",
|
key: "",
|
||||||
fetchLimit: 1,
|
fetchLimit: 1,
|
||||||
fetchInterval: 500,
|
fetchInterval: 500,
|
||||||
|
apiName: OPT_TRANS_CLOUDFLAREAI,
|
||||||
|
isDisabled: false,
|
||||||
|
httpTimeout: DEFAULT_HTTP_TIMEOUT * 2,
|
||||||
},
|
},
|
||||||
[OPT_TRANS_OLLAMA]: defaultOllamaApi,
|
[OPT_TRANS_OLLAMA]: defaultOllamaApi,
|
||||||
[OPT_TRANS_OLLAMA_2]: defaultOllamaApi,
|
[OPT_TRANS_OLLAMA_2]: defaultOllamaApi,
|
||||||
@@ -607,6 +764,7 @@ export const DEFAULT_SETTING = {
|
|||||||
minLength: TRANS_MIN_LENGTH,
|
minLength: TRANS_MIN_LENGTH,
|
||||||
maxLength: TRANS_MAX_LENGTH,
|
maxLength: TRANS_MAX_LENGTH,
|
||||||
newlineLength: TRANS_NEWLINE_LENGTH,
|
newlineLength: TRANS_NEWLINE_LENGTH,
|
||||||
|
httpTimeout: DEFAULT_HTTP_TIMEOUT,
|
||||||
clearCache: false, // 是否在浏览器下次启动时清除缓存
|
clearCache: false, // 是否在浏览器下次启动时清除缓存
|
||||||
injectRules: true, // 是否注入订阅规则
|
injectRules: true, // 是否注入订阅规则
|
||||||
// injectWebfix: true, // 是否注入修复补丁(作废)
|
// injectWebfix: true, // 是否注入修复补丁(作废)
|
||||||
@@ -628,6 +786,7 @@ export const DEFAULT_SETTING = {
|
|||||||
csplist: DEFAULT_CSPLIST.join(",\n"), // 禁用CSP名单
|
csplist: DEFAULT_CSPLIST.join(",\n"), // 禁用CSP名单
|
||||||
// disableLangs: [], // 不翻译的语言(移至rule,作废)
|
// disableLangs: [], // 不翻译的语言(移至rule,作废)
|
||||||
transInterval: 500, // 翻译间隔时间
|
transInterval: 500, // 翻译间隔时间
|
||||||
|
langDetector: OPT_TRANS_MICROSOFT, // 远程语言识别服务
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_RULES = [GLOBLA_RULE];
|
export const DEFAULT_RULES = [GLOBLA_RULE];
|
||||||
|
|||||||
@@ -26,10 +26,14 @@ export const DEFAULT_RULE = {
|
|||||||
transTiming: GLOBAL_KEY, // 翻译时机/鼠标悬停翻译
|
transTiming: GLOBAL_KEY, // 翻译时机/鼠标悬停翻译
|
||||||
transTag: GLOBAL_KEY, // 译文元素标签
|
transTag: GLOBAL_KEY, // 译文元素标签
|
||||||
transTitle: GLOBAL_KEY, // 是否同时翻译页面标题
|
transTitle: GLOBAL_KEY, // 是否同时翻译页面标题
|
||||||
|
transSelected: GLOBAL_KEY, // 是否启用划词翻译
|
||||||
detectRemote: GLOBAL_KEY, // 是否使用远程语言检测
|
detectRemote: GLOBAL_KEY, // 是否使用远程语言检测
|
||||||
skipLangs: [], // 不翻译的语言
|
skipLangs: [], // 不翻译的语言
|
||||||
fixerSelector: "", // 修复函数选择器
|
fixerSelector: "", // 修复函数选择器
|
||||||
fixerFunc: GLOBAL_KEY, // 修复函数
|
fixerFunc: GLOBAL_KEY, // 修复函数
|
||||||
|
transStartHook: "", // 钩子函数
|
||||||
|
transEndHook: "", // 钩子函数
|
||||||
|
transRemoveHook: "", // 钩子函数
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_DIY_STYLE = `color: #666;
|
const DEFAULT_DIY_STYLE = `color: #666;
|
||||||
|
|||||||
@@ -30,7 +30,14 @@ export function useTranslate(q, rule, setting) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const deLang = await tryDetectLang(q, detectRemote === "true");
|
let deLang = "";
|
||||||
|
if (fromLang === "auto") {
|
||||||
|
deLang = await tryDetectLang(
|
||||||
|
q,
|
||||||
|
detectRemote === "true",
|
||||||
|
setting.langDetector
|
||||||
|
);
|
||||||
|
}
|
||||||
if (deLang && (toLang.includes(deLang) || skipLangs.includes(deLang))) {
|
if (deLang && (toLang.includes(deLang) || skipLangs.includes(deLang))) {
|
||||||
setSamelang(true);
|
setSamelang(true);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,20 +1,21 @@
|
|||||||
import { isExt, isGm } from "./client";
|
import { isExt, isGm } from "./client";
|
||||||
import { sendBgMsg } from "./msg";
|
import { sendBgMsg } from "./msg";
|
||||||
import { taskPool } from "./pool";
|
import { taskPool } from "./pool";
|
||||||
|
import { getSettingWithDefault } from "./storage";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
MSG_FETCH,
|
MSG_FETCH,
|
||||||
MSG_GET_HTTPCACHE,
|
MSG_GET_HTTPCACHE,
|
||||||
CACHE_NAME,
|
CACHE_NAME,
|
||||||
DEFAULT_FETCH_INTERVAL,
|
DEFAULT_FETCH_INTERVAL,
|
||||||
DEFAULT_FETCH_LIMIT,
|
DEFAULT_FETCH_LIMIT,
|
||||||
|
DEFAULT_HTTP_TIMEOUT,
|
||||||
} from "../config";
|
} from "../config";
|
||||||
import { isBg } from "./browser";
|
import { isBg } from "./browser";
|
||||||
import { genTransReq } from "../apis/trans";
|
import { genTransReq } from "../apis/trans";
|
||||||
import { kissLog } from "./log";
|
import { kissLog } from "./log";
|
||||||
import { blobToBase64 } from "./utils";
|
import { blobToBase64 } from "./utils";
|
||||||
|
|
||||||
const TIMEOUT = 5000;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造缓存 request
|
* 构造缓存 request
|
||||||
* @param {*} input
|
* @param {*} input
|
||||||
@@ -39,7 +40,10 @@ const newCacheReq = async (input, init) => {
|
|||||||
* @param {*} init
|
* @param {*} init
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const fetchGM = async (input, { method = "GET", headers, body } = {}) =>
|
export const fetchGM = async (
|
||||||
|
input,
|
||||||
|
{ method = "GET", headers, body, timeout } = {}
|
||||||
|
) =>
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
GM.xmlHttpRequest({
|
GM.xmlHttpRequest({
|
||||||
method,
|
method,
|
||||||
@@ -47,7 +51,7 @@ export const fetchGM = async (input, { method = "GET", headers, body } = {}) =>
|
|||||||
headers,
|
headers,
|
||||||
data: body,
|
data: body,
|
||||||
// withCredentials: true,
|
// withCredentials: true,
|
||||||
timeout: TIMEOUT,
|
timeout,
|
||||||
onload: ({ response, responseHeaders, status, statusText }) => {
|
onload: ({ response, responseHeaders, status, statusText }) => {
|
||||||
const headers = {};
|
const headers = {};
|
||||||
responseHeaders.split("\n").forEach((line) => {
|
responseHeaders.split("\n").forEach((line) => {
|
||||||
@@ -81,35 +85,60 @@ export const fetchPatcher = async (input, init, transOpts, apiSetting) => {
|
|||||||
throw new Error("url is empty");
|
throw new Error("url is empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isGm) {
|
let timeout = apiSetting?.httpTimeout || DEFAULT_HTTP_TIMEOUT;
|
||||||
let info;
|
if (!apiSetting) {
|
||||||
if (window.KISS_GM) {
|
try {
|
||||||
info = await window.KISS_GM.getInfo();
|
timeout = (await getSettingWithDefault()).httpTimeout;
|
||||||
} else {
|
} catch (err) {
|
||||||
info = GM.info;
|
//
|
||||||
}
|
|
||||||
|
|
||||||
// Tampermonkey --> .connects
|
|
||||||
// Violentmonkey --> .connect
|
|
||||||
const connects = info?.script?.connects || info?.script?.connect || [];
|
|
||||||
const url = new URL(input);
|
|
||||||
const isSafe = connects.find((item) => url.hostname.endsWith(item));
|
|
||||||
|
|
||||||
if (isSafe) {
|
|
||||||
const { body, headers, status, statusText } = window.KISS_GM
|
|
||||||
? await window.KISS_GM.fetch(input, init)
|
|
||||||
: await fetchGM(input, init);
|
|
||||||
|
|
||||||
return new Response(body, {
|
|
||||||
headers: new Headers(headers),
|
|
||||||
status,
|
|
||||||
statusText,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AbortSignal?.timeout) {
|
if (isGm) {
|
||||||
Object.assign(init, { signal: AbortSignal.timeout(TIMEOUT) });
|
// let info;
|
||||||
|
// if (window.KISS_GM) {
|
||||||
|
// info = await window.KISS_GM.getInfo();
|
||||||
|
// } else {
|
||||||
|
// info = GM.info;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Tampermonkey --> .connects
|
||||||
|
// Violentmonkey --> .connect
|
||||||
|
// const connects = info?.script?.connects || info?.script?.connect || [];
|
||||||
|
// const url = new URL(input);
|
||||||
|
// const isSafe = connects.find((item) => url.hostname.endsWith(item));
|
||||||
|
|
||||||
|
// if (isSafe) {
|
||||||
|
// // todo: 自定义接口 init 可能包含了 signal
|
||||||
|
// Object.assign(init, { timeout });
|
||||||
|
|
||||||
|
// const { body, headers, status, statusText } = window.KISS_GM
|
||||||
|
// ? await window.KISS_GM.fetch(input, init)
|
||||||
|
// : await fetchGM(input, init);
|
||||||
|
|
||||||
|
// return new Response(body, {
|
||||||
|
// headers: new Headers(headers),
|
||||||
|
// status,
|
||||||
|
// statusText,
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// todo: 自定义接口 init 可能包含了 signal
|
||||||
|
Object.assign(init, { timeout });
|
||||||
|
|
||||||
|
const { body, headers, status, statusText } = window.KISS_GM
|
||||||
|
? await window.KISS_GM.fetch(input, init)
|
||||||
|
: await fetchGM(input, init);
|
||||||
|
|
||||||
|
return new Response(body, {
|
||||||
|
headers: new Headers(headers),
|
||||||
|
status,
|
||||||
|
statusText,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AbortSignal?.timeout && !init.signal) {
|
||||||
|
Object.assign(init, { signal: AbortSignal.timeout(timeout) });
|
||||||
}
|
}
|
||||||
|
|
||||||
return fetch(input, init);
|
return fetch(input, init);
|
||||||
|
|||||||
@@ -1,8 +1,26 @@
|
|||||||
import { CACHE_NAME } from "../config";
|
import {
|
||||||
|
CACHE_NAME,
|
||||||
|
OPT_TRANS_GOOGLE,
|
||||||
|
OPT_TRANS_MICROSOFT,
|
||||||
|
OPT_TRANS_BAIDU,
|
||||||
|
OPT_TRANS_TENCENT,
|
||||||
|
} from "../config";
|
||||||
import { browser } from "./browser";
|
import { browser } from "./browser";
|
||||||
import { apiBaiduLangdetect } from "../apis";
|
import {
|
||||||
|
apiGoogleLangdetect,
|
||||||
|
apiMicrosoftLangdetect,
|
||||||
|
apiBaiduLangdetect,
|
||||||
|
apiTencentLangdetect,
|
||||||
|
} from "../apis";
|
||||||
import { kissLog } from "./log";
|
import { kissLog } from "./log";
|
||||||
|
|
||||||
|
const langdetectMap = {
|
||||||
|
[OPT_TRANS_GOOGLE]: apiGoogleLangdetect,
|
||||||
|
[OPT_TRANS_MICROSOFT]: apiMicrosoftLangdetect,
|
||||||
|
[OPT_TRANS_BAIDU]: apiBaiduLangdetect,
|
||||||
|
[OPT_TRANS_TENCENT]: apiTencentLangdetect,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清除缓存数据
|
* 清除缓存数据
|
||||||
*/
|
*/
|
||||||
@@ -19,12 +37,16 @@ export const tryClearCaches = async () => {
|
|||||||
* @param {*} q
|
* @param {*} q
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const tryDetectLang = async (q, useRemote = false) => {
|
export const tryDetectLang = async (
|
||||||
|
q,
|
||||||
|
useRemote = false,
|
||||||
|
langDetector = OPT_TRANS_MICROSOFT
|
||||||
|
) => {
|
||||||
let lang = "";
|
let lang = "";
|
||||||
|
|
||||||
if (useRemote) {
|
if (useRemote) {
|
||||||
try {
|
try {
|
||||||
lang = await apiBaiduLangdetect(q);
|
lang = await langdetectMap[langDetector](q);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
kissLog(err, "detect lang remote");
|
kissLog(err, "detect lang remote");
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/libs/interpreter.js
Normal file
16
src/libs/interpreter.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import Sval from "sval";
|
||||||
|
|
||||||
|
const interpreter = new Sval({
|
||||||
|
// ECMA Version of the code
|
||||||
|
// 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15
|
||||||
|
// or 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 2024
|
||||||
|
// or "latest"
|
||||||
|
ecmaVer: "latest",
|
||||||
|
// Code source type
|
||||||
|
// "script" or "module"
|
||||||
|
sourceType: "script",
|
||||||
|
// Whether the code runs in a sandbox
|
||||||
|
sandBox: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default interpreter;
|
||||||
@@ -74,6 +74,9 @@ export const matchRule = async (
|
|||||||
"injectJs",
|
"injectJs",
|
||||||
"injectCss",
|
"injectCss",
|
||||||
"fixerSelector",
|
"fixerSelector",
|
||||||
|
"transStartHook",
|
||||||
|
"transEndHook",
|
||||||
|
"transRemoveHook",
|
||||||
].forEach((key) => {
|
].forEach((key) => {
|
||||||
if (!rule[key]?.trim()) {
|
if (!rule[key]?.trim()) {
|
||||||
rule[key] = globalRule[key];
|
rule[key] = globalRule[key];
|
||||||
@@ -89,6 +92,7 @@ export const matchRule = async (
|
|||||||
"transTiming",
|
"transTiming",
|
||||||
"transTag",
|
"transTag",
|
||||||
"transTitle",
|
"transTitle",
|
||||||
|
"transSelected",
|
||||||
"detectRemote",
|
"detectRemote",
|
||||||
"fixerFunc",
|
"fixerFunc",
|
||||||
].forEach((key) => {
|
].forEach((key) => {
|
||||||
@@ -158,10 +162,14 @@ export const checkRules = (rules) => {
|
|||||||
transTiming,
|
transTiming,
|
||||||
transTag,
|
transTag,
|
||||||
transTitle,
|
transTitle,
|
||||||
|
transSelected,
|
||||||
detectRemote,
|
detectRemote,
|
||||||
skipLangs,
|
skipLangs,
|
||||||
fixerSelector,
|
fixerSelector,
|
||||||
fixerFunc,
|
fixerFunc,
|
||||||
|
transStartHook,
|
||||||
|
transEndHook,
|
||||||
|
transRemoveHook,
|
||||||
}) => ({
|
}) => ({
|
||||||
pattern: pattern.trim(),
|
pattern: pattern.trim(),
|
||||||
selector: type(selector) === "string" ? selector : "",
|
selector: type(selector) === "string" ? selector : "",
|
||||||
@@ -182,9 +190,14 @@ export const checkRules = (rules) => {
|
|||||||
transTiming: matchValue([GLOBAL_KEY, ...OPT_TIMING_ALL], transTiming),
|
transTiming: matchValue([GLOBAL_KEY, ...OPT_TIMING_ALL], transTiming),
|
||||||
transTag: matchValue([GLOBAL_KEY, "span", "font"], transTag),
|
transTag: matchValue([GLOBAL_KEY, "span", "font"], transTag),
|
||||||
transTitle: matchValue([GLOBAL_KEY, "true", "false"], transTitle),
|
transTitle: matchValue([GLOBAL_KEY, "true", "false"], transTitle),
|
||||||
|
transSelected: matchValue([GLOBAL_KEY, "true", "false"], transSelected),
|
||||||
detectRemote: matchValue([GLOBAL_KEY, "true", "false"], detectRemote),
|
detectRemote: matchValue([GLOBAL_KEY, "true", "false"], detectRemote),
|
||||||
skipLangs: type(skipLangs) === "array" ? skipLangs : [],
|
skipLangs: type(skipLangs) === "array" ? skipLangs : [],
|
||||||
fixerSelector: type(fixerSelector) === "string" ? fixerSelector : "",
|
fixerSelector: type(fixerSelector) === "string" ? fixerSelector : "",
|
||||||
|
transStartHook: type(transStartHook) === "string" ? transStartHook : "",
|
||||||
|
transEndHook: type(transEndHook) === "string" ? transEndHook : "",
|
||||||
|
transRemoveHook:
|
||||||
|
type(transRemoveHook) === "string" ? transRemoveHook : "",
|
||||||
fixerFunc: matchValue([GLOBAL_KEY, ...FIXER_ALL], fixerFunc),
|
fixerFunc: matchValue([GLOBAL_KEY, ...FIXER_ALL], fixerFunc),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import { sendBgMsg } from "./msg";
|
|||||||
import { isExt } from "./client";
|
import { isExt } from "./client";
|
||||||
import { injectInlineJs, injectInternalCss } from "./injector";
|
import { injectInlineJs, injectInternalCss } from "./injector";
|
||||||
import { kissLog } from "./log";
|
import { kissLog } from "./log";
|
||||||
|
import interpreter from "./interpreter";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 翻译类
|
* 翻译类
|
||||||
@@ -52,7 +53,7 @@ export class Translator {
|
|||||||
];
|
];
|
||||||
_eventName = genEventName();
|
_eventName = genEventName();
|
||||||
_mouseoverNode = null;
|
_mouseoverNode = null;
|
||||||
_keepSelector = [null, null];
|
_keepSelector = "";
|
||||||
_terms = [];
|
_terms = [];
|
||||||
_docTitle = "";
|
_docTitle = "";
|
||||||
|
|
||||||
@@ -124,9 +125,7 @@ export class Translator {
|
|||||||
this._setting = setting;
|
this._setting = setting;
|
||||||
this._rule = rule;
|
this._rule = rule;
|
||||||
|
|
||||||
this._keepSelector = (rule.keepSelector || "")
|
this._keepSelector = rule.keepSelector || "";
|
||||||
.split(SHADOW_KEY)
|
|
||||||
.map((item) => item.trim());
|
|
||||||
this._terms = (rule.terms || "")
|
this._terms = (rule.terms || "")
|
||||||
.split(/\n|;/)
|
.split(/\n|;/)
|
||||||
.map((item) => item.split(",").map((item) => item.trim()))
|
.map((item) => item.split(",").map((item) => item.trim()))
|
||||||
@@ -405,6 +404,7 @@ export class Translator {
|
|||||||
// 移除键盘监听
|
// 移除键盘监听
|
||||||
window.removeEventListener("keydown", this._handleKeydown);
|
window.removeEventListener("keydown", this._handleKeydown);
|
||||||
|
|
||||||
|
const { transRemoveHook } = this._rule;
|
||||||
this._tranNodes.forEach((innerHTML, node) => {
|
this._tranNodes.forEach((innerHTML, node) => {
|
||||||
if (
|
if (
|
||||||
!this._rule.transTiming ||
|
!this._rule.transTiming ||
|
||||||
@@ -420,10 +420,17 @@ export class Translator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 移除/恢复元素
|
// 移除/恢复元素
|
||||||
if (innerHTML && this._rule.transOnly === "true") {
|
if (innerHTML) {
|
||||||
node.innerHTML = innerHTML;
|
if (this._rule.transOnly === "true") {
|
||||||
} else {
|
node.innerHTML = innerHTML;
|
||||||
node.querySelector(APP_LCNAME)?.remove();
|
} else {
|
||||||
|
node.querySelector(APP_LCNAME)?.remove();
|
||||||
|
}
|
||||||
|
// 钩子函数
|
||||||
|
if (transRemoveHook?.trim()) {
|
||||||
|
interpreter.run(`exports.transRemoveHook = ${transRemoveHook}`);
|
||||||
|
interpreter.exports.transRemoveHook(node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -490,23 +497,26 @@ export class Translator {
|
|||||||
}
|
}
|
||||||
const keeps = [];
|
const keeps = [];
|
||||||
|
|
||||||
|
// 翻译开始钩子函数
|
||||||
|
const { transStartHook } = this._rule;
|
||||||
|
if (transStartHook?.trim()) {
|
||||||
|
interpreter.run(`exports.transStartHook = ${transStartHook}`);
|
||||||
|
interpreter.exports.transStartHook(el, q);
|
||||||
|
}
|
||||||
|
|
||||||
// 保留元素
|
// 保留元素
|
||||||
const [matchSelector, subSelector] = this._keepSelector;
|
const keepSelector = this._keepSelector.trim();
|
||||||
if (matchSelector || subSelector) {
|
if (keepSelector) {
|
||||||
let text = "";
|
let text = "";
|
||||||
el.childNodes.forEach((child) => {
|
el.childNodes.forEach((child) => {
|
||||||
if (
|
if (child.nodeType === 1 && child.matches(keepSelector)) {
|
||||||
child.nodeType === 1 &&
|
|
||||||
((matchSelector && child.matches(matchSelector)) ||
|
|
||||||
(subSelector && child.querySelector(subSelector)))
|
|
||||||
) {
|
|
||||||
if (child.nodeName === "IMG") {
|
if (child.nodeName === "IMG") {
|
||||||
child.style.cssText += `width: ${child.width}px;`;
|
child.style.cssText += `width: ${child.width}px;`;
|
||||||
child.style.cssText += `height: ${child.height}px;`;
|
child.style.cssText += `height: ${child.height}px;`;
|
||||||
}
|
}
|
||||||
text += `[${keeps.length}]`;
|
text += `[${keeps.length}]`;
|
||||||
keeps.push(child.outerHTML);
|
keeps.push(child.outerHTML);
|
||||||
} else {
|
} else if (child.nodeType === 1 || child.nodeType === 3) {
|
||||||
text += child.textContent;
|
text += child.textContent;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -538,18 +548,22 @@ export class Translator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
traEl = document.createElement(APP_LCNAME);
|
// 附加样式
|
||||||
traEl.style.visibility = "visible";
|
|
||||||
// if (this._rule.transOnly === "true") {
|
|
||||||
// el.innerHTML = "";
|
|
||||||
// }
|
|
||||||
const { selectStyle, parentStyle } = this._rule;
|
const { selectStyle, parentStyle } = this._rule;
|
||||||
el.appendChild(traEl);
|
|
||||||
el.style.cssText += selectStyle;
|
el.style.cssText += selectStyle;
|
||||||
if (el.parentElement) {
|
if (el.parentElement) {
|
||||||
el.parentElement.style.cssText += parentStyle;
|
el.parentElement.style.cssText += parentStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 插入译文节点
|
||||||
|
traEl = document.createElement(APP_LCNAME);
|
||||||
|
traEl.style.visibility = "visible";
|
||||||
|
// if (this._rule.transOnly === "true") {
|
||||||
|
// el.innerHTML = "";
|
||||||
|
// }
|
||||||
|
el.appendChild(traEl);
|
||||||
|
|
||||||
|
// 渲染译文节点
|
||||||
const root = createRoot(traEl);
|
const root = createRoot(traEl);
|
||||||
root.render(<Content q={q} keeps={keeps} translator={this} $el={el} />);
|
root.render(<Content q={q} keeps={keeps} translator={this} $el={el} />);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,6 +15,16 @@ export const limitNumber = (num, min = 0, max = 100) => {
|
|||||||
return number;
|
return number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const limitFloat = (num, min = 0, max = 100) => {
|
||||||
|
const number = parseFloat(num);
|
||||||
|
if (Number.isNaN(number) || number < min) {
|
||||||
|
return min;
|
||||||
|
} else if (number > max) {
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
return number;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 匹配是否为数组中的值
|
* 匹配是否为数组中的值
|
||||||
* @param {*} arr
|
* @param {*} arr
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
import { useTranslate } from "../../hooks/Translate";
|
import { useTranslate } from "../../hooks/Translate";
|
||||||
import { styled, css } from "@mui/material/styles";
|
import { styled, css } from "@mui/material/styles";
|
||||||
import { APP_LCNAME } from "../../config";
|
import { APP_LCNAME } from "../../config";
|
||||||
|
import interpreter from "../../libs/interpreter";
|
||||||
|
|
||||||
const LINE_STYLES = {
|
const LINE_STYLES = {
|
||||||
[OPT_STYLE_LINE]: "solid",
|
[OPT_STYLE_LINE]: "solid",
|
||||||
@@ -85,8 +86,15 @@ const StyledSpan = styled("span")`
|
|||||||
export default function Content({ q, keeps, translator, $el }) {
|
export default function Content({ q, keeps, translator, $el }) {
|
||||||
const [rule, setRule] = useState(translator.rule);
|
const [rule, setRule] = useState(translator.rule);
|
||||||
const { text, sameLang, loading } = useTranslate(q, rule, translator.setting);
|
const { text, sameLang, loading } = useTranslate(q, rule, translator.setting);
|
||||||
const { transOpen, textStyle, bgColor, textDiyStyle, transOnly, transTag } =
|
const {
|
||||||
rule;
|
transOpen,
|
||||||
|
textStyle,
|
||||||
|
bgColor,
|
||||||
|
textDiyStyle,
|
||||||
|
transOnly,
|
||||||
|
transTag,
|
||||||
|
transEndHook,
|
||||||
|
} = rule;
|
||||||
|
|
||||||
const { newlineLength } = translator.setting;
|
const { newlineLength } = translator.setting;
|
||||||
|
|
||||||
@@ -107,6 +115,14 @@ export default function Content({ q, keeps, translator, $el }) {
|
|||||||
};
|
};
|
||||||
}, [translator.eventName]);
|
}, [translator.eventName]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// 运行钩子函数
|
||||||
|
if (text && transEndHook?.trim()) {
|
||||||
|
interpreter.run(`exports.transEndHook = ${transEndHook}`);
|
||||||
|
interpreter.exports.transEndHook($el, q, text, keeps);
|
||||||
|
}
|
||||||
|
}, [$el, q, text, keeps, transEndHook]);
|
||||||
|
|
||||||
const gap = useMemo(() => {
|
const gap = useMemo(() => {
|
||||||
if (transOnly === "true") {
|
if (transOnly === "true") {
|
||||||
return "";
|
return "";
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ import Stack from "@mui/material/Stack";
|
|||||||
import TextField from "@mui/material/TextField";
|
import TextField from "@mui/material/TextField";
|
||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
import LoadingButton from "@mui/lab/LoadingButton";
|
import LoadingButton from "@mui/lab/LoadingButton";
|
||||||
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
|
import FormControlLabel from "@mui/material/FormControlLabel";
|
||||||
|
import Switch from "@mui/material/Switch";
|
||||||
import {
|
import {
|
||||||
OPT_TRANS_ALL,
|
OPT_TRANS_ALL,
|
||||||
OPT_TRANS_MICROSOFT,
|
OPT_TRANS_MICROSOFT,
|
||||||
@@ -10,20 +13,28 @@ import {
|
|||||||
OPT_TRANS_DEEPLFREE,
|
OPT_TRANS_DEEPLFREE,
|
||||||
OPT_TRANS_BAIDU,
|
OPT_TRANS_BAIDU,
|
||||||
OPT_TRANS_TENCENT,
|
OPT_TRANS_TENCENT,
|
||||||
|
OPT_TRANS_VOLCENGINE,
|
||||||
OPT_TRANS_OPENAI,
|
OPT_TRANS_OPENAI,
|
||||||
OPT_TRANS_OPENAI_2,
|
OPT_TRANS_OPENAI_2,
|
||||||
OPT_TRANS_OPENAI_3,
|
OPT_TRANS_OPENAI_3,
|
||||||
OPT_TRANS_GEMINI,
|
OPT_TRANS_GEMINI,
|
||||||
|
OPT_TRANS_GEMINI_2,
|
||||||
|
OPT_TRANS_CLAUDE,
|
||||||
OPT_TRANS_CLOUDFLAREAI,
|
OPT_TRANS_CLOUDFLAREAI,
|
||||||
OPT_TRANS_OLLAMA,
|
OPT_TRANS_OLLAMA,
|
||||||
OPT_TRANS_OLLAMA_2,
|
OPT_TRANS_OLLAMA_2,
|
||||||
OPT_TRANS_OLLAMA_3,
|
OPT_TRANS_OLLAMA_3,
|
||||||
OPT_TRANS_CUSTOMIZE,
|
OPT_TRANS_CUSTOMIZE,
|
||||||
|
OPT_TRANS_CUSTOMIZE_2,
|
||||||
|
OPT_TRANS_CUSTOMIZE_3,
|
||||||
|
OPT_TRANS_CUSTOMIZE_4,
|
||||||
|
OPT_TRANS_CUSTOMIZE_5,
|
||||||
OPT_TRANS_NIUTRANS,
|
OPT_TRANS_NIUTRANS,
|
||||||
URL_KISS_PROXY,
|
URL_KISS_PROXY,
|
||||||
URL_NIUTRANS_REG,
|
URL_NIUTRANS_REG,
|
||||||
DEFAULT_FETCH_LIMIT,
|
DEFAULT_FETCH_LIMIT,
|
||||||
DEFAULT_FETCH_INTERVAL,
|
DEFAULT_FETCH_INTERVAL,
|
||||||
|
DEFAULT_HTTP_TIMEOUT,
|
||||||
} from "../../config";
|
} from "../../config";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useI18n } from "../../hooks/I18n";
|
import { useI18n } from "../../hooks/I18n";
|
||||||
@@ -38,7 +49,7 @@ import { useApi } from "../../hooks/Api";
|
|||||||
import { apiTranslate } from "../../apis";
|
import { apiTranslate } from "../../apis";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import Link from "@mui/material/Link";
|
import Link from "@mui/material/Link";
|
||||||
import { limitNumber } from "../../libs/utils";
|
import { limitNumber, limitFloat } from "../../libs/utils";
|
||||||
|
|
||||||
function TestButton({ translator, api }) {
|
function TestButton({ translator, api }) {
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
@@ -56,7 +67,7 @@ function TestButton({ translator, api }) {
|
|||||||
useCache: false,
|
useCache: false,
|
||||||
});
|
});
|
||||||
if (!text) {
|
if (!text) {
|
||||||
throw new Error("empty reault");
|
throw new Error("empty result");
|
||||||
}
|
}
|
||||||
alert.success(i18n("test_success"));
|
alert.success(i18n("test_success"));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -114,12 +125,22 @@ function ApiFields({ translator }) {
|
|||||||
url = "",
|
url = "",
|
||||||
key = "",
|
key = "",
|
||||||
model = "",
|
model = "",
|
||||||
prompt = "",
|
systemPrompt = "",
|
||||||
|
userPrompt = "",
|
||||||
|
think = false,
|
||||||
|
thinkIgnore = "",
|
||||||
fetchLimit = DEFAULT_FETCH_LIMIT,
|
fetchLimit = DEFAULT_FETCH_LIMIT,
|
||||||
fetchInterval = DEFAULT_FETCH_INTERVAL,
|
fetchInterval = DEFAULT_FETCH_INTERVAL,
|
||||||
|
httpTimeout = DEFAULT_HTTP_TIMEOUT,
|
||||||
dictNo = "",
|
dictNo = "",
|
||||||
memoryNo = "",
|
memoryNo = "",
|
||||||
customOption = "",
|
reqHook = "",
|
||||||
|
resHook = "",
|
||||||
|
temperature = 0,
|
||||||
|
maxTokens = 256,
|
||||||
|
apiName = "",
|
||||||
|
isDisabled = false,
|
||||||
|
reasoningEffort = "low",
|
||||||
} = api;
|
} = api;
|
||||||
|
|
||||||
const handleChange = (e) => {
|
const handleChange = (e) => {
|
||||||
@@ -131,6 +152,15 @@ function ApiFields({ translator }) {
|
|||||||
case "fetchInterval":
|
case "fetchInterval":
|
||||||
value = limitNumber(value, 0, 5000);
|
value = limitNumber(value, 0, 5000);
|
||||||
break;
|
break;
|
||||||
|
case "httpTimeout":
|
||||||
|
value = limitNumber(value, 5000, 30000);
|
||||||
|
break;
|
||||||
|
case "temperature":
|
||||||
|
value = limitFloat(value, 0, 2);
|
||||||
|
break;
|
||||||
|
case "maxTokens":
|
||||||
|
value = limitNumber(value, 0, 2 ** 15);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
updateApi({
|
updateApi({
|
||||||
@@ -143,6 +173,7 @@ function ApiFields({ translator }) {
|
|||||||
OPT_TRANS_DEEPLFREE,
|
OPT_TRANS_DEEPLFREE,
|
||||||
OPT_TRANS_BAIDU,
|
OPT_TRANS_BAIDU,
|
||||||
OPT_TRANS_TENCENT,
|
OPT_TRANS_TENCENT,
|
||||||
|
OPT_TRANS_VOLCENGINE,
|
||||||
];
|
];
|
||||||
|
|
||||||
const mulkeysTranslators = [
|
const mulkeysTranslators = [
|
||||||
@@ -151,11 +182,18 @@ function ApiFields({ translator }) {
|
|||||||
OPT_TRANS_OPENAI_2,
|
OPT_TRANS_OPENAI_2,
|
||||||
OPT_TRANS_OPENAI_3,
|
OPT_TRANS_OPENAI_3,
|
||||||
OPT_TRANS_GEMINI,
|
OPT_TRANS_GEMINI,
|
||||||
|
OPT_TRANS_GEMINI_2,
|
||||||
|
OPT_TRANS_CLAUDE,
|
||||||
OPT_TRANS_CLOUDFLAREAI,
|
OPT_TRANS_CLOUDFLAREAI,
|
||||||
OPT_TRANS_OLLAMA,
|
OPT_TRANS_OLLAMA,
|
||||||
OPT_TRANS_OLLAMA_2,
|
OPT_TRANS_OLLAMA_2,
|
||||||
OPT_TRANS_OLLAMA_3,
|
OPT_TRANS_OLLAMA_3,
|
||||||
OPT_TRANS_NIUTRANS,
|
OPT_TRANS_NIUTRANS,
|
||||||
|
OPT_TRANS_CUSTOMIZE,
|
||||||
|
OPT_TRANS_CUSTOMIZE_2,
|
||||||
|
OPT_TRANS_CUSTOMIZE_3,
|
||||||
|
OPT_TRANS_CUSTOMIZE_4,
|
||||||
|
OPT_TRANS_CUSTOMIZE_5,
|
||||||
];
|
];
|
||||||
|
|
||||||
const keyHelper =
|
const keyHelper =
|
||||||
@@ -174,6 +212,14 @@ function ApiFields({ translator }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack spacing={3}>
|
<Stack spacing={3}>
|
||||||
|
<TextField
|
||||||
|
size="small"
|
||||||
|
label={i18n("api_name")}
|
||||||
|
name="apiName"
|
||||||
|
value={apiName}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
|
||||||
{!builtinTranslators.includes(translator) && (
|
{!builtinTranslators.includes(translator) && (
|
||||||
<>
|
<>
|
||||||
<TextField
|
<TextField
|
||||||
@@ -203,7 +249,8 @@ function ApiFields({ translator }) {
|
|||||||
|
|
||||||
{(translator.startsWith(OPT_TRANS_OPENAI) ||
|
{(translator.startsWith(OPT_TRANS_OPENAI) ||
|
||||||
translator.startsWith(OPT_TRANS_OLLAMA) ||
|
translator.startsWith(OPT_TRANS_OLLAMA) ||
|
||||||
translator === OPT_TRANS_GEMINI) && (
|
translator === OPT_TRANS_CLAUDE ||
|
||||||
|
translator.startsWith(OPT_TRANS_GEMINI)) && (
|
||||||
<>
|
<>
|
||||||
<TextField
|
<TextField
|
||||||
size="small"
|
size="small"
|
||||||
@@ -214,13 +261,94 @@ function ApiFields({ translator }) {
|
|||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
size="small"
|
size="small"
|
||||||
label={"PROMPT"}
|
label={"SYSTEM PROMPT"}
|
||||||
name="prompt"
|
name="systemPrompt"
|
||||||
value={prompt}
|
value={systemPrompt}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
multiline
|
multiline
|
||||||
maxRows={10}
|
maxRows={10}
|
||||||
/>
|
/>
|
||||||
|
<TextField
|
||||||
|
size="small"
|
||||||
|
label={"USER PROMPT"}
|
||||||
|
name="userPrompt"
|
||||||
|
value={userPrompt}
|
||||||
|
onChange={handleChange}
|
||||||
|
multiline
|
||||||
|
maxRows={10}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{translator.startsWith(OPT_TRANS_OLLAMA) && (
|
||||||
|
<>
|
||||||
|
<TextField
|
||||||
|
select
|
||||||
|
size="small"
|
||||||
|
name="think"
|
||||||
|
value={think}
|
||||||
|
label={i18n("if_think")}
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
<MenuItem value={false}>{i18n("nothink")}</MenuItem>
|
||||||
|
<MenuItem value={true}>{i18n("think")}</MenuItem>
|
||||||
|
</TextField>
|
||||||
|
<TextField
|
||||||
|
size="small"
|
||||||
|
label={i18n("think_ignore")}
|
||||||
|
name="thinkIgnore"
|
||||||
|
value={thinkIgnore}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{(translator.startsWith(OPT_TRANS_OPENAI) ||
|
||||||
|
translator === OPT_TRANS_CLAUDE ||
|
||||||
|
translator === OPT_TRANS_GEMINI) && (
|
||||||
|
<>
|
||||||
|
<TextField
|
||||||
|
size="small"
|
||||||
|
label={"Temperature"}
|
||||||
|
type="number"
|
||||||
|
name="temperature"
|
||||||
|
value={temperature}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
size="small"
|
||||||
|
label={"Max Tokens"}
|
||||||
|
type="number"
|
||||||
|
name="maxTokens"
|
||||||
|
value={maxTokens}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{translator === OPT_TRANS_GEMINI_2 && (
|
||||||
|
<>
|
||||||
|
<TextField
|
||||||
|
size="small"
|
||||||
|
label="Temperature"
|
||||||
|
type="number"
|
||||||
|
name="temperature"
|
||||||
|
value={temperature}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
select
|
||||||
|
size="small"
|
||||||
|
name="reasoningEffort"
|
||||||
|
value={reasoningEffort}
|
||||||
|
label="Reasoning Effort"
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
<MenuItem value={"none"}>none</MenuItem>
|
||||||
|
<MenuItem value={"low"}>low</MenuItem>
|
||||||
|
<MenuItem value={"medium"}>medium</MenuItem>
|
||||||
|
<MenuItem value={"high"}>high</MenuItem>
|
||||||
|
</TextField>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -244,15 +372,26 @@ function ApiFields({ translator }) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{translator.startsWith(OPT_TRANS_CUSTOMIZE) && (
|
{translator.startsWith(OPT_TRANS_CUSTOMIZE) && (
|
||||||
<TextField
|
<>
|
||||||
size="small"
|
<TextField
|
||||||
label={i18n("custom_option")}
|
size="small"
|
||||||
name="customOption"
|
label={"Request Hook"}
|
||||||
value={customOption}
|
name="reqHook"
|
||||||
onChange={handleChange}
|
value={reqHook}
|
||||||
multiline
|
onChange={handleChange}
|
||||||
maxRows={10}
|
multiline
|
||||||
/>
|
maxRows={10}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
size="small"
|
||||||
|
label={"Response Hook"}
|
||||||
|
name="resHook"
|
||||||
|
value={resHook}
|
||||||
|
onChange={handleChange}
|
||||||
|
multiline
|
||||||
|
maxRows={10}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
@@ -273,6 +412,29 @@ function ApiFields({ translator }) {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
size="small"
|
||||||
|
label={i18n("http_timeout")}
|
||||||
|
type="number"
|
||||||
|
name="httpTimeout"
|
||||||
|
defaultValue={httpTimeout}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Switch
|
||||||
|
size="small"
|
||||||
|
name="isDisabled"
|
||||||
|
checked={isDisabled}
|
||||||
|
onChange={() => {
|
||||||
|
updateApi({ isDisabled: !isDisabled });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={i18n("is_disabled")}
|
||||||
|
/>
|
||||||
|
|
||||||
<Stack direction="row" spacing={2}>
|
<Stack direction="row" spacing={2}>
|
||||||
<TestButton translator={translator} api={api} />
|
<TestButton translator={translator} api={api} />
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -96,9 +96,7 @@ export default function FavWords() {
|
|||||||
.join(" "),
|
.join(" "),
|
||||||
dictResult.content[0].mean
|
dictResult.content[0].mean
|
||||||
.map(({ pre, cont }) => {
|
.map(({ pre, cont }) => {
|
||||||
return ` - ${pre ? `[${pre}] ` : ""}${Object.keys(cont).join(
|
return ` - ${pre ? `[${pre}] ` : ""}${Object.keys(cont).join("; ")}`;
|
||||||
"; "
|
|
||||||
)}`;
|
|
||||||
})
|
})
|
||||||
.join("\n"),
|
.join("\n"),
|
||||||
].join("\n\n")
|
].join("\n\n")
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ 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";
|
||||||
@@ -93,10 +94,14 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
transTiming = OPT_TIMING_PAGESCROLL,
|
transTiming = OPT_TIMING_PAGESCROLL,
|
||||||
transTag = DEFAULT_TRANS_TAG,
|
transTag = DEFAULT_TRANS_TAG,
|
||||||
transTitle = "false",
|
transTitle = "false",
|
||||||
|
transSelected = "true",
|
||||||
detectRemote = "false",
|
detectRemote = "false",
|
||||||
skipLangs = [],
|
skipLangs = [],
|
||||||
fixerSelector = "",
|
fixerSelector = "",
|
||||||
fixerFunc = "-",
|
fixerFunc = "-",
|
||||||
|
transStartHook = "",
|
||||||
|
transEndHook = "",
|
||||||
|
transRemoveHook = "",
|
||||||
} = formValues;
|
} = formValues;
|
||||||
|
|
||||||
const hasSamePattern = (str) => {
|
const hasSamePattern = (str) => {
|
||||||
@@ -177,6 +182,30 @@ 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}>
|
||||||
@@ -339,95 +368,139 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<Box>
|
||||||
|
<Grid container spacing={2} columns={12}>
|
||||||
|
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||||
|
<TextField
|
||||||
|
select
|
||||||
|
size="small"
|
||||||
|
fullWidth
|
||||||
|
name="transOnly"
|
||||||
|
value={transOnly}
|
||||||
|
label={i18n("show_only_translations")}
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
{GlobalItem}
|
||||||
|
<MenuItem value={"false"}>{i18n("disable")}</MenuItem>
|
||||||
|
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
||||||
|
</TextField>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||||
|
<TextField
|
||||||
|
select
|
||||||
|
size="small"
|
||||||
|
fullWidth
|
||||||
|
name="transTiming"
|
||||||
|
value={transTiming}
|
||||||
|
label={i18n("trigger_mode")}
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
{GlobalItem}
|
||||||
|
{OPT_TIMING_ALL.map((item) => (
|
||||||
|
<MenuItem key={item} value={item}>
|
||||||
|
{i18n(item)}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</TextField>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||||
|
<TextField
|
||||||
|
select
|
||||||
|
size="small"
|
||||||
|
fullWidth
|
||||||
|
name="transTag"
|
||||||
|
value={transTag}
|
||||||
|
label={i18n("translation_element_tag")}
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
{GlobalItem}
|
||||||
|
<MenuItem value={"span"}>{`<span>`}</MenuItem>
|
||||||
|
<MenuItem value={"font"}>{`<font>`}</MenuItem>
|
||||||
|
</TextField>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||||
|
<TextField
|
||||||
|
select
|
||||||
|
size="small"
|
||||||
|
fullWidth
|
||||||
|
name="transTitle"
|
||||||
|
value={transTitle}
|
||||||
|
label={i18n("translate_page_title")}
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
{GlobalItem}
|
||||||
|
<MenuItem value={"false"}>{i18n("disable")}</MenuItem>
|
||||||
|
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
||||||
|
</TextField>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||||
|
<TextField
|
||||||
|
select
|
||||||
|
size="small"
|
||||||
|
fullWidth
|
||||||
|
name="transSelected"
|
||||||
|
value={transSelected}
|
||||||
|
label={i18n("translate_selected")}
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
{GlobalItem}
|
||||||
|
<MenuItem value={"false"}>{i18n("disable")}</MenuItem>
|
||||||
|
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
||||||
|
</TextField>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||||
|
<TextField
|
||||||
|
select
|
||||||
|
size="small"
|
||||||
|
fullWidth
|
||||||
|
name="detectRemote"
|
||||||
|
value={detectRemote}
|
||||||
|
label={i18n("detect_lang_remote")}
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
{GlobalItem}
|
||||||
|
<MenuItem value={"false"}>{i18n("disable")}</MenuItem>
|
||||||
|
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
||||||
|
</TextField>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
|
||||||
{showMore && (
|
{showMore && (
|
||||||
<>
|
<>
|
||||||
<Box>
|
<TextField
|
||||||
<Grid container spacing={2} columns={12}>
|
size="small"
|
||||||
<Grid item xs={12} sm={6} md={3} lg={2}>
|
label={i18n("fixer_selector")}
|
||||||
<TextField
|
name="fixerSelector"
|
||||||
select
|
value={fixerSelector}
|
||||||
size="small"
|
disabled={disabled}
|
||||||
fullWidth
|
onChange={handleChange}
|
||||||
name="transOnly"
|
multiline
|
||||||
value={transOnly}
|
maxRows={10}
|
||||||
label={i18n("show_only_translations")}
|
/>
|
||||||
disabled={disabled}
|
<TextField
|
||||||
onChange={handleChange}
|
select
|
||||||
>
|
size="small"
|
||||||
{GlobalItem}
|
name="fixerFunc"
|
||||||
<MenuItem value={"false"}>{i18n("disable")}</MenuItem>
|
value={fixerFunc}
|
||||||
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
label={i18n("fixer_function")}
|
||||||
</TextField>
|
helperText={i18n("fixer_function_helper")}
|
||||||
</Grid>
|
disabled={disabled}
|
||||||
<Grid item xs={12} sm={6} md={3} lg={2}>
|
onChange={handleChange}
|
||||||
<TextField
|
>
|
||||||
select
|
{GlobalItem}
|
||||||
size="small"
|
{FIXER_ALL.map((item) => (
|
||||||
fullWidth
|
<MenuItem key={item} value={item}>
|
||||||
name="transTiming"
|
{item}
|
||||||
value={transTiming}
|
</MenuItem>
|
||||||
label={i18n("trigger_mode")}
|
))}
|
||||||
disabled={disabled}
|
</TextField>
|
||||||
onChange={handleChange}
|
|
||||||
>
|
|
||||||
{GlobalItem}
|
|
||||||
{OPT_TIMING_ALL.map((item) => (
|
|
||||||
<MenuItem key={item} value={item}>
|
|
||||||
{i18n(item)}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</TextField>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={12} sm={6} md={3} lg={2}>
|
|
||||||
<TextField
|
|
||||||
select
|
|
||||||
size="small"
|
|
||||||
fullWidth
|
|
||||||
name="transTag"
|
|
||||||
value={transTag}
|
|
||||||
label={i18n("translation_element_tag")}
|
|
||||||
disabled={disabled}
|
|
||||||
onChange={handleChange}
|
|
||||||
>
|
|
||||||
{GlobalItem}
|
|
||||||
<MenuItem value={"span"}>{`<span>`}</MenuItem>
|
|
||||||
<MenuItem value={"font"}>{`<font>`}</MenuItem>
|
|
||||||
</TextField>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={12} sm={6} md={3} lg={2}>
|
|
||||||
<TextField
|
|
||||||
select
|
|
||||||
size="small"
|
|
||||||
fullWidth
|
|
||||||
name="transTitle"
|
|
||||||
value={transTitle}
|
|
||||||
label={i18n("translate_page_title")}
|
|
||||||
disabled={disabled}
|
|
||||||
onChange={handleChange}
|
|
||||||
>
|
|
||||||
{GlobalItem}
|
|
||||||
<MenuItem value={"false"}>{i18n("disable")}</MenuItem>
|
|
||||||
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
|
||||||
</TextField>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={12} sm={6} md={3} lg={2}>
|
|
||||||
<TextField
|
|
||||||
select
|
|
||||||
size="small"
|
|
||||||
fullWidth
|
|
||||||
name="detectRemote"
|
|
||||||
value={detectRemote}
|
|
||||||
label={i18n("detect_lang_remote")}
|
|
||||||
disabled={disabled}
|
|
||||||
onChange={handleChange}
|
|
||||||
>
|
|
||||||
{GlobalItem}
|
|
||||||
<MenuItem value={"false"}>{i18n("disable")}</MenuItem>
|
|
||||||
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
|
||||||
</TextField>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
@@ -458,34 +531,42 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
multiline
|
multiline
|
||||||
|
maxRows={10}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
size="small"
|
size="small"
|
||||||
label={i18n("fixer_selector")}
|
label={i18n("translate_start_hook")}
|
||||||
name="fixerSelector"
|
helperText={i18n("translate_start_hook_helper")}
|
||||||
value={fixerSelector}
|
name="transStartHook"
|
||||||
|
value={transStartHook}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
multiline
|
multiline
|
||||||
|
maxRows={10}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
|
||||||
size="small"
|
size="small"
|
||||||
name="fixerFunc"
|
label={i18n("translate_end_hook")}
|
||||||
value={fixerFunc}
|
helperText={i18n("translate_end_hook_helper")}
|
||||||
label={i18n("fixer_function")}
|
name="transEndHook"
|
||||||
helperText={i18n("fixer_function_helper")}
|
value={transEndHook}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
>
|
multiline
|
||||||
{GlobalItem}
|
maxRows={10}
|
||||||
{FIXER_ALL.map((item) => (
|
/>
|
||||||
<MenuItem key={item} value={item}>
|
<TextField
|
||||||
{item}
|
size="small"
|
||||||
</MenuItem>
|
label={i18n("translate_remove_hook")}
|
||||||
))}
|
helperText={i18n("translate_remove_hook_helper")}
|
||||||
</TextField>
|
name="transRemoveHook"
|
||||||
|
value={transRemoveHook}
|
||||||
|
disabled={disabled}
|
||||||
|
onChange={handleChange}
|
||||||
|
multiline
|
||||||
|
maxRows={10}
|
||||||
|
/>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
size="small"
|
size="small"
|
||||||
@@ -564,18 +645,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
{i18n("delete")}
|
{i18n("delete")}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{!showMore && (
|
{ShowMoreButton}
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
variant="text"
|
|
||||||
onClick={() => {
|
|
||||||
setShowMore(true);
|
|
||||||
}}
|
|
||||||
startIcon={<ExpandMoreIcon />}
|
|
||||||
>
|
|
||||||
{i18n("more")}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
@@ -595,18 +665,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
>
|
>
|
||||||
{i18n("cancel")}
|
{i18n("cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
{!showMore && (
|
{ShowMoreButton}
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
variant="text"
|
|
||||||
onClick={() => {
|
|
||||||
setShowMore(true);
|
|
||||||
}}
|
|
||||||
startIcon={<ExpandMoreIcon />}
|
|
||||||
>
|
|
||||||
{i18n("more")}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -629,17 +688,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
>
|
>
|
||||||
{i18n("cancel")}
|
{i18n("cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
{!showMore && (
|
{ShowMoreButton}
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
variant="text"
|
|
||||||
onClick={() => {
|
|
||||||
setShowMore(true);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{i18n("more")}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</Stack>
|
</Stack>
|
||||||
))}
|
))}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import {
|
|||||||
UI_LANGS,
|
UI_LANGS,
|
||||||
TRANS_NEWLINE_LENGTH,
|
TRANS_NEWLINE_LENGTH,
|
||||||
CACHE_NAME,
|
CACHE_NAME,
|
||||||
|
OPT_TRANS_MICROSOFT,
|
||||||
|
OPT_LANGDETECTOR_ALL,
|
||||||
OPT_SHORTCUT_TRANSLATE,
|
OPT_SHORTCUT_TRANSLATE,
|
||||||
OPT_SHORTCUT_STYLE,
|
OPT_SHORTCUT_STYLE,
|
||||||
OPT_SHORTCUT_POPUP,
|
OPT_SHORTCUT_POPUP,
|
||||||
@@ -25,12 +27,15 @@ import {
|
|||||||
DEFAULT_CSPLIST,
|
DEFAULT_CSPLIST,
|
||||||
MSG_CONTEXT_MENUS,
|
MSG_CONTEXT_MENUS,
|
||||||
MSG_UPDATE_CSP,
|
MSG_UPDATE_CSP,
|
||||||
|
DEFAULT_HTTP_TIMEOUT,
|
||||||
} from "../../config";
|
} from "../../config";
|
||||||
import { useShortcut } from "../../hooks/Shortcut";
|
import { useShortcut } from "../../hooks/Shortcut";
|
||||||
import ShortcutInput from "./ShortcutInput";
|
import ShortcutInput from "./ShortcutInput";
|
||||||
import { useFab } from "../../hooks/Fab";
|
import { useFab } from "../../hooks/Fab";
|
||||||
import { sendBgMsg } from "../../libs/msg";
|
import { sendBgMsg } from "../../libs/msg";
|
||||||
import { kissLog } from "../../libs/log";
|
import { kissLog } from "../../libs/log";
|
||||||
|
import UploadButton from "./UploadButton";
|
||||||
|
import DownloadButton from "./DownloadButton";
|
||||||
|
|
||||||
function ShortcutItem({ action, label }) {
|
function ShortcutItem({ action, label }) {
|
||||||
const { shortcut, setShortcut } = useShortcut(action);
|
const { shortcut, setShortcut } = useShortcut(action);
|
||||||
@@ -67,6 +72,9 @@ export default function Settings() {
|
|||||||
case "newlineLength":
|
case "newlineLength":
|
||||||
value = limitNumber(value, 1, 1000);
|
value = limitNumber(value, 1, 1000);
|
||||||
break;
|
break;
|
||||||
|
case "httpTimeout":
|
||||||
|
value = limitNumber(value, 5000, 30000);
|
||||||
|
break;
|
||||||
case "touchTranslate":
|
case "touchTranslate":
|
||||||
value = limitNumber(value, 0, 4);
|
value = limitNumber(value, 0, 4);
|
||||||
break;
|
break;
|
||||||
@@ -92,23 +100,48 @@ export default function Settings() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleImport = async (data) => {
|
||||||
|
try {
|
||||||
|
await updateSetting(JSON.parse(data));
|
||||||
|
} catch (err) {
|
||||||
|
kissLog(err, "import setting");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const {
|
const {
|
||||||
uiLang,
|
uiLang,
|
||||||
minLength,
|
minLength,
|
||||||
maxLength,
|
maxLength,
|
||||||
clearCache,
|
clearCache,
|
||||||
newlineLength = TRANS_NEWLINE_LENGTH,
|
newlineLength = TRANS_NEWLINE_LENGTH,
|
||||||
|
httpTimeout = DEFAULT_HTTP_TIMEOUT,
|
||||||
contextMenuType = 1,
|
contextMenuType = 1,
|
||||||
touchTranslate = 2,
|
touchTranslate = 2,
|
||||||
blacklist = DEFAULT_BLACKLIST.join(",\n"),
|
blacklist = DEFAULT_BLACKLIST.join(",\n"),
|
||||||
csplist = DEFAULT_CSPLIST.join(",\n"),
|
csplist = DEFAULT_CSPLIST.join(",\n"),
|
||||||
transInterval = 500,
|
transInterval = 500,
|
||||||
|
langDetector = OPT_TRANS_MICROSOFT,
|
||||||
} = setting;
|
} = setting;
|
||||||
const { isHide = false } = fab || {};
|
const { isHide = false } = fab || {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Stack spacing={3}>
|
<Stack spacing={3}>
|
||||||
|
<Stack
|
||||||
|
direction="row"
|
||||||
|
alignItems="center"
|
||||||
|
spacing={2}
|
||||||
|
useFlexGap
|
||||||
|
flexWrap="wrap"
|
||||||
|
>
|
||||||
|
<UploadButton text={i18n("import")} handleImport={handleImport} />
|
||||||
|
<DownloadButton
|
||||||
|
handleData={() => JSON.stringify(setting, null, 2)}
|
||||||
|
text={i18n("export")}
|
||||||
|
fileName={`kiss-setting_${Date.now()}.json`}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
<FormControl size="small">
|
<FormControl size="small">
|
||||||
<InputLabel>{i18n("ui_lang")}</InputLabel>
|
<InputLabel>{i18n("ui_lang")}</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
@@ -160,7 +193,14 @@ export default function Settings() {
|
|||||||
defaultValue={transInterval}
|
defaultValue={transInterval}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
|
<TextField
|
||||||
|
size="small"
|
||||||
|
label={i18n("http_timeout")}
|
||||||
|
type="number"
|
||||||
|
name="httpTimeout"
|
||||||
|
defaultValue={httpTimeout}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
<FormControl size="small">
|
<FormControl size="small">
|
||||||
<InputLabel>{i18n("touch_translate_shortcut")}</InputLabel>
|
<InputLabel>{i18n("touch_translate_shortcut")}</InputLabel>
|
||||||
<Select
|
<Select
|
||||||
@@ -206,6 +246,22 @@ export default function Settings() {
|
|||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
|
<FormControl size="small">
|
||||||
|
<InputLabel>{i18n("detect_lang_remote")}</InputLabel>
|
||||||
|
<Select
|
||||||
|
name="langDetector"
|
||||||
|
value={langDetector}
|
||||||
|
label={i18n("detect_lang_remote")}
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
{OPT_LANGDETECTOR_ALL.map((item) => (
|
||||||
|
<MenuItem value={item} key={item}>
|
||||||
|
{item}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
|
||||||
{isExt ? (
|
{isExt ? (
|
||||||
<>
|
<>
|
||||||
<FormControl size="small">
|
<FormControl size="small">
|
||||||
|
|||||||
@@ -9,10 +9,9 @@ import {
|
|||||||
OPT_LANGS_TO,
|
OPT_LANGS_TO,
|
||||||
OPT_TRANBOX_TRIGGER_CLICK,
|
OPT_TRANBOX_TRIGGER_CLICK,
|
||||||
OPT_TRANBOX_TRIGGER_ALL,
|
OPT_TRANBOX_TRIGGER_ALL,
|
||||||
|
OPT_DICT_BAIDU,
|
||||||
} from "../../config";
|
} from "../../config";
|
||||||
import ShortcutInput from "./ShortcutInput";
|
import ShortcutInput from "./ShortcutInput";
|
||||||
import FormControlLabel from "@mui/material/FormControlLabel";
|
|
||||||
import Switch from "@mui/material/Switch";
|
|
||||||
import { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
import { limitNumber } from "../../libs/utils";
|
import { limitNumber } from "../../libs/utils";
|
||||||
import { useTranbox } from "../../hooks/Tranbox";
|
import { useTranbox } from "../../hooks/Tranbox";
|
||||||
@@ -47,7 +46,6 @@ export default function Tranbox() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
transOpen,
|
|
||||||
translator,
|
translator,
|
||||||
fromLang,
|
fromLang,
|
||||||
toLang,
|
toLang,
|
||||||
@@ -63,25 +61,12 @@ export default function Tranbox() {
|
|||||||
followSelection = false,
|
followSelection = false,
|
||||||
triggerMode = OPT_TRANBOX_TRIGGER_CLICK,
|
triggerMode = OPT_TRANBOX_TRIGGER_CLICK,
|
||||||
extStyles = "",
|
extStyles = "",
|
||||||
|
enDict = OPT_DICT_BAIDU,
|
||||||
} = tranboxSetting;
|
} = tranboxSetting;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Stack spacing={3}>
|
<Stack spacing={3}>
|
||||||
<FormControlLabel
|
|
||||||
control={
|
|
||||||
<Switch
|
|
||||||
size="small"
|
|
||||||
name="transOpen"
|
|
||||||
checked={transOpen}
|
|
||||||
onChange={() => {
|
|
||||||
updateTranbox({ transOpen: !transOpen });
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label={i18n("toggle_selection_translate")}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
size="small"
|
size="small"
|
||||||
@@ -143,6 +128,18 @@ export default function Tranbox() {
|
|||||||
))}
|
))}
|
||||||
</TextField>
|
</TextField>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
select
|
||||||
|
size="small"
|
||||||
|
name="enDict"
|
||||||
|
value={enDict}
|
||||||
|
label={i18n("english_dict")}
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
<MenuItem value={"-"}>{i18n("disable")}</MenuItem>
|
||||||
|
<MenuItem value={OPT_DICT_BAIDU}>{OPT_DICT_BAIDU}</MenuItem>
|
||||||
|
</TextField>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
size="small"
|
size="small"
|
||||||
label={i18n("tranbtn_offset_x")}
|
label={i18n("tranbtn_offset_x")}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect, useMemo } from "react";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import Stack from "@mui/material/Stack";
|
import Stack from "@mui/material/Stack";
|
||||||
import MenuItem from "@mui/material/MenuItem";
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
OPT_LANGS_FROM,
|
OPT_LANGS_FROM,
|
||||||
OPT_LANGS_TO,
|
OPT_LANGS_TO,
|
||||||
OPT_STYLE_ALL,
|
OPT_STYLE_ALL,
|
||||||
|
DEFAULT_TRANS_APIS,
|
||||||
} from "../../config";
|
} from "../../config";
|
||||||
import { sendIframeMsg } from "../../libs/iframe";
|
import { sendIframeMsg } from "../../libs/iframe";
|
||||||
import { saveRule } from "../../libs/rules";
|
import { saveRule } from "../../libs/rules";
|
||||||
@@ -32,6 +33,7 @@ import { kissLog } from "../../libs/log";
|
|||||||
export default function Popup({ setShowPopup, translator: tran }) {
|
export default function Popup({ setShowPopup, translator: tran }) {
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
const [rule, setRule] = useState(tran?.rule);
|
const [rule, setRule] = useState(tran?.rule);
|
||||||
|
const [transApis, setTransApis] = useState(tran?.setting?.transApis || []);
|
||||||
const [commands, setCommands] = useState({});
|
const [commands, setCommands] = useState({});
|
||||||
|
|
||||||
const handleOpenSetting = () => {
|
const handleOpenSetting = () => {
|
||||||
@@ -106,7 +108,8 @@ export default function Popup({ setShowPopup, translator: tran }) {
|
|||||||
try {
|
try {
|
||||||
const res = await sendTabMsg(MSG_TRANS_GETRULE);
|
const res = await sendTabMsg(MSG_TRANS_GETRULE);
|
||||||
if (!res.error) {
|
if (!res.error) {
|
||||||
setRule(res.data);
|
setRule(res.rule);
|
||||||
|
setTransApis(res.setting.transApis);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
kissLog(err, "query rule");
|
kissLog(err, "query rule");
|
||||||
@@ -138,6 +141,20 @@ export default function Popup({ setShowPopup, translator: tran }) {
|
|||||||
})();
|
})();
|
||||||
}, [tran]);
|
}, [tran]);
|
||||||
|
|
||||||
|
const optApis = useMemo(
|
||||||
|
() =>
|
||||||
|
OPT_TRANS_ALL.map((key) => ({
|
||||||
|
...(transApis[key] || DEFAULT_TRANS_APIS[key]),
|
||||||
|
apiKey: key,
|
||||||
|
}))
|
||||||
|
.filter((item) => !item.isDisabled)
|
||||||
|
.map(({ apiKey, apiName }) => ({
|
||||||
|
key: apiKey,
|
||||||
|
name: apiName?.trim() || apiKey,
|
||||||
|
})),
|
||||||
|
[transApis]
|
||||||
|
);
|
||||||
|
|
||||||
if (!rule) {
|
if (!rule) {
|
||||||
return (
|
return (
|
||||||
<Box minWidth={300}>
|
<Box minWidth={300}>
|
||||||
@@ -197,9 +214,9 @@ export default function Popup({ setShowPopup, translator: tran }) {
|
|||||||
label={i18n("translate_service")}
|
label={i18n("translate_service")}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
>
|
>
|
||||||
{OPT_TRANS_ALL.map((item) => (
|
{optApis.map(({ key, name }) => (
|
||||||
<MenuItem key={item} value={item}>
|
<MenuItem key={key} value={key}>
|
||||||
{item}
|
{name}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</TextField>
|
</TextField>
|
||||||
|
|||||||
@@ -93,9 +93,7 @@ export default function DictCont({ text }) {
|
|||||||
key={key}
|
key={key}
|
||||||
style={{ display: "inline-block" }}
|
style={{ display: "inline-block" }}
|
||||||
>
|
>
|
||||||
<Typography component="span">{`${
|
<Typography component="span">{`${PHONIC_MAP[key]?.[0] || key} ${val}`}</Typography>
|
||||||
PHONIC_MAP[key]?.[0] || key
|
|
||||||
} ${val}`}</Typography>
|
|
||||||
<AudioBtn text={dictResult.src} lan={PHONIC_MAP[key]?.[1]} />
|
<AudioBtn text={dictResult.src} lan={PHONIC_MAP[key]?.[1]} />
|
||||||
</Typography>
|
</Typography>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -18,8 +18,13 @@ import LockIcon from "@mui/icons-material/Lock";
|
|||||||
import LockOpenIcon from "@mui/icons-material/LockOpen";
|
import LockOpenIcon from "@mui/icons-material/LockOpen";
|
||||||
import CloseIcon from "@mui/icons-material/Close";
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
import { useI18n } from "../../hooks/I18n";
|
import { useI18n } from "../../hooks/I18n";
|
||||||
import { OPT_TRANS_ALL, OPT_LANGS_FROM, OPT_LANGS_TO } from "../../config";
|
import {
|
||||||
import { useState, useRef } from "react";
|
OPT_TRANS_ALL,
|
||||||
|
OPT_LANGS_FROM,
|
||||||
|
OPT_LANGS_TO,
|
||||||
|
DEFAULT_TRANS_APIS,
|
||||||
|
} from "../../config";
|
||||||
|
import { useState, useRef, useMemo } from "react";
|
||||||
import TranCont from "./TranCont";
|
import TranCont from "./TranCont";
|
||||||
import DictCont from "./DictCont";
|
import DictCont from "./DictCont";
|
||||||
import SugCont from "./SugCont";
|
import SugCont from "./SugCont";
|
||||||
@@ -101,7 +106,15 @@ function Header({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function TranForm({ text, setText, tranboxSetting, transApis, simpleStyle }) {
|
function TranForm({
|
||||||
|
text,
|
||||||
|
setText,
|
||||||
|
tranboxSetting,
|
||||||
|
transApis,
|
||||||
|
simpleStyle,
|
||||||
|
langDetector,
|
||||||
|
enDict,
|
||||||
|
}) {
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
const [editMode, setEditMode] = useState(false);
|
const [editMode, setEditMode] = useState(false);
|
||||||
@@ -111,6 +124,20 @@ function TranForm({ text, setText, tranboxSetting, transApis, simpleStyle }) {
|
|||||||
const [toLang, setToLang] = useState(tranboxSetting.toLang);
|
const [toLang, setToLang] = useState(tranboxSetting.toLang);
|
||||||
const inputRef = useRef(null);
|
const inputRef = useRef(null);
|
||||||
|
|
||||||
|
const optApis = useMemo(
|
||||||
|
() =>
|
||||||
|
OPT_TRANS_ALL.map((key) => ({
|
||||||
|
...(transApis[key] || DEFAULT_TRANS_APIS[key]),
|
||||||
|
apiKey: key,
|
||||||
|
}))
|
||||||
|
.filter((item) => !item.isDisabled)
|
||||||
|
.map(({ apiKey, apiName }) => ({
|
||||||
|
key: apiKey,
|
||||||
|
name: apiName?.trim() || apiKey,
|
||||||
|
})),
|
||||||
|
[transApis]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack
|
<Stack
|
||||||
className="KT-transbox-container"
|
className="KT-transbox-container"
|
||||||
@@ -174,9 +201,9 @@ function TranForm({ text, setText, tranboxSetting, transApis, simpleStyle }) {
|
|||||||
setTranslator(e.target.value);
|
setTranslator(e.target.value);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{OPT_TRANS_ALL.map((item) => (
|
{optApis.map(({ key, name }) => (
|
||||||
<MenuItem key={item} value={item}>
|
<MenuItem key={key} value={key}>
|
||||||
{item}
|
{name}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</TextField>
|
</TextField>
|
||||||
@@ -233,7 +260,10 @@ function TranForm({ text, setText, tranboxSetting, transApis, simpleStyle }) {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{(!simpleStyle || !isValidWord(text) || !toLang.startsWith("zh")) && (
|
{(!simpleStyle ||
|
||||||
|
!isValidWord(text) ||
|
||||||
|
!toLang.startsWith("zh") ||
|
||||||
|
enDict === "-") && (
|
||||||
<TranCont
|
<TranCont
|
||||||
text={text}
|
text={text}
|
||||||
translator={translator}
|
translator={translator}
|
||||||
@@ -242,11 +272,16 @@ function TranForm({ text, setText, tranboxSetting, transApis, simpleStyle }) {
|
|||||||
toLang2={tranboxSetting.toLang2}
|
toLang2={tranboxSetting.toLang2}
|
||||||
transApis={transApis}
|
transApis={transApis}
|
||||||
simpleStyle={simpleStyle}
|
simpleStyle={simpleStyle}
|
||||||
|
langDetector={langDetector}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<DictCont text={text} />
|
{enDict !== "-" && (
|
||||||
<SugCont text={text} />
|
<>
|
||||||
|
<DictCont text={text} />
|
||||||
|
<SugCont text={text} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -268,6 +303,8 @@ export default function TranBox({
|
|||||||
followSelection,
|
followSelection,
|
||||||
setFollowSelection,
|
setFollowSelection,
|
||||||
extStyles,
|
extStyles,
|
||||||
|
langDetector,
|
||||||
|
enDict,
|
||||||
}) {
|
}) {
|
||||||
const [mouseHover, setMouseHover] = useState(false);
|
const [mouseHover, setMouseHover] = useState(false);
|
||||||
return (
|
return (
|
||||||
@@ -300,6 +337,8 @@ export default function TranBox({
|
|||||||
tranboxSetting={tranboxSetting}
|
tranboxSetting={tranboxSetting}
|
||||||
transApis={transApis}
|
transApis={transApis}
|
||||||
simpleStyle={simpleStyle}
|
simpleStyle={simpleStyle}
|
||||||
|
langDetector={langDetector}
|
||||||
|
enDict={enDict}
|
||||||
/>
|
/>
|
||||||
</DraggableResizable>
|
</DraggableResizable>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ import Stack from "@mui/material/Stack";
|
|||||||
import { useI18n } from "../../hooks/I18n";
|
import { useI18n } from "../../hooks/I18n";
|
||||||
import { DEFAULT_TRANS_APIS } from "../../config";
|
import { DEFAULT_TRANS_APIS } from "../../config";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { apiTranslate, apiBaiduLangdetect } from "../../apis";
|
import { apiTranslate } from "../../apis";
|
||||||
import CopyBtn from "./CopyBtn";
|
import CopyBtn from "./CopyBtn";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import Alert from "@mui/material/Alert";
|
import Alert from "@mui/material/Alert";
|
||||||
|
import { tryDetectLang } from "../../libs";
|
||||||
|
|
||||||
export default function TranCont({
|
export default function TranCont({
|
||||||
text,
|
text,
|
||||||
@@ -18,6 +19,7 @@ export default function TranCont({
|
|||||||
toLang2 = "en",
|
toLang2 = "en",
|
||||||
transApis,
|
transApis,
|
||||||
simpleStyle,
|
simpleStyle,
|
||||||
|
langDetector,
|
||||||
}) {
|
}) {
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
const [trText, setTrText] = useState("");
|
const [trText, setTrText] = useState("");
|
||||||
@@ -32,8 +34,8 @@ export default function TranCont({
|
|||||||
setError("");
|
setError("");
|
||||||
|
|
||||||
let to = toLang;
|
let to = toLang;
|
||||||
if (toLang !== toLang2 && toLang2 !== "none") {
|
if (fromLang === "auto" && toLang !== toLang2 && toLang2 !== "none") {
|
||||||
const detectLang = await apiBaiduLangdetect(text);
|
const detectLang = await tryDetectLang(text, true, langDetector);
|
||||||
if (detectLang === toLang) {
|
if (detectLang === toLang) {
|
||||||
to = toLang2;
|
to = toLang2;
|
||||||
}
|
}
|
||||||
@@ -55,7 +57,7 @@ export default function TranCont({
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
}, [text, translator, fromLang, toLang, toLang2, transApis]);
|
}, [text, translator, fromLang, toLang, toLang2, transApis, langDetector]);
|
||||||
|
|
||||||
if (simpleStyle) {
|
if (simpleStyle) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
OPT_TRANBOX_TRIGGER_CLICK,
|
OPT_TRANBOX_TRIGGER_CLICK,
|
||||||
OPT_TRANBOX_TRIGGER_HOVER,
|
OPT_TRANBOX_TRIGGER_HOVER,
|
||||||
OPT_TRANBOX_TRIGGER_SELECT,
|
OPT_TRANBOX_TRIGGER_SELECT,
|
||||||
|
OPT_DICT_BAIDU,
|
||||||
} from "../../config";
|
} from "../../config";
|
||||||
import { isMobile } from "../../libs/mobile";
|
import { isMobile } from "../../libs/mobile";
|
||||||
import { kissLog } from "../../libs/log";
|
import { kissLog } from "../../libs/log";
|
||||||
@@ -20,6 +21,7 @@ export default function Slection({
|
|||||||
tranboxSetting,
|
tranboxSetting,
|
||||||
transApis,
|
transApis,
|
||||||
uiLang,
|
uiLang,
|
||||||
|
langDetector,
|
||||||
}) {
|
}) {
|
||||||
const {
|
const {
|
||||||
hideTranBtn = false,
|
hideTranBtn = false,
|
||||||
@@ -33,6 +35,7 @@ export default function Slection({
|
|||||||
btnOffsetY,
|
btnOffsetY,
|
||||||
boxOffsetX = 0,
|
boxOffsetX = 0,
|
||||||
boxOffsetY = 10,
|
boxOffsetY = 10,
|
||||||
|
enDict = OPT_DICT_BAIDU,
|
||||||
} = tranboxSetting;
|
} = tranboxSetting;
|
||||||
|
|
||||||
const boxWidth =
|
const boxWidth =
|
||||||
@@ -234,6 +237,8 @@ export default function Slection({
|
|||||||
followSelection={followSelection}
|
followSelection={followSelection}
|
||||||
setFollowSelection={setFollowSelection}
|
setFollowSelection={setFollowSelection}
|
||||||
extStyles={extStyles}
|
extStyles={extStyles}
|
||||||
|
langDetector={langDetector}
|
||||||
|
enDict={enDict}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user