Bug 571897 (Sync UI) - Part 6: Pref Pane [r=dolske]
authorPaul O’Shannessy <paul@oshannessy.com>
Mon, 02 Aug 2010 16:37:56 -0700
changeset 48741 6fbf47730e4882ad72002e8209f2bb3806884c82
parent 48740 eaf2e61d63e32f31201fd8850a2a4e69957e30c6
child 48742 f2659f5555fe4bf139d55bde4e01b853bdb0ea22
push id14795
push userposhannessy@mozilla.com
push dateMon, 02 Aug 2010 23:41:56 +0000
treeherdermozilla-central@f2659f5555fe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdolske
bugs571897
milestone2.0b3pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 571897 (Sync UI) - Part 6: Pref Pane [r=dolske]
browser/components/preferences/jar.mn
browser/components/preferences/preferences.xul
browser/components/preferences/sync.js
browser/components/preferences/sync.xul
browser/locales/en-US/chrome/browser/preferences/preferences.dtd
browser/locales/en-US/chrome/browser/preferences/preferences.properties
browser/locales/en-US/chrome/browser/preferences/sync.dtd
browser/locales/jar.mn
--- a/browser/components/preferences/jar.mn
+++ b/browser/components/preferences/jar.mn
@@ -27,10 +27,14 @@ browser.jar:
 *   content/browser/preferences/preferences.xul
 *   content/browser/preferences/privacy.xul
 *   content/browser/preferences/privacy.js
 *   content/browser/preferences/sanitize.xul
 *   content/browser/preferences/security.xul
 *   content/browser/preferences/security.js
 *   content/browser/preferences/selectBookmark.xul
 *   content/browser/preferences/selectBookmark.js
+#ifdef MOZ_SERVICES_SYNC
+*   content/browser/preferences/sync.xul
+*   content/browser/preferences/sync.js
+#endif
 *   content/browser/preferences/tabs.xul
 *   content/browser/preferences/tabs.js
--- a/browser/components/preferences/preferences.xul
+++ b/browser/components/preferences/preferences.xul
@@ -108,15 +108,19 @@
     <prefpane id="paneApplications" label="&paneApplications.title;"
               src="chrome://browser/content/preferences/applications.xul"/>
     <prefpane id="panePrivacy" label="&panePrivacy.title;"
               src="chrome://browser/content/preferences/privacy.xul"/>
     <prefpane id="paneSecurity" label="&paneSecurity.title;"
               src="chrome://browser/content/preferences/security.xul"/>
     <prefpane id="paneAdvanced" label="&paneAdvanced.title;"
               src="chrome://browser/content/preferences/advanced.xul"/>
+#ifdef MOZ_SERVICES_SYNC
+    <prefpane id="paneSync" label="&paneSync.title;"
+              src="chrome://browser/content/preferences/sync.xul"/>
+#endif
 
 #ifdef XP_MACOSX
 #include ../../base/content/browserMountPoints.inc
 #endif
 
 </prefwindow>
 
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/sync.js
@@ -0,0 +1,244 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Weave.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Edward Lee <edilee@mozilla.com>
+ *   Mike Connor <mconnor@mozilla.com>
+ *   Paul O’Shannessy <paul@oshannessy.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+Components.utils.import("resource://services-sync/service.js");
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+const PAGE_NO_ACCOUNT = 0;
+const PAGE_HAS_ACCOUNT = 1;
+
+let gSyncPane = {
+  _stringBundle: null,
+  prefArray: ["engine.bookmarks", "engine.passwords", "engine.prefs",
+              "engine.tabs", "engine.history"],
+
+  get page() {
+    return document.getElementById("weavePrefsDeck").selectedIndex;
+  },
+
+  set page(val) {
+    document.getElementById("weavePrefsDeck").selectedIndex = val;
+  },
+
+  get _usingCustomServer() {
+    return Weave.Svc.Prefs.isSet("serverURL");
+  },
+
+  onLoginStart: function () {
+    if (this.page == PAGE_NO_ACCOUNT)
+      return;
+
+    document.getElementById("loginFeedbackRow").hidden = true;
+    document.getElementById("connectThrobber").hidden = false;
+  },
+
+  onLoginError: function () {
+    if (this.page == PAGE_NO_ACCOUNT)
+      return;
+
+    document.getElementById("connectThrobber").hidden = true;
+    document.getElementById("loginFeedbackRow").hidden = false;
+    let label = document.getElementById("loginError");
+    label.value = Weave.Utils.getErrorString(Weave.Status.login);
+    label.className = "error";
+  },
+
+  onLoginFinish: function () {
+    document.getElementById("connectThrobber").hidden = true;
+    this.updateWeavePrefs();
+  },
+
+  init: function () {
+    let obs = [
+      ["weave:service:login:start",   "onLoginStart"],
+      ["weave:service:login:error",   "onLoginError"],
+      ["weave:service:login:finish",  "onLoginFinish"],
+      ["weave:service:start-over",    "updateWeavePrefs"],
+      ["weave:service:setup-complete","updateWeavePrefs"],
+      ["weave:service:logout:finish", "updateWeavePrefs"]];
+
+    // Add the observers now and remove them on unload
+    let self = this;
+    let addRem = function(add) {
+      obs.forEach(function([topic, func]) {
+        //XXXzpao This should use Services.obs.* but Weave's Obs does nice handling
+        //        of `this`. Fix in a followup. (bug 583347)
+        if (add)
+          Weave.Svc.Obs.add(topic, self[func], self);
+        else
+          Weave.Svc.Obs.remove(topic, self[func], self);
+      });
+    };
+    addRem(true);
+    window.addEventListener("unload", function() addRem(false), false);
+
+    this._stringBundle =
+      Services.strings.createBundle("chrome://browser/locale/preferences/preferences.properties");;
+    this.updateWeavePrefs();
+  },
+
+  updateWeavePrefs: function () {
+    if (Weave.Status.service == Weave.CLIENT_NOT_CONFIGURED ||
+        Weave.Svc.Prefs.get("firstSync", "") == "notReady")
+      this.page = PAGE_NO_ACCOUNT;
+    else {
+      this.page = PAGE_HAS_ACCOUNT;
+      document.getElementById("currentUser").value = Weave.Service.username;
+      document.getElementById("syncComputerName").value = Weave.Clients.localName;
+      if (Weave.Status.service == Weave.LOGIN_FAILED)
+        this.onLoginError();
+      this.updateConnectButton();
+      let syncEverything = this._checkDefaultValues();
+      document.getElementById("weaveSyncMode").selectedIndex = syncEverything ? 0 : 1;
+      document.getElementById("syncModeOptions").selectedIndex = syncEverything ? 0 : 1;
+      document.getElementById("tosPP").hidden = this._usingCustomServer;
+    }
+  },
+
+  updateConnectButton: function () {
+    let str = Weave.Service.isLoggedIn ? this._stringBundle.GetStringFromName("disconnect.label")
+                                       : this._stringBundle.GetStringFromName("connect.label");
+    document.getElementById("connectButton").label = str;
+  },
+
+  handleConnectCommand: function () {
+    Weave.Service.isLoggedIn ? Weave.Service.logout() : Weave.Service.login();
+  },
+
+  startOver: function (showDialog) {
+    if (showDialog) {
+      let flags = Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_IS_STRING +
+                  Services.prompt.BUTTON_POS_1 * Services.prompt.BUTTON_TITLE_CANCEL;
+      let buttonChoice =
+        Services.prompt.confirmEx(window,
+                                  this._stringBundle.GetStringFromName("differentAccount.title"),
+                                  this._stringBundle.GetStringFromName("differentAccount.label"),
+                                  flags,
+                                  this._stringBundle.GetStringFromName("differentAccountConfirm.label"),
+                                  null, null, null, {});
+
+      // If the user selects cancel, just bail
+      if (buttonChoice == 1)
+        return;
+    }
+
+    this.handleExpanderClick();
+    Weave.Service.startOver();
+    this.updateWeavePrefs();
+    document.getElementById("manageAccountExpander").className = "expander-down";
+    document.getElementById("manageAccountControls").hidden = true;
+  },
+
+  updatePass: function () {
+    if (Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED)
+      gSyncUtils.changePassword();
+    else
+      gSyncUtils.updatePassphrase();
+  },
+
+  resetPass: function () {
+    if (Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED)
+      gSyncUtils.resetPassword();
+    else
+      gSyncUtils.resetPassphrase();
+  },
+
+  updateSyncPrefs: function () {
+    let syncEverything = document.getElementById("weaveSyncMode").selectedItem.value == "syncEverything";
+    document.getElementById("syncModeOptions").selectedIndex = syncEverything ? 0 : 1;
+
+    if (syncEverything) {
+      let prefs = this.prefArray;
+      for (let i = 0; i < prefs.length; ++i)
+        document.getElementById(prefs[i]).value = true;
+    }
+  },
+
+  /**
+   * Check whether all the preferences values are set to their default values
+   *
+   * @param aPrefs an array of pref names to check for
+   * @returns boolean true if all of the prefs are set to their default values,
+   *                  false otherwise
+   */
+  _checkDefaultValues: function () {
+    let prefs = this.prefArray;
+    for (let i = 0; i < prefs.length; ++i) {
+      let pref = document.getElementById(prefs[i]);
+      if (pref.value != pref.defaultValue)
+        return false;
+    }
+    return true;
+  },
+
+
+  handleExpanderClick: function () {
+    //XXXzpao Might be fixed in bug 583441, otherwise we'll need a new bug.
+    // ok, this is pretty evil, and likely fragile if the prefwindow
+    // binding changes, but that won't happen in 3.6 *fingers crossed*
+    let prefwindow = document.documentElement;
+    let pane = document.getElementById("paneSync");
+    if (prefwindow._shouldAnimate)
+      prefwindow._currentHeight = pane.contentHeight;
+
+    let expander = document.getElementById("manageAccountExpander");
+    let expand = expander.className == "expander-down";
+    expander.className =
+       expand ? "expander-up" : "expander-down";
+    document.getElementById("manageAccountControls").hidden = !expand;
+
+    // and... shazam
+    if (prefwindow._shouldAnimate)
+      prefwindow.animate("null", pane);
+  },
+
+  openSetup: function (resetSync) {
+    var win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
+    if (win)
+      win.focus();
+    else {
+      window.openDialog("chrome://browser/content/syncSetup.xul",
+                        "weaveSetup", "centerscreen,chrome,resizable=no", resetSync);
+    }
+  },
+
+  resetSync: function () {
+    this.openSetup(true);
+  }
+}
+
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/sync.xul
@@ -0,0 +1,207 @@
+<?xml version="1.0"?>
+
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Weave.
+#
+# The Initial Developer of the Original Code is the Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2009
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Edward Lee <edilee@mozilla.com>
+#   Mike Connor <mconnor@mozilla.com>
+#   Paul O’Shannessy <paul@oshannessy.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+<!DOCTYPE overlay [
+<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
+<!ENTITY % syncBrandDTD SYSTEM "chrome://browser/locale/syncBrand.dtd">
+<!ENTITY % syncDTD SYSTEM "chrome://browser/locale/preferences/sync.dtd">
+%brandDTD;
+%syncBrandDTD;
+%syncDTD;
+]>
+
+<overlay id="SyncPaneOverlay"
+         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+         xmlns:html="http://www.w3.org/1999/xhtml">
+
+  <prefpane id="paneSync"
+            helpTopic="prefs-weave"
+            onpaneload="gSyncPane.init()">
+
+    <preferences>
+      <preference id="engine.bookmarks" name="services.sync.engine.bookmarks" type="bool"/>
+      <preference id="engine.history"   name="services.sync.engine.history"   type="bool"/>
+      <preference id="engine.tabs"      name="services.sync.engine.tabs"      type="bool"/>
+      <preference id="engine.prefs"     name="services.sync.engine.prefs"     type="bool"/>
+      <preference id="engine.passwords" name="services.sync.engine.passwords" type="bool"/>
+    </preferences>
+
+
+    <script type="application/javascript"
+            src="chrome://browser/content/preferences/sync.js"/>
+    <script type="application/javascript"
+            src="chrome://browser/content/syncUtils.js"/>
+
+
+      <deck id="weavePrefsDeck">
+        <vbox id="noAccount" align="center">
+          <spacer flex="1"/>
+          <button id="setupButton"
+                  label="&setupButton.label;"
+                  accesskey="&setupButton.accesskey;"
+                  oncommand="gSyncPane.openSetup();"/>
+          <separator/>
+          <description id="syncDesc" flex="1">
+            &weaveDesc.label;
+          </description>
+          <spacer flex="3"/>
+        </vbox>
+        <vbox id="hasAccount">
+          <groupbox>
+            <caption label="&accountGroupboxCaption.label;"/>
+            <grid>
+              <rows>
+                <row align="center">
+                  <label value="&currentUser.label;" control="currentUser"/>
+                  <textbox id="currentUser" readonly="true">
+                    <image/>
+                  </textbox>
+                  <hbox align="center">
+                    <button id="connectButton" oncommand="gSyncPane.handleConnectCommand()"/>
+                    <image id="connectThrobber"
+                           hidden="true"/>
+                  </hbox>
+                </row>
+                <row id="loginFeedbackRow" hidden="true">
+                  <spacer/>
+                  <label id="loginError" value=""/>
+                  <hbox>
+                    <label class="text-link"
+                           onclick="gSyncPane.updatePass(); return false;"
+                           value="&updatePass.label;"/>
+                    <label class="text-link"
+                           onclick="gSyncPane.resetPass(); return false;"
+                           value="&resetPass.label;"/>
+                  </hbox>
+                </row>
+                <!-- XXXzpao We should make this behave like the "details" view in CRH.
+                             do in followup (bug 583441) -->
+                <row id="manageAccountControls" hidden="true">
+                  <spacer/>
+                    <vbox class="indent">
+                      <label class="text-link"
+                             onclick="gSyncUtils.changePassword(); return false;"
+                             value="&changePassword.label;"/>
+                      <label class="text-link"
+                             onclick="gSyncUtils.resetPassphrase(); return false;"
+                             value="&changePassphrase.label;"/>
+                      <label class="text-link"
+                             onclick="gSyncPane.resetSync(); return false;"
+                             value="&resetSync.label;"/>
+                      <label class="text-link"
+                             onclick="gSyncPane.startOver(true); return false;"
+                             value="&differentAccount.label;"/>
+                    </vbox>
+                  <spacer/>
+                </row>
+                <row>
+                  <spacer/>
+                  <button id="manageAccountExpander"
+                          class="expander-down"
+                          label="&manageAccount.label;"
+                          accesskey="&manageAccount.accesskey;"
+                          align="left"
+                          oncommand="gSyncPane.handleExpanderClick()"/>
+                  <spacer/>
+                </row>
+              </rows>
+            </grid>
+          </groupbox>
+          <groupbox>
+            <caption label="&syncPrefsCaption.label;"/>
+            <grid>
+              <rows>
+                <row align="center">
+                  <label value="&syncComputerName.label;"
+                         accesskey="&syncComputerName.accesskey;"
+                         control="syncComputerName"/>
+                  <textbox id="syncComputerName"
+                           onchange="gSyncUtils.changeName(this)"/>
+                </row>
+                <row align="center">
+              <label value="&syncModeSwitchDesc.label;"
+                     accesskey="&syncModeSwitchDesc.accesskey;"
+                     control="weaveSyncMode"/>
+              <menulist id="weaveSyncMode" oncommand="gSyncPane.updateSyncPrefs()">
+                <menupopup>
+                  <menuitem label="&syncEverything.label;" value="syncEverything"/>
+                  <menuitem label="&customSync.label;"     value="customSync"/>
+                </menupopup>
+              </menulist>
+                </row>
+              </rows>
+            </grid>
+            <separator/>
+            <deck id="syncModeOptions" class="indent">
+              <description id="syncEverythingDesc">
+                &syncEverythingDescription.label;
+              </description>
+              <vbox>
+                <checkbox label="&syncItem.bookmarks.label;"
+                          accesskey="&syncItem.bookmarks.accesskey;"
+                          preference="engine.bookmarks"/>
+                <checkbox label="&syncItem.passwords.label;"
+                          accesskey="&syncItem.passwords.accesskey;"
+                          preference="engine.passwords"/>
+                <checkbox label="&syncItem.prefs.label;"
+                          accesskey="&syncItem.prefs.accesskey;"
+                          preference="engine.prefs"/>
+                <checkbox label="&syncItem.history.label;"
+                          accesskey="&syncItem.history.accesskey;"
+                          preference="engine.history"/>
+                <checkbox label="&syncItem.tabs.label;"
+                          accesskey="&syncItem.tabs.accesskey;"
+                          preference="engine.tabs"/>
+              </vbox>
+            </deck>
+            <separator/>
+          </groupbox>
+          <hbox id="tosPP" pack="center">
+            <label class="text-link"
+                   onclick="event.stopPropagation();gSyncUtils.openToS();"
+                   value="&prefs.tosLink.label;"/>
+            <label class="text-link"
+                   onclick="event.stopPropagation();gSyncUtils.openPP();"
+                   value="&prefs.ppLink.label;"/>
+          </hbox>
+        </vbox>
+      </deck>
+  </prefpane>
+</overlay>
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.dtd
@@ -9,8 +9,11 @@
 
 <!ENTITY  paneGeneral.title       "General">
 <!ENTITY  paneTabs.title          "Tabs">
 <!ENTITY  paneContent.title       "Content">
 <!ENTITY  paneApplications.title  "Applications">
 <!ENTITY  panePrivacy.title       "Privacy">
 <!ENTITY  paneSecurity.title      "Security">
 <!ENTITY  paneAdvanced.title      "Advanced">
+
+<!-- LOCALIZATION NOTE (paneSync.title): This should match syncBrand.shortName.label in ../syncBrand.dtd -->
+<!ENTITY  paneSync.title          "Sync">
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.properties
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.properties
@@ -98,8 +98,17 @@ offlineAppRemoveConfirm=Remove offline d
 # offline application
 #   e.g. offlineAppUsage : "50.23 MB"
 #   %1$S = size (in bytes or megabytes, ...)
 #   %2$S = unit of measure (bytes, KB, MB, ...)
 offlineAppUsage=%1$S %2$S
 
 offlinepermissionstext=The following websites are not allowed to store data for offline use:
 offlinepermissionstitle=Offline Data
+
+
+#### Syncing
+connect.label=Connect
+disconnect.label=Disconnect
+
+differentAccount.title=Use a Different Account?
+differentAccount.label=This will reset all of your Sync account information and preferences.
+differentAccountConfirm.label=Reset All Information
new file mode 100644
--- /dev/null
+++ b/browser/locales/en-US/chrome/browser/preferences/sync.dtd
@@ -0,0 +1,44 @@
+<!-- The page shown when not logged in... -->
+<!ENTITY setupButton.label          "Set Up &syncBrand.fullName.label;">
+<!ENTITY setupButton.accesskey      "S">
+<!ENTITY weaveDesc.label            "&syncBrand.fullName.label; lets you access your history, bookmarks, passwords and open tabs across all your devices.">
+
+<!-- The page shown when logged in... -->
+<!ENTITY accountGroupboxCaption.label "&syncBrand.fullName.label; Account">
+<!ENTITY currentUser.label            "Current User:">
+
+<!-- Login error feedback -->
+<!ENTITY updatePass.label             "Update">
+<!ENTITY resetPass.label              "Reset">
+
+<!-- Manage Account -->
+<!ENTITY manageAccount.label          "Manage Account">
+<!ENTITY manageAccount.accesskey      "A">
+<!ENTITY changePassword.label         "Change Password">
+<!ENTITY changePassphrase.label       "Change Secret Phrase">
+<!ENTITY resetSync.label              "Reset Sync">
+<!ENTITY differentAccount.label       "Use a Different Account">
+
+<!-- Sync Settings -->
+<!ENTITY syncPrefsCaption.label       "Browser Sync">
+<!ENTITY syncComputerName.label       "Computer Name:">
+<!ENTITY syncComputerName.accesskey   "c">
+<!ENTITY syncModeSwitchDesc.label     "&brandShortName; will: ">
+<!ENTITY syncModeSwitchDesc.accesskey "w">
+<!ENTITY syncEverything.label         "Sync Everything">
+<!ENTITY customSync.label             "Use my custom settings">
+<!ENTITY syncEverythingDescription.label  "Your bookmarks, history, passwords, preferences, and tabs will be synced.">
+<!ENTITY syncItem.bookmarks.label     "Sync Bookmarks">
+<!ENTITY syncItem.bookmarks.accesskey "m">
+<!ENTITY syncItem.tabs.label          "Sync Tabs">
+<!ENTITY syncItem.tabs.accesskey      "T">
+<!ENTITY syncItem.history.label       "Sync History">
+<!ENTITY syncItem.history.accesskey   "r">
+<!ENTITY syncItem.passwords.label     "Sync Passwords">
+<!ENTITY syncItem.passwords.accesskey "P">
+<!ENTITY syncItem.prefs.label         "Sync Preferences">
+<!ENTITY syncItem.prefs.accesskey     "S">
+
+<!-- Footer stuff -->
+<!ENTITY prefs.tosLink.label        "Terms of Service">
+<!ENTITY prefs.ppLink.label         "Privacy Policy">
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -59,16 +59,19 @@
     locale/browser/preferences/fonts.dtd              (%chrome/browser/preferences/fonts.dtd)
     locale/browser/preferences/main.dtd               (%chrome/browser/preferences/main.dtd)
     locale/browser/preferences/languages.dtd          (%chrome/browser/preferences/languages.dtd)
     locale/browser/preferences/permissions.dtd        (%chrome/browser/preferences/permissions.dtd)
     locale/browser/preferences/preferences.dtd        (%chrome/browser/preferences/preferences.dtd)
     locale/browser/preferences/preferences.properties (%chrome/browser/preferences/preferences.properties)
     locale/browser/preferences/privacy.dtd            (%chrome/browser/preferences/privacy.dtd)
     locale/browser/preferences/security.dtd           (%chrome/browser/preferences/security.dtd)
+#ifdef MOZ_SERVICES_SYNC
+    locale/browser/preferences/sync.dtd               (%chrome/browser/preferences/sync.dtd)
+#endif
     locale/browser/preferences/tabs.dtd               (%chrome/browser/preferences/tabs.dtd)
     locale/browser/sidebar/sidebar.properties      (%chrome/browser/sidebar/sidebar.properties)
 #ifdef MOZ_SERVICES_SYNC
     locale/browser/syncBrand.dtd                (%chrome/browser/syncBrand.dtd)
     locale/browser/syncSetup.dtd                (%chrome/browser/syncSetup.dtd)
     locale/browser/syncSetup.properties         (%chrome/browser/syncSetup.properties)
     locale/browser/syncGenericChange.properties         (%chrome/browser/syncGenericChange.properties)
 #endif