tinker-translate 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/dist/preload/index.mjs +153 -0
- package/dist/renderer/assets/app-BS1_9Skb.js +164 -0
- package/dist/renderer/assets/app-C_Wxyl0_.css +1 -0
- package/dist/renderer/index.html +12 -0
- package/icon.png +0 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# tinker-translate
|
|
2
|
+
|
|
3
|
+
A translation plugin for [TINKER](https://github.com/liriliri/tinker), supporting Google, Bing, and DeepL translation services.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Google, Bing & DeepL** translation services
|
|
10
|
+
- **16+ languages** support
|
|
11
|
+
- **Auto-detect** source language
|
|
12
|
+
- **i18n** support for English and Chinese
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
Download and install TINKER from `https://tinker.liriliri.io/`, then run `npm i -g tinker-translate`.
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
1. Select translation service (Google, Bing, or DeepL)
|
|
21
|
+
2. Enter text in the source text area
|
|
22
|
+
3. Select source and target languages
|
|
23
|
+
4. Click "Translate" button
|
|
24
|
+
5. View the translated text in the result area
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { contextBridge as g } from "electron";
|
|
2
|
+
import f from "https";
|
|
3
|
+
function m(n, t) {
|
|
4
|
+
return new Promise((e, s) => {
|
|
5
|
+
const a = f.request(n, (o) => {
|
|
6
|
+
let c = "";
|
|
7
|
+
o.on("data", (i) => {
|
|
8
|
+
c += i;
|
|
9
|
+
}), o.on("end", () => {
|
|
10
|
+
e({ statusCode: o.statusCode, data: c });
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
a.on("error", s), t && a.write(t), a.end();
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
async function w(n, t, e) {
|
|
17
|
+
const a = {
|
|
18
|
+
hostname: "translate.google.com",
|
|
19
|
+
port: 443,
|
|
20
|
+
path: `/translate_a/single?dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&dt=t&${new URLSearchParams({
|
|
21
|
+
client: "gtx",
|
|
22
|
+
sl: t,
|
|
23
|
+
tl: e,
|
|
24
|
+
hl: e,
|
|
25
|
+
ie: "UTF-8",
|
|
26
|
+
oe: "UTF-8",
|
|
27
|
+
otf: "1",
|
|
28
|
+
ssel: "0",
|
|
29
|
+
tsel: "0",
|
|
30
|
+
kc: "7",
|
|
31
|
+
q: n
|
|
32
|
+
}).toString()}`,
|
|
33
|
+
method: "GET",
|
|
34
|
+
headers: {
|
|
35
|
+
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"
|
|
36
|
+
}
|
|
37
|
+
}, { statusCode: o, data: c } = await m(a);
|
|
38
|
+
if (o !== 200) throw new Error(`HTTP Error: ${o}`);
|
|
39
|
+
const i = JSON.parse(c);
|
|
40
|
+
let l = "";
|
|
41
|
+
if (i[0])
|
|
42
|
+
for (const r of i[0])
|
|
43
|
+
r[0] && (l += r[0]);
|
|
44
|
+
return { text: l.trim(), from: t, to: e };
|
|
45
|
+
}
|
|
46
|
+
async function T() {
|
|
47
|
+
const n = {
|
|
48
|
+
hostname: "edge.microsoft.com",
|
|
49
|
+
port: 443,
|
|
50
|
+
path: "/translate/auth",
|
|
51
|
+
method: "GET",
|
|
52
|
+
headers: {
|
|
53
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.42"
|
|
54
|
+
}
|
|
55
|
+
}, { statusCode: t, data: e } = await m(n);
|
|
56
|
+
if (t !== 200) throw new Error(`Failed to get token: ${t}`);
|
|
57
|
+
return e;
|
|
58
|
+
}
|
|
59
|
+
async function S(n, t, e) {
|
|
60
|
+
var d, p, h;
|
|
61
|
+
const s = await T(), a = new URLSearchParams({
|
|
62
|
+
from: t === "auto" ? "" : t,
|
|
63
|
+
to: e,
|
|
64
|
+
"api-version": "3.0",
|
|
65
|
+
includeSentenceLength: "true"
|
|
66
|
+
}), o = JSON.stringify([{ Text: n }]), c = {
|
|
67
|
+
hostname: "api-edge.cognitive.microsofttranslator.com",
|
|
68
|
+
port: 443,
|
|
69
|
+
path: `/translate?${a.toString()}`,
|
|
70
|
+
method: "POST",
|
|
71
|
+
headers: {
|
|
72
|
+
accept: "*/*",
|
|
73
|
+
"accept-language": "zh-TW,zh;q=0.9,ja;q=0.8,zh-CN;q=0.7,en-US;q=0.6,en;q=0.5",
|
|
74
|
+
authorization: "Bearer " + s,
|
|
75
|
+
"cache-control": "no-cache",
|
|
76
|
+
"content-type": "application/json",
|
|
77
|
+
"content-length": Buffer.byteLength(o),
|
|
78
|
+
pragma: "no-cache",
|
|
79
|
+
"sec-ch-ua": '"Microsoft Edge";v="113", "Chromium";v="113", "Not-A.Brand";v="24"',
|
|
80
|
+
"sec-ch-ua-mobile": "?0",
|
|
81
|
+
"sec-ch-ua-platform": '"Windows"',
|
|
82
|
+
"sec-fetch-dest": "empty",
|
|
83
|
+
"sec-fetch-mode": "cors",
|
|
84
|
+
"sec-fetch-site": "cross-site",
|
|
85
|
+
Referer: "https://appsumo.com/",
|
|
86
|
+
"Referrer-Policy": "strict-origin-when-cross-origin",
|
|
87
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.42"
|
|
88
|
+
}
|
|
89
|
+
}, { statusCode: i, data: l } = await m(c, o);
|
|
90
|
+
if (i !== 200) throw new Error(`HTTP Error: ${i}`);
|
|
91
|
+
const r = JSON.parse(l);
|
|
92
|
+
if (!((h = (p = (d = r[0]) == null ? void 0 : d.translations) == null ? void 0 : p[0]) != null && h.text))
|
|
93
|
+
throw new Error("Invalid response format");
|
|
94
|
+
return { text: r[0].translations[0].text.trim(), from: t, to: e };
|
|
95
|
+
}
|
|
96
|
+
function x(n) {
|
|
97
|
+
return n.split("i").length - 1;
|
|
98
|
+
}
|
|
99
|
+
function y(n) {
|
|
100
|
+
const t = Date.now();
|
|
101
|
+
if (n !== 0) {
|
|
102
|
+
const e = n + 1;
|
|
103
|
+
return t - t % e + e;
|
|
104
|
+
}
|
|
105
|
+
return t;
|
|
106
|
+
}
|
|
107
|
+
function C() {
|
|
108
|
+
return (Math.floor(Math.random() * 99999) + 1e5) * 1e3;
|
|
109
|
+
}
|
|
110
|
+
async function E(n, t, e) {
|
|
111
|
+
var d, p, h, u;
|
|
112
|
+
const s = C(), a = {
|
|
113
|
+
jsonrpc: "2.0",
|
|
114
|
+
method: "LMT_handle_texts",
|
|
115
|
+
id: s,
|
|
116
|
+
params: {
|
|
117
|
+
splitting: "newlines",
|
|
118
|
+
lang: {
|
|
119
|
+
source_lang_user_selected: t !== "auto" ? t.slice(0, 2).toUpperCase() : "auto",
|
|
120
|
+
target_lang: e.slice(0, 2).toUpperCase()
|
|
121
|
+
},
|
|
122
|
+
texts: [{ text: n, requestAlternatives: 3 }],
|
|
123
|
+
timestamp: y(x(n))
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
let o = JSON.stringify(a);
|
|
127
|
+
(s + 5) % 29 === 0 || (s + 3) % 13 === 0 ? o = o.replace('"method":"', '"method" : "') : o = o.replace('"method":"', '"method": "');
|
|
128
|
+
const c = {
|
|
129
|
+
hostname: "www2.deepl.com",
|
|
130
|
+
port: 443,
|
|
131
|
+
path: "/jsonrpc",
|
|
132
|
+
method: "POST",
|
|
133
|
+
headers: {
|
|
134
|
+
"Content-Type": "application/json",
|
|
135
|
+
"Content-Length": Buffer.byteLength(o)
|
|
136
|
+
}
|
|
137
|
+
}, { statusCode: i, data: l } = await m(c, o);
|
|
138
|
+
if (i !== 200) throw new Error(`HTTP Error: ${i}`);
|
|
139
|
+
const r = JSON.parse(l);
|
|
140
|
+
if ((h = (p = (d = r == null ? void 0 : r.result) == null ? void 0 : d.texts) == null ? void 0 : p[0]) != null && h.text)
|
|
141
|
+
return { text: r.result.texts[0].text.trim(), from: t, to: e };
|
|
142
|
+
throw new Error(((u = r == null ? void 0 : r.error) == null ? void 0 : u.message) ?? "Invalid response format");
|
|
143
|
+
}
|
|
144
|
+
const L = {
|
|
145
|
+
translate: async (n, t, e, s = "google") => {
|
|
146
|
+
try {
|
|
147
|
+
return s === "bing" ? await S(n, t, e) : s === "deepl" ? await E(n, t, e) : await w(n, t, e);
|
|
148
|
+
} catch (a) {
|
|
149
|
+
throw console.error("Translation failed:", a), a;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
g.exposeInMainWorld("translate", L);
|