Compare commits

...

7 Commits

Author SHA1 Message Date
Gabe Yuan
a8caa34bbe v1.4.6 2023-08-19 15:16:33 +08:00
Gabe Yuan
c2fd1fe9e0 fix storage bug 2023-08-19 13:48:03 +08:00
Gabe Yuan
2773a76af8 yarn install 2023-08-18 23:50:06 +08:00
Gabe Yuan
1dc7026e8f add rules generate script 2023-08-18 16:48:44 +08:00
Gabe Yuan
b36ede7393 fix userscript grant 2023-08-18 13:19:40 +08:00
Gabe Yuan
b18721a4e5 wildcard is supported 2023-08-18 13:16:17 +08:00
Gabe Yuan
01676bc682 fix fab at left default 2023-08-17 16:22:04 +08:00
16 changed files with 2547 additions and 2271 deletions

5
.babelrc Normal file
View File

@@ -0,0 +1,5 @@
{
"presets": [
"@babel/preset-env"
]
}

2
.env
View File

@@ -2,7 +2,7 @@ GENERATE_SOURCEMAP=false
REACT_APP_NAME=KISS Translator
REACT_APP_NAME_CN=简约翻译
REACT_APP_VERSION=1.4.5
REACT_APP_VERSION=1.4.6
REACT_APP_HOMEPAGE=https://github.com/fishjar/kiss-translator
REACT_APP_OPTIONSPAGE=https://kiss-translator.rayjar.com/options
REACT_APP_OPTIONSPAGE2=https://fishjar.github.io/kiss-translator/options.html

View File

@@ -83,13 +83,9 @@ const userscriptWebpack = (config, env) => {
// @icon ${process.env.REACT_APP_LOGOURL}
// @downloadURL ${process.env.REACT_APP_USERSCRIPT_DOWNLOADURL}
// @updateURL ${process.env.REACT_APP_USERSCRIPT_DOWNLOADURL}
// @grant GM_xmlhttpRequest
// @grant GM.xmlhttpRequest
// @grant GM_setValue
// @grant GM.xmlHttpRequest
// @grant GM.setValue
// @grant GM_getValue
// @grant GM.getValue
// @grant GM_deleteValue
// @grant GM.deleteValue
// @grant unsafeWindow
// @connect translate.googleapis.com

View File

@@ -1,7 +1,7 @@
{
"name": "kiss-translator",
"description": "A minimalist bilingual translation Extension & Greasemonkey Script",
"version": "1.4.5",
"version": "1.4.6",
"author": "Gabe<yugang2002@gmail.com>",
"private": true,
"dependencies": {
@@ -25,7 +25,8 @@
"build:firefox": "rm -rf build/firefox && cp -r build/chrome build/firefox && cat ./build/firefox/manifest.firefox.json > ./build/firefox/manifest.json",
"build:web": "rm -rf build/web && BUILD_PATH=./build/web REACT_APP_CLIENT=userscript react-app-rewired build",
"build:userscript": "rm -rf build/userscript && mkdir build/userscript && cp build/web/kiss-translator.user.js build/userscript/kiss-translator.user.js",
"build": "yarn build:chrome && yarn build:edge && yarn build:firefox && yarn build:web && yarn build:userscript",
"build:rules": "babel-node src/rules.js",
"build": "yarn build:chrome && yarn build:edge && yarn build:firefox && yarn build:web && yarn build:userscript && yarn build:rules",
"deploy:web": "wrangler pages deploy ./build/web --project-name kiss-translator",
"test": "react-app-rewired test",
"eject": "react-scripts eject"
@@ -53,6 +54,10 @@
]
},
"devDependencies": {
"@babel/core": "^7.22.10",
"@babel/node": "^7.22.10",
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@babel/preset-env": "^7.22.10",
"react-app-rewired": "^2.2.1",
"wrangler": "^3.4.0"
}

View File

@@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "__MSG_app_name__",
"description": "__MSG_app_description__",
"version": "1.4.5",
"version": "1.4.6",
"default_locale": "en",
"author": "Gabe<yugang2002@gmail.com>",
"homepage_url": "https://github.com/fishjar/kiss-translator",

View File

@@ -2,7 +2,7 @@
"manifest_version": 3,
"name": "__MSG_app_name__",
"description": "__MSG_app_description__",
"version": "1.4.5",
"version": "1.4.6",
"default_locale": "en",
"author": "Gabe<yugang2002@gmail.com>",
"homepage_url": "https://github.com/fishjar/kiss-translator",

View File

@@ -153,8 +153,8 @@ export const I18N = {
en: `URL pattern`,
},
pattern_helper: {
zh: `多个URL支持英文逗号“,”分隔`,
en: `Multiple URLs can be separated by English commas ","`,
zh: `1、支持星号(*)通配符。2、多个URL支持英文逗号“,”分隔`,
en: `1. The asterisk (*) wildcard is supported. 2. Multiple URLs can be separated by English commas ",".`,
},
selector_helper: {
zh: `1、遵循CSS选择器规则。2、留空表示采用全局设置。`,

View File

@@ -1,5 +1,11 @@
import { DEFAULT_SELECTOR, RULES } from "./rules";
import {
DEFAULT_SELECTOR,
GLOBAL_KEY,
DEFAULT_RULE,
BUILTIN_RULES,
} from "./rules";
export { I18N, UI_LANGS } from "./i18n";
export { GLOBAL_KEY, DEFAULT_RULE, BUILTIN_RULES };
const APP_NAME = process.env.REACT_APP_NAME.trim().split(/\s+/).join("-");
@@ -11,8 +17,6 @@ export const STOKEY_RULES = `${APP_NAME}_rules`;
export const STOKEY_SYNC = `${APP_NAME}_sync`;
export const STOKEY_FAB = `${APP_NAME}_fab`;
export const GLOBAL_KEY = "*";
export const CLIENT_WEB = "web";
export const CLIENT_CHROME = "chrome";
export const CLIENT_EDGE = "edge";
@@ -143,18 +147,6 @@ export const GLOBLA_RULE = {
bgColor: "",
};
// 默认规则
export const DEFAULT_RULE = {
pattern: "",
selector: "",
translator: GLOBAL_KEY,
fromLang: GLOBAL_KEY,
toLang: GLOBAL_KEY,
textStyle: GLOBAL_KEY,
transOpen: GLOBAL_KEY,
bgColor: "",
};
export const DEFAULT_SETTING = {
darkMode: false, // 深色模式
uiLang: "en", // 界面语言
@@ -169,20 +161,7 @@ export const DEFAULT_SETTING = {
openaiPrompt: `You will be provided with a sentence in ${PROMPT_PLACE_FROM}, and your task is to translate it into ${PROMPT_PLACE_TO}.`,
};
export const DEFAULT_RULES = [
{
...DEFAULT_RULE,
...RULES[0],
transOpen: "true",
},
GLOBLA_RULE,
];
export const BUILTIN_RULES = RULES.map((item) => ({
...DEFAULT_RULE,
...item,
transOpen: "true",
}));
export const DEFAULT_RULES = [GLOBLA_RULE];
export const TRANS_MIN_LENGTH = 5; // 最短翻译长度
export const TRANS_MAX_LENGTH = 5000; // 最长翻译长度

View File

@@ -2,7 +2,20 @@ const els = `li, p, h1, h2, h3, h4, h5, h6, dd`;
export const DEFAULT_SELECTOR = `:is(${els})`;
export const RULES = [
export const GLOBAL_KEY = "*";
export const DEFAULT_RULE = {
pattern: "",
selector: "",
translator: GLOBAL_KEY,
fromLang: GLOBAL_KEY,
toLang: GLOBAL_KEY,
textStyle: GLOBAL_KEY,
transOpen: GLOBAL_KEY,
bgColor: "",
};
const RULES = [
{
pattern: `www.google.com/search`,
selector: `h3, .IsZvec, .VwiC3b`,
@@ -132,3 +145,9 @@ export const RULES = [
selector: `h1, #video-title, #content-text, #title, yt-attributed-string>span>span`,
},
];
export const BUILTIN_RULES = RULES.map((item) => ({
...DEFAULT_RULE,
...item,
transOpen: "true",
}));

View File

@@ -3,7 +3,6 @@ import { browser, isExt, isGm, isWeb } from "../libs/browser";
import {
STOKEY_SETTING,
STOKEY_RULES,
STOKEY_MSAUTH,
STOKEY_SYNC,
DEFAULT_SETTING,
DEFAULT_RULES,
@@ -15,12 +14,13 @@ import storage from "../libs/storage";
* 默认配置
*/
export const defaultStorage = {
[STOKEY_MSAUTH]: null,
[STOKEY_SETTING]: DEFAULT_SETTING,
[STOKEY_RULES]: DEFAULT_RULES,
[STOKEY_SYNC]: DEFAULT_SYNC,
};
const activeKeys = Object.keys(defaultStorage);
const StoragesContext = createContext(null);
export function StoragesProvider({ children }) {
@@ -38,7 +38,10 @@ export function StoragesProvider({ children }) {
}
const newStorages = {};
Object.entries(changes)
.filter(([_, { oldValue, newValue }]) => oldValue !== newValue)
.filter(
([key, { oldValue, newValue }]) =>
activeKeys.includes(key) && oldValue !== newValue
)
.forEach(([key, { newValue }]) => {
newStorages[key] = JSON.parse(newValue);
});
@@ -51,8 +54,7 @@ export function StoragesProvider({ children }) {
// 首次从storage同步配置到内存
(async () => {
const curStorages = {};
const keys = Object.keys(defaultStorage);
for (const key of keys) {
for (const key of activeKeys) {
const val = await storage.get(key);
if (val) {
curStorages[key] = JSON.parse(val);

View File

@@ -9,6 +9,7 @@ import {
BUILTIN_RULES,
} from "../config";
import { browser } from "./browser";
import { isMatch } from "./utils";
/**
* 获取节点列表并转为数组
@@ -48,7 +49,6 @@ export const setFab = async (obj) => await storage.setObj(STOKEY_FAB, obj);
/**
* 根据href匹配规则
* TODO: 支持通配符(*)匹配
* @param {*} rules
* @param {string} href
* @returns
@@ -59,7 +59,7 @@ export const matchRule = (rules, href, { injectRules }) => {
}
const rule = rules.find((rule) =>
rule.pattern.split(",").some((p) => href.includes(p.trim()))
rule.pattern.split(",").some((p) => isMatch(href, p.trim()))
);
const globalRule =
rules.find((rule) =>

View File

@@ -6,7 +6,6 @@ import {
EVENT_KISS,
MSG_TRANS_CURRULE,
} from "../config";
import { StoragesProvider } from "../hooks/Storage";
import { queryEls } from ".";
import Content from "../views/Content";
import { fetchUpdate, fetchClear } from "./fetch";
@@ -144,10 +143,6 @@ export class Translator {
"-webkit-line-clamp: unset; max-height: none; height: auto;";
const root = createRoot(span);
root.render(
<StoragesProvider>
<Content q={q} translator={this} />
</StoragesProvider>
);
root.render(<Content q={q} translator={this} />);
};
}

View File

@@ -51,3 +51,40 @@ export const debounce = (func, delay = 200) => {
}, delay);
};
};
/**
* 字符串通配符(*)匹配
* @param {*} s
* @param {*} p
* @returns
*/
export const isMatch = (s, p) => {
if (s.length === 0 || p.length === 0) {
return false;
}
p = `*${p}*`;
let [sIndex, pIndex] = [0, 0];
let [sRecord, pRecord] = [-1, -1];
while (sIndex < s.length && pRecord < p.length) {
if (p[pIndex] === "*") {
pIndex++;
[sRecord, pRecord] = [sIndex, pIndex];
} else if (s[sIndex] === p[pIndex]) {
sIndex++;
pIndex++;
} else if (sRecord + 1 < s.length) {
sRecord++;
[sIndex, pIndex] = [sRecord, pRecord];
} else {
return false;
}
}
if (p.length === pIndex) {
return true;
}
return p.slice(pIndex).replaceAll("*", "") === "";
};

17
src/rules.js Normal file
View File

@@ -0,0 +1,17 @@
import fs from "fs";
import path from "path";
import { BUILTIN_RULES } from "./config/rules";
(() => {
try {
const data = JSON.stringify(BUILTIN_RULES, null, " ");
const file = path.resolve(
__dirname,
"../build/web/kiss-translator-rules.json"
);
fs.writeFileSync(file, data);
console.info(`Built-in rules generated: ${file}`);
} catch (err) {
console.error(err);
}
})();

View File

@@ -76,7 +76,7 @@ export default function Action({ translator, fab }) {
windowSize,
width: fabWidth,
height: fabWidth,
left: fab.x ?? windowSize.w - fabWidth,
left: fab.x ?? 0,
top: fab.y ?? windowSize.h / 2,
};

4651
yarn.lock

File diff suppressed because it is too large Load Diff