Bug 1400601 - Add responsive editing, browser.newtabpage.rows migration and bug fixes to Activity Stream. r?dmose draft
authorEd Lee <edilee@mozilla.com>
Mon, 18 Sep 2017 17:39:29 -0700
changeset 666608 e02984b5b985ec7d846c90aca3ef58e2176a2d1b
parent 666598 30a386ff1192cba08a2f899343f81f6946bc6148
child 732163 3e6ec733b3301d6e725bd724d58093eec3248f32
push id80468
push userbmo:edilee@mozilla.com
push dateTue, 19 Sep 2017 00:39:49 +0000
reviewersdmose
bugs1400601
milestone57.0a1
Bug 1400601 - Add responsive editing, browser.newtabpage.rows migration and bug fixes to Activity Stream. r?dmose MozReview-Commit-ID: 3ne06Od4PMv
browser/extensions/activity-stream/bootstrap.js
browser/extensions/activity-stream/common/Actions.jsm
browser/extensions/activity-stream/common/Reducers.jsm
browser/extensions/activity-stream/data/content/activity-stream.bundle.js
browser/extensions/activity-stream/data/locales.json
browser/extensions/activity-stream/install.rdf.in
browser/extensions/activity-stream/lib/SectionsManager.jsm
browser/extensions/activity-stream/lib/TopSitesFeed.jsm
browser/extensions/activity-stream/test/unit/common/Reducers.test.js
browser/extensions/activity-stream/test/unit/lib/TopSitesFeed.test.js
--- a/browser/extensions/activity-stream/bootstrap.js
+++ b/browser/extensions/activity-stream/bootstrap.js
@@ -90,28 +90,71 @@ function onPrefChanged() {
   if (Services.prefs.getBoolPref(ACTIVITY_STREAM_ENABLED_PREF, false)) {
     init(REASON_STARTUP_ON_PREF_CHANGE);
   } else {
     uninit(REASON_SHUTDOWN_ON_PREF_CHANGE);
   }
 }
 
 /**
+ * Check if an old pref has a custom value to migrate. Clears the pref so that
+ * it's the default after migrating (to avoid future need to migrate).
+ *
+ * @param oldPrefName {string} Pref to check and migrate
+ * @param cbIfNotDefault {function} Callback that gets the current pref value
+ */
+function migratePref(oldPrefName, cbIfNotDefault) {
+  // Nothing to do if the user doesn't have a custom value
+  if (!Services.prefs.prefHasUserValue(oldPrefName)) {
+    return;
+  }
+
+  // Figure out what kind of pref getter to use
+  let prefGetter;
+  switch (Services.prefs.getPrefType(oldPrefName)) {
+    case Services.prefs.PREF_BOOL:
+      prefGetter = "getBoolPref";
+      break;
+    case Services.prefs.PREF_INT:
+      prefGetter = "getIntPref";
+      break;
+    case Services.prefs.PREF_STRING:
+      prefGetter = "getStringPref";
+      break;
+  }
+
+  // Give the callback the current value then clear the pref
+  cbIfNotDefault(Services.prefs[prefGetter](oldPrefName));
+  Services.prefs.clearUserPref(oldPrefName);
+}
+
+/**
  * onBrowserReady - Continues startup of the add-on after browser is ready.
  */
 function onBrowserReady() {
   waitingForBrowserReady = false;
 
   // Listen for changes to the pref that enables Activity Stream
   Services.prefs.addObserver(ACTIVITY_STREAM_ENABLED_PREF, observe); // eslint-disable-line no-use-before-define
 
   // Only initialize if the pref is true
   if (Services.prefs.getBoolPref(ACTIVITY_STREAM_ENABLED_PREF, false)) {
     init(startupReason);
   }
+
+  // Do a one time migration of Tiles about:newtab prefs that have been modified
+  migratePref("browser.newtabpage.rows", rows => {
+    // Just disable top sites if rows are not desired
+    if (rows <= 0) {
+      Services.prefs.setBoolPref("browser.newtabpage.activity-stream.showTopSites", false);
+    } else {
+      // Assume we want a full row (6 sites per row)
+      Services.prefs.setIntPref("browser.newtabpage.activity-stream.topSitesCount", rows * 6);
+    }
+  });
 }
 
 /**
  * observe - nsIObserver callback to handle various browser notifications.
  */
 function observe(subject, topic, data) {
   switch (topic) {
     case BROWSER_READY_NOTIFICATION:
--- a/browser/extensions/activity-stream/common/Actions.jsm
+++ b/browser/extensions/activity-stream/common/Actions.jsm
@@ -40,17 +40,16 @@ for (const type of [
   "NEW_TAB_INITIAL_STATE",
   "NEW_TAB_LOAD",
   "NEW_TAB_REHYDRATED",
   "NEW_TAB_STATE_REQUEST",
   "NEW_TAB_UNLOAD",
   "OPEN_LINK",
   "OPEN_NEW_WINDOW",
   "OPEN_PRIVATE_WINDOW",
-  "PINNED_SITES_UPDATED",
   "PLACES_BOOKMARK_ADDED",
   "PLACES_BOOKMARK_CHANGED",
   "PLACES_BOOKMARK_REMOVED",
   "PLACES_HISTORY_CLEARED",
   "PLACES_LINK_BLOCKED",
   "PLACES_LINK_DELETED",
   "PREFS_INITIAL_VALUES",
   "PREF_CHANGED",
--- a/browser/extensions/activity-stream/common/Reducers.jsm
+++ b/browser/extensions/activity-stream/common/Reducers.jsm
@@ -93,17 +93,16 @@ function insertPinned(links, pinned) {
   });
 
   return newLinks;
 }
 
 function TopSites(prevState = INITIAL_STATE.TopSites, action) {
   let hasMatch;
   let newRows;
-  let pinned;
   switch (action.type) {
     case at.TOP_SITES_UPDATED:
       if (!action.data) {
         return prevState;
       }
       return Object.assign({}, prevState, {initialized: true, rows: action.data});
     case at.SCREENSHOT_UPDATED:
       newRows = prevState.rows.map(row => {
@@ -143,20 +142,16 @@ function TopSites(prevState = INITIAL_ST
       return Object.assign({}, prevState, {rows: newRows});
     case at.BLOCK_URL:
     case at.DELETE_HISTORY_URL:
       // Optimistically update the UI by responding to the context menu action
       // events and removing the site that was blocked/deleted with an empty slot.
       // Once refresh() finishes, we update the UI again with a new site
       newRows = prevState.rows.filter(val => val && val.url !== action.data.url);
       return Object.assign({}, prevState, {rows: newRows});
-    case at.PINNED_SITES_UPDATED:
-      pinned = action.data;
-      newRows = insertPinned(prevState.rows, pinned).slice(0, TOP_SITES_SHOWMORE_LENGTH);
-      return Object.assign({}, prevState, {rows: newRows});
     default:
       return prevState;
   }
 }
 
 function Dialog(prevState = INITIAL_STATE.Dialog, action) {
   switch (action.type) {
     case at.DIALOG_OPEN:
--- a/browser/extensions/activity-stream/data/content/activity-stream.bundle.js
+++ b/browser/extensions/activity-stream/data/content/activity-stream.bundle.js
@@ -89,17 +89,17 @@ const globalImportContext = typeof Windo
 
 
 // Create an object that avoids accidental differing key/value pairs:
 // {
 //   INIT: "INIT",
 //   UNINIT: "UNINIT"
 // }
 const actionTypes = {};
-for (const type of ["BLOCK_URL", "BOOKMARK_URL", "DELETE_BOOKMARK_BY_ID", "DELETE_HISTORY_URL", "DELETE_HISTORY_URL_CONFIRM", "DIALOG_CANCEL", "DIALOG_OPEN", "INIT", "LOCALE_UPDATED", "MIGRATION_CANCEL", "MIGRATION_COMPLETED", "MIGRATION_START", "NEW_TAB_INIT", "NEW_TAB_INITIAL_STATE", "NEW_TAB_LOAD", "NEW_TAB_REHYDRATED", "NEW_TAB_STATE_REQUEST", "NEW_TAB_UNLOAD", "OPEN_LINK", "OPEN_NEW_WINDOW", "OPEN_PRIVATE_WINDOW", "PINNED_SITES_UPDATED", "PLACES_BOOKMARK_ADDED", "PLACES_BOOKMARK_CHANGED", "PLACES_BOOKMARK_REMOVED", "PLACES_HISTORY_CLEARED", "PLACES_LINK_BLOCKED", "PLACES_LINK_DELETED", "PREFS_INITIAL_VALUES", "PREF_CHANGED", "SAVE_SESSION_PERF_DATA", "SAVE_TO_POCKET", "SCREENSHOT_UPDATED", "SEARCH_BOX_FOCUSED", "SECTION_DEREGISTER", "SECTION_DISABLE", "SECTION_ENABLE", "SECTION_REGISTER", "SECTION_UPDATE", "SECTION_UPDATE_CARD", "SET_PREF", "SHOW_FIREFOX_ACCOUNTS", "SNIPPETS_DATA", "SNIPPETS_RESET", "SYSTEM_TICK", "TELEMETRY_IMPRESSION_STATS", "TELEMETRY_PERFORMANCE_EVENT", "TELEMETRY_UNDESIRED_EVENT", "TELEMETRY_USER_EVENT", "TOP_SITES_ADD", "TOP_SITES_PIN", "TOP_SITES_UNPIN", "TOP_SITES_UPDATED", "UNINIT"]) {
+for (const type of ["BLOCK_URL", "BOOKMARK_URL", "DELETE_BOOKMARK_BY_ID", "DELETE_HISTORY_URL", "DELETE_HISTORY_URL_CONFIRM", "DIALOG_CANCEL", "DIALOG_OPEN", "INIT", "LOCALE_UPDATED", "MIGRATION_CANCEL", "MIGRATION_COMPLETED", "MIGRATION_START", "NEW_TAB_INIT", "NEW_TAB_INITIAL_STATE", "NEW_TAB_LOAD", "NEW_TAB_REHYDRATED", "NEW_TAB_STATE_REQUEST", "NEW_TAB_UNLOAD", "OPEN_LINK", "OPEN_NEW_WINDOW", "OPEN_PRIVATE_WINDOW", "PLACES_BOOKMARK_ADDED", "PLACES_BOOKMARK_CHANGED", "PLACES_BOOKMARK_REMOVED", "PLACES_HISTORY_CLEARED", "PLACES_LINK_BLOCKED", "PLACES_LINK_DELETED", "PREFS_INITIAL_VALUES", "PREF_CHANGED", "SAVE_SESSION_PERF_DATA", "SAVE_TO_POCKET", "SCREENSHOT_UPDATED", "SEARCH_BOX_FOCUSED", "SECTION_DEREGISTER", "SECTION_DISABLE", "SECTION_ENABLE", "SECTION_REGISTER", "SECTION_UPDATE", "SECTION_UPDATE_CARD", "SET_PREF", "SHOW_FIREFOX_ACCOUNTS", "SNIPPETS_DATA", "SNIPPETS_RESET", "SYSTEM_TICK", "TELEMETRY_IMPRESSION_STATS", "TELEMETRY_PERFORMANCE_EVENT", "TELEMETRY_UNDESIRED_EVENT", "TELEMETRY_USER_EVENT", "TOP_SITES_ADD", "TOP_SITES_PIN", "TOP_SITES_UNPIN", "TOP_SITES_UPDATED", "UNINIT"]) {
   actionTypes[type] = type;
 }
 
 // Helper function for creating routed actions between content and main
 // Not intended to be used by consumers
 function _RouteMessage(action, options) {
   const meta = action.meta ? Object.assign({}, action.meta) : {};
   if (!options || !options.from || !options.to) {
@@ -443,17 +443,16 @@ function insertPinned(links, pinned) {
   });
 
   return newLinks;
 }
 
 function TopSites(prevState = INITIAL_STATE.TopSites, action) {
   let hasMatch;
   let newRows;
-  let pinned;
   switch (action.type) {
     case at.TOP_SITES_UPDATED:
       if (!action.data) {
         return prevState;
       }
       return Object.assign({}, prevState, { initialized: true, rows: action.data });
     case at.SCREENSHOT_UPDATED:
       newRows = prevState.rows.map(row => {
@@ -493,20 +492,16 @@ function TopSites(prevState = INITIAL_ST
       return Object.assign({}, prevState, { rows: newRows });
     case at.BLOCK_URL:
     case at.DELETE_HISTORY_URL:
       // Optimistically update the UI by responding to the context menu action
       // events and removing the site that was blocked/deleted with an empty slot.
       // Once refresh() finishes, we update the UI again with a new site
       newRows = prevState.rows.filter(val => val && val.url !== action.data.url);
       return Object.assign({}, prevState, { rows: newRows });
-    case at.PINNED_SITES_UPDATED:
-      pinned = action.data;
-      newRows = insertPinned(prevState.rows, pinned).slice(0, TOP_SITES_SHOWMORE_LENGTH);
-      return Object.assign({}, prevState, { rows: newRows });
     default:
       return prevState;
   }
 }
 
 function Dialog(prevState = INITIAL_STATE.Dialog, action) {
   switch (action.type) {
     case at.DIALOG_OPEN:
@@ -1538,17 +1533,16 @@ class TopSitesEdit extends React.PureCom
         React.createElement(
           "div",
           { className: "modal" },
           React.createElement(TopSiteForm, {
             label: this.props.TopSites.rows[this.state.editIndex].label || this.props.TopSites.rows[this.state.editIndex].hostname,
             url: this.props.TopSites.rows[this.state.editIndex].url,
             index: this.state.editIndex,
             editMode: true,
-            link: this.props.TopSites.rows[this.state.editIndex],
             onClose: this.onFormClose,
             dispatch: this.props.dispatch,
             intl: this.props.intl })
         )
       )
     );
   }
 }
@@ -1613,23 +1607,16 @@ class TopSiteForm extends React.PureComp
   }
   onSaveButtonClick(ev) {
     ev.preventDefault();
     if (this.validateForm()) {
       let site = { url: this.cleanUrl() };
       if (this.state.label !== "") {
         site.label = this.state.label;
       }
-      // Unpin links if the URL changed.
-      if (this.props.link.isPinned && this.props.link.url !== site.url) {
-        this.props.dispatch(ac.SendToMain({
-          type: at.TOP_SITES_UNPIN,
-          data: { site: { url: this.props.link.url } }
-        }));
-      }
       this.props.dispatch(ac.SendToMain({
         type: at.TOP_SITES_PIN,
         data: { site, index: this.props.index }
       }));
       this.props.dispatch(ac.UserEvent({
         source: TOP_SITES_SOURCE,
         event: "TOP_SITES_EDIT",
         action_position: this.props.index
@@ -2459,17 +2446,17 @@ class Section extends React.PureComponen
   }
 
   // This sends an event when a user sees a set of new content. If content
   // changes while the page is hidden (i.e. preloaded or on a hidden tab),
   // only send the event if the page becomes visible again.
   sendImpressionStatsOrAddListener() {
     const { props } = this;
 
-    if (!props.dispatch) {
+    if (!props.shouldSendImpressionStats || !props.dispatch) {
       return;
     }
 
     if (props.document.visibilityState === VISIBLE) {
       this._dispatchImpressionStats();
     } else {
       // We should only ever send the latest impression stats ping, so remove any
       // older listeners.
--- a/browser/extensions/activity-stream/data/locales.json
+++ b/browser/extensions/activity-stream/data/locales.json
@@ -2364,17 +2364,17 @@
     "welcome_body": "Firefox utilisera cet espace pour afficher des éléments pertinents, comme des marque-pages, des articles, des vidéos, et des pages que vous avez visitées, afin que vous les retrouviez facilement.",
     "welcome_label": "Identification des éléments-clés",
     "time_label_less_than_minute": "<1 min",
     "time_label_minute": "{number} min",
     "time_label_hour": "{number} h",
     "time_label_day": "{number} j",
     "settings_pane_button_label": "Personnaliser la page Nouvel onglet",
     "settings_pane_header": "Préférences Nouvel onglet",
-    "settings_pane_body2": "Sélectionnez les éléments à afficher sur cette page.",
+    "settings_pane_body2": "Choisissez les éléments à afficher sur cette page.",
     "settings_pane_search_header": "Recherche",
     "settings_pane_search_body": "Effectuez une recherche sur le Web depuis le nouvel onglet.",
     "settings_pane_topsites_header": "Sites les plus visités",
     "settings_pane_topsites_body": "Accédez aux sites que vous consultez le plus.",
     "settings_pane_topsites_options_showmore": "Afficher deux lignes",
     "settings_pane_bookmarks_header": "Marque-pages récents",
     "settings_pane_bookmarks_body": "Vos nouveaux marque-pages, facilement accessibles.",
     "settings_pane_visit_again_header": "Visiter à nouveau",
@@ -2383,18 +2383,18 @@
     "settings_pane_highlights_body2": "Retrouvez des pages intéressantes que vous avez visitées récemment ou ajoutées aux marque-pages.",
     "settings_pane_highlights_options_bookmarks": "Marque-pages",
     "settings_pane_highlights_options_visited": "Sites visités",
     "settings_pane_snippets_header": "Brèves",
     "settings_pane_snippets_body": "Consultez les brèves de Mozilla à propos de Firefox, la culture Internet, mais aussi quelques mèmes Internet de temps en temps.",
     "settings_pane_done_button": "Terminé",
     "edit_topsites_button_text": "Modifier",
     "edit_topsites_button_label": "Personnaliser la section Sites les plus visités",
-    "edit_topsites_showmore_button": "Afficher plus",
-    "edit_topsites_showless_button": "Afficher moins",
+    "edit_topsites_showmore_button": "En afficher plus",
+    "edit_topsites_showless_button": "En afficher moins",
     "edit_topsites_done_button": "Terminé",
     "edit_topsites_pin_button": "Épingler ce site",
     "edit_topsites_unpin_button": "Relâcher ce site",
     "edit_topsites_edit_button": "Modifier ce site",
     "edit_topsites_dismiss_button": "Retirer ce site",
     "edit_topsites_add_button": "Ajouter",
     "topsites_form_add_header": "Nouveau site populaire",
     "topsites_form_edit_header": "Modifier le site populaire",
@@ -2671,41 +2671,104 @@
     "manual_migration_explanation": "Feuch Firefox leis na làraichean is comharran-lìn as fhearr leat o bhrabhsair eile.",
     "manual_migration_cancel_button": "Chan eil, tapadh leibh",
     "manual_migration_import_button": "Ion-phortaich an-dràsta"
   },
   "gu-IN": {
     "newtab_page_title": "નવું ટૅબ",
     "default_label_loading": "લોડ કરી રહ્યું છે...",
     "header_top_sites": "ટોપ સાઇટ્સ",
-    "header_highlights": "હાઇલાઇટ્સ",
+    "header_stories": "શીર્ષ વાર્તાઓ",
+    "header_highlights": "વીતી ગયેલું",
+    "header_visit_again": "ફરી મુલાકાત",
+    "header_bookmarks": "તાજેતરના બુકમાર્ક્સ",
+    "header_recommended_by": "દ્વારા ભલામણ",
+    "header_bookmarks_placeholder": "તમારી પાસે હજી સુધી કોઈ બુકમાર્ક્સ નથી.",
+    "header_stories_from": "થી",
     "type_label_visited": "જોવામા આવેલ:",
     "type_label_bookmarked": "બુકમાર્ક્સ",
     "type_label_synced": "બીજા ઉપકરણ થી સમન્વયિત કરેલ છે",
+    "type_label_recommended": "વલણ",
     "type_label_open": "ખોલો",
     "type_label_topic": "વિષય",
+    "type_label_now": "હવે",
     "menu_action_bookmark": "બુકમાર્ક",
     "menu_action_remove_bookmark": "બુકમાર્ક કાઢો",
     "menu_action_copy_address": "સરનામું કૉપિ કરો",
     "menu_action_email_link": "ઇમેલ કડી…",
     "menu_action_open_new_window": "નવી વિન્ડોમાં ખોલો",
     "menu_action_open_private_window": "ખાનગી વિન્ડોમાં ખોલો",
     "menu_action_dismiss": "રદ કરો",
     "menu_action_delete": "ઇતિહાસમાંથી દૂર કરો",
+    "menu_action_pin": "પિન",
+    "menu_action_unpin": "અનપિન",
+    "confirm_history_delete_p1": "શું તમે ખરેખર તમારા ઇતિહાસમાંથી આ પૃષ્ઠનાં દરેક ઘટકને કાઢી નાખવા માંગો છો?",
+    "confirm_history_delete_notice_p2": "આ ક્રિયા પૂર્વવત્ કરી શકાતી નથી.",
+    "menu_action_save_to_pocket": "પોકેટમાં સાચવો",
     "search_for_something_with": "શોધ કરો {search_term} ની સાથે:",
+    "search_button": "શોધો",
     "search_header": "{search_engine_name} શોધ કરો",
     "search_web_placeholder": "વેબ પર શોધો",
     "search_settings": "શોધ ના સેટિંગ્સ બદલો",
+    "section_info_option": "માહિતી",
+    "section_info_send_feedback": "પ્રતિસાદ મોકલ",
+    "section_info_privacy_notice": "ગોપનીયતા સૂચના",
     "welcome_title": "નવી વિન્ડોમાં આપનું સ્વાગત છે",
     "welcome_body": "ફાયરફોક્સ, તમારા સૌથી સંબંધિત બુકમાર્ક્સ, લેખો, વિડિઓઝ, અને પૃષ્ઠો જે તમે તાજેતરમાં મુલાકાત લીધી એ બતાવવા માટે આ જગ્યાનો ઉપયોગ કરશે જેથી તમે પાછા તેમને સરળતાથી મેળવી શકો છો.",
     "welcome_label": "તમારા હાઇલાઇટ્સ ઓળખવા",
     "time_label_less_than_minute": "<1મિનિટ",
     "time_label_minute": "{number}મિનિટ",
     "time_label_hour": "{number}કલાક",
-    "time_label_day": "{number}દિવસ"
+    "time_label_day": "{number}દિવસ",
+    "settings_pane_button_label": "તમારા નવા ટૅબ પૃષ્ઠને કસ્ટમાઇઝ કરો",
+    "settings_pane_header": "નવી ટેબ પસંદગીઓ",
+    "settings_pane_body2": "તમે આ પૃષ્ઠ પર જે જુઓ છો તે પસંદ કરો.",
+    "settings_pane_search_header": "શોધો",
+    "settings_pane_search_body": "તમારા નવા ટૅબમાંથી વેબ પર શોધો.",
+    "settings_pane_topsites_header": "ટોચની સાઇટ્સ",
+    "settings_pane_topsites_body": "તમે સૌથી વધુ મુલાકાત લો છો તે વેબસાઇટ્સને ઍક્સેસ કરો.",
+    "settings_pane_topsites_options_showmore": "બે પંક્તિઓ બતાવો",
+    "settings_pane_bookmarks_header": "તાજેતરના બુકમાર્ક્સ",
+    "settings_pane_bookmarks_body": "તમારા નવા બનાવેલ બુકમાર્ક્સ એક હાથમાં સ્થાનમાં.",
+    "settings_pane_visit_again_header": "ફરી મુલાકાત",
+    "settings_pane_visit_again_body": "ફાયરફોક્સ તમને તમારા બ્રાઉઝિંગ હિસ્ટરીનાં ભાગો બતાવશે જે તમે યાદ રાખવા અથવા પાછા આવવા ઇચ્છતા હોવ.",
+    "settings_pane_highlights_header": "વીતી ગયેલું",
+    "settings_pane_highlights_body2": "તમે તાજેતરમાં મુલાકાત લીધેલા અથવા બુકમાર્ક કરેલી રસપ્રદ વસ્તુઓ પર તમારી રીત શોધો.",
+    "settings_pane_highlights_options_bookmarks": "બુકમાર્ક્સ",
+    "settings_pane_highlights_options_visited": "મુલાકાત લીધેલ સાઇટ્સ",
+    "settings_pane_snippets_header": "જાણકારી આપનારા ઉતારા ક કાપલીઓ",
+    "settings_pane_snippets_body": "ટૂંકી અને મીઠી સુધારાઓ વાંચો મોઝિલ્લાથી ફાયરફોક્સ વિશે, ઇન્ટરનેટ સંસ્કૃતિ અને પ્રસંગોપાત ફાવે તેમ મેમે વિશે.",
+    "settings_pane_done_button": "પૂરું",
+    "edit_topsites_button_text": "ફેરફાર કરો",
+    "edit_topsites_button_label": "તમારા ટોચના સાઇટ્સ વિભાગને કસ્ટમાઇઝ કરો",
+    "edit_topsites_showmore_button": "વધારે બતાવો",
+    "edit_topsites_showless_button": "થોડું બતાવો",
+    "edit_topsites_done_button": "પૂરું",
+    "edit_topsites_pin_button": "આ સાઇટને પિન કરો",
+    "edit_topsites_unpin_button": "આ સાઇટ અનપિન કરો",
+    "edit_topsites_edit_button": "આ સાઇટને સંપાદિત કરો",
+    "edit_topsites_dismiss_button": "આ સાઇટને કાઢી નાખો",
+    "edit_topsites_add_button": "ઉમેરો",
+    "topsites_form_add_header": "નવી ટોચની સાઇટ",
+    "topsites_form_edit_header": "ટોચની સાઇટ સંપાદિત કરો",
+    "topsites_form_title_placeholder": "શીર્ષક દાખલ કરો",
+    "topsites_form_url_placeholder": "URL ટાઇપ કરો અથવા પેસ્ટ કરો",
+    "topsites_form_add_button": "ઉમેરો",
+    "topsites_form_save_button": "સાચવો",
+    "topsites_form_cancel_button": "રદ કરો",
+    "topsites_form_url_validation": "માન્ય URL આવશ્યક છે",
+    "pocket_read_more": "લોકપ્રિય વિષયો:",
+    "pocket_read_even_more": "વધુ વાર્તાઓ જુઓ",
+    "pocket_feedback_header": "2.5 કરોડ વધુ લોકો દ્વારા બનાવાયેલા શ્રેષ્ઠ વેબ.",
+    "pocket_description": "ઉચ્ચ ગુણવત્તાવાળી સામગ્રી શોધો અન્યથા તમે ચૂકી જશો, પોકેટની સહાયથી, હવે મોઝિલાનો એક ભાગ છે.",
+    "highlights_empty_state": "બ્રાઉઝ કરવું પ્રારંભ કરો અને અમે અહીં કેટલાક સરસ લેખો, વિડિઓઝ અને અન્ય પૃષ્ઠો દર્શાવીશું જે તમે તાજેતરમાં મુલાકાત લીધાં છે અથવા બુકમાર્ક કર્યા છે.",
+    "topstories_empty_state": "તમે પકડાઈ ગયા છો. {પ્રદાતા} તરફથી વધુ ટોચની વાતો માટે પછીથી પાછા તપાસો. રાહ નથી જોઈ શકતા? સમગ્ર વેબ પરથી વધુ સુંદર વાર્તાઓ શોધવા માટે એક લોકપ્રિય વિષય પસંદ કરો.",
+    "manual_migration_explanation2": "અન્ય બ્રાઉઝરથી બુકમાર્ક્સ, ઇતિહાસ અને પાસવર્ડ્સ સાથે ફાયરફોક્સ અજમાવો.",
+    "manual_migration_cancel_button": "ના અભાર",
+    "manual_migration_import_button": "હવે આયાત કરો"
   },
   "he": {
     "newtab_page_title": "לשונית חדשה",
     "default_label_loading": "בטעינה…",
     "header_top_sites": "אתרים מובילים",
     "header_stories": "סיפורים מובילים",
     "header_visit_again": "ביקור חוזר",
     "header_bookmarks": "סימניות אחרונות",
@@ -2840,16 +2903,17 @@
     "pocket_read_even_more": "और कहानियाँ देखें",
     "pocket_send_feedback": "प्रतिक्रिया भेजें"
   },
   "hr": {
     "newtab_page_title": "Nova kartica",
     "default_label_loading": "Učitavanje…",
     "header_top_sites": "Najbolje stranice",
     "header_stories": "Najbolje priče",
+    "header_highlights": "Istaknuto",
     "header_visit_again": "Posjetite ponovno",
     "header_bookmarks": "Nedavne zabilješke",
     "header_recommended_by": "Preporučeno od {provider}",
     "header_bookmarks_placeholder": "Još nemate niti jednu zabilješku.",
     "header_stories_from": "od",
     "type_label_visited": "Posjećeno",
     "type_label_bookmarked": "Zabilježeno",
     "type_label_synced": "Sinkronizirano s drugog uređaja",
@@ -2871,37 +2935,43 @@
     "confirm_history_delete_notice_p2": "Ova radnja je nepovratna.",
     "menu_action_save_to_pocket": "Spremi u Pocket",
     "search_for_something_with": "Traži {search_term} s:",
     "search_button": "Traži",
     "search_header": "{search_engine_name} pretraživanje",
     "search_web_placeholder": "Pretraži web",
     "search_settings": "Promijeni postavke pretraživanja",
     "section_info_option": "Info",
+    "section_info_send_feedback": "Pošaljite povratnu informaciju",
+    "section_info_privacy_notice": "Politika privatnosti",
     "welcome_title": "Dobro došli u novu karticu",
     "welcome_body": "Firefox će koristiti ovaj prostor kako bi vam pokazao najbitnije zabilješke, članke, video uratke i stranice koje ste nedavno posjetili, tako da se možete lako vratiti na njih.",
     "welcome_label": "Identificiranje istaknutog",
     "time_label_less_than_minute": "<1m",
     "time_label_minute": "{number}m",
     "time_label_hour": "{number}h",
     "time_label_day": "{number}d",
     "settings_pane_button_label": "Prilagodite svoju početnu stranicu nove kartice",
     "settings_pane_header": "Postavke nove kartice",
-    "settings_pane_body": "Odaberite što ćete vidjeti kada otvorite novu karticu.",
+    "settings_pane_body2": "Odaberite što vidite na ovoj stranici.",
     "settings_pane_search_header": "Traži",
     "settings_pane_search_body": "Pretražite Web iz nove kartice.",
     "settings_pane_topsites_header": "Najbolje stranice",
     "settings_pane_topsites_body": "Pristupite stranicama koje najčešće posjećujete.",
     "settings_pane_topsites_options_showmore": "Prikaži dva reda",
     "settings_pane_bookmarks_header": "Nedavne zabilješke",
     "settings_pane_bookmarks_body": "Vaše novo stvorene zabilješke na jednom praktičnom mjestu.",
     "settings_pane_visit_again_header": "Posjetite ponovno",
     "settings_pane_visit_again_body": "Firefox će vam prikazati dijelove vaše povijesti pretraživanja koje možda želite zapamtiti ili posjetiti ponovno.",
-    "settings_pane_pocketstories_header": "Najbolje priče",
-    "settings_pane_pocketstories_body": "Pocket, dio Mozilla obitelji, povezat će vas sa sadržajem visoke kvalitete koji možda inače ne biste pronašli.",
+    "settings_pane_highlights_header": "Istaknuto",
+    "settings_pane_highlights_body2": "Pronađite put natrag do zanimljivih stvari koje ste nedavno posjetili ili zabilježili.",
+    "settings_pane_highlights_options_bookmarks": "Zabilješke",
+    "settings_pane_highlights_options_visited": "Posjećene stranice",
+    "settings_pane_snippets_header": "Isječci",
+    "settings_pane_snippets_body": "Pročitajte kratke i slatke obavijesti od Mozille o Firefoxu, internet kulturi i povremenim nasumičnim temama.",
     "settings_pane_done_button": "Gotovo",
     "edit_topsites_button_text": "Uredi",
     "edit_topsites_button_label": "Prilagodite odjel s najboljim stranicama",
     "edit_topsites_showmore_button": "Prikaži više",
     "edit_topsites_showless_button": "Prikaži manje",
     "edit_topsites_done_button": "Gotovo",
     "edit_topsites_pin_button": "Zakači stranicu",
     "edit_topsites_unpin_button": "Otkači ovu stranicu",
@@ -2914,20 +2984,20 @@
     "topsites_form_url_placeholder": "Utipkajte ili zalijepite URL",
     "topsites_form_add_button": "Dodaj",
     "topsites_form_save_button": "Spremi",
     "topsites_form_cancel_button": "Otkaži",
     "topsites_form_url_validation": "Potrebno je unijeti ispravan URL",
     "pocket_read_more": "Popularne teme:",
     "pocket_read_even_more": "Prikaži više priča",
     "pocket_feedback_header": "Najbolje od interneta, birano od preko 25 miliona ljudi.",
-    "pocket_feedback_body": "Pocket, dio Mozilla obitelji, povezat će vas sa sadržajem visoke kvalitete koji možda inače ne biste pronašli.",
-    "pocket_send_feedback": "Pošaljite povratnu informaciju",
+    "pocket_description": "Otkrijte visoko kvalitetan sadržaj koji ste možda propustili, uz pomoć Pocketa koji je sada dio Mozille.",
+    "highlights_empty_state": "Započnite pretraživati i pokazat ćemo vam neke od izvrsnih članaka, videa i drugih web stranica prema vašim nedavno posjećenim stranicama ili zabilješkama.",
     "topstories_empty_state": "Provjerite kasnije za više najpopularnijih priča od {provider}. Ne možete čekati? Odaberite popularne teme kako biste pronašli više kvalitetnih priča s cijelog weba.",
-    "manual_migration_explanation": "Probajte Firefox s vašim omiljenim stranicama i zabilješkama iz drugog pretraživača.",
+    "manual_migration_explanation2": "Probajte Firefox s zabilješkama, povijesti i lozinkama iz drugog pretraživača.",
     "manual_migration_cancel_button": "Ne hvala",
     "manual_migration_import_button": "Uvezi sada"
   },
   "hsb": {
     "newtab_page_title": "Nowy rajtark",
     "default_label_loading": "Začituje so…",
     "header_top_sites": "Najhusćišo wopytane sydła",
     "header_stories": "Najhusćišo přečitane zdźělenki",
@@ -3139,23 +3209,106 @@
     "welcome_label": "Նույնացնում է ձեր գունանշումը",
     "time_label_less_than_minute": "<1 ր",
     "time_label_minute": "{number} ր",
     "time_label_hour": "{number} ժ",
     "time_label_day": "{number} օր"
   },
   "ia": {
     "newtab_page_title": "Nove scheda",
-    "default_label_loading": "Cargamento…",
-    "header_top_sites": "Sitos principal",
-    "header_stories": "Articulos popular",
+    "default_label_loading": "Cargante…",
+    "header_top_sites": "Sitos popular",
+    "header_stories": "Historias popular",
     "header_highlights": "In evidentia",
     "header_visit_again": "Visita de novo",
-    "header_bookmarks": "Marcatores recente",
-    "header_recommended_by": "Recommendate per {provider}"
+    "header_bookmarks": "Paginas marcate recentemente",
+    "header_recommended_by": "Recommendate per {provider}",
+    "header_bookmarks_placeholder": "Vos ha ancora nulle paginas marcate.",
+    "header_stories_from": "de",
+    "type_label_visited": "Visitate",
+    "type_label_bookmarked": "Marcate",
+    "type_label_synced": "Synchronisate de altere apparato",
+    "type_label_recommended": "Tendentias",
+    "type_label_open": "Aperite",
+    "type_label_topic": "Subjecto",
+    "type_label_now": "Ora",
+    "menu_action_bookmark": "Marcar le pagina",
+    "menu_action_remove_bookmark": "Dismarcar le pagina",
+    "menu_action_copy_address": "Copiar le adresse",
+    "menu_action_email_link": "Inviar le ligamine per email…",
+    "menu_action_open_new_window": "Aperir in un nove fenestra",
+    "menu_action_open_private_window": "Aperir in un nove fenestra private",
+    "menu_action_dismiss": "Dimitter",
+    "menu_action_delete": "Deler del chronologia",
+    "menu_action_pin": "Clavar",
+    "menu_action_unpin": "Disclavar",
+    "confirm_history_delete_p1": "Desira vos vermente deler cata instantia de iste pagina de vostre chronologia?",
+    "confirm_history_delete_notice_p2": "Iste action es irreversibile.",
+    "menu_action_save_to_pocket": "Salvar in Pocket",
+    "search_for_something_with": "Cercar {search_term} con:",
+    "search_button": "Cercar",
+    "search_header": "Recerca {search_engine_name}",
+    "search_web_placeholder": "Cercar in le Web",
+    "search_settings": "Cambiar le parametros de recerca",
+    "section_info_option": "Informationes",
+    "section_info_send_feedback": "Inviar feedback",
+    "section_info_privacy_notice": "Advertentia de privacitate",
+    "welcome_title": "Benvenite al nove scheda",
+    "welcome_body": "Firefox usara iste spatio pro monstrar vostre paginas marcate le plus relevante, articulos, videos e paginas que vos ha visitate recentemente, de sorta que vos pote revider los facilemente.",
+    "welcome_label": "Identificante vostre evidentias",
+    "time_label_less_than_minute": "<1 min",
+    "time_label_minute": "{number} min",
+    "time_label_hour": "{number} h",
+    "time_label_day": "{number} d",
+    "settings_pane_button_label": "Personalisar vostre pagina de nove scheda",
+    "settings_pane_header": "Preferentias de nove scheda",
+    "settings_pane_body2": "Selige lo que vos vole vider in iste pagina.",
+    "settings_pane_search_header": "Cercar",
+    "settings_pane_search_body": "Cercar in le Web ab vostre nove scheda.",
+    "settings_pane_topsites_header": "Sitos popular",
+    "settings_pane_topsites_body": "Acceder al sitos web que vos plus visita.",
+    "settings_pane_topsites_options_showmore": "Monstrar duo lineas",
+    "settings_pane_bookmarks_header": "Paginas marcate recentemente",
+    "settings_pane_bookmarks_body": "Vostre paginas marcate recentemente a un sol loco.",
+    "settings_pane_visit_again_header": "Visitar de novo",
+    "settings_pane_visit_again_body": "Firefox vos monstrara partes de vostre chronologia de navigation que vos pote voler rememorar o visitar novemente.",
+    "settings_pane_highlights_header": "In evidentia",
+    "settings_pane_highlights_body2": "Retrova cosas interessante que vos ha recentemente visitate o marcate.",
+    "settings_pane_highlights_options_bookmarks": "Paginas marcate",
+    "settings_pane_highlights_options_visited": "Sitos visitate",
+    "settings_pane_snippets_header": "Breve novas",
+    "settings_pane_snippets_body": "Lege breve e legier novas de Mozilla super Firefox, cultura internet e occasionalmente super alcun meme.",
+    "settings_pane_done_button": "Facite",
+    "edit_topsites_button_text": "Editar",
+    "edit_topsites_button_label": "Personalisar vostre section de sitos popular",
+    "edit_topsites_showmore_button": "Monstrar plus",
+    "edit_topsites_showless_button": "Monstrar minus",
+    "edit_topsites_done_button": "Facite",
+    "edit_topsites_pin_button": "Clavar iste sito",
+    "edit_topsites_unpin_button": "Disclavar iste sito",
+    "edit_topsites_edit_button": "Editar iste sito",
+    "edit_topsites_dismiss_button": "Dimitter iste sito",
+    "edit_topsites_add_button": "Adder",
+    "topsites_form_add_header": "Nove sito popular",
+    "topsites_form_edit_header": "Editar le sito popular",
+    "topsites_form_title_placeholder": "Scriber un titulo",
+    "topsites_form_url_placeholder": "Scriber o collar un URL",
+    "topsites_form_add_button": "Adder",
+    "topsites_form_save_button": "Salvar",
+    "topsites_form_cancel_button": "Cancellar",
+    "topsites_form_url_validation": "Il es necessari un URL valide",
+    "pocket_read_more": "Subjectos popular:",
+    "pocket_read_even_more": "Vider plus historias",
+    "pocket_feedback_header": "Le melior del web, selectionate per 25 milliones de personas.",
+    "pocket_description": "Discoperir contento de alte qualitate que vos poterea alteremente non cognoscer, con le adjuta de Pocket, ora parte de Mozilla.",
+    "highlights_empty_state": "Comencia navigar e nos vos monstrara alcun del grande articulos, videos e altere paginas que vos ha recentemente visitate o marcate hic.",
+    "topstories_empty_state": "Vos ja es in die con toto. Reveni plus tarde pro plus historias popular de {provider}. Non vole attender? Selectiona un subjecto popular pro trovar plus altere historias interessante del web.",
+    "manual_migration_explanation2": "Essaya Firefox con le paginas marcate, le chronologia e le contrasignos de altere navigator.",
+    "manual_migration_cancel_button": "No, gratias",
+    "manual_migration_import_button": "Importar ora"
   },
   "id": {
     "newtab_page_title": "Tab Baru",
     "default_label_loading": "Memuat…",
     "header_top_sites": "Situs Teratas",
     "header_stories": "Cerita Utama",
     "header_highlights": "Sorotan",
     "header_visit_again": "Kunjungi Lagi",
@@ -3999,16 +4152,17 @@
     "settings_pane_bookmarks_body": "Jūsų naujai sukurti adresyno įrašai vienoje vietoje.",
     "settings_pane_visit_again_header": "Aplankykite vėl",
     "settings_pane_visit_again_body": "„Firefox“ pateiks ištraukas iš jūsų naršymo žurnalo, kurias galbūt norėtumėte prisiminti.",
     "settings_pane_highlights_header": "Akcentai",
     "settings_pane_highlights_body2": "Sugrįžkite prie įdomių dalykų, kuriuose neseniai lankėtės ar įtraukėte į adresyną.",
     "settings_pane_highlights_options_bookmarks": "Adresynas",
     "settings_pane_highlights_options_visited": "Aplankytos svetainės",
     "settings_pane_snippets_header": "Iškarpos",
+    "settings_pane_snippets_body": "Skaitykite trumpas ir mielas naujienas iš „Mozillos“ apie „Firefox“, interneto kultūrą bei atsitiktinį memą.",
     "settings_pane_done_button": "Atlikta",
     "edit_topsites_button_text": "Keisti",
     "edit_topsites_button_label": "Tinkinkite savo lankomiausių svetainių skiltį",
     "edit_topsites_showmore_button": "Rodyti daugiau",
     "edit_topsites_showless_button": "Rodyti mažiau",
     "edit_topsites_done_button": "Atlikta",
     "edit_topsites_pin_button": "Įsegti šią svetainę",
     "edit_topsites_unpin_button": "Išsegti šią svetainę",
@@ -4721,61 +4875,75 @@
     "manual_migration_explanation2": "Prøv Firefox med bokmerka, historikk og passord frå ein annan nettlesar.",
     "manual_migration_cancel_button": "Nei takk",
     "manual_migration_import_button": "Importer no"
   },
   "pa-IN": {
     "newtab_page_title": "ਨਵੀਂ ਟੈਬ",
     "default_label_loading": "…ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ",
     "header_top_sites": "ਸਿਖਰਲੀਆਂ ਸਾਈਟਾਂ",
-    "header_highlights": "ਹਾਈਲਾਈਟ",
+    "header_stories": "ਸਿਖਰਲੇ ਕਿੱਸੇ",
+    "header_highlights": "ਸੁਰਖੀਆਂ",
+    "header_visit_again": "ਮੁੜ ਦੌਰਾ ਕਰੋ",
+    "header_bookmarks": "ਤਾਜ਼ਾ ਬੁੱਕਮਾਰਕ",
+    "header_recommended_by": "{provider} ਵਲੋਂ ਸਿਫਾਰਸ਼ੀ",
     "type_label_visited": "ਖੋਲ੍ਹੀਆਂ",
     "type_label_bookmarked": "ਬੁੱਕਮਾਰਕ ਕੀਤੀਆਂ",
     "type_label_synced": "ਹੋਰ ਡਿਵਾਈਸ ਤੋਂ ਸਿੰਕ ਕੀਤੀਆਂ",
     "type_label_open": "ਖੋਲ੍ਹੋ",
     "type_label_topic": "ਵਿਸ਼ੇ",
+    "type_label_now": "ਹੁਣ",
     "menu_action_bookmark": "ਬੁੱਕਮਾਰਕ",
     "menu_action_remove_bookmark": "ਬੁੱਕਮਾਰਕ ਨੂੰ ਹਟਾਓ",
     "menu_action_copy_address": "ਸਿਰਨਾਵੇਂ ਨੂੰ ਕਾਪੀ ਕਰੋ",
     "menu_action_email_link": "…ਲਿੰਕ ਨੂੰ ਈਮੇਲ ਕਰੋ",
     "menu_action_open_new_window": "ਨਵੀਂ ਵਿੰਡੋ ਵਿੱਚ ਖੋਲ੍ਹੋ",
     "menu_action_open_private_window": "ਨਵੀਂ ਪ੍ਰਾਈਵੇਟ ਵਿੰਡੋ ਵਿੱਚ ਖੋਲ੍ਹੋ",
     "menu_action_dismiss": "ਰੱਦ ਕਰੋ",
     "menu_action_delete": "ਅਤੀਤ ਵਿੱਚੋਂ ਹਟਾਓ",
+    "menu_action_pin": "ਟੰਗੋ",
     "search_for_something_with": "{search_term} ਨੂੰ ਇਸ ਨਾਲ ਖੋਜੋ:",
     "search_button": "ਖੋਜੋ",
     "search_header": "{search_engine_name} ਖੋਜ",
     "search_web_placeholder": "ਵੈੱਬ ਨੂੰ ਖੋਜੋ",
     "search_settings": "ਖੋਜ ਸੈਟਿੰਗਾਂ ਨੂੰ ਬਦਲੋ",
+    "section_info_option": "ਜਾਣਕਾਰੀ",
+    "section_info_send_feedback": "ਫੀਡਬੈਕ ਭੇਜੋ",
+    "section_info_privacy_notice": "ਪਰਦੇਦਾਰੀ ਨੋਟਿਸ",
     "welcome_title": "ਨਵੀਂ ਟੈਬ ਉੱਤੇ ਜੀ ਆਇਆਂ ਨੂੰ",
     "welcome_body": "ਫਾਇਰਫਾਕਸ ਇਸ ਥਾਂ ਨੂੰ ਤੁਹਾਡੇ ਲਈ ਸਭ ਤੋਂ ਵੱਧ ਢੁੱਕਵੇਂ ਬੁੱਕਮਾਰਕ, ਲੇਖ, ਵੀਡੀਓ ਅਤੇ ਸਫ਼ੇ ਵਿਖਾਉਣ ਲਈ ਵਰਤੇਗਾ, ਜਿਹਨਾਂ ਨੂੰ ਤੁਸੀਂ ਹਾਲ ਵਿੱਚ ਹੀ ਖੋਲ੍ਹਿਆ ਹੈ ਤਾਂ ਕਿ ਤੁਸੀਂ ਉਹਨਾਂ ਉੱਤੇ ਸੌਖੀ ਤਰ੍ਹਾਂ ਵਾਪਸ ਜਾ ਸਕੋ।",
     "welcome_label": "ਤੁਹਾਡੇ ਹਾਈਲਾਈਟ ਨੂੰ ਪਛਾਣਿਆ ਜਾ ਰਿਹਾ ਹੈ",
     "time_label_less_than_minute": "<1ਮਿੰ",
     "time_label_minute": "{number}ਮਿੰ",
     "time_label_hour": "{number}ਘੰ",
     "time_label_day": "{number}ਦਿ",
     "settings_pane_button_label": "ਆਪਣੇ ਨਵੀਂ ਟੈਬ ਸਫ਼ੇ ਨੂੰ ਆਪਣੇ ਮੁਤਾਬਕ ਢਾਲੋ",
     "settings_pane_header": "ਨਵੀਂ ਟੈਬ ਲਈ ਪਸੰਦਾਂ",
-    "settings_pane_body": "ਉਹ ਚੁਣੋ, ਜੋ ਤੁਸੀਂ ਨਵੀਂ ਟੈਬ ਨੂੰ ਖੋਲ੍ਹਣ ਦੇ ਬਾਅਦ ਵੇਖਣਾ ਚਾਹੁੰਦੇ ਹੋ।",
     "settings_pane_search_header": "ਖੋਜੋ",
     "settings_pane_search_body": "ਆਪਣੀ ਨਵੀਂ ਟੈਬ ਤੋਂ ਵੈੱਬ ਨੂੰ ਖੋਜੋ।",
     "settings_pane_topsites_header": "ਸਿਖਰਲੀਆਂ ਸਾਈਟਾਂ",
     "settings_pane_topsites_body": "ਵੈੱਬਸਾਈਟਾਂ, ਜਿਹਨਾਂ ਨੂੰ ਤੁਸੀਂ ਸਭ ਤੋਂ ਵੱਧ ਖੋਲ੍ਹਿਆ ਹੈ, ਲਈ ਪਹੁੰਚ।",
     "settings_pane_topsites_options_showmore": "ਦੋ ਕਤਾਰਾਂ ਵੇਖਾਓ",
     "settings_pane_highlights_header": "ਹਾਈਲਾਈਟ",
-    "settings_pane_highlights_body": "ਆਪਣੇ ਹਾਲ ਦੇ ਬਰਾਊਜ਼ ਕਰਨ ਦੇ ਅਤੀਤ ਅਤੇ ਨਵੇਂ ਬਣਾਏ ਬੁੱਕਮਾਰਕਾਂ ਉੱਤੇ ਝਲਕ ਮਾਰੋ।",
+    "settings_pane_highlights_options_bookmarks": "ਬੁੱਕਮਾਰਕ",
     "settings_pane_done_button": "ਮੁਕੰਮਲ",
     "edit_topsites_button_text": "ਸੋਧੋ",
     "edit_topsites_button_label": "ਆਪਣੇ ਸਿਖਰਲੀਆਂ ਸਾਈਟਾਂ ਭਾਗ ਨੂੰ ਲੋੜ ਮੁਤਾਬਕ ਢਾਲੋ",
     "edit_topsites_showmore_button": "ਹੋਰ ਵੇਖਾਓ",
     "edit_topsites_showless_button": "ਘੱਟ ਵੇਖਾਓ",
     "edit_topsites_done_button": "ਮੁਕੰਮਲ",
     "edit_topsites_pin_button": "ਇਸ ਸਾਈਟ ਨੂੰ ਟੰਗੋ",
     "edit_topsites_edit_button": "ਇਹ ਸਾਈਟ ਨੂੰ ਸੋਧੋ",
-    "edit_topsites_dismiss_button": "ਇਸ ਸਾਈਟ ਰੱਦ ਕਰੋ"
+    "edit_topsites_dismiss_button": "ਇਸ ਸਾਈਟ ਰੱਦ ਕਰੋ",
+    "edit_topsites_add_button": "ਜੋੜੋ",
+    "topsites_form_add_button": "ਜੋੜੋ",
+    "topsites_form_save_button": "ਸੰਭਾਲੋ",
+    "topsites_form_cancel_button": "ਰੱਦ ਕਰੋ",
+    "manual_migration_cancel_button": "ਨਹੀਂ, ਧੰਨਵਾਦ",
+    "manual_migration_import_button": "ਹੁਣੇ ਇੰਪੋਰਟ ਕਰੋ"
   },
   "pl": {
     "newtab_page_title": "Nowa karta",
     "default_label_loading": "Wczytywanie…",
     "header_top_sites": "Popularne",
     "header_stories": "Popularne artykuły",
     "header_highlights": "Wyróżnione",
     "header_visit_again": "Odwiedź ponownie",
@@ -5970,16 +6138,17 @@
     "topsites_form_url_placeholder": "พิมพ์หรือวาง URL",
     "topsites_form_add_button": "เพิ่ม",
     "topsites_form_save_button": "บันทึก",
     "topsites_form_cancel_button": "ยกเลิก",
     "topsites_form_url_validation": "ต้องการ URL ที่ถูกต้อง",
     "pocket_read_more": "หัวข้อยอดนิยม:",
     "pocket_read_even_more": "ดูเรื่องราวเพิ่มเติม",
     "pocket_feedback_header": "ที่สุดของเว็บ จัดรายการโดยผู้คนกว่า 25 ล้านคน",
+    "highlights_empty_state": "เริ่มการท่องเว็บและเราจะแสดงบทความ, วิดีโอ และหน้าอื่น ๆ บางส่วนที่ยอดเยี่ยมที่คุณได้เยี่ยมชมหรือเพิ่มที่คั่นหน้าไว้เมื่อเร็ว ๆ นี้ที่นี่",
     "manual_migration_explanation2": "ลอง Firefox ด้วยที่คั่นหน้า, ประวัติ และรหัสผ่านจากเบราว์เซอร์อื่น",
     "manual_migration_cancel_button": "ไม่ ขอบคุณ",
     "manual_migration_import_button": "นำเข้าตอนนี้"
   },
   "tl": {
     "newtab_page_title": "Bagong Tab",
     "default_label_loading": "Pagkarga…",
     "header_top_sites": "Tuktok na mga Site",
@@ -6027,17 +6196,17 @@
     "edit_topsites_done_button": "Tapos",
     "edit_topsites_pin_button": "I-pin sa site na ito",
     "edit_topsites_edit_button": "I-edit ang site na ito",
     "edit_topsites_dismiss_button": "I-dismiss sa site na ito"
   },
   "tr": {
     "newtab_page_title": "Yeni Sekme",
     "default_label_loading": "Yükleniyor…",
-    "header_top_sites": "En Sık Kullanılan Siteler",
+    "header_top_sites": "Sık Kullanılan Siteler",
     "header_stories": "İlginç Yazılar",
     "header_highlights": "Öne Çıkanlar",
     "header_visit_again": "Yeniden Ziyaret Edin",
     "header_bookmarks": "Son Yer imleri",
     "header_recommended_by": "{provider} öneriyor",
     "header_bookmarks_placeholder": "Henüz hiç yer iminiz yok.",
     "header_stories_from": "kaynak:",
     "type_label_visited": "Ziyaret etmiştiniz",
@@ -6075,32 +6244,32 @@
     "time_label_minute": "{number} dk",
     "time_label_hour": "{number} sa",
     "time_label_day": "{number} g",
     "settings_pane_button_label": "Yeni Sekme sayfanızı özelleştirin",
     "settings_pane_header": "Yeni Sekme Tercihleri",
     "settings_pane_body2": "Bu sayfada görmek istediklerinizi seçin.",
     "settings_pane_search_header": "Arama",
     "settings_pane_search_body": "Yeni sekme üzerinden web’de arama yapın.",
-    "settings_pane_topsites_header": "Sık Kullandıklarınız",
+    "settings_pane_topsites_header": "Sık kullanılan siteler",
     "settings_pane_topsites_body": "En sık ziyaret ettiğiniz web sitelerine erişin.",
     "settings_pane_topsites_options_showmore": "İki satır göster",
     "settings_pane_bookmarks_header": "Son Yer İmleri",
     "settings_pane_bookmarks_body": "Yeni eklediğiniz yer imlerini bir araya topladık.",
     "settings_pane_visit_again_header": "Yeniden Ziyaret Edin",
     "settings_pane_visit_again_body": "Firefox, gezinti geçmişinizden hatırlamak veya yeniden ziyaret etmek isteyebileceğiniz sayfaları burada gösterecek.",
     "settings_pane_highlights_header": "Öne çıkanlar",
     "settings_pane_highlights_body2": "Son zamanlarda baktığınız veya yer imlerinize eklediğiniz ilginç şeyleri yeniden keşfedin.",
     "settings_pane_highlights_options_bookmarks": "Yer imleri",
     "settings_pane_highlights_options_visited": "Ziyaret ettiğim siteler",
-    "settings_pane_snippets_header": "Mesajlar",
+    "settings_pane_snippets_header": "Duyurular",
     "settings_pane_snippets_body": "Firefox, internet kültürü ve önemli gelişmeler hakkında Mozilla’dan gelen kısa güncelleme notlarını okuyun.",
     "settings_pane_done_button": "Tamam",
     "edit_topsites_button_text": "Düzenle",
-    "edit_topsites_button_label": "Sık Kullandıklarınız bölümünü özelleştirin",
+    "edit_topsites_button_label": "Sık Kullanılan Siteler bölümünü özelleştirin",
     "edit_topsites_showmore_button": "Daha fazla göster",
     "edit_topsites_showless_button": "Daha az göster",
     "edit_topsites_done_button": "Tamam",
     "edit_topsites_pin_button": "Bu siteyi sabitle",
     "edit_topsites_unpin_button": "Siteyi sabitlikten çıkar",
     "edit_topsites_edit_button": "Bu siteyi düzenle",
     "edit_topsites_dismiss_button": "Bu siteyi görmezden gel",
     "edit_topsites_add_button": "Ekle",
@@ -6536,15 +6705,15 @@
     "topsites_form_add_button": "新增",
     "topsites_form_save_button": "儲存",
     "topsites_form_cancel_button": "取消",
     "topsites_form_url_validation": "請輸入有效的網址",
     "pocket_read_more": "熱門主題:",
     "pocket_read_even_more": "檢視更多文章",
     "pocket_feedback_header": "由超過兩千五百萬人找出來的 Web 最佳內容。",
     "pocket_description": "透過現在也是 Mozilla 旗下一員的 Pocket 的幫助,發現您先前可能錯過的高品質內容。",
-    "highlights_empty_state": "開始上網,我們就會把您在網路上發現的好文章、影片、剛加入書籤的頁面顯示於此處。",
+    "highlights_empty_state": "開始上網,我們就會把您在網路上發現的好文章、影片、剛加入書籤的頁面顯示於此。",
     "topstories_empty_state": "所有文章都讀完啦!晚點再來,{provider} 將提供更多推薦故事。等不及了?選擇熱門主題,看看 Web 上各式精采資訊。",
-    "manual_migration_explanation2": "試試將其他瀏覽器的書籤、瀏覽記錄與密碼匯入到 Firefox。",
+    "manual_migration_explanation2": "試試將其他瀏覽器的書籤、瀏覽記錄與密碼匯入 Firefox。",
     "manual_migration_cancel_button": "不必了",
     "manual_migration_import_button": "立即匯入"
   }
 }
\ No newline at end of file
--- a/browser/extensions/activity-stream/install.rdf.in
+++ b/browser/extensions/activity-stream/install.rdf.in
@@ -3,17 +3,17 @@
 #filter substitution
 
 <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
   <Description about="urn:mozilla:install-manifest">
     <em:id>activity-stream@mozilla.org</em:id>
     <em:type>2</em:type>
     <em:bootstrap>true</em:bootstrap>
     <em:unpack>false</em:unpack>
-    <em:version>2017.09.16.0001-2fc82208</em:version>
+    <em:version>2017.09.19.0036-50fae6d7</em:version>
     <em:name>Activity Stream</em:name>
     <em:description>A rich visual history feed and a reimagined home page make it easier than ever to find exactly what you're looking for in Firefox.</em:description>
     <em:multiprocessCompatible>true</em:multiprocessCompatible>
 
     <em:targetApplication>
       <Description>
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
         <em:minVersion>@MOZ_APP_VERSION@</em:minVersion>
--- a/browser/extensions/activity-stream/lib/SectionsManager.jsm
+++ b/browser/extensions/activity-stream/lib/SectionsManager.jsm
@@ -30,16 +30,17 @@ const BUILT_IN_SECTIONS = {
       header: {id: options.provider_header || "pocket_feedback_header"},
       body: {id: options.provider_description || "pocket_feedback_body"},
       link: {href: options.info_link, id: "section_info_privacy_notice"}
     },
     emptyState: {
       message: {id: "topstories_empty_state", values: {provider: options.provider_name}},
       icon: "check"
     },
+    shouldSendImpressionStats: true,
     order: 0
   }),
   "feeds.section.highlights": options => ({
     id: "highlights",
     pref: {
       titleString: {id: "settings_pane_highlights_header"},
       descString: {id: "settings_pane_highlights_body2"}
     },
@@ -48,16 +49,17 @@ const BUILT_IN_SECTIONS = {
     icon: "highlights",
     title: {id: "header_highlights"},
     maxRows: 3,
     availableContextMenuOptions: ["CheckBookmark", "SaveToPocket", "Separator", "OpenInNewWindow", "OpenInPrivateWindow", "Separator", "BlockUrl", "DeleteUrl"],
     emptyState: {
       message: {id: "highlights_empty_state"},
       icon: "highlights"
     },
+    shouldSendImpressionStats: false,
     order: 1
   })
 };
 
 const SectionsManager = {
   ACTIONS_TO_PROXY: ["SYSTEM_TICK", "NEW_TAB_LOAD"],
   CONTEXT_MENU_PREFS: {"SaveToPocket": "extensions.pocket.enabled"},
   initialized: false,
--- a/browser/extensions/activity-stream/lib/TopSitesFeed.jsm
+++ b/browser/extensions/activity-stream/lib/TopSitesFeed.jsm
@@ -51,17 +51,20 @@ this.TopSitesFeed = class TopSitesFeed {
     }
   }
   async getScreenshot(url) {
     let screenshot = await Screenshots.getScreenshotForURL(url);
     const action = {type: at.SCREENSHOT_UPDATED, data: {url, screenshot}};
     this.store.dispatch(ac.BroadcastToContent(action));
   }
   async getLinksWithDefaults(action) {
-    let frecent = await NewTabUtils.activityStreamLinks.getTopSites();
+    // Get at least SHOWMORE amount so toggling between 1 and 2 rows has sites
+    const numItems = Math.max(this.store.getState().Prefs.values.topSitesCount,
+      TOP_SITES_SHOWMORE_LENGTH);
+    let frecent = await NewTabUtils.activityStreamLinks.getTopSites({numItems});
     const notBlockedDefaultSites = DEFAULT_TOP_SITES.filter(site => !NewTabUtils.blockedLinks.isBlocked({url: site.url}));
     const defaultUrls = notBlockedDefaultSites.map(site => site.url);
     let pinned = this._getPinnedWithData(frecent);
     pinned = pinned.map(site => site && Object.assign({}, site, {
       isDefault: defaultUrls.indexOf(site.url) !== -1,
       hostname: shortURL(site)
     }));
 
@@ -81,17 +84,17 @@ this.TopSitesFeed = class TopSitesFeed {
       pinned, frecent, notBlockedDefaultSites);
     const dedupedUnpinned = [...dedupedFrecent, ...dedupedDefaults];
 
     // Remove adult sites if we need to
     const checkedAdult = this.store.getState().Prefs.values.filterAdult ?
       filterAdult(dedupedUnpinned) : dedupedUnpinned;
 
     // Insert the original pinned sites into the deduped frecent and defaults
-    return insertPinned(checkedAdult, pinned).slice(0, TOP_SITES_SHOWMORE_LENGTH);
+    return insertPinned(checkedAdult, pinned).slice(0, numItems);
   }
   async refresh(target = null) {
     if (!this._tippyTopProvider.initialized) {
       await this._tippyTopProvider.init();
     }
 
     const links = await this.getLinksWithDefaults();
 
@@ -146,49 +149,76 @@ this.TopSitesFeed = class TopSitesFeed {
         if (!originalLink) {
           this._fetchIcon(pinnedLink);
         }
         return Object.assign(originalLink || {hostname}, pinnedLink);
       }
       return pinnedLink;
     });
   }
+
+  /**
+   * Inform others that top sites data has been updated due to pinned changes.
+   */
   _broadcastPinnedSitesUpdated() {
-    this.store.dispatch(ac.BroadcastToContent({
-      type: at.PINNED_SITES_UPDATED,
-      data: this._getPinnedWithData()
-    }));
+    // Refresh to update pinned sites with screenshots, trigger deduping, etc.
+    this.refresh();
   }
+
+  /**
+   * Pin a site at a specific position saving only the desired keys.
+   */
+  _pinSiteAt({label, url}, index) {
+    const toPin = {url};
+    if (label) {
+      toPin.label = label;
+    }
+    NewTabUtils.pinnedLinks.pin(toPin, index);
+  }
+
+  /**
+   * Handle a pin action of a site to a position.
+   */
   pin(action) {
     const {site, index} = action.data;
-    NewTabUtils.pinnedLinks.pin(site, index);
+    this._pinSiteAt(site, index);
     this._broadcastPinnedSitesUpdated();
   }
+
+  /**
+   * Handle an unpin action of a site.
+   */
   unpin(action) {
     const {site} = action.data;
     NewTabUtils.pinnedLinks.unpin(site);
     this._broadcastPinnedSitesUpdated();
   }
+
+  /**
+   * Insert a site to pin at a position shifting over any other pinned sites.
+   */
   _insertPin(site, index) {
-    // Insert a pin at the given index. If that slot is already taken, we need
-    // to insert it in the next slot. Rinse and repeat if that next slot is also
-    // taken.
+    // For existing sites, recursively push it and others to the next positions
     let pinned = NewTabUtils.pinnedLinks.links;
     if (pinned.length > index && pinned[index]) {
       this._insertPin(pinned[index], index + 1);
     }
-    NewTabUtils.pinnedLinks.pin(site, index);
+    this._pinSiteAt(site, index);
   }
+
+  /**
+   * Handle an add action of a site.
+   */
   add(action) {
     // Adding a top site pins it in the first slot, pushing over any link already
     // pinned in the slot.
     this._insertPin(action.data.site, 0);
-
     this._broadcastPinnedSitesUpdated();
   }
+
   async onAction(action) {
     switch (action.type) {
       case at.INIT:
         this.refresh();
         break;
       case at.NEW_TAB_LOAD:
         if (
           // When a new tab is opened, if the last time we refreshed the data
--- a/browser/extensions/activity-stream/test/unit/common/Reducers.test.js
+++ b/browser/extensions/activity-stream/test/unit/common/Reducers.test.js
@@ -1,9 +1,9 @@
-const {reducers, INITIAL_STATE, insertPinned, TOP_SITES_SHOWMORE_LENGTH} = require("common/Reducers.jsm");
+const {reducers, INITIAL_STATE, insertPinned} = require("common/Reducers.jsm");
 const {TopSites, App, Snippets, Prefs, Dialog, Sections} = reducers;
 
 const {actionTypes: at} = require("common/Actions.jsm");
 
 describe("Reducers", () => {
   describe("App", () => {
     it("should return the initial state", () => {
       const nextState = App(undefined, {type: "FOO"});
@@ -123,32 +123,16 @@ describe("Reducers", () => {
       const events = [at.BLOCK_URL, at.DELETE_HISTORY_URL];
       events.forEach(event => {
         const oldState = {rows: [{url: "foo.com"}, {url: "bar.com"}]};
         const action = {type: event, data: {url: "bar.com"}};
         const nextState = TopSites(oldState, action);
         assert.deepEqual(nextState.rows, [{url: "foo.com"}]);
       });
     });
-    it("should insert pinned links on PINNED_SITES_UPDATED", () => {
-      const oldState = {rows: [{url: "foo.com"}, {url: "bar.com"}]};
-      const action = {type: at.PINNED_SITES_UPDATED, data: [{url: "baz.com", title: "baz"}]};
-      const nextState = TopSites(oldState, action);
-      assert.deepEqual(nextState.rows, [{url: "baz.com", title: "baz", isPinned: true, pinIndex: 0}, {url: "foo.com"}, {url: "bar.com"}]);
-    });
-    it("should return at most TOP_SITES_SHOWMORE_LENGTH sites on PINNED_SITES_UPDATED", () => {
-      const oldState = {rows: [{url: "foo.com"}, {url: "bar.com"}]};
-      const data = new Array(20).fill(null).map((s, i) => ({
-        url: "foo.com",
-        pinIndex: i
-      }));
-      const action = {type: at.PINNED_SITES_UPDATED, data};
-      const nextState = TopSites(oldState, action);
-      assert.lengthOf(nextState.rows, TOP_SITES_SHOWMORE_LENGTH);
-    });
   });
   describe("Prefs", () => {
     function prevState(custom = {}) {
       return Object.assign({}, INITIAL_STATE.Prefs, custom);
     }
     it("should have the correct initial state", () => {
       const state = Prefs(undefined, {});
       assert.deepEqual(state, INITIAL_STATE.Prefs);
--- a/browser/extensions/activity-stream/test/unit/lib/TopSitesFeed.test.js
+++ b/browser/extensions/activity-stream/test/unit/lib/TopSitesFeed.test.js
@@ -1,14 +1,14 @@
 "use strict";
 const injector = require("inject!lib/TopSitesFeed.jsm");
 const {UPDATE_TIME} = require("lib/TopSitesFeed.jsm");
 const {FakePrefs, GlobalOverrider} = require("test/unit/utils");
 const action = {meta: {fromTarget: {}}};
-const {actionCreators: ac, actionTypes: at} = require("common/Actions.jsm");
+const {actionTypes: at} = require("common/Actions.jsm");
 const {insertPinned, TOP_SITES_SHOWMORE_LENGTH} = require("common/Reducers.jsm");
 
 const FAKE_FRECENCY = 200;
 const FAKE_LINKS = new Array(TOP_SITES_SHOWMORE_LENGTH).fill(null).map((v, i) => ({
   frecency: FAKE_FRECENCY,
   url: `http://www.site${i}.com`
 }));
 const FAKE_SCREENSHOT = "data123";
@@ -63,17 +63,17 @@ describe("Top Sites Feed", () => {
       "lib/TippyTopProvider.jsm": {TippyTopProvider: FakeTippyTopProvider},
       "lib/ShortURL.jsm": {shortURL: shortURLStub}
     }));
     feed = new TopSitesFeed();
     feed.store = {
       dispatch: sinon.spy(),
       getState() { return this.state; },
       state: {
-        Prefs: {values: {filterAdult: false}},
+        Prefs: {values: {filterAdult: false, topSitesCount: 6}},
         TopSites: {rows: Array(12).fill("site")}
       }
     };
     feed.dedupe.group = (...sites) => sites;
     links = FAKE_LINKS;
     clock = sinon.useFakeTimers();
   });
   afterEach(() => {
@@ -207,16 +207,23 @@ describe("Top Sites Feed", () => {
       assert.deepEqual(result, reference);
     });
     it("should not throw if NewTabUtils returns null", () => {
       links = null;
       assert.doesNotThrow(() => {
         feed.getLinksWithDefaults(action);
       });
     });
+    it("should get more if the user has asked for more", async () => {
+      feed.store.state.Prefs.values.topSitesCount = TOP_SITES_SHOWMORE_LENGTH + 1;
+
+      const result = await feed.getLinksWithDefaults();
+
+      assert.propertyVal(result, "length", feed.store.state.Prefs.values.topSitesCount);
+    });
     describe("deduping", () => {
       beforeEach(() => {
         ({TopSitesFeed, DEFAULT_TOP_SITES} = injector({
           "lib/ActivityStreamPrefs.jsm": {Prefs: FakePrefs},
           "common/Reducers.jsm": {insertPinned, TOP_SITES_SHOWMORE_LENGTH},
           "lib/Screenshots.jsm": {Screenshots: fakeScreenshot}
         }));
         sandbox.stub(global.Services.eTLD, "getPublicSuffix").returns("com");
@@ -385,83 +392,42 @@ describe("Top Sites Feed", () => {
       const pinAction = {
         type: at.TOP_SITES_PIN,
         data: {site: {url: "foo.com"}, index: 7}
       };
       feed.onAction(pinAction);
       assert.calledOnce(fakeNewTabUtils.pinnedLinks.pin);
       assert.calledWith(fakeNewTabUtils.pinnedLinks.pin, pinAction.data.site, pinAction.data.index);
     });
-    it("should get correct isDefault and index property", () => {
-      // When calling _getPinnedWithData the state in `pinnedLinks` and in the store should merge.
-      const site = {url: "foo.com"};
-      const siteWithIndex = {url: "foo.com", isDefault: true, index: 7};
-      fakeNewTabUtils.pinnedLinks.links = [siteWithIndex];
-      feed.store = {dispatch: sinon.spy(), getState() { return {TopSites: {rows: [site]}}; }};
-      const pinAction = {
-        type: at.TOP_SITES_PIN,
-        data: {}
-      };
-      feed.onAction(pinAction);
-      assert.calledOnce(feed.store.dispatch);
-      assert.calledWith(feed.store.dispatch, ac.BroadcastToContent({
-        type: at.PINNED_SITES_UPDATED,
-        data: [siteWithIndex]
-      }));
-    });
-    it("should get correct pinned links and data", () => {
-      // When calling _getPinnedWithData the state in `pinnedLinks` and in the store should merge.
-      // In this case `site1` is a pinned site and should be returned.
-      const site1 = {url: "foo.com", isDefault: true};
-      const site2 = {url: "bar.com", isDefault: false};
-      fakeNewTabUtils.pinnedLinks.links = [site1];
-      feed.store = {dispatch: sinon.spy(), getState() { return {TopSites: {rows: [site2]}}; }};
-      const pinAction = {
-        type: at.TOP_SITES_PIN,
-        data: {}
-      };
-      feed.onAction(pinAction);
-      assert.calledOnce(feed.store.dispatch);
-      assert.calledWith(feed.store.dispatch, ac.BroadcastToContent({
-        type: at.PINNED_SITES_UPDATED,
-        data: [Object.assign({}, site1, {hostname: "foo.com"})]
-      }));
-    });
     it("should compare against links if available, instead of getting from store", () => {
       const frecentSite = {url: "foo.com", faviconSize: 32, favicon: "favicon.png"};
       const pinnedSite1 = {url: "bar.com"};
       const pinnedSite2 = {url: "foo.com"};
       fakeNewTabUtils.pinnedLinks.links = [pinnedSite1, pinnedSite2];
       feed.store = {getState() { return {TopSites: {rows: sinon.spy()}}; }};
       let result = feed._getPinnedWithData([frecentSite]);
       assert.include(result[0], pinnedSite1);
       assert.include(result[1], Object.assign({}, frecentSite, pinnedSite2));
       assert.notCalled(feed.store.getState().TopSites.rows);
     });
-    it("should fetch an icon on TOP_SITES_PIN and TOP_SITES_ADD for new urls", () => {
-      feed.store.getState = () => ({TopSites: {rows: FAKE_LINKS}});
-      fakeNewTabUtils.pinnedLinks = {
-        links: new Array(6).fill(null),
-        pin(site, index) {
-          this.links[index] = site;
-        }
-      };
-      sinon.spy(feed, "_fetchIcon");
-
+    it("should trigger refresh on TOP_SITES_PIN", () => {
+      sinon.stub(feed, "refresh");
       const pinExistingAction = {type: at.TOP_SITES_PIN, data: {site: FAKE_LINKS[4], index: 4}};
+
+      feed.onAction(pinExistingAction);
+
+      assert.calledOnce(feed.refresh);
+    });
+    it("should trigger refresh on TOP_SITES_ADD", () => {
+      sinon.stub(feed, "refresh");
       const addAction = {type: at.TOP_SITES_ADD, data: {site: {url: "foo.com"}}};
-      const pinNewAction = {type: at.TOP_SITES_PIN, data: {site: {url: "bar.net"}, index: 0}};
-      feed.onAction(pinExistingAction);
+
       feed.onAction(addAction);
-      feed.onAction(pinNewAction);
 
-      assert.calledTwice(feed._fetchIcon);
-      assert.neverCalledWithMatch(feed._fetchIcon, {url: FAKE_LINKS[4].url});
-      assert.calledWithMatch(feed._fetchIcon, {url: "foo.com"});
-      assert.calledWithMatch(feed._fetchIcon, {url: "bar.net"});
+      assert.calledOnce(feed.refresh);
     });
     it("should call unpin with correct parameters on TOP_SITES_UNPIN", () => {
       fakeNewTabUtils.pinnedLinks.links = [null, null, {url: "foo.com"}, null, null, null, null, null, FAKE_LINKS[0]];
       const unpinAction = {
         type: at.TOP_SITES_UNPIN,
         data: {site: {url: "foo.com"}}
       };
       feed.onAction(unpinAction);