Skip to content

Commit

Permalink
Add CNKI Segmented Translation (#762)
Browse files Browse the repository at this point in the history
* Add CNKI Segmented Translation

* Add CNKI Segmented Translation

* Merge cnkisplit.ts to cnki.ts

* remove unnecessary reminder

* remove progressWindow

* segment output results

* chore: lint

---------

Co-authored-by: windingwind <33902321+windingwind@users.noreply.github.com>
  • Loading branch information
sasaju and windingwind authored Jul 26, 2024
1 parent 2d4b4d5 commit bc2d7a9
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 59 deletions.
1 change: 1 addition & 0 deletions addon/locale/en-US/addon.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ service-cnki-dialog-regex=CNKI Addvertisements Regex
service-cnki-dialog-save=Save
service-cnki-dialog-close=Close
service-cnki-dialog-title=CNKI Config
service-cnki-dialog-split=Automatically split translation for more than 800 characters
readerpopup-translate-label=Translate
Expand Down
1 change: 1 addition & 0 deletions addon/locale/it-IT/addon.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ service-cnki-dialog-regex=Regex per gli annunci CNKI
service-cnki-dialog-save=Salva
service-cnki-dialog-close=Chiudi
service-cnki-dialog-title=Configura CNKI
service-cnki-dialog-split=Dividi automaticamente la traduzione per più di 800 caratteri
readerpopup-translate-label=Traduci
Expand Down
1 change: 1 addition & 0 deletions addon/locale/zh-CN/addon.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ service-cnki-dialog-regex=CNKI广告移除正则表达式
service-cnki-dialog-save=保存
service-cnki-dialog-close=关闭
service-cnki-dialog-title=CNKI 设置
service-cnki-dialog-split=超过800字符自动拆分翻译
readerpopup-translate-label=翻译
Expand Down
2 changes: 2 additions & 0 deletions addon/prefs.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,5 @@ pref(
"__prefsPrefix__.cnkiRegex",
"(查看名企职位.+?https://dict.cnki.net[a-zA-Z./]+.html?)",
);
pref("__prefsPrefix__.cnkiSplitSecond", 1);
pref("__prefsPrefix__.cnkiUseSplit", false);
131 changes: 73 additions & 58 deletions src/modules/services/cnki.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,68 +3,83 @@ import { getPref, getPrefJSON, setPref } from "../../utils/prefs";
import { TranslateTaskProcessor } from "../../utils/task";

export default <TranslateTaskProcessor>async function (data) {
if (data.raw.length > 1000 && !data.silent) {
new ztoolkit.ProgressWindow("PDF Translate")
.createLine({
text: `Maximam text length is 1000, ${data.raw.length} selected. Will only translate first 1000 characters.`,
})
.show();
data.raw = data.raw.slice(0, 1000);
let progressWindow;
const useSplit = getPref("cnkiUseSplit") as boolean;
const splitSecond = getPref("cnkiSplitSecond") as number;
if (!data.silent) {
progressWindow = new ztoolkit.ProgressWindow("PDF Translate");
}

const xhr = await Zotero.HTTP.request(
"POST",
"https://dict.cnki.net/fyzs-front-api/translate/literaltranslation",
{
headers: {
"Content-Type": "application/json;charset=UTF-8",
Token: await getToken(),
const processTranslation = async (text: string) => {
const xhr = await Zotero.HTTP.request(
"POST",
"https://dict.cnki.net/fyzs-front-api/translate/literaltranslation",
{
headers: {
"Content-Type": "application/json;charset=UTF-8",
Token: await getToken(),
},
body: JSON.stringify({
words: await getWord(text),
translateType: null,
}),
responseType: "json",
},
body: JSON.stringify({
words: await getWord(data.raw),
translateType: null,
}),
responseType: "json",
},
);
);

if (xhr.response.data?.isInputVerificationCode) {
throw "Your access is temporarily banned by the CNKI service. Please goto https://dict.cnki.net/, translate manually and pass human verification.";
}
if (xhr.response.data?.isInputVerificationCode) {
throw "Your access is temporarily banned by the CNKI service. Please goto https://dict.cnki.net/, translate manually and pass human verification.";
}

// if (retry && xhr.response.data?.isInputVerificationCode) {
// // Monitor verification
// await Zotero.HTTP.request(
// "GET",
// "https://dict.cnki.net/fyzs-front-api/captchaImage",
// {
// headers: {
// "Content-Type": "application/json;charset=UTF-8",
// Token: await getToken(),
// },
// }
// );
// await Zotero.HTTP.request(
// "POST",
// "https://dict.cnki.net/fyzs-front-api/translate/addVerificationCodeTimes",
// {
// headers: {
// "Content-Type": "application/json;charset=UTF-8",
// Token: await getToken(),
// },
// }
// );
// await getToken(true);
// // Call translation again
// return await cnki.call(this, text, false);
// // throw "CNKI requires verification. Please verify manually in popup or open dict.cnki.net in browser.";
// }
let tgt = xhr.response.data?.mResult;
tgt = tgt.replace(new RegExp(getPref("cnkiRegex") as string, "g"), "");
data.result = tgt;
let tgt = xhr.response.data?.mResult;
tgt = tgt.replace(new RegExp(getPref("cnkiRegex") as string, "g"), "");
return tgt;
};

if (useSplit) {
const sentences = data.raw
.split(/[.?!]/)
.map((s) => s.trim())
.filter((s) => s.length > 0);
const chunks = [];
let currentChunk = "";
sentences.forEach((sentence: string) => {
const sentenceWithPeriod = sentence + ". ";
if (currentChunk.length + sentenceWithPeriod.length > 800) {
chunks.push(currentChunk);
currentChunk = sentenceWithPeriod;
} else {
currentChunk += sentenceWithPeriod;
}
});
if (currentChunk) {
chunks.push(currentChunk);
}
let translatedText = "";
for (const chunk of chunks) {
translatedText += (await processTranslation(chunk)) + " ";
data.result = translatedText.trim();
addon.hooks.onReaderPopupRefresh();
addon.hooks.onReaderTabPanelRefresh();
// 停顿几秒
await new Promise((resolve) => setTimeout(resolve, splitSecond * 1000));
}
// data.result = translatedText.trim();
} else {
if (data.raw.length > 800) {
progressWindow
?.createLine({
text: `Maximum text length is 800, ${data.raw.length} selected. Will only translate first 800 characters. If you want the plugin to automatically split the translation based on punctuation, you can enable the split switch in the preferences.`,
})
.show();
data.raw = data.raw.slice(0, 800);
}

data.result = await processTranslation(data.raw);
}
};

async function getToken(forceRefresh: boolean = false) {
export async function getToken(forceRefresh: boolean = false) {
let token = "";
// Just in case the update fails
let doRefresh = true;
Expand Down Expand Up @@ -103,8 +118,8 @@ async function getToken(forceRefresh: boolean = false) {
return token;
}

async function getWord(text: string) {
const encrtypted = await aesEcbEncrypt(text, "4e87183cfd3a45fe");
const base64str = base64(encrtypted);
export async function getWord(text: string) {
const encrypted = await aesEcbEncrypt(text, "4e87183cfd3a45fe");
const base64str = base64(encrypted);
return base64str.replace(/\//g, "_").replace(/\+/g, "-");
}
43 changes: 42 additions & 1 deletion src/modules/settings/cnki.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { getString } from "../../utils/locale";
import { getPref, setPref } from "../../utils/prefs";

export async function cnkiStatusCallback(status: boolean) {
const dialog = new ztoolkit.Dialog(2, 1);
const dialog = new ztoolkit.Dialog(4, 1);
const dialogData: { [key: string | number]: any } = {
removeRegex: getPref("cnkiRegex"),
useSplit: getPref("cnkiUseSplit"),
};
dialog
.setDialogData(dialogData)
Expand All @@ -26,6 +27,45 @@ export async function cnkiStatusCallback(status: boolean) {
"data-prop": "value",
},
})
.addCell(
2,
0,
{
tag: "div",
namespace: "html",
styles: {
display: "grid",
gridTemplateColumns: "1fr 4fr",
rowGap: "2px",
},
children: [
{
tag: "input",
namespace: "html",
attributes: {
type: "checkbox",
id: "cnkiUseSplit",
"data-bind": "useSplit",
"data-prop": "checked",
},
},
{
tag: "label",
namespace: "html",
attributes: {
for: "cnkiUseSplit",
},
properties: {
innerHTML: getString("service-cnki-dialog-split"),
},
styles: {
textAlign: "left",
},
},
],
},
false,
)
.addButton(getString("service-cnki-dialog-save"), "save")
.addButton(getString("service-cnki-dialog-close"), "close")
.open(getString("service-cnki-dialog-title"));
Expand All @@ -35,6 +75,7 @@ export async function cnkiStatusCallback(status: boolean) {
case "save":
{
setPref("cnkiRegex", dialogData.removeRegex);
setPref("cnkiUseSplit", dialogData.useSplit);
}
break;
default:
Expand Down

0 comments on commit bc2d7a9

Please sign in to comment.