Bug 1523763 - Move tab context menu strings to FTL file loaded on-demand. r=Gijs,flod
authorBrian <chenbri2@msu.edu>
Fri, 29 Mar 2019 14:55:12 +0000
changeset 466771 028c0eff90a7ad121827f45040699bbca433c5e7
parent 466770 a1cfb4874e277b523330f3595ac138897b49f41a
child 466772 0e99a57e21d69b63116be0dd3f62b8791de51964
push id35780
push useropoprus@mozilla.com
push dateFri, 29 Mar 2019 21:53:01 +0000
treeherdermozilla-central@414f37afbe07 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGijs, flod
bugs1523763
milestone68.0a1
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 1523763 - Move tab context menu strings to FTL file loaded on-demand. r=Gijs,flod Moved tab context menu out of browser.dtd to browser.xul except for sendPageToDevice, sendLinkToDevice, moveTabOptions, moveSelectedTabOptions, undoCloseTab. Not sure if tabbrowser.js and tabbrowser.xul are working as intended. Differential Revision: https://phabricator.services.mozilla.com/D19312
browser/base/content/browser.xul
browser/base/content/tabbrowser.js
browser/base/content/test/general/browser_typeAheadFind.js
browser/base/content/test/permissions/browser_temporary_permissions_navigation.js
browser/base/content/test/sanitize/browser_sanitize-formhistory.js
browser/base/content/test/sync/browser_contextmenu_sendtab.js
browser/components/customizableui/test/browser_947914_button_find.js
browser/components/customizableui/test/browser_947914_button_history.js
browser/components/extensions/test/browser/head.js
browser/locales/en-US/browser/tabContextMenu.ftl
browser/locales/en-US/chrome/browser/browser.dtd
devtools/client/webconsole/test/mochitest/browser_jsterm_ctrl_a_select_all.js
python/l10n/fluent_migrations/bug_1523763_tabContextMenu.py
toolkit/components/extensions/test/browser/browser_ext_themes_findbar.js
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -120,101 +120,83 @@
 # *must* go into the browser-sets.inc file so that they can be shared with other
 # top level windows in macWindow.inc.xul.
 #include browser-sets.inc
 
   <popupset id="mainPopupSet">
     <menupopup id="tabContextMenu"
                onpopupshowing="if (event.target == this) TabContextMenu.updateContextMenu(this);"
                onpopuphidden="if (event.target == this) TabContextMenu.contextTab = null;">
-      <menuitem id="context_reloadTab" label="&reloadTab.label;" accesskey="&reloadTab.accesskey;"
+      <menuitem id="context_reloadTab" data-lazy-l10n-id="reload-tab"
                 oncommand="gBrowser.reloadTab(TabContextMenu.contextTab);"/>
-      <menuitem id="context_reloadSelectedTabs" label="&reloadTabs.label;" hidden="true"
-                accesskey="&reloadTabs.accesskey;"
+      <menuitem id="context_reloadSelectedTabs" data-lazy-l10n-id="reload-tabs" hidden="true"
                 oncommand="gBrowser.reloadMultiSelectedTabs();"/>
       <menuitem id="context_toggleMuteTab" oncommand="TabContextMenu.contextTab.toggleMuteAudio();"/>
       <menuitem id="context_toggleMuteSelectedTabs" hidden="true"
                 oncommand="gBrowser.toggleMuteAudioOnMultiSelectedTabs(TabContextMenu.contextTab);"/>
-      <menuitem id="context_pinTab" label="&pinTab.label;"
-                accesskey="&pinTab.accesskey;"
+      <menuitem id="context_pinTab" data-lazy-l10n-id="pin-tab"
                 oncommand="gBrowser.pinTab(TabContextMenu.contextTab);"/>
-      <menuitem id="context_unpinTab" label="&unpinTab.label;" hidden="true"
-                accesskey="&unpinTab.accesskey;"
+      <menuitem id="context_unpinTab" data-lazy-l10n-id="unpin-tab" hidden="true"
                 oncommand="gBrowser.unpinTab(TabContextMenu.contextTab);"/>
-      <menuitem id="context_pinSelectedTabs" label="&pinSelectedTabs.label;" hidden="true"
-                accesskey="&pinSelectedTabs.accesskey;"
+      <menuitem id="context_pinSelectedTabs" data-lazy-l10n-id="pin-selected-tabs" hidden="true"
                 oncommand="gBrowser.pinMultiSelectedTabs();"/>
-      <menuitem id="context_unpinSelectedTabs" label="&unpinSelectedTabs.label;" hidden="true"
-                accesskey="&unpinSelectedTabs.accesskey;"
+      <menuitem id="context_unpinSelectedTabs" data-lazy-l10n-id="unpin-selected-tabs" hidden="true"
                 oncommand="gBrowser.unpinMultiSelectedTabs();"/>
-      <menuitem id="context_duplicateTab" label="&duplicateTab.label;"
-                accesskey="&duplicateTab.accesskey;"
+      <menuitem id="context_duplicateTab" data-lazy-l10n-id="duplicate-tab"
                 oncommand="duplicateTabIn(TabContextMenu.contextTab, 'tab');"/>
-      <menuitem id="context_duplicateTabs" label="&duplicateTabs.label;"
-                accesskey="&duplicateTabs.accesskey;"
+      <menuitem id="context_duplicateTabs" data-lazy-l10n-id="duplicate-tabs"
                 oncommand="TabContextMenu.duplicateSelectedTabs();"/>
       <menuseparator/>
-      <menuitem id="context_selectAllTabs" label="&selectAllTabs.label;" accesskey="&selectAllTabs.accesskey;"
+      <menuitem id="context_selectAllTabs" data-lazy-l10n-id="select-all-tabs"
                 oncommand="gBrowser.selectAllTabs();"/>
       <menuitem id="context_bookmarkSelectedTabs"
                 hidden="true"
-                label="&bookmarkSelectedTabs.label;"
-                accesskey="&bookmarkSelectedTabs.accesskey;"
+                data-lazy-l10n-id="bookmark-selected-tabs"
                 oncommand="PlacesCommandHook.bookmarkPages(PlacesCommandHook.uniqueSelectedPages);"/>
       <menuitem id="context_bookmarkTab"
-                label="&bookmarkTab.label;"
-                accesskey="&bookmarkTab.accesskey;"
+                data-lazy-l10n-id="bookmark-tab"
                 oncommand="PlacesCommandHook.bookmarkPages(PlacesCommandHook.getUniquePages([TabContextMenu.contextTab]));"/>
       <menu id="context_reopenInContainer"
-            label="&reopenInContainer.label;"
-            accesskey="&reopenInContainer.accesskey;"
+            data-lazy-l10n-id="reopen-in-container"
             hidden="true">
         <menupopup oncommand="TabContextMenu.reopenInContainer(event);"
                    onpopupshowing="TabContextMenu.createReopenInContainerMenu(event);"/>
       </menu>
-      <menu id="context_moveTabOptions"
-            multiselectcontextlabel="&moveSelectedTabOptions.label;"
-            multiselectcontextaccesskey="&moveSelectedTabOptions.accesskey;"
-            nonmultiselectcontextlabel="&moveTabOptions.label;"
-            nonmultiselectcontextaccesskey="&moveTabOptions.accesskey;">
+      <menu id="context_moveTabOptions">
         <menupopup id="moveTabOptionsMenu">
           <menuitem id="context_moveToStart"
-                    label="&moveToStart.label;"
-                    accesskey="&moveToStart.accesskey;"
+                    data-lazy-l10n-id="move-to-start"
                     tbattr="tabbrowser-multiple"
                     oncommand="gBrowser.moveTabsToStart(TabContextMenu.contextTab);"/>
           <menuitem id="context_moveToEnd"
-                    label="&moveToEnd.label;"
-                    accesskey="&moveToEnd.accesskey;"
+                    data-lazy-l10n-id="move-to-end"
                     tbattr="tabbrowser-multiple"
                     oncommand="gBrowser.moveTabsToEnd(TabContextMenu.contextTab);"/>
-          <menuitem id="context_openTabInWindow" label="&moveToNewWindow.label;"
-                    accesskey="&moveToNewWindow.accesskey;"
+          <menuitem id="context_openTabInWindow" data-lazy-l10n-id="move-to-new-window"
                     tbattr="tabbrowser-multiple"
                     oncommand="gBrowser.replaceTabsWithWindow(TabContextMenu.contextTab);"/>
         </menupopup>
       </menu>
       <menu id="context_sendTabToDevice"
             class="sync-ui-item">
         <menupopup id="context_sendTabToDevicePopupMenu"
                    onpopupshowing="gSync.populateSendTabToDevicesMenu(event.target, TabContextMenu.contextTab.linkedBrowser.currentURI.spec, TabContextMenu.contextTab.linkedBrowser.contentTitle, TabContextMenu.contextTab.multiselected);"/>
       </menu>
       <menuseparator/>
-      <menuitem id="context_closeTabsToTheEnd" label="&closeTabsToTheEnd.label;" accesskey="&closeTabsToTheEnd.accesskey;"
+      <menuitem id="context_closeTabsToTheEnd" data-lazy-l10n-id="close-tabs-to-the-end"
                 oncommand="gBrowser.removeTabsToTheEndFrom(TabContextMenu.contextTab, {animate: true});"/>
-      <menuitem id="context_closeOtherTabs" label="&closeOtherTabs.label;" accesskey="&closeOtherTabs.accesskey;"
+      <menuitem id="context_closeOtherTabs" data-lazy-l10n-id="close-other-tabs"
                 oncommand="gBrowser.removeAllTabsBut(TabContextMenu.contextTab);"/>
       <menuitem id="context_undoCloseTab"
-                label="&undoCloseTab.label;"
-                accesskey="&undoCloseTab.accesskey;"
+                data-lazy-l10n-id="undo-close-tab"
                 observes="History:UndoCloseTab"/>
-      <menuitem id="context_closeTab" label="&closeTab.label;" accesskey="&closeTab.accesskey;"
+      <menuitem id="context_closeTab" data-lazy-l10n-id="close-tab"
                 oncommand="gBrowser.removeTab(TabContextMenu.contextTab, { animate: true });"/>
-      <menuitem id="context_closeSelectedTabs" label="&closeTabs.label;"
-                hidden="true" accesskey="&closeTabs.accesskey;"
+      <menuitem id="context_closeSelectedTabs" data-lazy-l10n-id="close-tabs"
+                hidden="true"
                 oncommand="gBrowser.removeMultiSelectedTabs();"/>
     </menupopup>
 
     <!-- bug 415444/582485: event.stopPropagation is here for the cloned version
          of this menupopup -->
     <menupopup id="backForwardMenu"
                onpopupshowing="return FillHistoryMenu(event.target);"
                oncommand="gotoHistoryIndex(event); event.stopPropagation();"
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -4740,16 +4740,29 @@ window._gBrowser = {
         return;
       }
 
       SitePermissions.set(event.detail.url, "autoplay-media",
                           SitePermissions.BLOCK,
                           SitePermissions.SCOPE_GLOBAL,
                           browser);
     });
+
+    let tabContextFTLInserter = () => {
+      MozXULElement.insertFTLIfNeeded("browser/tabContextMenu.ftl");
+      // Un-lazify the l10n-ids now that the FTL file has been inserted.
+      document.getElementById("tabContextMenu").querySelectorAll("[data-lazy-l10n-id]").forEach(el => {
+        el.setAttribute("data-l10n-id", el.getAttribute("data-lazy-l10n-id"));
+        el.removeAttribute("data-lazy-l10n-id");
+      });
+      this.tabContainer.removeEventListener("mouseover", tabContextFTLInserter);
+      this.tabContainer.removeEventListener("focus", tabContextFTLInserter, true);
+    };
+    this.tabContainer.addEventListener("mouseover", tabContextFTLInserter);
+    this.tabContainer.addEventListener("focus", tabContextFTLInserter, true);
   },
 
   setSuccessor(aTab, successorTab) {
     if (aTab.ownerGlobal != window) {
       throw new Error("Cannot set the successor of another window's tab");
     }
     if (successorTab == aTab) {
       successorTab = null;
@@ -5397,21 +5410,17 @@ var TabContextMenu = {
     contextUnpinTab.hidden = !this.contextTab.pinned || multiselectionContext;
     let contextPinSelectedTabs = document.getElementById("context_pinSelectedTabs");
     contextPinSelectedTabs.hidden = this.contextTab.pinned || !multiselectionContext;
     let contextUnpinSelectedTabs = document.getElementById("context_unpinSelectedTabs");
     contextUnpinSelectedTabs.hidden = !this.contextTab.pinned || !multiselectionContext;
 
     let contextMoveTabOptions = document.getElementById("context_moveTabOptions");
     contextMoveTabOptions.disabled = gBrowser.allTabsSelected();
-    let moveTabOptionsStringPrefix = multiselectionContext ? "multiselectcontext" : "nonmultiselectcontext";
-    let moveTabOptionsLabel = contextMoveTabOptions.getAttribute(moveTabOptionsStringPrefix + "label");
-    let moveTabOptionsAccessKey = contextMoveTabOptions.getAttribute(moveTabOptionsStringPrefix + "accesskey");
-    contextMoveTabOptions.setAttribute("label", moveTabOptionsLabel);
-    contextMoveTabOptions.setAttribute("accesskey", moveTabOptionsAccessKey);
+    document.l10n.setAttributes(contextMoveTabOptions, multiselectionContext ? "move-tabs" : "move-tab");
     let selectedTabs = gBrowser.selectedTabs;
     let contextMoveTabToEnd = document.getElementById("context_moveToEnd");
     let allSelectedTabsAdjacent = selectedTabs.every((element, index, array) => {
       return array.length > index + 1 ? element._tPos + 1 == array[index + 1]._tPos : true;
     });
     let contextTabIsSelected = this.contextTab.multiselected;
     let visibleTabs = gBrowser.visibleTabs;
     let lastVisibleTab = visibleTabs[visibleTabs.length - 1];
--- a/browser/base/content/test/general/browser_typeAheadFind.js
+++ b/browser/base/content/test/general/browser_typeAheadFind.js
@@ -1,14 +1,17 @@
 /* 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/. */
 
 add_task(async function() {
   let testWindow = await BrowserTestUtils.openNewBrowserWindow();
+  // The TabContextMenu initializes its strings only on a focus or mouseover event.
+  // Calls focus event on the TabContextMenu early in the test.
+  testWindow.gBrowser.selectedTab.focus();
 
   BrowserTestUtils.loadURI(testWindow.gBrowser, "data:text/html,<h1>A Page</h1>");
   await BrowserTestUtils.browserLoaded(testWindow.gBrowser.selectedBrowser);
 
   await SimpleTest.promiseFocus(testWindow.gBrowser.selectedBrowser);
 
   ok(!testWindow.gFindBarInitialized, "find bar is not initialized");
 
--- a/browser/base/content/test/permissions/browser_temporary_permissions_navigation.js
+++ b/browser/base/content/test/permissions/browser_temporary_permissions_navigation.js
@@ -45,16 +45,19 @@ add_task(async function testTempPermissi
       scope: SitePermissions.SCOPE_PERSISTENT,
     });
 
     // Set the permission again.
     SitePermissions.set(uri, id, SitePermissions.BLOCK, SitePermissions.SCOPE_TEMPORARY, browser);
 
     // Open the tab context menu.
     let contextMenu = document.getElementById("tabContextMenu");
+    // The TabContextMenu initializes its strings only on a focus or mouseover event.
+    // Calls focus event on the TabContextMenu early in the test.
+    gBrowser.selectedTab.focus();
     let popupShownPromise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
     EventUtils.synthesizeMouseAtCenter(gBrowser.selectedTab, {type: "contextmenu", button: 2});
     await popupShownPromise;
 
     let reloadMenuItem = document.getElementById("context_reloadTab");
 
     reloaded = BrowserTestUtils.browserLoaded(browser, false, uri.spec);
 
@@ -80,16 +83,19 @@ add_task(async function testTempPermissi
   await BrowserTestUtils.withNewTab(uri.spec, async function(browser) {
     SitePermissions.set(uri, id, SitePermissions.BLOCK, SitePermissions.SCOPE_TEMPORARY, browser);
 
     // Select all tabs before opening the context menu.
     gBrowser.selectAllTabs();
 
     // Open the tab context menu.
     let contextMenu = document.getElementById("tabContextMenu");
+    // The TabContextMenu initializes its strings only on a focus or mouseover event.
+    // Calls focus event on the TabContextMenu early in the test.
+    gBrowser.selectedTab.focus();
     let popupShownPromise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
     EventUtils.synthesizeMouseAtCenter(gBrowser.selectedTab, {type: "contextmenu", button: 2});
     await popupShownPromise;
 
     let reloadMenuItem = document.getElementById("context_reloadSelectedTabs");
 
     let reloaded = Promise.all(gBrowser.visibleTabs.map(
       tab => BrowserTestUtils.browserLoaded(gBrowser.getBrowserForTab(tab))));
--- a/browser/base/content/test/sanitize/browser_sanitize-formhistory.js
+++ b/browser/base/content/test/sanitize/browser_sanitize-formhistory.js
@@ -1,15 +1,18 @@
 /* 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/. */
 
 add_task(async function test() {
   // This test relies on the form history being empty to start with delete
   // all the items first.
+  // The TabContextMenu initializes its strings only on a focus or mouseover event.
+  // Calls focus event on the TabContextMenu early in the test.
+  gBrowser.selectedTab.focus();
   await new Promise((resolve, reject) => {
     FormHistory.update({ op: "remove" },
                        { handleError(error) {
                            reject(error);
                          },
                          handleCompletion(reason) {
                            if (!reason) {
                              resolve();
--- a/browser/base/content/test/sync/browser_contextmenu_sendtab.js
+++ b/browser/base/content/test/sync/browser_contextmenu_sendtab.js
@@ -14,16 +14,19 @@ const fxaDevices = [
 ];
 
 let [testTab] = gBrowser.visibleTabs;
 
 function updateTabContextMenu(tab = gBrowser.selectedTab) {
   let menu = document.getElementById("tabContextMenu");
   var evt = new Event("");
   tab.dispatchEvent(evt);
+  // The TabContextMenu initializes its strings only on a focus or mouseover event.
+  // Calls focus event on the TabContextMenu early in the test
+  gBrowser.selectedTab.focus();
   menu.openPopup(tab, "end_after", 0, 0, true, false, evt);
   is(window.TabContextMenu.contextTab, tab, "TabContextMenu context is the expected tab");
   menu.hidePopup();
 }
 
 add_task(async function setup() {
   await promiseSyncReady();
   // gSync.init() is called in a requestIdleCallback. Force its initialization.
--- a/browser/components/customizableui/test/browser_947914_button_find.js
+++ b/browser/components/customizableui/test/browser_947914_button_find.js
@@ -1,16 +1,19 @@
 /* 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/. */
 
 "use strict";
 
 add_task(async function() {
   info("Check find button existence and functionality");
+  // The TabContextMenu initializes its strings only on a focus or mouseover event.
+  // Calls focus event on the TabContextMenu early in the test.
+  gBrowser.selectedTab.focus();
   CustomizableUI.addWidgetToArea("find-button", CustomizableUI.AREA_FIXED_OVERFLOW_PANEL);
   registerCleanupFunction(() => CustomizableUI.reset());
 
   await waitForOverflowButtonShown();
 
   await document.getElementById("nav-bar").overflowable.show();
   info("Menu panel was opened");
 
--- a/browser/components/customizableui/test/browser_947914_button_history.js
+++ b/browser/components/customizableui/test/browser_947914_button_history.js
@@ -3,16 +3,19 @@
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const TEST_PATH = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "http://example.com");
 
 add_task(async function() {
   info("Check history button existence and functionality");
+  // The TabContextMenu initializes its strings only on a focus or mouseover event.
+  // Calls focus event on the TabContextMenu early in the test.
+  gBrowser.selectedTab.focus();
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PATH + "dummy_history_item.html");
   BrowserTestUtils.removeTab(tab);
 
   tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PATH); // will 404, but we don't care.
 
   CustomizableUI.addWidgetToArea("history-panelmenu", CustomizableUI.AREA_FIXED_OVERFLOW_PANEL);
   registerCleanupFunction(() => CustomizableUI.reset());
 
--- a/browser/components/extensions/test/browser/head.js
+++ b/browser/components/extensions/test/browser/head.js
@@ -498,16 +498,19 @@ async function openActionContextMenu(ext
 }
 
 function closeActionContextMenu(itemToSelect, kind, win = window) {
   let menuID = kind == "page" ? "pageActionContextMenu" : "toolbar-context-menu";
   return closeChromeContextMenu(menuID, itemToSelect, win);
 }
 
 function openTabContextMenu(win = window) {
+  // The TabContextMenu initializes its strings only on a focus or mouseover event.
+  // Calls focus event on the TabContextMenu before opening.
+  gBrowser.selectedTab.focus();
   return openChromeContextMenu("tabContextMenu", ".tabbrowser-tab[selected]", win);
 }
 
 function closeTabContextMenu(itemToSelect, win = window) {
   return closeChromeContextMenu("tabContextMenu", itemToSelect, win);
 }
 
 function getPageActionPopup(extension, win = window) {
new file mode 100644
--- /dev/null
+++ b/browser/locales/en-US/browser/tabContextMenu.ftl
@@ -0,0 +1,70 @@
+# 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/.
+
+reload-tab =
+    .label = Reload Tab
+    .accesskey = R
+select-all-tabs =
+    .label = Select All Tabs
+    .accesskey = S
+duplicate-tab =
+    .label = Duplicate Tab
+    .accesskey = D
+duplicate-tabs =
+    .label = Duplicate Tabs
+    .accesskey = D
+close-tabs-to-the-end =
+    .label = Close Tabs to the Right
+    .accesskey = i
+close-other-tabs =
+    .label = Close Other Tabs
+    .accesskey = o
+reload-tabs =
+    .label = Reload Tabs
+    .accesskey = R
+pin-tab =
+    .label = Pin Tab
+    .accesskey = P
+unpin-tab =
+    .label = Unpin Tab
+    .accesskey = p
+pin-selected-tabs =
+    .label = Pin Tabs
+    .accesskey = P
+unpin-selected-tabs =
+    .label = Unpin Tabs
+    .accesskey = p
+bookmark-selected-tabs =
+    .label = Bookmark Tabs…
+    .accesskey = B
+bookmark-tab =
+    .label = Bookmark Tab
+    .accesskey = B
+reopen-in-container =
+    .label = Reopen in Container
+    .accesskey = e
+move-to-start =
+    .label = Move to Start
+    .accesskey = S
+move-to-end =
+    .label = Move to End
+    .accesskey = E
+move-to-new-window =
+    .label = Move to New Window
+    .accesskey = W
+undo-close-tab =
+    .label = Undo Close Tab
+    .accesskey = U
+close-tab =
+    .label = Close Tab
+    .accesskey = c
+close-tabs =
+    .label = Close Tabs
+    .accesskey = S
+move-tabs =
+    .label = Move Tabs
+    .accesskey = v
+move-tab =
+    .label = Move Tab
+    .accesskey = v
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -14,60 +14,16 @@
 <!-- LOCALIZATION NOTE (mainWindow.titlePrivateBrowsingSuffix): This will be appended to the window's title
                                                                 inside the private browsing mode -->
 <!ENTITY mainWindow.titlePrivateBrowsingSuffix "(Private Browsing)">
 
 <!ENTITY appmenu.tooltip                     "Open menu">
 <!ENTITY navbarOverflow.label                "More tools…">
 
 <!-- Tab context menu -->
-<!ENTITY  reloadTab.label                    "Reload Tab">
-<!ENTITY  reloadTab.accesskey                "R">
-<!ENTITY  selectAllTabs.label                "Select All Tabs">
-<!ENTITY  selectAllTabs.accesskey            "S">
-<!-- LOCALIZATION NOTE (duplicateTab.label): This is a command to duplicate
-a tab (i.e. it is a verb, not adjective). -->
-<!ENTITY  duplicateTab.label                 "Duplicate Tab">
-<!-- LOCALIZATION NOTE (duplicateTab.accesskey, duplicateTabs.accesskey):
-These items have the same accesskey but will never be visible at the same time. -->
-<!ENTITY  duplicateTab.accesskey             "D">
-<!-- LOCALIZATION NOTE (duplicateTabs.label): This is a command to duplicate
-a tab (i.e. it is a verb, not adjective). -->
-<!ENTITY  duplicateTabs.label                "Duplicate Tabs">
-<!-- LOCALIZATION NOTE (duplicateTab.accesskey, duplicateTabs.accesskey):
-These items have the same accesskey but will never be visible at the same time. -->
-<!ENTITY  duplicateTabs.accesskey            "D">
-<!-- LOCALIZATION NOTE (closeTabsToTheEnd.label): This should indicate the
-direction in which tabs are closed, i.e. locales that use RTL mode should say
-left instead of right. -->
-<!ENTITY  closeTabsToTheEnd.label            "Close Tabs to the Right">
-<!ENTITY  closeTabsToTheEnd.accesskey        "i">
-<!ENTITY  closeOtherTabs.label               "Close Other Tabs">
-<!ENTITY  closeOtherTabs.accesskey           "o">
-
-<!ENTITY  closeTabs.label                    "Close Tabs">
-<!ENTITY  closeTabs.accesskey                "S">
-<!ENTITY  pinSelectedTabs.label              "Pin Tabs">
-<!-- LOCALIZATION NOTE(pinTab.accesskey, pinSelectedTabs.accesskey,
-unpinTab.accesskey, unpinSelectedTabs.accesskey): These share the
-same accesskey but will never be visible at the same time. -->
-<!ENTITY  pinSelectedTabs.accesskey          "P">
-<!ENTITY  unpinSelectedTabs.label            "Unpin Tabs">
-<!-- LOCALIZATION NOTE(pinTab.accesskey, pinSelectedTabs.accesskey,
-unpinTab.accesskey, unpinSelectedTabs.accesskey): These share the
-same accesskey but will never be visible at the same time. -->
-<!ENTITY  unpinSelectedTabs.accesskey        "p">
-<!-- LOCALIZATION NOTE(reloadTab.label, reloadTabs.label): have the same accesskey
-but will never be visible at the same time. -->
-<!ENTITY  reloadTabs.label                   "Reload Tabs">
-<!ENTITY  reloadTabs.accesskey               "R">
-<!ENTITY  bookmarkSelectedTabs.label         "Bookmark Tabs…">
-<!-- LOCALIZATION NOTE(bookmarkTab.accesskey, bookmarkSelectedTabs.accesskey):
-These items have the same accesskey but will never be visible at the same time. -->
-<!ENTITY  bookmarkSelectedTabs.accesskey     "B">
 
 <!-- LOCALIZATION NOTE (pinTab.label, unpinTab.label): "Pin" is being
 used as a metaphor for expressing the fact that these tabs are "pinned" to the
 left edge of the tabstrip. Really we just want the string to express the idea
 that this is a lightweight and reversible action that keeps your tab where you
 can reach it easily. -->
 <!ENTITY  pinTab.label                       "Pin Tab">
 <!-- LOCALIZATION NOTE(pinTab.accesskey, pinSelectedTabs.accesskey,
@@ -78,38 +34,18 @@ same accesskey but will never be visible
 <!-- LOCALIZATION NOTE(pinTab.accesskey, pinSelectedTabs.accesskey,
 unpinTab.accesskey, unpinSelectedTabs.accesskey): These share the
 same accesskey but will never be visible at the same time. -->
 <!ENTITY  unpinTab.accesskey                 "p">
 <!ENTITY  sendPageToDevice.label             "Send Page to Device">
 <!ENTITY  sendPageToDevice.accesskey         "n">
 <!ENTITY  sendLinkToDevice.label             "Send Link to Device">
 <!ENTITY  sendLinkToDevice.accesskey         "n">
-<!-- LOCALIZATION NOTE (moveTabOptions.label and moveSelectedTabOptions.label):
-These two items have the same accesskey but will never be visible at the same time. -->
-<!ENTITY  moveTabOptions.label               "Move Tab">
-<!ENTITY  moveTabOptions.accesskey           "v">
-<!ENTITY  moveSelectedTabOptions.label       "Move Tabs">
-<!ENTITY  moveSelectedTabOptions.accesskey   "v">
-<!ENTITY  moveToStart.label                  "Move to Start">
-<!ENTITY  moveToStart.accesskey              "S">
-<!ENTITY  moveToEnd.label                    "Move to End">
-<!ENTITY  moveToEnd.accesskey                "E">
-<!ENTITY  moveToNewWindow.label              "Move to New Window">
-<!ENTITY  moveToNewWindow.accesskey          "W">
-<!ENTITY  reopenInContainer.label            "Reopen in Container">
-<!ENTITY  reopenInContainer.accesskey        "e">
-<!ENTITY  bookmarkTab.label                  "Bookmark Tab">
-<!-- LOCALIZATION NOTE(bookmarkTab.accesskey, bookmarkSelectedTabs.accesskey):
-These items have the same accesskey but will never be visible at the same time. -->
-<!ENTITY  bookmarkTab.accesskey              "B">
 <!ENTITY  undoCloseTab.label                 "Undo Close Tab">
 <!ENTITY  undoCloseTab.accesskey             "U">
-<!ENTITY  closeTab.label                     "Close Tab">
-<!ENTITY  closeTab.accesskey                 "c">
 <!ENTITY  hiddenTabs.label                   "Hidden Tabs">
 
 <!ENTITY  listAllTabs.label      "List all tabs">
 <!-- LOCALIZATION NOTE (allTabsMenu.searchTabs.label): "Search" is a verb, as
 in "Search through tabs". -->
 <!ENTITY  allTabsMenu.searchTabs.label       "Search Tabs">
 
 <!ENTITY tabCmd.label "New Tab">
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_ctrl_a_select_all.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_ctrl_a_select_all.js
@@ -14,16 +14,19 @@ add_task(async function() {
   await pushPref("devtools.webconsole.jsterm.codeMirror", false);
   await performTests();
   // And then run it with the CodeMirror-powered one.
   await pushPref("devtools.webconsole.jsterm.codeMirror", true);
   await performTests();
 });
 
 async function performTests() {
+  // The TabContextMenu initializes its strings only on a focus or mouseover event.
+  // Calls focus event on the TabContextMenu early in the test.
+  gBrowser.selectedTab.focus();
   const hud = await openNewTabAndConsole(TEST_URI);
   const {jsterm} = hud;
 
   setInputValue(hud, "Ignore These Four Words");
 
   // Test select all with (cmd|control) + a.
   EventUtils.synthesizeKey("a", { accelKey: true });
 
new file mode 100644
--- /dev/null
+++ b/python/l10n/fluent_migrations/bug_1523763_tabContextMenu.py
@@ -0,0 +1,89 @@
+
+# coding=utf8
+
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+from __future__ import absolute_import
+import fluent.syntax.ast as FTL
+from fluent.migrate.helpers import transforms_from
+from fluent.migrate.helpers import MESSAGE_REFERENCE, TERM_REFERENCE
+from fluent.migrate import COPY
+
+
+def migrate(ctx):
+    """Bug 15237631 - Convert tab context menu strings from browser.dtd to Fluent, part {index}."""
+
+    ctx.add_transforms(
+        "browser/browser/tabContextMenu.ftl",
+        "browser/browser/tabContextMenu.ftl",
+        transforms_from(
+"""
+reload-tab =
+    .label = { COPY("browser/chrome/browser/browser.dtd","reloadTab.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","reloadTab.accesskey" ) }
+select-all-tabs =
+    .label = { COPY("browser/chrome/browser/browser.dtd","selectAllTabs.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","selectAllTabs.accesskey") }
+duplicate-tab =
+    .label = { COPY("browser/chrome/browser/browser.dtd","duplicateTab.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","duplicateTab.accesskey") }
+duplicate-tabs =
+    .label = { COPY("browser/chrome/browser/browser.dtd","duplicateTabs.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","duplicateTabs.accesskey") }
+close-tabs-to-the-end =
+    .label = { COPY("browser/chrome/browser/browser.dtd","closeTabsToTheEnd.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","closeTabsToTheEnd.accesskey") }
+close-other-tabs =
+    .label = { COPY("browser/chrome/browser/browser.dtd","closeOtherTabs.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","closeOtherTabs.accesskey") }
+reload-tabs =
+    .label = { COPY("browser/chrome/browser/browser.dtd","reloadTabs.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","reloadTabs.accesskey") }
+pin-tab =
+    .label = { COPY("browser/chrome/browser/browser.dtd","pinTab.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","pinTab.accesskey") }
+unpin-tab =
+    .label = { COPY("browser/chrome/browser/browser.dtd","unpinTab.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","unpinTab.accesskey") }
+pin-selected-tabs =
+    .label = { COPY("browser/chrome/browser/browser.dtd","pinSelectedTabs.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","pinSelectedTabs.accesskey") }
+unpin-selected-tabs = 
+    .label = { COPY("browser/chrome/browser/browser.dtd","unpinSelectedTabs.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","unpinSelectedTabs.accesskey") }
+bookmark-selected-tabs =
+    .label = { COPY("browser/chrome/browser/browser.dtd","bookmarkSelectedTabs.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","bookmarkSelectedTabs.accesskey") }
+bookmark-tab =
+    .label = { COPY("browser/chrome/browser/browser.dtd","bookmarkTab.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","bookmarkTab.accesskey") }
+reopen-in-container =
+    .label = { COPY("browser/chrome/browser/browser.dtd","reopenInContainer.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","reopenInContainer.accesskey") }
+move-to-start =
+    .label = { COPY("browser/chrome/browser/browser.dtd","moveToStart.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","moveToStart.accesskey") }
+move-to-end =
+    .label = { COPY("browser/chrome/browser/browser.dtd","moveToEnd.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","moveToEnd.accesskey") }
+move-to-new-window =
+    .label = { COPY("browser/chrome/browser/browser.dtd","moveToNewWindow.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","moveToNewWindow.accesskey") }
+undo-close-tab =
+    .label = { COPY("browser/chrome/browser/browser.dtd","undoCloseTab.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","undoCloseTab.accesskey") }
+close-tab =
+    .label = { COPY("browser/chrome/browser/browser.dtd","closeTab.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","closeTab.accesskey") }
+close-tabs =
+    .label = { COPY("browser/chrome/browser/browser.dtd","closeTabs.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","closeTabs.accesskey") }
+move-tabs =
+    .label = { COPY("browser/chrome/browser/browser.dtd","moveSelectedTabOptions.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","moveSelectedTabOptions.accesskey") }
+move-tab =
+    .label = { COPY("browser/chrome/browser/browser.dtd","moveTabOptions.label") }
+    .accesskey = { COPY("browser/chrome/browser/browser.dtd","moveTabOptions.accesskey") }
+""")
+)
--- a/toolkit/components/extensions/test/browser/browser_ext_themes_findbar.js
+++ b/toolkit/components/extensions/test/browser/browser_ext_themes_findbar.js
@@ -1,16 +1,19 @@
 "use strict";
 
 // This test checks whether applied WebExtension themes that attempt to change
 // the toolbar and toolbar_field properties also theme the findbar.
 
 add_task(async function test_support_toolbar_properties_on_findbar() {
   const TOOLBAR_COLOR = "#ff00ff";
   const TOOLBAR_TEXT_COLOR = "#9400ff";
+  // The TabContextMenu initializes its strings only on a focus or mouseover event.
+  // Calls focus event on the TabContextMenu early in the test.
+  gBrowser.selectedTab.focus();
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "theme": {
         "images": {
           "theme_frame": "image1.png",
         },
         "colors": {
           "frame": ACCENT_COLOR,
@@ -45,16 +48,19 @@ add_task(async function test_support_too
 
   await extension.unload();
 });
 
 add_task(async function test_support_toolbar_field_properties_on_findbar() {
   const TOOLBAR_FIELD_COLOR = "#ff00ff";
   const TOOLBAR_FIELD_TEXT_COLOR = "#9400ff";
   const TOOLBAR_FIELD_BORDER_COLOR = "#ffffff";
+  // The TabContextMenu initializes its strings only on a focus or mouseover event.
+  // Calls focus event on the TabContextMenu early in the test.
+  gBrowser.selectedTab.focus();
   let extension = ExtensionTestUtils.loadExtension({
     manifest: {
       "theme": {
         "images": {
           "theme_frame": "image1.png",
         },
         "colors": {
           "frame": ACCENT_COLOR,