-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathbackground.js
187 lines (150 loc) · 5.72 KB
/
background.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// "people got mad when i put it all in one file" —Julia Evans
/*
===============================
WebExtension specific functions
===============================
*/
/*
Returns true only if the URL's protocol is in APPLICABLE_PROTOCOLS.
*/
function protocolIsApplicable(tabUrl) {
const APPLICABLE_PROTOCOLS = ['http:', 'https:'];
let url = new URL(tabUrl);
return APPLICABLE_PROTOCOLS.includes(url.protocol);
}
/*
Returns true if user set option to always display the page action
*/
async function userAlwaysWantsIcon() {
let option = await browser.storage.local.get("alwaysShowPageAction");
if (typeof option.alwaysShowPageAction !== "boolean") {
return false;
} else {
return option.alwaysShowPageAction;
}
}
async function pageIsInForeignLanguage(tabId) {
// Get the page's language. If not found, assume it's foreign.
// Better to show the translate icon when it is not needed than vice versa
try {
var pageLanguage = await browser.tabs.detectLanguage(tabId);
} catch (err) {
return true;
}
if (!pageLanguage || pageLanguage === "und") {
return true;
}
// Normalize page language and browser languages
pageLanguage = pageLanguage.toLowerCase();
let navigatorLanguages = navigator.languages.map(navigatorLanguage => {
return navigatorLanguage.toLowerCase();
});
// Check if the page's language explicitly matches any of browser's preferred languages
if (navigatorLanguages.includes(pageLanguage)) {
return false;
}
// If you're still here, then check for match of primary language subtags
// If so, assume close enough to native language.
// Get array of the primary languages from the browser, i.e. those without a hyphen
// Ex: `en` but not `en-SV`
let primaryLanguageSubtags = navigatorLanguages.filter(language => {
return language.indexOf('-') === -1;
});
// If no primary language subtag specified in browser, the user has explicitly removed it,
// so assume they want explicit language match instead of partial match.
if (primaryLanguageSubtags.length === 0) {
return true;
}
// Get page's language subtag
let pageLanguageSubtag = pageLanguage.split('-', 1)[0];
// Look for primary language subtag match
if (primaryLanguageSubtags.includes(pageLanguageSubtag)) {
return false;
}
// No match, so page is in foreign language.
return true;
}
/*
Show the Page Translator page action in the browser address bar, if applicable.
*/
async function initializePageAction(tab) {
if (protocolIsApplicable(tab.url) &&
(await userAlwaysWantsIcon() === true || await pageIsInForeignLanguage(tab.id) === true)
) {
browser.pageAction.show(tab.id);
} else {
browser.pageAction.hide(tab.id);
}
}
/*
=============================
Page Translator functionality
=============================
*/
function injectTranslatorCode() {
let googleCode = `
let docBody = document.body;
if (docBody !== null) {
let googleTranslateCallback = document.createElement('script');
googleTranslateCallback.innerHTML = "function googleTranslateElementInit(){ new google.translate.TranslateElement(); }";
docBody.insertBefore(googleTranslateCallback, docBody.firstChild);
let googleTranslateScript = document.createElement('script');
googleTranslateScript.charset="UTF-8";
googleTranslateScript.src = "https://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit&tl=&sl=&hl=";
docBody.insertBefore(googleTranslateScript, docBody.firstChild);
}
// Firefox 53 will (erroneously?) complain if non-structured-clonable data isn't returned.
// https://github.com/mdn/webextensions-examples/issues/193
true;
`;
let microsoftCode = `
let docBody = document.body;
if (docBody !== null) {
let div = '<div id="MicrosoftTranslatorWidget" class="Dark" style="color:white;background-color:#555555"></div>';
docBody.insertAdjacentHTML("afterbegin", div);
let microsoftTranslatorScript = document.createElement("script");
microsoftTranslatorScript.charset="UTF-8";
microsoftTranslatorScript.src = "https://ssl.microsofttranslator.com/ajax/v3/WidgetV3.ashx?siteData=ueOIGRSKkd965FeEGM5JtQ**&ctf=False&ui=true&settings=Auto&from=";
docBody.insertBefore(microsoftTranslatorScript, docBody.firstChild);
}
// Firefox 53 will (erroneously?) complain if non-structured-clonable data isn't returned.
// https://github.com/mdn/webextensions-examples/issues/193
true;
`;
let executeScript = function(option) {
let injectDetails = {};
if ((typeof option.translationService !== "undefined") &&
(option.translationService === "microsoft")) {
injectDetails.code = microsoftCode;
} else {
injectDetails.code = googleCode;
}
browser.tabs.executeScript(injectDetails);
};
browser.storage.local.get("translationService").then(executeScript);
}
/*
==========
INITIALIZE
==========
*/
/*
When initialized, add the page action for all tabs.
*/
browser.tabs.query({}).then((tabs) => {
for (tab of tabs) {
initializePageAction(tab);
}
});
/*
When a tab is updated, reset the page action for that tab.
*/
browser.tabs.onUpdated.addListener((id, changeInfo, tab) => {
if ((typeof changeInfo.status === "string") && (changeInfo.status === "complete")) {
initializePageAction(tab);
}
});
/*
Bind clicks on the page action icon to the WebExtension
*/
browser.pageAction.onClicked.addListener(injectTranslatorCode);