mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 971048 - Run language detection on webpages and display infobar when language is not the current UI locale, r=felipe.
This commit is contained in:
parent
4647de30f2
commit
d6b7a6b944
@ -1425,6 +1425,8 @@ pref("browser.cache.auto_delete_cache_version", 1);
|
||||
// -1 means no experiment is run and we use the preferred value for frecency (6h)
|
||||
pref("browser.cache.frecency_experiment", 0);
|
||||
|
||||
pref("browser.translation.detectLanguage", false);
|
||||
|
||||
// Telemetry experiments settings.
|
||||
pref("experiments.enabled", false);
|
||||
pref("experiments.manifest.fetchIntervalSeconds", 86400);
|
||||
|
@ -147,6 +147,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "gCustomizationTabPreloader",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
|
||||
"resource://gre/modules/PrivateBrowsingUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Translation",
|
||||
"resource:///modules/translation/Translation.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "SitePermissions",
|
||||
"resource:///modules/SitePermissions.jsm");
|
||||
|
||||
@ -1033,6 +1036,7 @@ var gBrowserInit = {
|
||||
gFormSubmitObserver.init();
|
||||
gRemoteTabsUI.init();
|
||||
gPageStyleMenu.init();
|
||||
LanguageDetectionListener.init();
|
||||
|
||||
// Initialize the full zoom setting.
|
||||
// We do this before the session restore service gets initialized so we can
|
||||
@ -5342,6 +5346,15 @@ function setStyleDisabled(disabled) {
|
||||
}
|
||||
|
||||
|
||||
var LanguageDetectionListener = {
|
||||
init: function() {
|
||||
window.messageManager.addMessageListener("LanguageDetection:Result", msg => {
|
||||
Translation.languageDetected(msg.target, msg.data);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var BrowserOffline = {
|
||||
_inited: false,
|
||||
|
||||
|
@ -12,6 +12,8 @@ Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ContentLinkHandler",
|
||||
"resource:///modules/ContentLinkHandler.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LanguageDetector",
|
||||
"resource:///modules/translation/LanguageDetector.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerContent",
|
||||
"resource://gre/modules/LoginManagerContent.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "InsecurePasswordUtils",
|
||||
@ -387,3 +389,49 @@ let PageStyleHandler = {
|
||||
},
|
||||
};
|
||||
PageStyleHandler.init();
|
||||
|
||||
let TranslationHandler = {
|
||||
init: function() {
|
||||
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebProgress);
|
||||
webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
|
||||
},
|
||||
|
||||
/* nsIWebProgressListener implementation */
|
||||
onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
|
||||
if (!aWebProgress.isTopLevel ||
|
||||
!(aStateFlags & Ci.nsIWebProgressListener.STATE_STOP))
|
||||
return;
|
||||
|
||||
let url = aRequest.name;
|
||||
if (!url.startsWith("http://") && !url.startsWith("https://"))
|
||||
return;
|
||||
|
||||
// Grab a 60k sample of text from the page.
|
||||
let encoder = Cc["@mozilla.org/layout/documentEncoder;1?type=text/plain"]
|
||||
.createInstance(Ci.nsIDocumentEncoder);
|
||||
encoder.init(content.document, "text/plain", encoder.SkipInvisibleContent);
|
||||
let string = encoder.encodeToStringWithMaxLength(60 * 1024);
|
||||
|
||||
// Language detection isn't reliable on very short strings.
|
||||
if (string.length < 100)
|
||||
return;
|
||||
|
||||
LanguageDetector.detectLanguage(string).then(result => {
|
||||
if (result.confident)
|
||||
sendAsyncMessage("LanguageDetection:Result", result.language);
|
||||
});
|
||||
},
|
||||
|
||||
// Unused methods.
|
||||
onProgressChange: function() {},
|
||||
onLocationChange: function() {},
|
||||
onStatusChange: function() {},
|
||||
onSecurityChange: function() {},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
|
||||
Ci.nsISupportsWeakReference])
|
||||
};
|
||||
|
||||
if (Services.prefs.getBoolPref("browser.translation.detectLanguage"))
|
||||
TranslationHandler.init();
|
||||
|
@ -11,42 +11,11 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LanguageDetector",
|
||||
"resource:///modules/translation/LanguageDetector.jsm");
|
||||
|
||||
/* Create an object keeping the information related to translation for
|
||||
* a specific browser. This object is passed to the translation
|
||||
* infobar so that it can initialize itself. The properties exposed to
|
||||
* the infobar are:
|
||||
* - supportedSourceLanguages, array of supported source language codes
|
||||
* - supportedTargetLanguages, array of supported target language codes
|
||||
* - detectedLanguage, code of the language detected on the web page.
|
||||
* - defaultTargetLanguage, code of the language to use by default for
|
||||
* translation.
|
||||
* - state, the state in which the infobar should be displayed
|
||||
* - STATE_{OFFER,TRANSLATING,TRANSLATED,ERROR} constants.
|
||||
* - translatedFrom, if already translated, source language code.
|
||||
* - translatedTo, if already translated, target language code.
|
||||
* - translate, method starting the translation of the current page.
|
||||
* - showOriginalContent, method showing the original page content.
|
||||
* - showTranslatedContent, method showing the translation for an
|
||||
* already translated page whose original content is shown.
|
||||
* - originalShown, boolean indicating if the original or translated
|
||||
* version of the page is shown.
|
||||
*/
|
||||
this.Translation = function(aBrowser) {
|
||||
this.browser = aBrowser;
|
||||
};
|
||||
|
||||
this.Translation.prototype = {
|
||||
this.Translation = {
|
||||
supportedSourceLanguages: ["en", "zh", "ja", "es", "de", "fr", "ru", "ar", "ko", "pt"],
|
||||
supportedTargetLanguages: ["en", "pl", "tr", "vi"],
|
||||
|
||||
STATE_OFFER: 0,
|
||||
STATE_TRANSLATING: 1,
|
||||
STATE_TRANSLATED: 2,
|
||||
STATE_ERROR: 3,
|
||||
|
||||
_defaultTargetLanguage: "",
|
||||
get defaultTargetLanguage() {
|
||||
if (!this._defaultTargetLanguage) {
|
||||
@ -58,6 +27,43 @@ this.Translation.prototype = {
|
||||
return this._defaultTargetLanguage;
|
||||
},
|
||||
|
||||
languageDetected: function(aBrowser, aDetectedLanguage) {
|
||||
if (this.supportedSourceLanguages.indexOf(aDetectedLanguage) != -1 &&
|
||||
aDetectedLanguage != this.defaultTargetLanguage) {
|
||||
if (!aBrowser.translationUI)
|
||||
aBrowser.translationUI = new TranslationUI(aBrowser);
|
||||
|
||||
aBrowser.translationUI.showTranslationUI(aDetectedLanguage);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* TranslationUI objects keep the information related to translation for
|
||||
* a specific browser. This object is passed to the translation
|
||||
* infobar so that it can initialize itself. The properties exposed to
|
||||
* the infobar are:
|
||||
* - detectedLanguage, code of the language detected on the web page.
|
||||
* - state, the state in which the infobar should be displayed
|
||||
* - STATE_{OFFER,TRANSLATING,TRANSLATED,ERROR} constants.
|
||||
* - translatedFrom, if already translated, source language code.
|
||||
* - translatedTo, if already translated, target language code.
|
||||
* - translate, method starting the translation of the current page.
|
||||
* - showOriginalContent, method showing the original page content.
|
||||
* - showTranslatedContent, method showing the translation for an
|
||||
* already translated page whose original content is shown.
|
||||
* - originalShown, boolean indicating if the original or translated
|
||||
* version of the page is shown.
|
||||
*/
|
||||
function TranslationUI(aBrowser) {
|
||||
this.browser = aBrowser;
|
||||
}
|
||||
|
||||
TranslationUI.prototype = {
|
||||
STATE_OFFER: 0,
|
||||
STATE_TRANSLATING: 1,
|
||||
STATE_TRANSLATED: 2,
|
||||
STATE_ERROR: 3,
|
||||
|
||||
get doc() this.browser.contentDocument,
|
||||
|
||||
translate: function(aFrom, aTo) {
|
||||
|
@ -29,8 +29,6 @@ function waitForCondition(condition, nextTest, errorMsg) {
|
||||
}
|
||||
|
||||
var TranslationStub = {
|
||||
__proto__: Translation.prototype,
|
||||
|
||||
translate: function(aFrom, aTo) {
|
||||
this.state = this.STATE_TRANSLATING;
|
||||
this.translatedFrom = aFrom;
|
||||
@ -54,6 +52,14 @@ var TranslationStub = {
|
||||
}
|
||||
};
|
||||
|
||||
function showTranslationUI(aDetectedLanguage) {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
Translation.languageDetected(browser, aDetectedLanguage);
|
||||
let ui = browser.translationUI;
|
||||
for (let name of ["translate", "_reset", "failTranslation", "finishTranslation"])
|
||||
ui[name] = TranslationStub[name];
|
||||
return ui.notificationBox.getNotificationWithValue("translation");
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
@ -83,35 +89,35 @@ function checkURLBarIcon(aExpectTranslated = false) {
|
||||
|
||||
function run_tests(aFinishCallback) {
|
||||
info("Show an info bar saying the current page is in French");
|
||||
let notif = TranslationStub.showTranslationUI("fr");
|
||||
is(notif.state, TranslationStub.STATE_OFFER, "the infobar is offering translation");
|
||||
let notif = showTranslationUI("fr");
|
||||
is(notif.state, notif.translation.STATE_OFFER, "the infobar is offering translation");
|
||||
is(notif._getAnonElt("detectedLanguage").value, "fr", "The detected language is displayed");
|
||||
checkURLBarIcon();
|
||||
|
||||
info("Click the 'Translate' button");
|
||||
notif._getAnonElt("translate").click();
|
||||
is(notif.state, TranslationStub.STATE_TRANSLATING, "the infobar is in the translating state");
|
||||
ok(!!TranslationStub.translatedFrom, "Translation.translate has been called");
|
||||
is(TranslationStub.translatedFrom, "fr", "from language correct");
|
||||
is(TranslationStub.translatedTo, TranslationStub.defaultTargetLanguage, "from language correct");
|
||||
is(notif.state, notif.translation.STATE_TRANSLATING, "the infobar is in the translating state");
|
||||
ok(!!notif.translation.translatedFrom, "Translation.translate has been called");
|
||||
is(notif.translation.translatedFrom, "fr", "from language correct");
|
||||
is(notif.translation.translatedTo, Translation.defaultTargetLanguage, "from language correct");
|
||||
checkURLBarIcon();
|
||||
|
||||
info("Make the translation fail and check we are in the error state.");
|
||||
TranslationStub.failTranslation();
|
||||
is(notif.state, TranslationStub.STATE_ERROR, "infobar in the error state");
|
||||
notif.translation.failTranslation();
|
||||
is(notif.state, notif.translation.STATE_ERROR, "infobar in the error state");
|
||||
checkURLBarIcon();
|
||||
|
||||
info("Click the try again button");
|
||||
notif._getAnonElt("tryAgain").click();
|
||||
is(notif.state, TranslationStub.STATE_TRANSLATING, "infobar in the translating state");
|
||||
ok(!!TranslationStub.translatedFrom, "Translation.translate has been called");
|
||||
is(TranslationStub.translatedFrom, "fr", "from language correct");
|
||||
is(TranslationStub.translatedTo, TranslationStub.defaultTargetLanguage, "from language correct");
|
||||
is(notif.state, notif.translation.STATE_TRANSLATING, "infobar in the translating state");
|
||||
ok(!!notif.translation.translatedFrom, "Translation.translate has been called");
|
||||
is(notif.translation.translatedFrom, "fr", "from language correct");
|
||||
is(notif.translation.translatedTo, Translation.defaultTargetLanguage, "from language correct");
|
||||
checkURLBarIcon();
|
||||
|
||||
info("Make the translation succeed and check we are in the 'translated' state.");
|
||||
TranslationStub.finishTranslation();
|
||||
is(notif.state, TranslationStub.STATE_TRANSLATED, "infobar in the translated state");
|
||||
notif.translation.finishTranslation();
|
||||
is(notif.state, notif.translation.STATE_TRANSLATED, "infobar in the translated state");
|
||||
checkURLBarIcon(true);
|
||||
|
||||
info("Test 'Show original' / 'Show Translation' buttons.");
|
||||
@ -137,45 +143,45 @@ function run_tests(aFinishCallback) {
|
||||
let from = notif._getAnonElt("fromLanguage");
|
||||
from.value = "es";
|
||||
from.doCommand();
|
||||
is(notif.state, TranslationStub.STATE_TRANSLATING, "infobar in the translating state");
|
||||
ok(!!TranslationStub.translatedFrom, "Translation.translate has been called");
|
||||
is(TranslationStub.translatedFrom, "es", "from language correct");
|
||||
is(TranslationStub.translatedTo, TranslationStub.defaultTargetLanguage, "to language correct");
|
||||
is(notif.state, notif.translation.STATE_TRANSLATING, "infobar in the translating state");
|
||||
ok(!!notif.translation.translatedFrom, "Translation.translate has been called");
|
||||
is(notif.translation.translatedFrom, "es", "from language correct");
|
||||
is(notif.translation.translatedTo, Translation.defaultTargetLanguage, "to language correct");
|
||||
// We want to show the 'translated' icon while re-translating,
|
||||
// because we are still displaying the previous translation.
|
||||
checkURLBarIcon(true);
|
||||
TranslationStub.finishTranslation();
|
||||
notif.translation.finishTranslation();
|
||||
checkURLBarIcon(true);
|
||||
|
||||
info("Check that changing the target language causes a re-translation");
|
||||
let to = notif._getAnonElt("toLanguage");
|
||||
to.value = "pl";
|
||||
to.doCommand();
|
||||
is(notif.state, TranslationStub.STATE_TRANSLATING, "infobar in the translating state");
|
||||
ok(!!TranslationStub.translatedFrom, "Translation.translate has been called");
|
||||
is(TranslationStub.translatedFrom, "es", "from language correct");
|
||||
is(TranslationStub.translatedTo, "pl", "to language correct");
|
||||
is(notif.state, notif.translation.STATE_TRANSLATING, "infobar in the translating state");
|
||||
ok(!!notif.translation.translatedFrom, "Translation.translate has been called");
|
||||
is(notif.translation.translatedFrom, "es", "from language correct");
|
||||
is(notif.translation.translatedTo, "pl", "to language correct");
|
||||
checkURLBarIcon(true);
|
||||
TranslationStub.finishTranslation();
|
||||
notif.translation.finishTranslation();
|
||||
checkURLBarIcon(true);
|
||||
|
||||
// Cleanup.
|
||||
notif.close();
|
||||
|
||||
info("Reopen the info bar to check that it's possible to override the detected language.");
|
||||
notif = TranslationStub.showTranslationUI("fr");
|
||||
is(notif.state, TranslationStub.STATE_OFFER, "the infobar is offering translation");
|
||||
notif = showTranslationUI("fr");
|
||||
is(notif.state, notif.translation.STATE_OFFER, "the infobar is offering translation");
|
||||
is(notif._getAnonElt("detectedLanguage").value, "fr", "The detected language is displayed");
|
||||
// Change the language and click 'Translate'
|
||||
notif._getAnonElt("detectedLanguage").value = "ja";
|
||||
notif._getAnonElt("translate").click();
|
||||
is(notif.state, TranslationStub.STATE_TRANSLATING, "the infobar is in the translating state");
|
||||
ok(!!TranslationStub.translatedFrom, "Translation.translate has been called");
|
||||
is(TranslationStub.translatedFrom, "ja", "from language correct");
|
||||
is(notif.state, notif.translation.STATE_TRANSLATING, "the infobar is in the translating state");
|
||||
ok(!!notif.translation.translatedFrom, "Translation.translate has been called");
|
||||
is(notif.translation.translatedFrom, "ja", "from language correct");
|
||||
notif.close();
|
||||
|
||||
info("Reopen to check the 'Not Now' button closes the notification.");
|
||||
notif = TranslationStub.showTranslationUI("fr");
|
||||
notif = showTranslationUI("fr");
|
||||
let notificationBox = gBrowser.getNotificationBox();
|
||||
ok(!!notificationBox.getNotificationWithValue("translation"), "there's a 'translate' notification");
|
||||
notif._getAnonElt("notNow").click();
|
||||
|
@ -102,7 +102,7 @@
|
||||
// Fill the lists of supported source languages.
|
||||
let detectedLanguage = this._getAnonElt("detectedLanguage");
|
||||
let fromLanguage = this._getAnonElt("fromLanguage");
|
||||
for (let code of this.translation.supportedSourceLanguages) {
|
||||
for (let code of Translation.supportedSourceLanguages) {
|
||||
let name = bundle.GetStringFromName(code);
|
||||
detectedLanguage.appendItem(name, code);
|
||||
fromLanguage.appendItem(name, code);
|
||||
@ -115,7 +115,7 @@
|
||||
|
||||
// Fill the list of supporter target languages.
|
||||
let toLanguage = this._getAnonElt("toLanguage");
|
||||
for (let code of this.translation.supportedTargetLanguages)
|
||||
for (let code of Translation.supportedTargetLanguages)
|
||||
toLanguage.appendItem(bundle.GetStringFromName(code), code);
|
||||
|
||||
if (aTranslation.translatedTo)
|
||||
@ -143,7 +143,7 @@
|
||||
this._getAnonElt("fromLanguage").value =
|
||||
this._getAnonElt("detectedLanguage").value;
|
||||
this._getAnonElt("toLanguage").value =
|
||||
this.translation.defaultTargetLanguage;
|
||||
Translation.defaultTargetLanguage;
|
||||
}
|
||||
|
||||
this._handleButtonHiding(false);
|
||||
|
Loading…
Reference in New Issue
Block a user