Compare commits

...

12 Commits

Author SHA1 Message Date
Gabe Yuan
71bbd2e54a v1.8.1 2024-02-06 10:09:33 +08:00
Gabe Yuan
3083d8e147 feat: context menu type 2024-02-05 11:28:34 +08:00
Gabe Yuan
e74883e9c2 fix: contextMenus: duplicate id err 2024-02-05 10:51:42 +08:00
Gabe Yuan
0816a9d167 fix: add BLOCKQUOTE to webfix 2024-02-05 10:02:30 +08:00
Gabe Yuan
4b3e91fa84 v1.8.1 2024-02-02 15:45:33 +08:00
Gabe Yuan
0973a0b60e fix: some js syntax 2024-02-02 15:44:44 +08:00
Gabe Yuan
de5f61126d fix: terms hepler text 2024-02-02 12:35:56 +08:00
Gabe Yuan
0c20ca761f fix: update toggle_translate CN text 2024-02-02 12:22:08 +08:00
Gabe Yuan
4bce56207e fix: optimize terms function 2024-02-02 12:10:27 +08:00
Gabe Yuan
dca54e0033 feat: setting: translate page title 2024-02-02 11:20:39 +08:00
Gabe Yuan
309646bf1d feat: setting: translate page title 2024-02-02 11:13:41 +08:00
Gabe Yuan
18b9961b39 fix: try add context menux on startup 2024-02-02 10:49:15 +08:00
16 changed files with 147 additions and 103 deletions

2
.env
View File

@@ -2,7 +2,7 @@ GENERATE_SOURCEMAP=false
REACT_APP_NAME=KISS Translator
REACT_APP_NAME_CN=简约翻译
REACT_APP_VERSION=1.8.0
REACT_APP_VERSION=1.8.2
REACT_APP_HOMEPAGE=https://github.com/fishjar/kiss-translator

View File

@@ -29,7 +29,7 @@
- [x] 自定义专业术语
- [x] 自定义译文样式
- [x] 自定义快捷键
- `Alt+Q` 启翻译
- `Alt+Q`翻译
- `Alt+C` 切换样式
- `Alt+K` 打开设置弹窗
- `Alt+S` 打开翻译弹窗/翻译选中文字

View File

@@ -1,7 +1,7 @@
{
"name": "kiss-translator",
"description": "A minimalist bilingual translation Extension & Greasemonkey Script",
"version": "1.8.0",
"version": "1.8.2",
"author": "Gabe<yugang2002@gmail.com>",
"private": true,
"dependencies": {

View File

@@ -6,7 +6,7 @@
"message": "一个简约的双语对照翻译扩展 & 油猴脚本"
},
"toggle_translate": {
"message": "启翻译"
"message": "启翻译"
},
"toggle_style": {
"message": "切换样式"

View File

@@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "__MSG_app_name__",
"description": "__MSG_app_description__",
"version": "1.8.0",
"version": "1.8.2",
"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.8.0",
"version": "1.8.2",
"default_locale": "en",
"author": "Gabe<yugang2002@gmail.com>",
"homepage_url": "https://github.com/fishjar/kiss-translator",

View File

@@ -28,39 +28,51 @@ globalThis.ContextType = "BACKGROUND";
/**
* 添加右键菜单
*/
function addContextMenus() {
browser.contextMenus.create({
id: CMD_TOGGLE_TRANSLATE,
title: browser.i18n.getMessage("toggle_translate"),
contexts: ["page", "selection"],
});
browser.contextMenus.create({
id: CMD_TOGGLE_STYLE,
title: browser.i18n.getMessage("toggle_style"),
contexts: ["page", "selection"],
});
browser.contextMenus.create({
id: CMD_OPEN_TRANBOX,
title: browser.i18n.getMessage("open_tranbox"),
contexts: ["page", "selection"],
});
browser.contextMenus.create({
id: "options_separator",
type: "separator",
contexts: ["page", "selection"],
});
browser.contextMenus.create({
id: CMD_OPEN_OPTIONS,
title: browser.i18n.getMessage("open_options"),
contexts: ["page", "selection"],
});
}
async function addContextMenus(contextMenuType = 1) {
// 添加前先删除,避免重复ID的错误
try {
await browser.contextMenus.removeAll();
} catch (err) {
//
}
/**
* 清除右键菜单
*/
function removeContextMenus() {
browser.contextMenus.removeAll();
switch (contextMenuType) {
case 1:
browser.contextMenus.create({
id: CMD_TOGGLE_TRANSLATE,
title: browser.i18n.getMessage("toggle_translate"),
contexts: ["page", "selection"],
});
break;
case 2:
browser.contextMenus.create({
id: CMD_TOGGLE_TRANSLATE,
title: browser.i18n.getMessage("toggle_translate"),
contexts: ["page", "selection"],
});
browser.contextMenus.create({
id: CMD_TOGGLE_STYLE,
title: browser.i18n.getMessage("toggle_style"),
contexts: ["page", "selection"],
});
browser.contextMenus.create({
id: CMD_OPEN_TRANBOX,
title: browser.i18n.getMessage("open_tranbox"),
contexts: ["page", "selection"],
});
browser.contextMenus.create({
id: "options_separator",
type: "separator",
contexts: ["page", "selection"],
});
browser.contextMenus.create({
id: CMD_OPEN_OPTIONS,
title: browser.i18n.getMessage("open_options"),
contexts: ["page", "selection"],
});
break;
default:
}
}
/**
@@ -80,11 +92,8 @@ browser.runtime.onStartup.addListener(async () => {
// 同步数据
await trySyncSettingAndRules();
const {
clearCache,
contextMenus = true,
subrulesList,
} = await getSettingWithDefault();
const { clearCache, contextMenuType, subrulesList } =
await getSettingWithDefault();
// 清除缓存
if (clearCache) {
@@ -92,9 +101,8 @@ browser.runtime.onStartup.addListener(async () => {
}
// 右键菜单
if (!contextMenus) {
removeContextMenus();
}
// firefox重启后菜单会消失,故重复添加
addContextMenus(contextMenuType);
// 同步订阅规则
trySyncAllSubRules({ subrulesList });
@@ -132,12 +140,8 @@ browser.runtime.onMessage.addListener(
saveRule(args);
break;
case MSG_CONTEXT_MENUS:
const { contextMenus } = args;
if (contextMenus) {
addContextMenus();
} else {
removeContextMenus();
}
const { contextMenuType } = args;
addContextMenus(contextMenuType);
break;
case MSG_COMMAND_SHORTCUTS:
browser.commands

View File

@@ -140,7 +140,7 @@ async function showFab(translator) {
* @returns
*/
function showTransbox({
contextMenus = true,
contextMenuType,
tranboxSetting = DEFAULT_TRANBOX_SETTING,
transApis,
}) {
@@ -165,7 +165,7 @@ function showTransbox({
<React.StrictMode>
<CacheProvider value={cache}>
<Slection
contextMenus={contextMenus}
contextMenuType={contextMenuType}
tranboxSetting={tranboxSetting}
transApis={transApis}
/>

View File

@@ -376,7 +376,7 @@ export const I18N = {
en: `1. Follow CSS selector syntax. 2. Leave blank to adopt the global setting. 3. Separate multiple CSS selectors with ";". 4. The "shadow root" selector and the internal selector are separated by ">>>".`,
},
translate_switch: {
zh: `启翻译`,
zh: `翻译`,
en: `Translate Switch`,
},
default_enabled: {
@@ -404,8 +404,8 @@ export const I18N = {
en: `Terms`,
},
terms_helper: {
zh: `1、多条术语用换行或分号“;”隔开。2、术语和译文用英文逗号“,”隔开。3、没有译文视为不翻译术语。4、留空表示采用全局设置。`,
en: `1. Separate multiple terms with newlines or semicolons ";". 2. Terms and translations are separated by English commas ",". 3. If there is no translation, the term will be deemed not to be translated. 4. Leave blank to adopt the global setting.`,
zh: `0、支持正则表达式匹配。1、多条术语用换行或分号“;”隔开。2、术语和译文用英文逗号“,”隔开。3、没有译文视为不翻译术语。4、留空表示采用全局设置。`,
en: `0. Supports regular expression matching. 1. Separate multiple terms with newlines or semicolons ";". 2. Terms and translations are separated by English commas ",". 3. If there is no translation, the term will be deemed not to be translated. 4. Leave blank to adopt the global setting.`,
},
root_selector: {
zh: `根选择器`,
@@ -560,7 +560,7 @@ export const I18N = {
en: `Shortcuts Setting`,
},
toggle_translate_shortcut: {
zh: `"启翻译"快捷键`,
zh: `"启翻译"快捷键`,
en: `"Toggle Translate" Shortcut`,
},
toggle_style_shortcut: {
@@ -723,12 +723,28 @@ export const I18N = {
zh: `此功能依赖准确的语言检测,建议启用远程语言检测。`,
en: `This feature relies on accurate language detection. It is recommended to enable remote language detection.`,
},
add_context_menus: {
zh: `添加右键菜单`,
en: `Add Context Menus`,
context_menus: {
zh: `右键菜单`,
en: `Context Menus`,
},
hide_context_menus: {
zh: `隐藏右键菜单`,
en: `Hide Context Menus`,
},
simple_context_menus: {
zh: `简单右键菜单`,
en: `Simple_context_menus Context Menus`,
},
secondary_context_menus: {
zh: `二级右键菜单`,
en: `Secondary Context Menus`,
},
mulkeys_help: {
zh: `支持用换行或英文逗号“,”分隔多个KEY轮询调用。`,
en: `Supports multiple KEY polling calls separated by newlines or English commas ",".`,
},
translate_page_title: {
zh: `是否同时翻译页面标题`,
en: `Translate Page Title`,
},
};

View File

@@ -298,8 +298,8 @@ export const OPT_STYLE_USE_COLOR = [
OPT_STYLE_BLOCKQUOTE,
];
export const OPT_MOUSEKEY_DISABLE = "mk_disable";
export const OPT_MOUSEKEY_PAGEOPEN = "mk_pageopen";
export const OPT_MOUSEKEY_DISABLE = "mk_disable"; // 滚动加载翻译
export const OPT_MOUSEKEY_PAGEOPEN = "mk_pageopen"; // 直接翻译到底
export const OPT_MOUSEKEY_MOUSEOVER = "mk_mouseover";
export const OPT_MOUSEKEY_CONTROL = "mk_ctrlKey";
export const OPT_MOUSEKEY_SHIFT = "mk_shiftKey";
@@ -452,11 +452,13 @@ export const DEFAULT_SETTING = {
injectRules: true, // 是否注入订阅规则
injectWebfix: true, // 是否注入修复补丁
detectRemote: false, // 是否使用远程语言检测
contextMenus: true, // 是否添加右键菜单
contextMenus: true, // 是否添加右键菜单(作废)
contextMenuType: 1, // 右键菜单类型(0不显示1简单菜单2多级菜单)
transTitle: false, // 是否同时翻译页面标题
subrulesList: DEFAULT_SUBRULES_LIST, // 订阅列表
owSubrule: DEFAULT_OW_RULE, // 覆写订阅规则
transApis: DEFAULT_TRANS_APIS, // 翻译接口
mouseKey: OPT_MOUSEKEY_DISABLE, // 鼠标悬停翻译
mouseKey: OPT_MOUSEKEY_DISABLE, // 翻译时机/鼠标悬停翻译
shortcuts: DEFAULT_SHORTCUTS, // 快捷键
inputRule: DEFAULT_INPUT_RULE, // 输入框设置
tranboxSetting: DEFAULT_TRANBOX_SETTING, // 划词翻译设置

View File

@@ -42,7 +42,7 @@ export const syncSubRules = async (url) => {
* @returns
*/
export const syncAllSubRules = async (subrulesList) => {
for (let subrules of subrulesList) {
for (const subrules of subrulesList) {
try {
await syncSubRules(subrules.url);
await updateSyncDataCache(subrules.url);

View File

@@ -46,7 +46,7 @@ export class Translator {
_eventName = genEventName();
_mouseoverNode = null;
_keepSelector = [null, null];
_terms = new Map();
_terms = [];
_docTitle = "";
// 显示
@@ -111,13 +111,10 @@ export class Translator {
this._keepSelector = (rule.keepSelector || "")
.split(SHADOW_KEY)
.map((item) => item.trim());
const terms = (rule.terms || "")
this._terms = (rule.terms || "")
.split(/\n|;/)
.map((item) => item.split(",").map((item) => item.trim()))
.filter(([term]) => Boolean(term));
if (terms.length > 0) {
this._terms = new Map(terms);
}
if (rule.transOpen === "true") {
this._register();
@@ -309,11 +306,11 @@ export class Translator {
}
// 翻译页面标题
const title = document.title;
if (!title.endsWith("| ByKT")) {
if (this._setting.transTitle && !this._docTitle) {
const title = document.title;
this._docTitle = title;
this.translateText(title).then((trText) => {
document.title = `${trText} | ${title} | ByKT`;
document.title = `${trText} | ${title}`;
});
}
};
@@ -364,7 +361,10 @@ export class Translator {
_unRegister = () => {
// 恢复页面标题
document.title = this._docTitle;
if (this._docTitle) {
document.title = this._docTitle;
this._docTitle = "";
}
// 解除节点变化监听
this._mutaObserver.disconnect();
@@ -472,13 +472,15 @@ export class Translator {
}
// 专业术语
if (this._terms.size > 0) {
const re = new RegExp([...this._terms.keys()].join("|"), "g");
q = q.replace(re, (term) => {
const text = `[${keeps.length}]`;
keeps.push(this._terms.get(term) || term);
return text;
});
if (this._terms.length > 0) {
for (const term of this._terms) {
const re = new RegExp(term[0], "g");
q = q.replace(re, (t) => {
const text = `[${keeps.length}]`;
keeps.push(term[1] || t);
return text;
});
}
}
traEl = document.createElement(APP_LCNAME);

View File

@@ -69,8 +69,8 @@ function brFixer(node, tag = "p") {
}
node.setAttribute(fixedSign, "true");
var gapTags = ["BR", "WBR"];
var newlineTags = [
const gapTags = ["BR", "WBR"];
const newlineTags = [
"DIV",
"UL",
"OL",
@@ -85,9 +85,10 @@ function brFixer(node, tag = "p") {
"HR",
"PRE",
"TABLE",
"BLOCKQUOTE",
];
var html = "";
let html = "";
node.childNodes.forEach(function (child, index) {
if (index === 0) {
html += `<${tag} class="kiss-p">`;
@@ -160,7 +161,7 @@ const fixerMap = {
* @param {*} rootSelector
*/
function run(selector, fixer, rootSelector) {
var mutaObserver = new MutationObserver(function (mutations) {
const mutaObserver = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
mutation.addedNodes.forEach(function (addNode) {
if (addNode && addNode.querySelectorAll) {
@@ -172,7 +173,7 @@ function run(selector, fixer, rootSelector) {
});
});
var rootNodes = [document];
let rootNodes = [document];
if (rootSelector) {
rootNodes = document.querySelectorAll(rootSelector);
}
@@ -241,8 +242,8 @@ export async function matchFixer(href, { injectWebfix }) {
const userSites = await getWebfixRulesWithDefault();
const subSites = await loadOrFetchWebfix(process.env.REACT_APP_WEBFIXURL);
const sites = [...userSites, ...subSites];
for (var i = 0; i < sites.length; i++) {
var site = sites[i];
for (let i = 0; i < sites.length; i++) {
const site = sites[i];
if (isMatch(href, site.pattern) && fixerMap[site.fixer]) {
return site;
}

View File

@@ -95,8 +95,8 @@ export default function Action({ translator, fab }) {
// 注册菜单
try {
const menuCommandIds = [];
const { contextMenus = true } = translator.setting;
contextMenus &&
const { contextMenuType } = translator.setting;
contextMenuType !== 0 &&
menuCommandIds.push(
GM.registerMenuCommand(
"Toggle Translate",

View File

@@ -67,8 +67,8 @@ export default function Settings() {
case "touchTranslate":
value = limitNumber(value, 0, 4);
break;
case "contextMenus":
isExt && sendBgMsg(MSG_CONTEXT_MENUS, { contextMenus: value });
case "contextMenuType":
isExt && sendBgMsg(MSG_CONTEXT_MENUS, { contextMenuType: value });
break;
default:
}
@@ -96,7 +96,8 @@ export default function Settings() {
newlineLength = TRANS_NEWLINE_LENGTH,
mouseKey = OPT_MOUSEKEY_DISABLE,
detectRemote = false,
contextMenus = true,
contextMenuType = 1,
transTitle = false,
touchTranslate = 2,
blacklist = DEFAULT_BLACKLIST.join(",\n"),
disableLangs = [],
@@ -183,6 +184,19 @@ export default function Settings() {
</Select>
</FormControl>
<FormControl size="small">
<InputLabel>{i18n("translate_page_title")}</InputLabel>
<Select
name="transTitle"
value={transTitle}
label={i18n("translate_page_title")}
onChange={handleChange}
>
<MenuItem value={false}>{i18n("disable")}</MenuItem>
<MenuItem value={true}>{i18n("enable")}</MenuItem>
</Select>
</FormControl>
<FormControl size="small">
<InputLabel>{i18n("touch_translate_shortcut")}</InputLabel>
<Select
@@ -215,15 +229,16 @@ export default function Settings() {
</FormControl>
<FormControl size="small">
<InputLabel>{i18n("add_context_menus")}</InputLabel>
<InputLabel>{i18n("context_menus")}</InputLabel>
<Select
name="contextMenus"
value={contextMenus}
label={i18n("add_context_menus")}
name="contextMenuType"
value={contextMenuType}
label={i18n("context_menus")}
onChange={handleChange}
>
<MenuItem value={false}>{i18n("disable")}</MenuItem>
<MenuItem value={true}>{i18n("enable")}</MenuItem>
<MenuItem value={0}>{i18n("hide_context_menus")}</MenuItem>
<MenuItem value={1}>{i18n("simple_context_menus")}</MenuItem>
<MenuItem value={2}>{i18n("secondary_context_menus")}</MenuItem>
</Select>
</FormControl>

View File

@@ -7,7 +7,11 @@ import { isGm, isExt } from "../../libs/client";
import { MSG_OPEN_TRANBOX, DEFAULT_TRANBOX_SHORTCUT } from "../../config";
import { isMobile } from "../../libs/mobile";
export default function Slection({ contextMenus, tranboxSetting, transApis }) {
export default function Slection({
contextMenuType,
tranboxSetting,
transApis,
}) {
const boxWidth = limitNumber(window.innerWidth, 300, 600);
const boxHeight = limitNumber(window.innerHeight, 200, 400);
@@ -106,7 +110,7 @@ export default function Slection({ contextMenus, tranboxSetting, transApis }) {
// 注册菜单
try {
const menuCommandIds = [];
contextMenus &&
contextMenuType !== 0 &&
menuCommandIds.push(
GM.registerMenuCommand(
"Translate Selected Text",
@@ -125,7 +129,7 @@ export default function Slection({ contextMenus, tranboxSetting, transApis }) {
} catch (err) {
console.log("[registerMenuCommand]", err);
}
}, [handleTranbox, contextMenus]);
}, [handleTranbox, contextMenuType]);
return (
<>