Bug 979424 - Implement structure and state switching for translation infobar, r=felipe.

This commit is contained in:
Florian Quèze 2014-03-21 19:07:38 +01:00
Родитель 9e742dea43
Коммит 8861e06a05
8 изменённых файлов: 392 добавлений и 0 удалений

Просмотреть файл

@ -793,6 +793,12 @@ panelview > .social-panel-frame {
height: auto;
}
/* Translation */
notification[value="translation"] {
-moz-binding: url("chrome://browser/content/translation-infobar.xml#translationbar");
}
/* Social */
/* Note the chatbox 'width' values are duplicated in socialchat.xml */
chatbox {
-moz-binding: url("chrome://browser/content/socialchat.xml#chatbox");

Просмотреть файл

@ -0,0 +1,5 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
browser.jar:
content/browser/translation-infobar.xml

Просмотреть файл

@ -10,6 +10,12 @@ EXTRA_JS_MODULES = [
'LanguageDetector.jsm'
]
JAR_MANIFESTS += ['jar.mn']
BROWSER_CHROME_MANIFESTS += [
'test/browser.ini'
]
XPCSHELL_TESTS_MANIFESTS += [
'test/xpcshell.ini'
]

Просмотреть файл

@ -0,0 +1,3 @@
[DEFAULT]
[browser_translation_infobar.js]

Просмотреть файл

@ -0,0 +1,155 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// tests the translation infobar, using a fake 'Translation' implementation.
var Translation = {
supportedSourceLanguages: ["en", "zh", "ja", "es", "de", "fr", "ru", "ar", "ko", "pt"],
supportedTargetLanguages: ["en", "pl", "tr", "vi"],
defaultTargetLanguage: "en",
_translateFrom: "",
_translateTo: "",
_deferred: null,
translate: function(aFrom, aTo) {
this._translateFrom = aFrom;
this._translateTo = aTo;
this._deferred = Promise.defer();
return this._deferred.promise;
},
_reset: function() {
this._translateFrom = "";
this._translateTo = "";
this._deferred = null;
},
failTranslation: function() {
this._deferred.reject();
this._reset();
},
finishTranslation: function() {
this._deferred.resolve();
this._reset();
},
_showOriginalCalled: false,
showOriginalContent: function() {
this._showOriginalCalled = true;
},
_showTranslationCalled: false,
showTranslatedContent: function() {
this._showTranslationCalled = true;
},
showTranslationUI: function(aLanguage) {
let notificationBox = gBrowser.getNotificationBox();
let notif = notificationBox.appendNotification("", "translation", null,
notificationBox.PRIORITY_INFO_HIGH);
notif.init(this);
notif.detectedLanguage = aLanguage;
return notif;
}
};
function test() {
waitForExplicitFinish();
// Show an info bar saying the current page is in French
let notif = Translation.showTranslationUI("fr");
is(notif.state, notif.STATE_OFFER, "the infobar is offering translation");
is(notif._getAnonElt("detectedLanguage").value, "fr", "The detected language is displayed");
// Click the "Translate" button
notif._getAnonElt("translate").click();
is(notif.state, notif.STATE_TRANSLATING, "the infobar is in the translating state");
ok(!!Translation._deferred, "Translation.translate has been called");
is(Translation._translateFrom, "fr", "from language correct");
is(Translation._translateTo, Translation.defaultTargetLanguage, "from language correct");
// Make the translation fail and check we are in the error state.
Translation.failTranslation();
is(notif.state, notif.STATE_ERROR, "infobar in the error state");
// Click the try again button
notif._getAnonElt("tryAgain").click();
is(notif.state, notif.STATE_TRANSLATING, "infobar in the translating state");
ok(!!Translation._deferred, "Translation.translate has been called");
is(Translation._translateFrom, "fr", "from language correct");
is(Translation._translateTo, Translation.defaultTargetLanguage, "to language correct");
// Make the translation succeed and check we are in the 'translated' state.
Translation.finishTranslation();
is(notif.state, notif.STATE_TRANSLATED, "infobar in the translated state");
// Test 'Show Original' / 'Show Translation' buttons.
// First check 'Show Original' is visible and 'Show Translation' is hidden.
ok(!notif._getAnonElt("showOriginal").hidden, "'Show Original' button visible");
ok(notif._getAnonElt("showTranslation").hidden, "'Show Translation' button hidden");
// Click the button.
notif._getAnonElt("showOriginal").click();
// Check the correct function has been called.
ok(Translation._showOriginalCalled, "'Translation.showOriginalContent' called")
ok(!Translation._showTranslationCalled, "'Translation.showTranslatedContent' not called")
Translation._showOriginalCalled = false;
// And the 'Show Translation' button is now visible.
ok(notif._getAnonElt("showOriginal").hidden, "'Show Original' button hidden");
ok(!notif._getAnonElt("showTranslation").hidden, "'Show Translation' button visible");
// Click the 'Show Translation' button
notif._getAnonElt("showTranslation").click();
// Check the correct function has been called.
ok(!Translation._showOriginalCalled, "'Translation.showOriginalContent' not called")
ok(Translation._showTranslationCalled, "'Translation.showTranslatedContent' called")
Translation._showTranslationCalled = false;
// Check that the 'Show Original' button is visible again.
ok(!notif._getAnonElt("showOriginal").hidden, "'Show Original' button visible");
ok(notif._getAnonElt("showTranslation").hidden, "'Show Translation' button hidden");
// Check that changing the source language causes a re-translation
let from = notif._getAnonElt("fromLanguage");
from.value = "es";
from.doCommand();
is(notif.state, notif.STATE_TRANSLATING, "infobar in the translating state");
ok(!!Translation._deferred, "Translation.translate has been called");
is(Translation._translateFrom, "es", "from language correct");
is(Translation._translateTo, Translation.defaultTargetLanguage, "to language correct");
Translation.finishTranslation();
// Check that changing the target language causes a re-translation
let to = notif._getAnonElt("toLanguage");
to.value = "pl";
to.doCommand();
is(notif.state, notif.STATE_TRANSLATING, "infobar in the translating state");
ok(!!Translation._deferred, "Translation.translate has been called");
is(Translation._translateFrom, "es", "from language correct");
is(Translation._translateTo, "pl", "to language correct");
Translation.finishTranslation();
// Cleanup.
notif.close();
// Reopen the info bar to check that it's possible to override the detected language.
notif = Translation.showTranslationUI("fr");
is(notif.state, notif.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, notif.STATE_TRANSLATING, "the infobar is in the translating state");
ok(!!Translation._deferred, "Translation.translate has been called");
is(Translation._translateFrom, "ja", "from language correct");
notif.close();
// Reopen one last time to check the 'Not Now' button closes the notification.
notif = Translation.showTranslationUI("fr");
let notificationBox = gBrowser.getNotificationBox();
ok(!!notificationBox.getNotificationWithValue("translation"), "there's a 'translate' notification");
notif._getAnonElt("notNow").click();
ok(!notificationBox.getNotificationWithValue("translation"), "no 'translate' notification after clicking 'not now'");
finish();
}

Просмотреть файл

@ -0,0 +1,196 @@
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE bindings [
<!ENTITY % notificationDTD SYSTEM "chrome://global/locale/notification.dtd">
%notificationDTD;
<!ENTITY % translationDTD SYSTEM "chrome://browser/locale/translation.dtd" >
%translationDTD;
]>
<bindings id="translationBindings"
xmlns="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:xbl="http://www.mozilla.org/xbl">
<binding id="translationbar" extends="chrome://global/content/bindings/notification.xml#notification" role="xul:alert">
<resources>
<stylesheet src="chrome://global/skin/notification.css"/>
</resources>
<content>
<xul:hbox class="notification-inner outset" flex="1" xbl:inherits="type">
<xul:hbox anonid="details" align="center" flex="1">
<xul:image anonid="messageImage" class="messageImage" xbl:inherits="src=image,type,value"/>
<xul:deck anonid="translationStates" selectedIndex="0">
<!-- offer to translate -->
<xul:hbox class="translate-offer-box" align="baseline">
<xul:label value="&translation.thisPageIsIn.label;"/>
<xul:menulist anonid="detectedLanguage">
<xul:menupopup/>
</xul:menulist>
<xul:label value="&translation.translateThisPage.label;"/>
<xul:button label="&translation.translate.button;" anonid="translate"
oncommand="document.getBindingParent(this).translate();"/>
<xul:button label="&translation.notNow.button;" anonid="notNow"
oncommand="document.getBindingParent(this).close();"/>
</xul:hbox>
<!-- translating -->
<xul:vbox class="translating-box" pack="center">
<xul:label value="&translation.translatingContent.label;"/>
</xul:vbox>
<!-- translated -->
<xul:hbox class="translated-box" align="baseline">
<xul:label value="&translation.translatedFrom.label;"/>
<xul:menulist anonid="fromLanguage"
oncommand="document.getBindingParent(this).translate()">
<xul:menupopup/>
</xul:menulist>
<xul:label value="&translation.translatedTo.label;"/>
<xul:menulist anonid="toLanguage"
oncommand="document.getBindingParent(this).translate()">
<xul:menupopup/>
</xul:menulist>
<xul:button anonid="showOriginal"
label="&translation.showOriginal.button;"
oncommand="document.getBindingParent(this).showOriginal();"/>
<xul:button anonid="showTranslation"
label="&translation.showTranslation.button;"
oncommand="document.getBindingParent(this).showTranslation();"/>
</xul:hbox>
<!-- error -->
<xul:hbox class="translation-error" align="baseline">
<xul:label value="&translation.errorTranslating.label;"/>
<xul:button label="&translation.tryAgain.button;" anonid="tryAgain"
oncommand="document.getBindingParent(this).translate();"/>
</xul:hbox>
</xul:deck>
<xul:spacer flex="1"/>
<xul:button type="menu" label="&translation.options.menu;">
<xul:menupopup/>
</xul:button>
</xul:hbox>
<xul:toolbarbutton ondblclick="event.stopPropagation();"
class="messageCloseButton close-icon tabbable"
xbl:inherits="hidden=hideclose"
tooltiptext="&closeNotification.tooltip;"
oncommand="document.getBindingParent(this).close();"/>
</xul:hbox>
</content>
<implementation>
<field name="STATE_OFFER" readonly="true">0</field>
<field name="STATE_TRANSLATING" readonly="true">1</field>
<field name="STATE_TRANSLATED" readonly="true">2</field>
<field name="STATE_ERROR" readonly="true">3</field>
<property name="state"
onget="return this._getAnonElt('translationStates').selectedIndex;"
onset="this._getAnonElt('translationStates').selectedIndex = val;"/>
<!-- Initialize the infobar with a translation object exposing these
properties:
- supportedSourceLanguages, array of supported source language codes
- supportedTargetLanguages, array of supported target language codes
- defaultTargetLanguage, code of the language to use by default for
translation.
- translate, method starting the translation of the current page.
Returns a promise.
- showOriginalContent, method showing the original page content.
- showTranslatedContent, method showing the translation for an
already translated page whose original content is shown.
-->
<method name="init">
<parameter name="aTranslation"/>
<body>
<![CDATA[
this.translation = aTranslation;
let bundle = Cc["@mozilla.org/intl/stringbundle;1"]
.getService(Ci.nsIStringBundleService)
.createBundle("chrome://global/locale/languageNames.properties");
let detectedLanguage = this._getAnonElt("detectedLanguage");
let fromLanguage = this._getAnonElt("fromLanguage");
for (let code of this.translation.supportedSourceLanguages) {
let name = bundle.GetStringFromName(code);
detectedLanguage.appendItem(name, code);
fromLanguage.appendItem(name, code);
}
let toLanguage = this._getAnonElt("toLanguage");
for (let code of this.translation.supportedTargetLanguages)
toLanguage.appendItem(bundle.GetStringFromName(code), code);
]]>
</body>
</method>
<method name="_getAnonElt">
<parameter name="aAnonId"/>
<body>
return document.getAnonymousElementByAttribute(this, "anonid", aAnonId);
</body>
</method>
<field name="_detectedLanguage">""</field>
<property name="detectedLanguage" onget="return this._detectedLanguage;">
<setter><![CDATA[
this._getAnonElt("detectedLanguage").value = val;
this._detectedLanguage = val;
return val;
]]></setter>
</property>
<method name="translate">
<body>
<![CDATA[
if (this.state == this.STATE_OFFER) {
this._getAnonElt("fromLanguage").value =
this._getAnonElt("detectedLanguage").value;
this._getAnonElt("toLanguage").value =
this.translation.defaultTargetLanguage;
}
this._getAnonElt("showOriginal").hidden = false;
this._getAnonElt("showTranslation").hidden = true;
this.state = this.STATE_TRANSLATING;
this.translation.translate(this._getAnonElt("fromLanguage").value,
this._getAnonElt("toLanguage").value)
.then(() => { this.state = this.STATE_TRANSLATED; },
() => { this.state = this.STATE_ERROR; });
]]>
</body>
</method>
<method name="showOriginal">
<body>
<![CDATA[
this._getAnonElt("showOriginal").hidden = true;
this._getAnonElt("showTranslation").hidden = false;
this.translation.showOriginalContent();
]]>
</body>
</method>
<method name="showTranslation">
<body>
<![CDATA[
this._getAnonElt("showOriginal").hidden = false;
this._getAnonElt("showTranslation").hidden = true;
this.translation.showTranslatedContent();
]]>
</body>
</method>
</implementation>
</binding>
</bindings>

Просмотреть файл

@ -0,0 +1,20 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!ENTITY translation.thisPageIsIn.label "This page is in">
<!ENTITY translation.translateThisPage.label "Translate this page?">
<!ENTITY translation.translate.button "Translate">
<!ENTITY translation.notNow.button "Not Now">
<!ENTITY translation.translatingContent.label "Translating page content…">
<!ENTITY translation.translatedFrom.label "This page has been translated from">
<!ENTITY translation.translatedTo.label "to">
<!ENTITY translation.showOriginal.button "Show Original">
<!ENTITY translation.showTranslation.button "Show Translation">
<!ENTITY translation.errorTranslating.label "There has been an error translating this page.">
<!ENTITY translation.tryAgain.button "Try Again">
<!ENTITY translation.options.menu "Options">

Просмотреть файл

@ -76,6 +76,7 @@
locale/browser/tabbrowser.properties (%chrome/browser/tabbrowser.properties)
locale/browser/tabview.properties (%chrome/browser/tabview.properties)
locale/browser/taskbar.properties (%chrome/browser/taskbar.properties)
locale/browser/translation.dtd (%chrome/browser/translation.dtd)
locale/browser/downloads/downloads.dtd (%chrome/browser/downloads/downloads.dtd)
locale/browser/downloads/downloads.properties (%chrome/browser/downloads/downloads.properties)
locale/browser/places/places.dtd (%chrome/browser/places/places.dtd)