From 890f8a66d626a5ba6cd9a139240abcc99c47ee9f Mon Sep 17 00:00:00 2001 From: Marina Samuel Date: Fri, 8 May 2015 12:39:02 -0700 Subject: [PATCH 1/6] Bug 1138818 - Part 3a - strings only - Change to localizable strings. r=adw --- .../en-US/chrome/browser/newTab.properties | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/browser/locales/en-US/chrome/browser/newTab.properties b/browser/locales/en-US/chrome/browser/newTab.properties index 20d30d8510d88..4ca53260a035d 100644 --- a/browser/locales/en-US/chrome/browser/newTab.properties +++ b/browser/locales/en-US/chrome/browser/newTab.properties @@ -34,14 +34,38 @@ newtab.suggested.explain=This site is suggested to you by Mozilla. You can remov # the gear icon used to customize the new tab window. %2$S will be replaced by # an active link using string newtab.learn.link as text. newtab.enhanced.explain=A Mozilla partner has visually enhanced this tile, replacing the screenshot. You can turn off enhanced tiles by clicking the %1$S button for your preferences. %2$S -# LOCALIZATION NOTE(newtab.intro.paragraph1): %1$S will be replaced inline by -# active link using string newtab.learn.link as text. -newtab.intro.paragraph1=When you open a new tab, you’ll see tiles from the sites you frequently visit, along with tiles that we think might be of interest to you. Some of these tiles may be sponsored by Mozilla partners. We’ll always indicate to you which tiles are sponsored. %1$S # LOCALIZATION NOTE(newtab.intro.paragraph2): %1$S will be replaced inline by # active link using string newtab.privacy.link as text. newtab.intro.paragraph2=In order to provide this service, Mozilla collects and uses certain analytics information relating to your use of the tiles in accordance with our %1$S. -# LOCALIZATION NOTE(newtab.intro.paragraph3): %1$S will be replaced inline by -# the gear icon used to customize the new tab window. -newtab.intro.paragraph3=You can turn off the tiles feature by clicking the %1$S button for your preferences. +# LOCALIZATION NOTE(newtab.intro.paragraph4): %1$S will be replaced inline by +# the gear icon used to customize the new tab window. %2$S will be replaced by +# newtab.intro.controls as text +newtab.intro.paragraph4=You can turn off this feature by clicking the gear (%1$S) button and selecting "Show blank page" in the %2$S menu. +newtab.intro.paragraph5=New Tab will show the sites you visit most frequently, along with sites we think might be of interest to you. To get started, you'll see several sites from Mozilla. +# LOCALIZATION NOTE(newtab.intro.paragraph6): %1$S will be replaced by +# newtab.intro.remove as bold text. %2$S will be replaced by +# newtab.intro.pin as bold text +newtab.intro.paragraph6=You can %1$S or %2$S any site by using the controls available on rollover. +newtab.intro.paragraph7=Some of the sites you will see may be suggested by Mozilla and may be sponsored by a Mozilla partner. We'll always indicate which sites are sponsored. +# LOCALIZATION NOTE(newtab.intro.paragraph8): %1$S will be replaced inline by +# an active link using string newtab.learn.link as text. +newtab.intro.paragraph8=Firefox will only show sites that most closely match your interests on the Web. %1$S +newtab.intro.paragraph9=Now when you open New Tab, you'll also see sites we think might be interesting to you. +# LOCALIZATION NOTE(newtab.intro.controls): the controls in the gear icon +# menu for customizing the new tab window. Used in newtab.intro.paragraph4 +newtab.intro.controls=New Tab Controls newtab.learn.link=Learn more… newtab.privacy.link=Privacy Notice +newtab.learn.link2=More about New Tab +newtab.privacy.link2=About your privacy +newtab.intro.remove=remove +newtab.intro.pin=pin +# LOCALIZATION NOTE(newtab.intro.header.welcome): %1$S will be replaced by +# brandShortName as bold text. +newtab.intro.header.welcome=Welcome to New Tab on %1$S! +newtab.intro.header.update=New Tab got an update! +newtab.intro.skip=Skip this +newtab.intro.continue=Continue tour +newtab.intro.back=Back +newtab.intro.next=Next +newtab.intro.gotit=Got it! From 71f9090aabab33ff889e38f90de7a672ccc63ba7 Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Sun, 10 May 2015 07:01:48 -0700 Subject: [PATCH 2/6] Back out adbc210cb42b (bug 1138818) for bc1 bustage CLOSED TREE --- .../en-US/chrome/browser/newTab.properties | 36 ++++--------------- 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/browser/locales/en-US/chrome/browser/newTab.properties b/browser/locales/en-US/chrome/browser/newTab.properties index 4ca53260a035d..20d30d8510d88 100644 --- a/browser/locales/en-US/chrome/browser/newTab.properties +++ b/browser/locales/en-US/chrome/browser/newTab.properties @@ -34,38 +34,14 @@ newtab.suggested.explain=This site is suggested to you by Mozilla. You can remov # the gear icon used to customize the new tab window. %2$S will be replaced by # an active link using string newtab.learn.link as text. newtab.enhanced.explain=A Mozilla partner has visually enhanced this tile, replacing the screenshot. You can turn off enhanced tiles by clicking the %1$S button for your preferences. %2$S +# LOCALIZATION NOTE(newtab.intro.paragraph1): %1$S will be replaced inline by +# active link using string newtab.learn.link as text. +newtab.intro.paragraph1=When you open a new tab, you’ll see tiles from the sites you frequently visit, along with tiles that we think might be of interest to you. Some of these tiles may be sponsored by Mozilla partners. We’ll always indicate to you which tiles are sponsored. %1$S # LOCALIZATION NOTE(newtab.intro.paragraph2): %1$S will be replaced inline by # active link using string newtab.privacy.link as text. newtab.intro.paragraph2=In order to provide this service, Mozilla collects and uses certain analytics information relating to your use of the tiles in accordance with our %1$S. -# LOCALIZATION NOTE(newtab.intro.paragraph4): %1$S will be replaced inline by -# the gear icon used to customize the new tab window. %2$S will be replaced by -# newtab.intro.controls as text -newtab.intro.paragraph4=You can turn off this feature by clicking the gear (%1$S) button and selecting "Show blank page" in the %2$S menu. -newtab.intro.paragraph5=New Tab will show the sites you visit most frequently, along with sites we think might be of interest to you. To get started, you'll see several sites from Mozilla. -# LOCALIZATION NOTE(newtab.intro.paragraph6): %1$S will be replaced by -# newtab.intro.remove as bold text. %2$S will be replaced by -# newtab.intro.pin as bold text -newtab.intro.paragraph6=You can %1$S or %2$S any site by using the controls available on rollover. -newtab.intro.paragraph7=Some of the sites you will see may be suggested by Mozilla and may be sponsored by a Mozilla partner. We'll always indicate which sites are sponsored. -# LOCALIZATION NOTE(newtab.intro.paragraph8): %1$S will be replaced inline by -# an active link using string newtab.learn.link as text. -newtab.intro.paragraph8=Firefox will only show sites that most closely match your interests on the Web. %1$S -newtab.intro.paragraph9=Now when you open New Tab, you'll also see sites we think might be interesting to you. -# LOCALIZATION NOTE(newtab.intro.controls): the controls in the gear icon -# menu for customizing the new tab window. Used in newtab.intro.paragraph4 -newtab.intro.controls=New Tab Controls +# LOCALIZATION NOTE(newtab.intro.paragraph3): %1$S will be replaced inline by +# the gear icon used to customize the new tab window. +newtab.intro.paragraph3=You can turn off the tiles feature by clicking the %1$S button for your preferences. newtab.learn.link=Learn more… newtab.privacy.link=Privacy Notice -newtab.learn.link2=More about New Tab -newtab.privacy.link2=About your privacy -newtab.intro.remove=remove -newtab.intro.pin=pin -# LOCALIZATION NOTE(newtab.intro.header.welcome): %1$S will be replaced by -# brandShortName as bold text. -newtab.intro.header.welcome=Welcome to New Tab on %1$S! -newtab.intro.header.update=New Tab got an update! -newtab.intro.skip=Skip this -newtab.intro.continue=Continue tour -newtab.intro.back=Back -newtab.intro.next=Next -newtab.intro.gotit=Got it! From 34a2745c1a4b5b4d1c2f4838159fcfaee837c1bd Mon Sep 17 00:00:00 2001 From: Mike Conley Date: Mon, 4 May 2015 21:58:21 -0400 Subject: [PATCH 3/6] Bug 1128050 - [e10s] Save page as... doesn't always load from cache. r=billm. --- toolkit/content/contentAreaUtils.js | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/toolkit/content/contentAreaUtils.js b/toolkit/content/contentAreaUtils.js index df5a8e998c542..89668042902bd 100644 --- a/toolkit/content/contentAreaUtils.js +++ b/toolkit/content/contentAreaUtils.js @@ -145,20 +145,26 @@ function saveDocument(aDocument, aSkipPrompt) // Failure to get a content-disposition is ok } - var cacheKey = null; + let cacheKey = null; try { - cacheKey = + let shEntry = ifreq.getInterface(Components.interfaces.nsIWebNavigation) - .QueryInterface(Components.interfaces.nsIWebPageDescriptor); + .QueryInterface(Components.interfaces.nsIWebPageDescriptor) + .currentDescriptor + .QueryInterface(Components.interfaces.nsISHEntry); + + shEntry.cacheKey.QueryInterface(Components.interfaces.nsISupportsPRUint32); + + // In the event that the cacheKey is a CPOW, we cannot pass it to + // nsIWebBrowserPersist, so we create a new one and copy the value + // over. This is a workaround until bug 1101100 is fixed. + cacheKey = Cc["@mozilla.org/supports-PRUint32;1"] + .createInstance(Ci.nsISupportsPRUint32); + cacheKey.data = shEntry.cacheKey.data; } catch (ex) { // We might not find it in the cache. Oh, well. } - if (cacheKey && Components.utils.isCrossProcessWrapper(cacheKey)) { - // Don't use a cache key from another process. See bug 1128050. - cacheKey = null; - } - internalSave(aDocument.location.href, aDocument, null, contentDisposition, aDocument.contentType, false, null, null, aDocument.referrer ? makeURI(aDocument.referrer) : null, @@ -339,6 +345,9 @@ function internalSave(aURL, aDocument, aDefaultFileName, aContentDisposition, // If we're saving a document, and are saving either in complete mode or // as converted text, pass the document to the web browser persist component. // If we're just saving the HTML (second option in the list), send only the URI. + let nonCPOWDocument = + aDocument && !Components.utils.isCrossProcessWrapper(aDocument); + var persistArgs = { sourceURI : sourceURI, sourceReferrer : aReferrer, @@ -346,7 +355,7 @@ function internalSave(aURL, aDocument, aDefaultFileName, aContentDisposition, targetContentType : (saveAsType == kSaveAsType_Text) ? "text/plain" : null, targetFile : file, sourceCacheKey : aCacheKey, - sourcePostData : aDocument ? getPostData(aDocument) : null, + sourcePostData : nonCPOWDocument ? getPostData(aDocument) : null, bypassCache : aShouldBypassCache, initiatingWindow : aInitiatingDocument.defaultView }; From be496fe77e6e9d48abc3b3ccd81e6033987c14f9 Mon Sep 17 00:00:00 2001 From: Brian Grinstead Date: Sun, 10 May 2015 11:55:27 -0700 Subject: [PATCH 4/6] Bug 1143224 - Use getBoundsWithoutFlushing and scroll less often in the SideMenuWidget to speed up the netmonitor UI;r=vporof --- .../netmonitor/test/browser_net_autoscroll.js | 99 +++++++++---------- .../shared/widgets/SideMenuWidget.jsm | 63 +++++++++++- 2 files changed, 104 insertions(+), 58 deletions(-) diff --git a/browser/devtools/netmonitor/test/browser_net_autoscroll.js b/browser/devtools/netmonitor/test/browser_net_autoscroll.js index c13e6f4586a8e..2e69d6afefbb3 100644 --- a/browser/devtools/netmonitor/test/browser_net_autoscroll.js +++ b/browser/devtools/netmonitor/test/browser_net_autoscroll.js @@ -11,80 +11,59 @@ thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: aValue.content is un /** * Bug 863102 - Automatically scroll down upon new network requests. */ - -function test() { +add_task(function*() { requestLongerTimeout(2); let monitor, debuggee, requestsContainer, scrollTop; - initNetMonitor(INFINITE_GET_URL).then(([aTab, aDebuggee, aMonitor]) => { - monitor = aMonitor; - debuggee = aDebuggee; - let win = monitor.panelWin; - let topNode = win.document.getElementById("requests-menu-contents"); - requestsContainer = topNode.getElementsByTagName("scrollbox")[0]; - ok(!!requestsContainer, "Container element exists as expected."); - }) + let [aTab, aDebuggee, aMonitor] = yield initNetMonitor(INFINITE_GET_URL); + monitor = aMonitor; + debuggee = aDebuggee; + let win = monitor.panelWin; + let topNode = win.document.getElementById("requests-menu-contents"); + requestsContainer = topNode.getElementsByTagName("scrollbox")[0]; + ok(!!requestsContainer, "Container element exists as expected."); // (1) Check that the scroll position is maintained at the bottom // when the requests overflow the vertical size of the container. - .then(() => { - return waitForRequestsToOverflowContainer(monitor, requestsContainer); - }) - .then(() => { - ok(scrolledToBottom(requestsContainer), "Scrolled to bottom on overflow."); - }) + yield waitForRequestsToOverflowContainer(monitor, requestsContainer); + yield waitForScroll(monitor); + ok(scrolledToBottom(requestsContainer), "Scrolled to bottom on overflow."); // (2) Now set the scroll position somewhere in the middle and check // that additional requests do not change the scroll position. - .then(() => { - let children = requestsContainer.childNodes; - let middleNode = children.item(children.length / 2); - middleNode.scrollIntoView(); - ok(!scrolledToBottom(requestsContainer), "Not scrolled to bottom."); - scrollTop = requestsContainer.scrollTop; // save for comparison later - return waitForNetworkEvents(monitor, 8); - }) - .then(() => { - is(requestsContainer.scrollTop, scrollTop, "Did not scroll."); - }) + let children = requestsContainer.childNodes; + let middleNode = children.item(children.length / 2); + middleNode.scrollIntoView(); + ok(!scrolledToBottom(requestsContainer), "Not scrolled to bottom."); + scrollTop = requestsContainer.scrollTop; // save for comparison later + yield waitForNetworkEvents(monitor, 8); + yield waitSomeTime(); + is(requestsContainer.scrollTop, scrollTop, "Did not scroll."); // (3) Now set the scroll position back at the bottom and check that // additional requests *do* cause the container to scroll down. - .then(() => { - requestsContainer.scrollTop = requestsContainer.scrollHeight; - ok(scrolledToBottom(requestsContainer), "Set scroll position to bottom."); - return waitForNetworkEvents(monitor, 8); - }) - .then(() => { - ok(scrolledToBottom(requestsContainer), "Still scrolled to bottom."); - }) + requestsContainer.scrollTop = requestsContainer.scrollHeight; + ok(scrolledToBottom(requestsContainer), "Set scroll position to bottom."); + yield waitForNetworkEvents(monitor, 8); + yield waitForScroll(monitor); + ok(scrolledToBottom(requestsContainer), "Still scrolled to bottom."); // (4) Now select an item in the list and check that additional requests // do not change the scroll position. - .then(() => { - monitor.panelWin.NetMonitorView.RequestsMenu.selectedIndex = 0; - return waitForNetworkEvents(monitor, 8); - }) - .then(() => { - is(requestsContainer.scrollTop, 0, "Did not scroll."); - }) + monitor.panelWin.NetMonitorView.RequestsMenu.selectedIndex = 0; + yield waitForNetworkEvents(monitor, 8); + yield waitSomeTime(); + is(requestsContainer.scrollTop, 0, "Did not scroll."); - // Done; clean up. - .then(() => { - return teardown(monitor).then(finish); - }) + // Done: clean up. + yield teardown(monitor); - // Handle exceptions in the chain of promises. - .then(null, (err) => { - ok(false, err); - finish(); - }); + finish(); - function waitForRequestsToOverflowContainer (aMonitor, aContainer) { + function waitForRequestsToOverflowContainer(aMonitor, aContainer) { return waitForNetworkEvents(aMonitor, 1).then(() => { if (aContainer.scrollHeight > aContainer.clientHeight) { - // Wait for some more just for good measure. - return waitForNetworkEvents(aMonitor, 8); + return promise.resolve(); } else { return waitForRequestsToOverflowContainer(aMonitor, aContainer); } @@ -94,4 +73,14 @@ function test() { function scrolledToBottom(aElement) { return aElement.scrollTop + aElement.clientHeight >= aElement.scrollHeight; } -} + + function waitSomeTime() { + let waitSomeTime = promise.defer(); + setTimeout(waitSomeTime.resolve, 50); // Wait to make sure no scrolls happen + return waitSomeTime.promise; + } + + function waitForScroll(aMonitor) { + return aMonitor._view.RequestsMenu.widget.once("scroll-to-bottom"); + } +}); diff --git a/browser/devtools/shared/widgets/SideMenuWidget.jsm b/browser/devtools/shared/widgets/SideMenuWidget.jsm index fb445fbe55854..d8094f2200429 100644 --- a/browser/devtools/shared/widgets/SideMenuWidget.jsm +++ b/browser/devtools/shared/widgets/SideMenuWidget.jsm @@ -10,9 +10,12 @@ const Cu = Components.utils; Cu.import("resource:///modules/devtools/ViewHelpers.jsm"); Cu.import("resource://gre/modules/devtools/event-emitter.js"); +const {DeferredTask} = Cu.import("resource://gre/modules/DeferredTask.jsm", {}); this.EXPORTED_SYMBOLS = ["SideMenuWidget"]; +const SCROLL_FREQUENCY = 16; + /** * A simple side menu, with the ability of grouping menu items. * @@ -113,20 +116,74 @@ SideMenuWidget.prototype = { !this._selectedItem && // 3. The new item should be appended at the end of the list. (aIndex < 0 || aIndex >= this._orderedMenuElementsArray.length) && - // 4. The list should already be scrolled at the bottom. - (this._list.scrollTop + this._list.clientHeight >= this._list.scrollHeight); + // 4. We aren't waiting for a scroll to happen. + (!this._scrollToBottomTask || !this._scrollToBottomTask.isArmed) && + // 5. The list should already be scrolled at the bottom. + this.isScrolledToBottom(); let group = this._getMenuGroupForName(aAttachment.group); let item = this._getMenuItemForGroup(group, aContents, aAttachment); let element = item.insertSelfAt(aIndex); if (maintainScrollAtBottom) { - this._list.scrollTop = this._list.scrollHeight; + this.scrollToBottom(); } return element; }, + /** + * Checks to see if the list is scrolled all the way to the bottom. + * Uses getBoundsWithoutFlushing to limit the performance impact + * of this function. + * + * @return bool + */ + isScrolledToBottom: function() { + if (this._list.lastElementChild) { + let utils = this.window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + let childRect = utils.getBoundsWithoutFlushing(this._list.lastElementChild); + let listRect = utils.getBoundsWithoutFlushing(this._list); + + // Cheap way to check if it's scrolled all the way to the bottom. + return (childRect.height + childRect.top) <= listRect.bottom; + } + + return false; + }, + + /** + * Scroll the list to the bottom after a timeout. + * If the user scrolls in the meantime, cancel this operation. + */ + scrollToBottom: function() { + // Lazily attach this functionality to the object, so it won't get + // created unless if this scrollToBottom behavior is needed. + if (!this._scrollToBottomTask) { + // The scroll event fires asynchronously, so we need to keep a bit to + // distinguish between user-initiated events and scrollTop assignment. + let ignoreNextScroll = false; + + this._scrollToBottomTask = new DeferredTask(() => { + ignoreNextScroll = true; + this._list.scrollTop = this._list.scrollHeight; + this.emit("scroll-to-bottom"); + }, SCROLL_FREQUENCY); + + // On a user scroll, cancel any pending calls to the scroll function. + this._list.addEventListener("scroll", () => { + if (!ignoreNextScroll && this._scrollToBottomTask.isArmed && + !this.isScrolledToBottom()) { + this._scrollToBottomTask.disarm(); + } + ignoreNextScroll = false; + }, true); + } + + this._scrollToBottomTask.arm(); + }, + /** * Returns the child node in this container situated at the specified index. * From ba512a4546bd16df36ec3c0b46f303d75de02803 Mon Sep 17 00:00:00 2001 From: Brian Grinstead Date: Sun, 10 May 2015 12:44:47 -0700 Subject: [PATCH 5/6] Bug 835896 - Update inspector search string for better localization practice;r=flod --- .../en-US/chrome/browser/devtools/inspector.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/browser/locales/en-US/chrome/browser/devtools/inspector.properties b/browser/locales/en-US/chrome/browser/devtools/inspector.properties index c278831b78c9c..20ecd43624da6 100644 --- a/browser/locales/en-US/chrome/browser/devtools/inspector.properties +++ b/browser/locales/en-US/chrome/browser/devtools/inspector.properties @@ -74,10 +74,10 @@ inspector.collapsePane=Collapse pane inspector.expandPane=Expand pane # LOCALIZATION NOTE (inspector.searchResultsCount): This is the label that -# will show up next to the inspector search box showing the current result -# index alongside the total number of search results. For example, "3 of 9". +# will show up next to the inspector search box. %1$S is the current result +# index and %2$S is the total number of search results. For example: "3 of 9". # This won't be visible until the search box is updated in Bug 835896. -inspector.searchResultsCount=%S of %S +inspector.searchResultsCount2=%1$S of %2$S # LOCALIZATION NOTE (inspector.searchResultsNone): This is the label that # will show up next to the inspector search box when no matches were found From 54033c1f80a8bd938713b72ebe44210ac76bf8c6 Mon Sep 17 00:00:00 2001 From: Marina Samuel Date: Fri, 8 May 2015 12:39:02 -0700 Subject: [PATCH 6/6] Bug 1138818 - Part 3a - strings only - Change to localizable strings. r=adw, f=flod --- .../en-US/chrome/browser/newTab.properties | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/browser/locales/en-US/chrome/browser/newTab.properties b/browser/locales/en-US/chrome/browser/newTab.properties index 20d30d8510d88..609447bf4565f 100644 --- a/browser/locales/en-US/chrome/browser/newTab.properties +++ b/browser/locales/en-US/chrome/browser/newTab.properties @@ -43,5 +43,36 @@ newtab.intro.paragraph2=In order to provide this service, Mozilla collects and u # LOCALIZATION NOTE(newtab.intro.paragraph3): %1$S will be replaced inline by # the gear icon used to customize the new tab window. newtab.intro.paragraph3=You can turn off the tiles feature by clicking the %1$S button for your preferences. +# LOCALIZATION NOTE(newtab.intro.paragraph4): %1$S will be replaced inline by +# the gear icon used to customize the new tab window. %2$S will be replaced by +# newtab.intro.controls as text +newtab.intro.paragraph4=You can turn off this feature by clicking the gear (%1$S) button and selecting "Show blank page" in the %2$S menu. +newtab.intro.paragraph5=New Tab will show the sites you visit most frequently, along with sites we think might be of interest to you. To get started, you'll see several sites from Mozilla. +# LOCALIZATION NOTE(newtab.intro.paragraph6): %1$S will be replaced by +# newtab.intro.paragraph6.remove as bold text. %2$S will be replaced by +# newtab.intro.paragraph6.pin as bold text +newtab.intro.paragraph6=You can %1$S or %2$S any site by using the controls available on rollover. +newtab.intro.paragraph6.remove=remove +newtab.intro.paragraph6.pin=pin +newtab.intro.paragraph7=Some of the sites you will see may be suggested by Mozilla and may be sponsored by a Mozilla partner. We'll always indicate which sites are sponsored. +# LOCALIZATION NOTE(newtab.intro.paragraph8): %1$S will be replaced by +# brandShortName as text. %2$S will be replaced inline by an active link using +# string newtab.learn.link as text. +newtab.intro.paragraph8=%1$S will only show sites that most closely match your interests on the Web. %2$S +newtab.intro.paragraph9=Now when you open New Tab, you'll also see sites we think might be interesting to you. +# LOCALIZATION NOTE(newtab.intro.controls): the controls in the gear icon +# menu for customizing the new tab window. Used in newtab.intro.paragraph4 +newtab.intro.controls=New Tab Controls newtab.learn.link=Learn more… newtab.privacy.link=Privacy Notice +newtab.learn.link2=More about New Tab +newtab.privacy.link2=About your privacy +# LOCALIZATION NOTE(newtab.intro.header.welcome): %1$S will be replaced by +# brandShortName as bold text. +newtab.intro.header.welcome=Welcome to New Tab on %1$S! +newtab.intro.header.update=New Tab got an update! +newtab.intro.skip=Skip this +newtab.intro.continue=Continue tour +newtab.intro.back=Back +newtab.intro.next=Next +newtab.intro.gotit=Got it!