Bug 1363085 - Part 2. Add telemetry, context menu, react-intl to Activity Stream system add-on. r=ursula draft
authorEd Lee <edilee@mozilla.com>
Tue, 09 May 2017 16:09:43 -0700
changeset 576528 afc2d1f4a50c3b1253d8f19db9550edb88043532
parent 576379 d554c18932bdedbfc009d768563fbb89d1aa33b3
child 628222 6639e43a0cc7530c3124a4eab5539f2d0ad33b49
push id58390
push useredilee@gmail.com
push dateThu, 11 May 2017 19:55:21 +0000
reviewersursula
bugs1363085
milestone55.0a1
Bug 1363085 - Part 2. Add telemetry, context menu, react-intl to Activity Stream system add-on. r=ursula MozReview-Commit-ID: 9ouqxOFvTg4
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/content/activity-stream.css
browser/extensions/activity-stream/data/content/activity-stream.html
browser/extensions/activity-stream/data/content/assets/glyph-bookmark-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-bookmark-remove-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-delete-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-dismiss-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-more-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-newWindow-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-newWindow-private-16.svg
browser/extensions/activity-stream/data/locales.json
browser/extensions/activity-stream/jar.mn
browser/extensions/activity-stream/lib/ActivityStream.jsm
browser/extensions/activity-stream/lib/ActivityStreamMessageChannel.jsm
browser/extensions/activity-stream/lib/LocalizationFeed.jsm
browser/extensions/activity-stream/lib/PlacesFeed.jsm
browser/extensions/activity-stream/lib/SearchFeed.jsm
browser/extensions/activity-stream/lib/Store.jsm
browser/extensions/activity-stream/lib/TelemetryFeed.jsm
browser/extensions/activity-stream/lib/TelemetrySender.jsm
browser/extensions/activity-stream/lib/TopSitesFeed.jsm
browser/extensions/activity-stream/test/schemas/pings.js
browser/extensions/activity-stream/test/unit/common/Actions.test.js
browser/extensions/activity-stream/test/unit/common/Reducers.test.js
browser/extensions/activity-stream/test/unit/lib/ActivityStream.test.js
browser/extensions/activity-stream/test/unit/lib/LocalizationFeed.test.js
browser/extensions/activity-stream/test/unit/lib/PlacesFeed.test.js
browser/extensions/activity-stream/test/unit/lib/SearchFeed.test.js
browser/extensions/activity-stream/test/unit/lib/TelemetryFeed.test.js
browser/extensions/activity-stream/test/unit/lib/TelemetrySender.test.js
browser/extensions/activity-stream/test/unit/lib/TopSitesFeed.test.js
browser/extensions/activity-stream/test/unit/unit-entry.js
browser/extensions/activity-stream/test/unit/utils.js
browser/extensions/activity-stream/vendor/REACT_INTL_LICENSE
browser/extensions/activity-stream/vendor/react-intl.js
--- a/browser/extensions/activity-stream/common/Actions.jsm
+++ b/browser/extensions/activity-stream/common/Actions.jsm
@@ -1,26 +1,54 @@
 /* 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";
 
-const MAIN_MESSAGE_TYPE = "ActivityStream:Main";
-const CONTENT_MESSAGE_TYPE = "ActivityStream:Content";
+this.MAIN_MESSAGE_TYPE = "ActivityStream:Main";
+this.CONTENT_MESSAGE_TYPE = "ActivityStream:Content";
+this.UI_CODE = 1;
+this.BACKGROUND_PROCESS = 2;
+
+/**
+ * globalImportContext - Are we in UI code (i.e. react, a dom) or some kind of background process?
+ *                       Use this in action creators if you need different logic
+ *                       for ui/background processes.
+ */
+const globalImportContext = typeof Window === "undefined" ? BACKGROUND_PROCESS : UI_CODE;
+// Export for tests
+this.globalImportContext = globalImportContext;
 
 const actionTypes = [
+  "BLOCK_URL",
+  "BOOKMARK_URL",
+  "DELETE_BOOKMARK_BY_ID",
+  "DELETE_HISTORY_URL",
   "INIT",
-  "UNINIT",
+  "LOCALE_UPDATED",
   "NEW_TAB_INITIAL_STATE",
   "NEW_TAB_LOAD",
   "NEW_TAB_UNLOAD",
+  "NEW_TAB_VISIBLE",
+  "OPEN_NEW_WINDOW",
+  "OPEN_PRIVATE_WINDOW",
   "PERFORM_SEARCH",
+  "PLACES_BOOKMARK_ADDED",
+  "PLACES_BOOKMARK_CHANGED",
+  "PLACES_BOOKMARK_REMOVED",
+  "PLACES_HISTORY_CLEARED",
+  "PLACES_LINK_BLOCKED",
+  "PLACES_LINK_DELETED",
   "SCREENSHOT_UPDATED",
   "SEARCH_STATE_UPDATED",
-  "TOP_SITES_UPDATED"
+  "TELEMETRY_PERFORMANCE_EVENT",
+  "TELEMETRY_UNDESIRED_EVENT",
+  "TELEMETRY_USER_EVENT",
+  "TOP_SITES_UPDATED",
+  "UNINIT"
 // The line below creates an object like this:
 // {
 //   INIT: "INIT",
 //   UNINIT: "UNINIT"
 // }
 // It prevents accidentally adding a different key/value name.
 ].reduce((obj, type) => { obj[type] = type; return obj; }, {});
 
@@ -43,24 +71,24 @@ function _RouteMessage(action, options) 
   return Object.assign({}, action, {meta});
 }
 
 /**
  * SendToMain - Creates a message that will be sent to the Main process.
  *
  * @param  {object} action Any redux action (required)
  * @param  {object} options
- * @param  {string} options.fromTarget The id of the content port from which the action originated. (optional)
+ * @param  {string} fromTarget The id of the content port from which the action originated. (optional)
  * @return {object} An action with added .meta properties
  */
-function SendToMain(action, options = {}) {
+function SendToMain(action, fromTarget) {
   return _RouteMessage(action, {
     from: CONTENT_MESSAGE_TYPE,
     to: MAIN_MESSAGE_TYPE,
-    fromTarget: options.fromTarget
+    fromTarget
   });
 }
 
 /**
  * BroadcastToContent - Creates a message that will be sent to ALL content processes.
  *
  * @param  {object} action Any redux action (required)
  * @return {object} An action with added .meta properties
@@ -85,22 +113,69 @@ function SendToContent(action, target) {
   }
   return _RouteMessage(action, {
     from: MAIN_MESSAGE_TYPE,
     to: CONTENT_MESSAGE_TYPE,
     toTarget: target
   });
 }
 
+/**
+ * UserEvent - A telemetry ping indicating a user action. This should only
+ *                   be sent from the UI during a user session.
+ *
+ * @param  {object} data Fields to include in the ping (source, etc.)
+ * @return {object} An SendToMain action
+ */
+function UserEvent(data) {
+  return SendToMain({
+    type: actionTypes.TELEMETRY_USER_EVENT,
+    data
+  });
+}
+
+/**
+ * UndesiredEvent - A telemetry ping indicating an undesired state.
+ *
+ * @param  {object} data Fields to include in the ping (value, etc.)
+ * @param {int} importContext (For testing) Override the import context for testing.
+ * @return {object} An action. For UI code, a SendToMain action.
+ */
+function UndesiredEvent(data, importContext = globalImportContext) {
+  const action = {
+    type: actionTypes.TELEMETRY_UNDESIRED_EVENT,
+    data
+  };
+  return importContext === UI_CODE ? SendToMain(action) : action;
+}
+
+/**
+ * PerfEvent - A telemetry ping indicating a performance-related event.
+ *
+ * @param  {object} data Fields to include in the ping (value, etc.)
+ * @param {int} importContext (For testing) Override the import context for testing.
+ * @return {object} An action. For UI code, a SendToMain action.
+ */
+function PerfEvent(data, importContext = globalImportContext) {
+  const action = {
+    type: actionTypes.TELEMETRY_PERFORMANCE_EVENT,
+    data
+  };
+  return importContext === UI_CODE ? SendToMain(action) : action;
+}
+
 this.actionTypes = actionTypes;
 
 this.actionCreators = {
-  SendToMain,
+  BroadcastToContent,
+  UserEvent,
+  UndesiredEvent,
+  PerfEvent,
   SendToContent,
-  BroadcastToContent
+  SendToMain
 };
 
 // These are helpers to test for certain kinds of actions
 this.actionUtils = {
   isSendToMain(action) {
     if (!action.meta) {
       return false;
     }
@@ -119,18 +194,24 @@ this.actionUtils = {
     if (!action.meta) {
       return false;
     }
     if (action.meta.to === CONTENT_MESSAGE_TYPE && action.meta.toTarget) {
       return true;
     }
     return false;
   },
+  getPortIdOfSender(action) {
+    return (action.meta && action.meta.fromTarget) || null;
+  },
   _RouteMessage
 };
 
 this.EXPORTED_SYMBOLS = [
   "actionTypes",
   "actionCreators",
   "actionUtils",
+  "globalImportContext",
+  "UI_CODE",
+  "BACKGROUND_PROCESS",
   "MAIN_MESSAGE_TYPE",
   "CONTENT_MESSAGE_TYPE"
 ];
--- a/browser/extensions/activity-stream/common/Reducers.jsm
+++ b/browser/extensions/activity-stream/common/Reducers.jsm
@@ -1,48 +1,105 @@
 /* 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";
 
 const {actionTypes: at} = Components.utils.import("resource://activity-stream/common/Actions.jsm", {});
 
 const INITIAL_STATE = {
+  App: {
+    // Have we received real data from the app yet?
+    initialized: false,
+    // The locale of the browser
+    locale: "",
+    // Localized strings with defaults
+    strings: {},
+    // The version of the system-addon
+    version: null
+  },
   TopSites: {
-    init: false,
+    // Have we received real data from history yet?
+    initialized: false,
+    // The history (and possibly default) links
     rows: []
   },
   Search: {
+    // The search engine currently set by the browser
     currentEngine: {
       name: "",
       icon: ""
     },
+    // All possible search engines
     engines: []
   }
 };
 
-// TODO: Handle some real actions here, once we have a TopSites feed working
+function App(prevState = INITIAL_STATE.App, action) {
+  switch (action.type) {
+    case at.INIT:
+      return Object.assign({}, action.data || {}, {initialized: true});
+    case at.LOCALE_UPDATED: {
+      if (!action.data) {
+        return prevState;
+      }
+      let {locale, strings} = action.data;
+      return Object.assign({}, prevState, {
+        locale,
+        strings
+      });
+    }
+    default:
+      return prevState;
+  }
+}
+
 function TopSites(prevState = INITIAL_STATE.TopSites, action) {
   let hasMatch;
   let newRows;
   switch (action.type) {
     case at.TOP_SITES_UPDATED:
       if (!action.data) {
         return prevState;
       }
-      return Object.assign({}, prevState, {init: true, rows: action.data});
+      return Object.assign({}, prevState, {initialized: true, rows: action.data});
     case at.SCREENSHOT_UPDATED:
       newRows = prevState.rows.map(row => {
         if (row.url === action.data.url) {
           hasMatch = true;
           return Object.assign({}, row, {screenshot: action.data.screenshot});
         }
         return row;
       });
       return hasMatch ? Object.assign({}, prevState, {rows: newRows}) : prevState;
+    case at.PLACES_BOOKMARK_ADDED:
+      newRows = prevState.rows.map(site => {
+        if (site.url === action.data.url) {
+          const {bookmarkGuid, bookmarkTitle, lastModified} = action.data;
+          return Object.assign({}, site, {bookmarkGuid, bookmarkTitle, bookmarkDateCreated: lastModified});
+        }
+        return site;
+      });
+      return Object.assign({}, prevState, {rows: newRows});
+    case at.PLACES_BOOKMARK_REMOVED:
+      newRows = prevState.rows.map(site => {
+        if (site.url === action.data.url) {
+          const newSite = Object.assign({}, site);
+          delete newSite.bookmarkGuid;
+          delete newSite.bookmarkTitle;
+          delete newSite.bookmarkDateCreated;
+          return newSite;
+        }
+        return site;
+      });
+      return Object.assign({}, prevState, {rows: newRows});
+    case at.PLACES_LINK_DELETED:
+    case at.PLACES_LINK_BLOCKED:
+      newRows = prevState.rows.filter(val => val.url !== action.data.url);
+      return Object.assign({}, prevState, {rows: newRows});
     default:
       return prevState;
   }
 }
 
 function Search(prevState = INITIAL_STATE.Search, action) {
   switch (action.type) {
     case at.SEARCH_STATE_UPDATED: {
@@ -55,11 +112,11 @@ function Search(prevState = INITIAL_STAT
         engines
       });
     }
     default:
       return prevState;
   }
 }
 this.INITIAL_STATE = INITIAL_STATE;
-this.reducers = {TopSites, Search};
+this.reducers = {TopSites, App, Search};
 
 this.EXPORTED_SYMBOLS = ["reducers", "INITIAL_STATE"];
--- a/browser/extensions/activity-stream/data/content/activity-stream.bundle.js
+++ b/browser/extensions/activity-stream/data/content/activity-stream.bundle.js
@@ -58,45 +58,51 @@
 /******/
 /******/ 	// Object.prototype.hasOwnProperty.call
 /******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
 /******/
 /******/ 	// __webpack_public_path__
 /******/ 	__webpack_require__.p = "";
 /******/
 /******/ 	// Load entry module and return exports
-/******/ 	return __webpack_require__(__webpack_require__.s = 10);
+/******/ 	return __webpack_require__(__webpack_require__.s = 15);
 /******/ })
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, exports) {
 
 module.exports = React;
 
 /***/ }),
 /* 1 */
-/***/ (function(module, exports) {
-
-module.exports = ReactRedux;
-
-/***/ }),
-/* 2 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 /* 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/. */
 
 
-const MAIN_MESSAGE_TYPE = "ActivityStream:Main";
-const CONTENT_MESSAGE_TYPE = "ActivityStream:Content";
+var MAIN_MESSAGE_TYPE = "ActivityStream:Main";
+var CONTENT_MESSAGE_TYPE = "ActivityStream:Content";
+var UI_CODE = 1;
+var BACKGROUND_PROCESS = 2;
 
-const actionTypes = ["INIT", "UNINIT", "NEW_TAB_INITIAL_STATE", "NEW_TAB_LOAD", "NEW_TAB_UNLOAD", "PERFORM_SEARCH", "SCREENSHOT_UPDATED", "SEARCH_STATE_UPDATED", "TOP_SITES_UPDATED"
+/**
+ * globalImportContext - Are we in UI code (i.e. react, a dom) or some kind of background process?
+ *                       Use this in action creators if you need different logic
+ *                       for ui/background processes.
+ */
+
+const globalImportContext = typeof Window === "undefined" ? BACKGROUND_PROCESS : UI_CODE;
+// Export for tests
+
+
+const actionTypes = ["BLOCK_URL", "BOOKMARK_URL", "DELETE_BOOKMARK_BY_ID", "DELETE_HISTORY_URL", "INIT", "LOCALE_UPDATED", "NEW_TAB_INITIAL_STATE", "NEW_TAB_LOAD", "NEW_TAB_UNLOAD", "NEW_TAB_VISIBLE", "OPEN_NEW_WINDOW", "OPEN_PRIVATE_WINDOW", "PERFORM_SEARCH", "PLACES_BOOKMARK_ADDED", "PLACES_BOOKMARK_CHANGED", "PLACES_BOOKMARK_REMOVED", "PLACES_HISTORY_CLEARED", "PLACES_LINK_BLOCKED", "PLACES_LINK_DELETED", "SCREENSHOT_UPDATED", "SEARCH_STATE_UPDATED", "TELEMETRY_PERFORMANCE_EVENT", "TELEMETRY_UNDESIRED_EVENT", "TELEMETRY_USER_EVENT", "TOP_SITES_UPDATED", "UNINIT"
 // The line below creates an object like this:
 // {
 //   INIT: "INIT",
 //   UNINIT: "UNINIT"
 // }
 // It prevents accidentally adding a different key/value name.
 ].reduce((obj, type) => {
   obj[type] = type;return obj;
@@ -121,26 +127,24 @@ function _RouteMessage(action, options) 
   return Object.assign({}, action, { meta });
 }
 
 /**
  * SendToMain - Creates a message that will be sent to the Main process.
  *
  * @param  {object} action Any redux action (required)
  * @param  {object} options
- * @param  {string} options.fromTarget The id of the content port from which the action originated. (optional)
+ * @param  {string} fromTarget The id of the content port from which the action originated. (optional)
  * @return {object} An action with added .meta properties
  */
-function SendToMain(action) {
-  let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
-
+function SendToMain(action, fromTarget) {
   return _RouteMessage(action, {
     from: CONTENT_MESSAGE_TYPE,
     to: MAIN_MESSAGE_TYPE,
-    fromTarget: options.fromTarget
+    fromTarget
   });
 }
 
 /**
  * BroadcastToContent - Creates a message that will be sent to ALL content processes.
  *
  * @param  {object} action Any redux action (required)
  * @return {object} An action with added .meta properties
@@ -165,20 +169,71 @@ function SendToContent(action, target) {
   }
   return _RouteMessage(action, {
     from: MAIN_MESSAGE_TYPE,
     to: CONTENT_MESSAGE_TYPE,
     toTarget: target
   });
 }
 
+/**
+ * UserEvent - A telemetry ping indicating a user action. This should only
+ *                   be sent from the UI during a user session.
+ *
+ * @param  {object} data Fields to include in the ping (source, etc.)
+ * @return {object} An SendToMain action
+ */
+function UserEvent(data) {
+  return SendToMain({
+    type: actionTypes.TELEMETRY_USER_EVENT,
+    data
+  });
+}
+
+/**
+ * UndesiredEvent - A telemetry ping indicating an undesired state.
+ *
+ * @param  {object} data Fields to include in the ping (value, etc.)
+ * @param {int} importContext (For testing) Override the import context for testing.
+ * @return {object} An action. For UI code, a SendToMain action.
+ */
+function UndesiredEvent(data) {
+  let importContext = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : globalImportContext;
+
+  const action = {
+    type: actionTypes.TELEMETRY_UNDESIRED_EVENT,
+    data
+  };
+  return importContext === UI_CODE ? SendToMain(action) : action;
+}
+
+/**
+ * PerfEvent - A telemetry ping indicating a performance-related event.
+ *
+ * @param  {object} data Fields to include in the ping (value, etc.)
+ * @param {int} importContext (For testing) Override the import context for testing.
+ * @return {object} An action. For UI code, a SendToMain action.
+ */
+function PerfEvent(data) {
+  let importContext = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : globalImportContext;
+
+  const action = {
+    type: actionTypes.TELEMETRY_PERFORMANCE_EVENT,
+    data
+  };
+  return importContext === UI_CODE ? SendToMain(action) : action;
+}
+
 var actionCreators = {
-  SendToMain,
+  BroadcastToContent,
+  UserEvent,
+  UndesiredEvent,
+  PerfEvent,
   SendToContent,
-  BroadcastToContent
+  SendToMain
 };
 
 // These are helpers to test for certain kinds of actions
 
 var actionUtils = {
   isSendToMain(action) {
     if (!action.meta) {
       return false;
@@ -198,66 +253,207 @@ var actionUtils = {
     if (!action.meta) {
       return false;
     }
     if (action.meta.to === CONTENT_MESSAGE_TYPE && action.meta.toTarget) {
       return true;
     }
     return false;
   },
+  getPortIdOfSender(action) {
+    return action.meta && action.meta.fromTarget || null;
+  },
   _RouteMessage
 };
 module.exports = {
   actionTypes,
   actionCreators,
   actionUtils,
+  globalImportContext,
+  UI_CODE,
+  BACKGROUND_PROCESS,
   MAIN_MESSAGE_TYPE,
   CONTENT_MESSAGE_TYPE
 };
 
 /***/ }),
-/* 3 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
+/* 2 */
+/***/ (function(module, exports) {
 
-
-const React = __webpack_require__(0);
-const TopSites = __webpack_require__(8);
-const Search = __webpack_require__(7);
+module.exports = ReactRedux;
 
-const Base = () => React.createElement(
-  "div",
-  { className: "outer-wrapper" },
-  React.createElement(
-    "main",
-    null,
-    React.createElement(Search, null),
-    React.createElement(TopSites, null)
-  )
-);
+/***/ }),
+/* 3 */
+/***/ (function(module, exports) {
 
-module.exports = Base;
+module.exports = ReactIntl;
 
 /***/ }),
 /* 4 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
+const React = __webpack_require__(0);
+
+var _require = __webpack_require__(2);
+
+const connect = _require.connect;
+
+var _require2 = __webpack_require__(3);
+
+const addLocaleData = _require2.addLocaleData,
+      IntlProvider = _require2.IntlProvider;
+
+const TopSites = __webpack_require__(12);
+const Search = __webpack_require__(11);
+
+// Locales that should be displayed RTL
+const RTL_LIST = ["ar", "he", "fa", "ur"];
+
+// Add the locale data for pluralization and relative-time formatting for now,
+// this just uses english locale data. We can make this more sophisticated if
+// more features are needed.
+function addLocaleDataForReactIntl(_ref) {
+  let locale = _ref.locale;
+
+  addLocaleData([{ locale, parentLocale: "en" }]);
+  document.documentElement.lang = locale;
+  document.documentElement.dir = RTL_LIST.indexOf(locale.split("-")[0]) >= 0 ? "rtl" : "ltr";
+}
+
+class Base extends React.Component {
+  componentDidMount() {
+    // Also wait for the preloaded page to show, so the tab's title updates
+    addEventListener("visibilitychange", () => this.updateTitle(this.props.App), { once: true });
+  }
+  componentWillUpdate(_ref2) {
+    let App = _ref2.App;
+
+    if (App.locale !== this.props.App.locale) {
+      addLocaleDataForReactIntl(App);
+      this.updateTitle(App);
+    }
+  }
+
+  updateTitle(_ref3) {
+    let strings = _ref3.strings;
+
+    document.title = strings.newtab_page_title;
+  }
+
+  render() {
+    var _props$App = this.props.App;
+    let locale = _props$App.locale,
+        strings = _props$App.strings,
+        initialized = _props$App.initialized;
+
+    if (!initialized) {
+      return null;
+    }
+
+    return React.createElement(
+      IntlProvider,
+      { key: locale, locale: locale, messages: strings },
+      React.createElement(
+        "div",
+        { className: "outer-wrapper" },
+        React.createElement(
+          "main",
+          null,
+          React.createElement(Search, null),
+          React.createElement(TopSites, null)
+        )
+      )
+    );
+  }
+}
+
+module.exports = connect(state => ({ App: state.App }))(Base);
+
+/***/ }),
+/* 5 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+var _require = __webpack_require__(1);
+
+const at = _require.actionTypes;
+
+
+const VISIBLE = "visible";
+const VISIBILITY_CHANGE_EVENT = "visibilitychange";
+
+module.exports = class DetectUserSessionStart {
+  constructor() {
+    let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+
+    // Overrides for testing
+    this.sendAsyncMessage = options.sendAsyncMessage || window.sendAsyncMessage;
+    this.document = options.document || document;
+
+    this._onVisibilityChange = this._onVisibilityChange.bind(this);
+  }
+
+  /**
+   * sendEventOrAddListener - Notify immediately if the page is already visible,
+   *                    or else set up a listener for when visibility changes.
+   *                    This is needed for accurate session tracking for telemetry,
+   *                    because tabs are pre-loaded.
+   */
+  sendEventOrAddListener() {
+    if (this.document.visibilityState === VISIBLE) {
+      // If the document is already visible, to the user, send a notification
+      // immediately that a session has started.
+      this._sendEvent();
+    } else {
+      // If the document is not visible, listen for when it does become visible.
+      this.document.addEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
+    }
+  }
+
+  /**
+   * _sendEvent - Sends a message to the main process to indicate the current tab
+   *             is now visible to the user.
+   */
+  _sendEvent() {
+    this.sendAsyncMessage("ActivityStream:ContentToMain", { type: at.NEW_TAB_VISIBLE });
+  }
+
+  /**
+   * _onVisibilityChange - If the visibility has changed to visible, sends a notification
+   *                      and removes the event listener. This should only be called once per tab.
+   */
+  _onVisibilityChange() {
+    if (this.document.visibilityState === VISIBLE) {
+      this._sendEvent();
+      this.document.removeEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
+    }
+  }
+};
+
+/***/ }),
+/* 6 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
 /* globals sendAsyncMessage, addMessageListener */
 
-var _require = __webpack_require__(9);
+var _require = __webpack_require__(14);
 
 const createStore = _require.createStore,
       combineReducers = _require.combineReducers,
       applyMiddleware = _require.applyMiddleware;
 
-var _require2 = __webpack_require__(2);
+var _require2 = __webpack_require__(1);
 
 const au = _require2.actionUtils;
 
 
 const MERGE_STORE_ACTION = "NEW_TAB_INITIAL_STATE";
 const OUTGOING_MESSAGE_NAME = "ActivityStream:ContentToMain";
 const INCOMING_MESSAGE_NAME = "ActivityStream:MainToContent";
 
@@ -313,255 +509,621 @@ module.exports = function initStore(redu
   return store;
 };
 
 module.exports.MERGE_STORE_ACTION = MERGE_STORE_ACTION;
 module.exports.OUTGOING_MESSAGE_NAME = OUTGOING_MESSAGE_NAME;
 module.exports.INCOMING_MESSAGE_NAME = INCOMING_MESSAGE_NAME;
 
 /***/ }),
-/* 5 */
+/* 7 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 /* 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/. */
 
 
-var _require = __webpack_require__(2);
+var _require = __webpack_require__(1);
 
 const at = _require.actionTypes;
 
 
 const INITIAL_STATE = {
+  App: {
+    // Have we received real data from the app yet?
+    initialized: false,
+    // The locale of the browser
+    locale: "",
+    // Localized strings with defaults
+    strings: {},
+    // The version of the system-addon
+    version: null
+  },
   TopSites: {
-    init: false,
+    // Have we received real data from history yet?
+    initialized: false,
+    // The history (and possibly default) links
     rows: []
   },
   Search: {
+    // The search engine currently set by the browser
     currentEngine: {
       name: "",
       icon: ""
     },
+    // All possible search engines
     engines: []
   }
 };
 
-// TODO: Handle some real actions here, once we have a TopSites feed working
+function App() {
+  let prevState = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : INITIAL_STATE.App;
+  let action = arguments[1];
+
+  switch (action.type) {
+    case at.INIT:
+      return Object.assign({}, action.data || {}, { initialized: true });
+    case at.LOCALE_UPDATED:
+      {
+        if (!action.data) {
+          return prevState;
+        }
+        var _action$data = action.data;
+        let locale = _action$data.locale,
+            strings = _action$data.strings;
+
+        return Object.assign({}, prevState, {
+          locale,
+          strings
+        });
+      }
+    default:
+      return prevState;
+  }
+}
+
 function TopSites() {
   let prevState = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : INITIAL_STATE.TopSites;
   let action = arguments[1];
 
   let hasMatch;
   let newRows;
   switch (action.type) {
     case at.TOP_SITES_UPDATED:
       if (!action.data) {
         return prevState;
       }
-      return Object.assign({}, prevState, { init: true, rows: action.data });
+      return Object.assign({}, prevState, { initialized: true, rows: action.data });
     case at.SCREENSHOT_UPDATED:
       newRows = prevState.rows.map(row => {
         if (row.url === action.data.url) {
           hasMatch = true;
           return Object.assign({}, row, { screenshot: action.data.screenshot });
         }
         return row;
       });
       return hasMatch ? Object.assign({}, prevState, { rows: newRows }) : prevState;
+    case at.PLACES_BOOKMARK_ADDED:
+      newRows = prevState.rows.map(site => {
+        if (site.url === action.data.url) {
+          var _action$data2 = action.data;
+          const bookmarkGuid = _action$data2.bookmarkGuid,
+                bookmarkTitle = _action$data2.bookmarkTitle,
+                lastModified = _action$data2.lastModified;
+
+          return Object.assign({}, site, { bookmarkGuid, bookmarkTitle, bookmarkDateCreated: lastModified });
+        }
+        return site;
+      });
+      return Object.assign({}, prevState, { rows: newRows });
+    case at.PLACES_BOOKMARK_REMOVED:
+      newRows = prevState.rows.map(site => {
+        if (site.url === action.data.url) {
+          const newSite = Object.assign({}, site);
+          delete newSite.bookmarkGuid;
+          delete newSite.bookmarkTitle;
+          delete newSite.bookmarkDateCreated;
+          return newSite;
+        }
+        return site;
+      });
+      return Object.assign({}, prevState, { rows: newRows });
+    case at.PLACES_LINK_DELETED:
+    case at.PLACES_LINK_BLOCKED:
+      newRows = prevState.rows.filter(val => val.url !== action.data.url);
+      return Object.assign({}, prevState, { rows: newRows });
     default:
       return prevState;
   }
 }
 
 function Search() {
   let prevState = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : INITIAL_STATE.Search;
   let action = arguments[1];
 
   switch (action.type) {
     case at.SEARCH_STATE_UPDATED:
       {
         if (!action.data) {
           return prevState;
         }
-        var _action$data = action.data;
-        let currentEngine = _action$data.currentEngine,
-            engines = _action$data.engines;
+        var _action$data3 = action.data;
+        let currentEngine = _action$data3.currentEngine,
+            engines = _action$data3.engines;
 
         return Object.assign({}, prevState, {
           currentEngine,
           engines
         });
       }
     default:
       return prevState;
   }
 }
-var reducers = { TopSites, Search };
+var reducers = { TopSites, App, Search };
 module.exports = {
   reducers,
   INITIAL_STATE
 };
 
 /***/ }),
-/* 6 */
+/* 8 */
 /***/ (function(module, exports) {
 
 module.exports = ReactDOM;
 
 /***/ }),
-/* 7 */
+/* 9 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+const React = __webpack_require__(0);
+
+class ContextMenu extends React.Component {
+  constructor(props) {
+    super(props);
+    this.hideContext = this.hideContext.bind(this);
+  }
+  hideContext() {
+    this.props.onUpdate(false);
+  }
+  componentWillMount() {
+    this.hideContext();
+  }
+  componentDidUpdate(prevProps) {
+    if (this.props.visible && !prevProps.visible) {
+      setTimeout(() => {
+        window.addEventListener("click", this.hideContext);
+      }, 0);
+    }
+    if (!this.props.visible && prevProps.visible) {
+      window.removeEventListener("click", this.hideContext);
+    }
+  }
+  componentDidUnmount() {
+    window.removeEventListener("click", this.hideContext);
+  }
+  onKeyDown(event, option) {
+    switch (event.key) {
+      case "Tab":
+        // tab goes down in context menu, shift + tab goes up in context menu
+        // if we're on the last item, one more tab will close the context menu
+        // similarly, if we're on the first item, one more shift + tab will close it
+        if (event.shiftKey && option.first || !event.shiftKey && option.last) {
+          this.hideContext();
+        }
+        break;
+      case "Enter":
+        this.hideContext();
+        option.onClick();
+        break;
+    }
+  }
+  render() {
+    return React.createElement(
+      "span",
+      { hidden: !this.props.visible, className: "context-menu" },
+      React.createElement(
+        "ul",
+        { role: "menu", className: "context-menu-list" },
+        this.props.options.map((option, i) => {
+          if (option.type === "separator") {
+            return React.createElement("li", { key: i, className: "separator" });
+          }
+          return React.createElement(
+            "li",
+            { role: "menuitem", className: "context-menu-item", key: i },
+            React.createElement(
+              "a",
+              { tabIndex: "0",
+                onKeyDown: e => this.onKeyDown(e, option),
+                onClick: () => {
+                  this.hideContext();
+                  option.onClick();
+                } },
+              option.icon && React.createElement("span", { className: `icon icon-spacer icon-${option.icon}` }),
+              option.label
+            )
+          );
+        })
+      )
+    );
+  }
+}
+
+module.exports = ContextMenu;
+
+/***/ }),
+/* 10 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 const React = __webpack_require__(0);
 
-var _require = __webpack_require__(1);
+var _require = __webpack_require__(3);
+
+const injectIntl = _require.injectIntl;
 
-const connect = _require.connect;
+const ContextMenu = __webpack_require__(9);
 
-var _require2 = __webpack_require__(2);
+var _require2 = __webpack_require__(1);
 
 const actionTypes = _require2.actionTypes,
       actionCreators = _require2.actionCreators;
 
 
-const Search = React.createClass({
-  displayName: "Search",
+class LinkMenu extends React.Component {
+  getBookmarkStatus(site) {
+    return site.bookmarkGuid ? {
+      id: "menu_action_remove_bookmark",
+      icon: "bookmark-remove",
+      action: "DELETE_BOOKMARK_BY_ID",
+      data: site.bookmarkGuid
+    } : {
+      id: "menu_action_bookmark",
+      icon: "bookmark",
+      action: "BOOKMARK_URL",
+      data: site.url
+    };
+  }
+  getDefaultContextMenu(site) {
+    return [{
+      id: "menu_action_open_new_window",
+      icon: "new-window",
+      action: "OPEN_NEW_WINDOW",
+      data: { url: site.url }
+    }, {
+      id: "menu_action_open_private_window",
+      icon: "new-window-private",
+      action: "OPEN_PRIVATE_WINDOW",
+      data: { url: site.url }
+    }];
+  }
+  getOptions() {
+    var _props = this.props;
+    const dispatch = _props.dispatch,
+          site = _props.site;
+
+    // default top sites have a limited set of context menu options
+
+    let options = this.getDefaultContextMenu(site);
+
+    // all other top sites have all the following context menu options
+    if (!site.isDefault) {
+      options = [this.getBookmarkStatus(site), { type: "separator" }, ...options, { type: "separator" }, {
+        id: "menu_action_dismiss",
+        icon: "dismiss",
+        action: "BLOCK_URL",
+        data: site.url
+      }, {
+        id: "menu_action_delete",
+        icon: "delete",
+        action: "DELETE_HISTORY_URL",
+        data: site.url
+      }];
+    }
+    options.forEach(option => {
+      let action = option.action,
+          data = option.data,
+          id = option.id,
+          type = option.type;
+      // Convert message ids to localized labels and add onClick function
 
-  getInitialState() {
-    return { searchString: "" };
-  },
+      if (!type && id) {
+        option.label = this.props.intl.formatMessage(option);
+        option.onClick = () => dispatch(actionCreators.SendToMain({ type: actionTypes[action], data }));
+      }
+    });
+
+    // this is for a11y - we want to know which item is the first and which item
+    // is the last, so we can close the context menu accordingly
+    options[0].first = true;
+    options[options.length - 1].last = true;
+    return options;
+  }
+  render() {
+    return React.createElement(ContextMenu, {
+      visible: this.props.visible,
+      onUpdate: this.props.onUpdate,
+      options: this.getOptions() });
+  }
+}
+
+module.exports = injectIntl(LinkMenu);
+module.exports._unconnected = LinkMenu;
+
+/***/ }),
+/* 11 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+const React = __webpack_require__(0);
+
+var _require = __webpack_require__(2);
+
+const connect = _require.connect;
+
+var _require2 = __webpack_require__(3);
+
+const FormattedMessage = _require2.FormattedMessage,
+      injectIntl = _require2.injectIntl;
+
+var _require3 = __webpack_require__(1);
+
+const actionTypes = _require3.actionTypes,
+      actionCreators = _require3.actionCreators;
+
+
+class Search extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = { searchString: "" };
+    this.onClick = this.onClick.bind(this);
+    this.onChange = this.onChange.bind(this);
+  }
+
+  componentWillMount() {
+    // Trigger initialization of ContentSearch in case it hasn't happened yet
+    dispatchEvent(new CustomEvent("ContentSearchClient", { detail: {} }));
+  }
+
   performSearch(options) {
     let searchData = {
       engineName: options.engineName,
       searchString: options.searchString,
       searchPurpose: "newtab",
       healthReportKey: "newtab"
     };
     this.props.dispatch(actionCreators.SendToMain({ type: actionTypes.PERFORM_SEARCH, data: searchData }));
-  },
+  }
   onClick(event) {
     const currentEngine = this.props.Search.currentEngine;
 
     event.preventDefault();
     this.performSearch({ engineName: currentEngine.name, searchString: this.state.searchString });
-  },
+  }
   onChange(event) {
     this.setState({ searchString: event.target.value });
-  },
+  }
   render() {
     return React.createElement(
       "form",
       { className: "search-wrapper" },
-      React.createElement("span", { className: "search-label" }),
-      React.createElement("input", { value: this.state.searchString, type: "search",
+      React.createElement(
+        "label",
+        { htmlFor: "search-input", className: "search-label" },
+        React.createElement(
+          "span",
+          { className: "sr-only" },
+          React.createElement(FormattedMessage, { id: "search_web_placeholder" })
+        )
+      ),
+      React.createElement("input", {
+        id: "search-input",
+        maxLength: "256",
         onChange: this.onChange,
-        maxLength: "256", title: "Submit search",
-        placeholder: "Search the Web" }),
-      React.createElement("button", { onClick: this.onClick })
+        placeholder: this.props.intl.formatMessage({ id: "search_web_placeholder" }),
+        title: this.props.intl.formatMessage({ id: "search_web_placeholder" }),
+        type: "search",
+        value: this.state.searchString }),
+      React.createElement(
+        "button",
+        {
+          className: "search-button",
+          onClick: this.onClick,
+          title: this.props.intl.formatMessage({ id: "search_button" }) },
+        React.createElement(
+          "span",
+          { className: "sr-only" },
+          React.createElement(FormattedMessage, { id: "search_button" })
+        )
+      )
     );
   }
-});
+}
 
-module.exports = connect(state => ({ Search: state.Search }))(Search);
+module.exports = connect(state => ({ Search: state.Search }))(injectIntl(Search));
+module.exports._unconnected = Search;
 
 /***/ }),
-/* 8 */
+/* 12 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 const React = __webpack_require__(0);
 
-var _require = __webpack_require__(1);
+var _require = __webpack_require__(2);
 
 const connect = _require.connect;
 
+var _require2 = __webpack_require__(3);
 
-function displayURL(url) {
-  return new URL(url).hostname.replace(/^www./, "");
+const FormattedMessage = _require2.FormattedMessage;
+
+const shortURL = __webpack_require__(13);
+const LinkMenu = __webpack_require__(10);
+
+class TopSite extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = { showContextMenu: false, activeTile: null };
+  }
+  toggleContextMenu(event, index) {
+    this.setState({ showContextMenu: true, activeTile: index });
+  }
+  render() {
+    var _props = this.props;
+    const link = _props.link,
+          index = _props.index,
+          dispatch = _props.dispatch;
+
+    const isContextMenuOpen = this.state.showContextMenu && this.state.activeTile === index;
+    const title = shortURL(link);
+    const screenshotClassName = `screenshot${link.screenshot ? " active" : ""}`;
+    const topSiteOuterClassName = `top-site-outer${isContextMenuOpen ? " active" : ""}`;
+    const style = { backgroundImage: link.screenshot ? `url(${link.screenshot})` : "none" };
+    return React.createElement(
+      "li",
+      { className: topSiteOuterClassName, key: link.url },
+      React.createElement(
+        "a",
+        { href: link.url },
+        React.createElement(
+          "div",
+          { className: "tile", "aria-hidden": true },
+          React.createElement(
+            "span",
+            { className: "letter-fallback" },
+            title[0]
+          ),
+          React.createElement("div", { className: screenshotClassName, style: style })
+        ),
+        React.createElement(
+          "div",
+          { className: "title" },
+          title
+        )
+      ),
+      React.createElement(
+        "button",
+        { className: "context-menu-button",
+          onClick: e => {
+            e.preventDefault();
+            this.toggleContextMenu(e, index);
+          } },
+        React.createElement(
+          "span",
+          { className: "sr-only" },
+          `Open context menu for ${title}`
+        )
+      ),
+      React.createElement(LinkMenu, {
+        dispatch: dispatch,
+        visible: isContextMenuOpen,
+        onUpdate: val => this.setState({ showContextMenu: val }),
+        site: link,
+        index: index })
+    );
+  }
 }
 
 const TopSites = props => React.createElement(
   "section",
   null,
   React.createElement(
     "h3",
     { className: "section-title" },
-    "Top Sites"
+    React.createElement(FormattedMessage, { id: "header_top_sites" })
   ),
   React.createElement(
     "ul",
     { className: "top-sites-list" },
-    props.TopSites.rows.map(link => {
-      const title = displayURL(link.url);
-      const className = `screenshot${link.screenshot ? " active" : ""}`;
-      const style = { backgroundImage: link.screenshot ? `url(${link.screenshot})` : "none" };
-      return React.createElement(
-        "li",
-        { key: link.url },
-        React.createElement(
-          "a",
-          { href: link.url },
-          React.createElement(
-            "div",
-            { className: "tile" },
-            React.createElement(
-              "span",
-              { className: "letter-fallback", ariaHidden: true },
-              title[0]
-            ),
-            React.createElement("div", { className: className, style: style })
-          ),
-          React.createElement(
-            "div",
-            { className: "title" },
-            title
-          )
-        )
-      );
-    })
+    props.TopSites.rows.map((link, index) => React.createElement(TopSite, { dispatch: props.dispatch, key: link.url, link: link, index: index }))
   )
 );
 
 module.exports = connect(state => ({ TopSites: state.TopSites }))(TopSites);
+module.exports._unconnected = TopSites;
+module.exports.TopSite = TopSite;
 
 /***/ }),
-/* 9 */
+/* 13 */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+/**
+ * shortURL - Creates a short version of a link's url, used for display purposes
+ *            e.g. {url: http://www.foosite.com, eTLD: "com"}  =>  "foosite"
+ *
+ * @param  {obj} link A link object
+ *         {str} link.url (required)- The url of the link
+ *         {str} link.eTLD (required) - The tld of the link
+ *               e.g. for https://foo.org, the tld would be "org"
+ *               Note that this property is added in various queries for ActivityStream
+ *               via Services.eTLD.getPublicSuffix
+ *         {str} link.hostname (optional) - The hostname of the url
+ *               e.g. for http://www.hello.com/foo/bar, the hostname would be "www.hello.com"
+ * @return {str}   A short url
+ */
+module.exports = function shortURL(link) {
+  if (!link.url && !link.hostname) {
+    return "";
+  }
+  const eTLD = link.eTLD;
+
+  const hostname = (link.hostname || new URL(link.url).hostname).replace(/^www\./i, "");
+
+  // Remove the eTLD (e.g., com, net) and the preceding period from the hostname
+  const eTLDLength = (eTLD || "").length || hostname.match(/\.com$/) && 3;
+  const eTLDExtra = eTLDLength > 0 ? -(eTLDLength + 1) : Infinity;
+  return hostname.slice(0, eTLDExtra).toLowerCase();
+};
+
+/***/ }),
+/* 14 */
 /***/ (function(module, exports) {
 
 module.exports = Redux;
 
 /***/ }),
-/* 10 */
+/* 15 */
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-/* globals addMessageListener, removeMessageListener */
 const React = __webpack_require__(0);
-const ReactDOM = __webpack_require__(6);
-const Base = __webpack_require__(3);
+const ReactDOM = __webpack_require__(8);
+const Base = __webpack_require__(4);
 
-var _require = __webpack_require__(1);
+var _require = __webpack_require__(2);
 
 const Provider = _require.Provider;
 
-const initStore = __webpack_require__(4);
+const initStore = __webpack_require__(6);
 
-var _require2 = __webpack_require__(5);
+var _require2 = __webpack_require__(7);
 
 const reducers = _require2.reducers;
 
+const DetectUserSessionStart = __webpack_require__(5);
+
+new DetectUserSessionStart().sendEventOrAddListener();
 
 const store = initStore(reducers);
 
 ReactDOM.render(React.createElement(
   Provider,
   { store: store },
   React.createElement(Base, null)
 ), document.getElementById("root"));
--- a/browser/extensions/activity-stream/data/content/activity-stream.css
+++ b/browser/extensions/activity-stream/data/content/activity-stream.css
@@ -1,27 +1,53 @@
 html {
   box-sizing: border-box; }
 
 *,
 *::before,
 *::after {
   box-sizing: inherit; }
 
+*::-moz-focus-inner {
+  border: 0; }
+
 body {
   margin: 0; }
 
 button,
 input {
   font-family: inherit;
   font-size: inherit; }
 
 [hidden] {
   display: none !important; }
 
+.icon {
+  display: inline-block;
+  width: 16px;
+  height: 16px;
+  background-size: 16px;
+  background-position: center center;
+  background-repeat: no-repeat;
+  vertical-align: middle; }
+  .icon.icon-spacer {
+    margin-inline-end: 8px; }
+  .icon.icon-bookmark {
+    background-image: url("assets/glyph-bookmark-16.svg"); }
+  .icon.icon-bookmark-remove {
+    background-image: url("assets/glyph-bookmark-remove-16.svg"); }
+  .icon.icon-delete {
+    background-image: url("assets/glyph-delete-16.svg"); }
+  .icon.icon-dismiss {
+    background-image: url("assets/glyph-dismiss-16.svg"); }
+  .icon.icon-new-window {
+    background-image: url("assets/glyph-newWindow-16.svg"); }
+  .icon.icon-new-window-private {
+    background-image: url("assets/glyph-newWindow-private-16.svg"); }
+
 html,
 body,
 #root {
   height: 100%; }
 
 body {
   background: #F6F6F8;
   color: #383E49;
@@ -129,59 +155,91 @@ main {
       width: 640px; } }
   @media (min-width: 800px) {
     .top-sites-list {
       width: 768px; } }
   .top-sites-list li {
     display: inline-block;
     margin: 0 0 18px;
     margin-inline-end: 32px; }
-  .top-sites-list a {
-    display: block;
-    color: inherit; }
-  .top-sites-list .tile {
-    position: relative;
-    height: 96px;
-    width: 96px;
-    border-radius: 6px;
-    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
-    color: #A0A0A0;
-    font-weight: 200;
-    font-size: 32px;
-    text-transform: uppercase;
-    display: flex;
-    align-items: center;
-    justify-content: center; }
-    .top-sites-list .tile:hover {
+  .top-sites-list .top-site-outer {
+    position: relative; }
+    .top-sites-list .top-site-outer > a {
+      display: block;
+      color: inherit;
+      outline: none; }
+      .top-sites-list .top-site-outer > a.active .tile, .top-sites-list .top-site-outer > a:focus .tile {
+        box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1), 0 0 0 5px rgba(0, 0, 0, 0.1);
+        transition: box-shadow 150ms; }
+    .top-sites-list .top-site-outer .context-menu-button {
+      cursor: pointer;
+      position: absolute;
+      top: -13.5px;
+      offset-inline-end: -13.5px;
+      width: 27px;
+      height: 27px;
+      background-color: #FFF;
+      background-image: url("assets/glyph-more-16.svg");
+      background-position: 65%;
+      background-repeat: no-repeat;
+      background-clip: padding-box;
+      border: 1px solid rgba(0, 0, 0, 0.2);
+      border-radius: 100%;
+      box-shadow: 0 2px 0 rgba(0, 0, 0, 0.1);
+      transform: scale(0.25);
+      opacity: 0;
+      transition-property: transform, opacity;
+      transition-duration: 200ms;
+      z-index: 399; }
+      .top-sites-list .top-site-outer .context-menu-button:focus, .top-sites-list .top-site-outer .context-menu-button:active {
+        transform: scale(1);
+        opacity: 1; }
+    .top-sites-list .top-site-outer:hover .tile, .top-sites-list .top-site-outer:active .tile, .top-sites-list .top-site-outer:focus .tile, .top-sites-list .top-site-outer.active .tile {
       box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1), 0 0 0 5px rgba(0, 0, 0, 0.1);
       transition: box-shadow 150ms; }
-  .top-sites-list .screenshot {
-    position: absolute;
-    top: 0;
-    left: 0;
-    height: 100%;
-    width: 100%;
-    background-color: #FFF;
-    border-radius: 6px;
-    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
-    background-size: 250%;
-    background-position: top left;
-    transition: opacity 1s;
-    opacity: 0; }
-    .top-sites-list .screenshot.active {
+    .top-sites-list .top-site-outer:hover .context-menu-button, .top-sites-list .top-site-outer:active .context-menu-button, .top-sites-list .top-site-outer:focus .context-menu-button, .top-sites-list .top-site-outer.active .context-menu-button {
+      transform: scale(1);
       opacity: 1; }
-  .top-sites-list .title {
-    height: 30px;
-    line-height: 30px;
-    text-align: center;
-    white-space: nowrap;
-    font-size: 11px;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    width: 96px; }
+    .top-sites-list .top-site-outer .tile {
+      position: relative;
+      height: 96px;
+      width: 96px;
+      border-radius: 6px;
+      box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
+      color: #A0A0A0;
+      font-weight: 200;
+      font-size: 32px;
+      text-transform: uppercase;
+      display: flex;
+      align-items: center;
+      justify-content: center; }
+    .top-sites-list .top-site-outer .screenshot {
+      position: absolute;
+      top: 0;
+      left: 0;
+      height: 100%;
+      width: 100%;
+      background-color: #FFF;
+      border-radius: 6px;
+      box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
+      background-size: 250%;
+      background-position: top left;
+      transition: opacity 1s;
+      opacity: 0; }
+      .top-sites-list .top-site-outer .screenshot.active {
+        opacity: 1; }
+    .top-sites-list .top-site-outer .title {
+      height: 30px;
+      line-height: 30px;
+      text-align: center;
+      white-space: nowrap;
+      font-size: 11px;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      width: 96px; }
 
 .search-wrapper {
   cursor: default;
   display: flex;
   position: relative;
   margin: 0 0 48px;
   width: 100%;
   height: 36px; }
@@ -286,21 +344,19 @@ main {
     padding: 0 12px 0 35px;
     height: 100%;
     border-top-left-radius: 4px;
     border-bottom-left-radius: 4px;
     padding-inline-start: 35px; }
     .search-wrapper input:focus {
       border-color: #0996F8;
       box-shadow: 0 0 0 2px #0996F8;
-      transition: box-shadow 150ms;
       z-index: 1; }
     .search-wrapper input:focus + button {
       z-index: 1;
-      transition: box-shadow 150ms;
       box-shadow: 0 0 0 2px #0996F8;
       background-color: #0996F8;
       background-image: url("assets/glyph-forward-16-white.svg");
       color: #FFF; }
   .search-wrapper input:dir(rtl) {
     border-radius: 0 4px 4px 0; }
   .search-wrapper .search-label {
     background: url("assets/glyph-search-16.svg") no-repeat center center/20px;
@@ -314,21 +370,57 @@ main {
     justify-content: center;
     z-index: 2; }
   .search-wrapper button {
     border-radius: 0 3px 3px 0;
     margin-inline-start: -1px;
     border: 0;
     width: 36px;
     padding: 0;
-    transition: box-shadow 150ms;
     box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.1);
     background: #FFF url("assets/glyph-forward-16.svg") no-repeat center center;
     background-size: 16px 16px; }
     .search-wrapper button:hover {
       z-index: 1;
-      transition: box-shadow 150ms;
       box-shadow: 0 1px 0 0 rgba(0, 0, 1, 0.5);
       background-color: #0996F8;
       background-image: url("assets/glyph-forward-16-white.svg");
       color: #FFF; }
   .search-wrapper button:dir(rtl) {
     transform: scaleX(-1); }
+
+.context-menu {
+  display: block;
+  position: absolute;
+  font-size: 14px;
+  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3), 0 0 0 1px rgba(0, 0, 0, 0.2);
+  top: 6.75px;
+  offset-inline-start: 100%;
+  margin-inline-start: 5px;
+  z-index: 10000;
+  background: #FBFBFB;
+  border-radius: 5px; }
+  .context-menu > ul {
+    margin: 0;
+    padding: 5px 0;
+    list-style: none; }
+    .context-menu > ul > li {
+      margin: 0;
+      width: 100%; }
+      .context-menu > ul > li.separator {
+        margin: 5px 0;
+        border-bottom: 1px solid rgba(0, 0, 0, 0.2); }
+      .context-menu > ul > li > a {
+        outline: none;
+        cursor: pointer;
+        color: inherit;
+        white-space: nowrap;
+        padding: 3px 12px;
+        line-height: 16px;
+        display: flex;
+        align-items: center; }
+        .context-menu > ul > li > a:hover, .context-menu > ul > li > a:focus {
+          background: #2B99FF;
+          color: #FFF; }
+          .context-menu > ul > li > a:hover a, .context-menu > ul > li > a:focus a {
+            color: #383E49; }
+          .context-menu > ul > li > a:hover:hover, .context-menu > ul > li > a:hover:focus, .context-menu > ul > li > a:focus:hover, .context-menu > ul > li > a:focus:focus {
+            color: #FFF; }
--- a/browser/extensions/activity-stream/data/content/activity-stream.html
+++ b/browser/extensions/activity-stream/data/content/activity-stream.html
@@ -1,16 +1,17 @@
 <!doctype html>
 <html lang="en-us" dir="ltr">
   <head>
     <meta charset="utf-8">
-    <title>New Tab</title>
+    <title></title>
     <link rel="stylesheet" href="resource://activity-stream/data/content/activity-stream.css" />
   </head>
   <body class="activity-stream">
     <div id="root"></div>
     <script src="resource://activity-stream/vendor/react.js"></script>
     <script src="resource://activity-stream/vendor/react-dom.js"></script>
+    <script src="resource://activity-stream/vendor/react-intl.js"></script>
     <script src="resource://activity-stream/vendor/redux.js"></script>
     <script src="resource://activity-stream/vendor/react-redux.js"></script>
     <script src="resource://activity-stream/data/content/activity-stream.bundle.js"></script>
   </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/browser/extensions/activity-stream/data/content/assets/glyph-bookmark-16.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
+  <style>
+    path {
+      fill-rule: evenodd;
+      fill:#4d4d4d;
+    }
+  </style>
+  <path d="M198.992,18a0.955,0.955,0,0,0-.772.651l-1.984,4.122-4.332.72a0.851,0.851,0,0,0-.53,1.563l3.112,3.262-0.69,4.589c-0.1.69,0.173,1.094,0.658,1.094a1.4,1.4,0,0,0,.635-0.181l3.9-2.075,3.9,2.075a1.4,1.4,0,0,0,.634.181c0.485,0,.761-0.4.659-1.094L203.5,28.317l3.108-3.259a0.853,0.853,0,0,0-.53-1.566l-4.3-.719-2.016-4.122A0.953,0.953,0,0,0,198.992,18h0Z" transform="translate(-191 -18)"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/browser/extensions/activity-stream/data/content/assets/glyph-bookmark-remove-16.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
+  <style>
+    path {
+      fill-rule: evenodd;
+      fill:#4d4d4d;
+    }
+  </style>
+  <path d="M199.008,47.642l0.983,2.01,0.452,0.924,1.015,0.17,2.324,0.389-1.719,1.8-0.676.708,0.145,0.968,0.36,2.4-1.953-1.038-0.938-.5-0.939.5-1.951,1.037,0.36-2.4,0.146-.969-0.676-.709-1.718-1.8,2.349-.39,1.024-.17,0.45-.935,0.962-2M199,44a0.953,0.953,0,0,0-.772.651l-1.984,4.122-4.332.72a0.851,0.851,0,0,0-.53,1.563l3.112,3.262-0.69,4.589c-0.1.69,0.172,1.094,0.658,1.094a1.394,1.394,0,0,0,.634-0.181L199,57.744l3.9,2.075a1.4,1.4,0,0,0,.635.181c0.485,0,.761-0.4.658-1.094l-0.687-4.589,3.108-3.259a0.853,0.853,0,0,0-.53-1.566l-4.3-.72-2.016-4.122A0.953,0.953,0,0,0,199,44h0Z" transform="translate(-191 -44)"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/browser/extensions/activity-stream/data/content/assets/glyph-delete-16.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
+  <style>
+    path {
+      fill-rule: evenodd;
+      fill:#4d4d4d;
+    }
+  </style>
+  <path d="M426,22H416a1,1,0,0,1,0-2h3a1,1,0,0,1,1-1h2a1,1,0,0,1,1,1h3A1,1,0,0,1,426,22Zm-0.9,10a1.132,1.132,0,0,1-1.1,1H418a1.125,1.125,0,0,1-1.1-1L416,23h10Z" transform="translate(-413 -18)"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/browser/extensions/activity-stream/data/content/assets/glyph-dismiss-16.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
+  <style>
+    path {
+      fill-rule: evenodd;
+      fill:#4d4d4d;
+    }
+  </style>
+  <path d="M422.414,52l3.531-3.531a1,1,0,1,0-1.414-1.414L421,50.586l-3.531-3.531a1,1,0,1,0-1.414,1.414L419.586,52l-3.531,3.531a1,1,0,1,0,1.414,1.414L421,53.414l3.531,3.531a1,1,0,1,0,1.414-1.414Z" transform="translate(-413 -44)"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/browser/extensions/activity-stream/data/content/assets/glyph-more-16.svg
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
+  <style>
+    circle {
+      fill: #4d4d4d;
+    }
+  </style>
+  
+  <g>
+    <circle cx="2" cy="8" r="2"/>
+    <circle cx="7" cy="8" r="2"/>
+    <circle cx="12" cy="8" r="2"/>
+  </g>
+</svg>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/extensions/activity-stream/data/content/assets/glyph-newWindow-16.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
+  <style>
+    path {
+      fill-rule: evenodd;
+      fill:#4d4d4d;
+    }
+  </style>
+  <path d="M382,20.007A1,1,0,0,1,383,19h14a1,1,0,0,1,1,1.007V31.993A1,1,0,0,1,397,33H383a1,1,0,0,1-1-1.007V20.007ZM384,23h12v8H384V23Zm0.5-3a0.5,0.5,0,1,1-.5.5A0.5,0.5,0,0,1,384.5,20Zm2,0a0.5,0.5,0,1,1-.5.5A0.5,0.5,0,0,1,386.5,20Zm2,0a0.5,0.5,0,1,1-.5.5A0.5,0.5,0,0,1,388.5,20Z" transform="translate(-382 -18)"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/browser/extensions/activity-stream/data/content/assets/glyph-newWindow-private-16.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
+  <style>
+    path {
+      fill-rule: evenodd;
+      fill:#4d4d4d;
+    }
+  </style>
+  <path d="M356.994,24.619c-1.954.47-1.714,1.625-1.714,1.625s2.264,0.849,3.368.258a8.76,8.76,0,0,0,1.167-.668s-1.493-1.534-2.821-1.215m-5.987,0c-1.328-.32-2.821,1.215-2.821,1.215a8.76,8.76,0,0,0,1.167.668c1.1,0.591,3.368-.258,3.368-0.258s0.24-1.155-1.714-1.625M362,24.667c0,2.006-.647,5.334-3.755,5.333-1.143,0-3.1-1.993-4.245-1.993S350.9,30,349.755,30C346.647,30,346,26.673,346,24.667c0-2.094.984-2.813,3.628-2.638,2.739,0.181,3.066,1.087,4.372,1.087s1.8-.906,4.373-1.087c2.713-.191,3.627.544,3.627,2.638" transform="translate(-346 -18)"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/browser/extensions/activity-stream/data/locales.json
@@ -0,0 +1,2997 @@
+{
+  "ach": {
+    "newtab_page_title": "Dirica matidi manyen",
+    "default_label_loading": "Tye ka cano…",
+    "header_top_sites": "Kakube maloyo",
+    "header_highlights": "Wiye madito",
+    "type_label_visited": "Kilimo",
+    "type_label_bookmarked": "Kiketo alamabuk",
+    "type_label_synced": "Kiribo ki i nyonyo mukene",
+    "type_label_open": "Tye ayaba",
+    "type_label_topic": "Lok",
+    "menu_action_bookmark": "Alamabuk",
+    "menu_action_remove_bookmark": "Kwany alamabuk",
+    "menu_action_copy_address": "Lok kabedo",
+    "menu_action_email_link": "Kakube me email…",
+    "menu_action_open_new_window": "Yab i dirica manyen",
+    "menu_action_open_private_window": "Yab i dirica manyen me mung",
+    "menu_action_dismiss": "Kwer",
+    "menu_action_delete": "Kwany ki ii gin mukato",
+    "search_for_something_with": "Yeny pi {search_term} ki:",
+    "search_button": "Yeny",
+    "search_header": "Yeny me {search_engine_name}",
+    "search_web_placeholder": "Yeny kakube",
+    "search_settings": "Lok ter me yeny",
+    "welcome_title": "Wajoli i dirica matidi manyen",
+    "welcome_body": "Firefox bi tic ki kabedo man me nyuto alamabukke mamegi, coc akwana, vidio, ki potbukke ma ilimo cokcoki ma pi gi tego loyo, wek i dok ii gi ma yot.",
+    "welcome_label": "Tye ka kube ki wiye madito mamegi",
+    "time_label_less_than_minute": "<dakika1",
+    "time_label_minute": "dakika{number}",
+    "time_label_hour": "cawa{number}",
+    "time_label_day": "nino{number}",
+    "settings_pane_button_label": "Yub potbuk me dirica matidi mamegi manyen",
+    "settings_pane_header": "Ter me dirica matidi manyen",
+    "settings_pane_body": "Yer ngo ma i neno ka i yabo dirica matidi manyen.",
+    "settings_pane_search_header": "Yeny",
+    "settings_pane_search_body": "Yeny Kakube ki i dirica ni matidi manyen.",
+    "settings_pane_topsites_header": "Kakube ma gi loyo",
+    "settings_pane_topsites_body": "Nong kakube ma ilimo loyo.",
+    "settings_pane_topsites_options_showmore": "Nyut rek ariyo",
+    "settings_pane_highlights_header": "Wiye madito",
+    "settings_pane_highlights_body": "Nen angec i yeny mamegi mukato ki alamabukke ni ma i cweyo manyen.",
+    "settings_pane_done_button": "Otum",
+    "edit_topsites_button_text": "Yubi",
+    "edit_topsites_button_label": "Yub bute pi kakubi ni ma giloyo",
+    "edit_topsites_showmore_button": "Nyut mukene",
+    "edit_topsites_showless_button": "Nyut manok",
+    "edit_topsites_done_button": "Otum",
+    "edit_topsites_pin_button": "Mwon kakube man",
+    "edit_topsites_edit_button": "Yub kakube man",
+    "edit_topsites_dismiss_button": "Kwer kakube man"
+  },
+  "af": {},
+  "an": {},
+  "ar": {
+    "newtab_page_title": "لسان جديد",
+    "default_label_loading": "يُحمّل…",
+    "header_top_sites": "المواقع الأكثر زيارة",
+    "header_highlights": "أهم الأحداث",
+    "type_label_visited": "مُزارة",
+    "type_label_bookmarked": "معلّمة",
+    "type_label_synced": "مُزامنة من جهاز آخر",
+    "type_label_open": "مفتوحة",
+    "type_label_topic": "الموضوع",
+    "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": "احذف من التأريخ",
+    "search_for_something_with": "ابحث عن {search_term} مستخدما:",
+    "search_button": "ابحث",
+    "search_header": "بحث {search_engine_name}",
+    "search_web_placeholder": "ابحث في الوِب",
+    "search_settings": "غيّر إعدادات البحث",
+    "welcome_title": "مرحبًا في لسان جديد",
+    "welcome_body": "سيستخدم فيرفكس هذا المكان لعرض أكثر العلامات، و المقالات، و الفيديوهات والصفحات التي زرتها مؤخرا، ليمكنك العودة إليها بسهولة.",
+    "welcome_label": "تعرّف على أهم الأخبار",
+    "time_label_less_than_minute": "< دقيقة",
+    "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_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": "احذف هذا الموقع"
+  },
+  "as": {},
+  "ast": {
+    "newtab_page_title": "Llingüeta nueva",
+    "default_label_loading": "Cargando…",
+    "header_top_sites": "Sitios destacaos",
+    "type_label_open": "Abrir",
+    "type_label_topic": "Tema",
+    "welcome_title": "Bienllegáu/ada a la llingüeta nueva",
+    "welcome_body": "Firefox usará esti espaciu p'amosate los marcadores, artículos, vídeos y páxines más relevantes de los que visitares apocayá, asina pues volver a ello de mou cenciellu."
+  },
+  "az": {
+    "newtab_page_title": "Yeni Vərəq",
+    "default_label_loading": "Yüklənir…",
+    "header_top_sites": "Qabaqcıl Saytlar",
+    "header_highlights": "Seçilmişlər",
+    "type_label_visited": "Ziyarət edilib",
+    "type_label_bookmarked": "Əlfəcinlənib",
+    "type_label_synced": "Digər cihazdan sync edilib",
+    "type_label_open": "Açıq",
+    "type_label_topic": "Mövzu",
+    "menu_action_bookmark": "Əlfəcinlə",
+    "menu_action_remove_bookmark": "Əlfəcini sil",
+    "menu_action_copy_address": "Ünvanı köçür",
+    "menu_action_email_link": "Keçidi e-poçt ilə göndər…",
+    "menu_action_open_new_window": "Yeni Pəncərədə Aç",
+    "menu_action_open_private_window": "Yeni Məxfi Pəncərədə Aç",
+    "menu_action_dismiss": "Rədd et",
+    "menu_action_delete": "Tarixçədən Sil",
+    "search_for_something_with": "{search_term} üçün bununla axtar:",
+    "search_header": "{search_engine_name} Axtarış",
+    "search_web_placeholder": "İnternetdə Axtar",
+    "search_settings": "Axtarış Tənzimləmələrini Dəyiş",
+    "welcome_title": "Yeni vərəqə xoş gəldiniz",
+    "welcome_body": "Firefox bu səhifədə ən uyğun əlfəcin, məqalə, video və son ziyarət etdiyiniz səhifələri göstərərək onları rahat tapmağınıza kömək edəcək.",
+    "welcome_label": "Seçilmişləriniz təyin edilir",
+    "time_label_less_than_minute": "<1d",
+    "time_label_minute": "{number}d",
+    "time_label_hour": "{number}s",
+    "time_label_day": "{number}g"
+  },
+  "be": {
+    "newtab_page_title": "Новая картка",
+    "default_label_loading": "Загрузка…",
+    "header_top_sites": "Папулярныя сайты",
+    "header_highlights": "Выбранае",
+    "type_label_visited": "Наведанае",
+    "type_label_bookmarked": "У закладках",
+    "type_label_synced": "Сінхранізаванае з іншай прылады",
+    "type_label_open": "Адкрыта",
+    "type_label_topic": "Тэма",
+    "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": "Выдаліць з гісторыі",
+    "search_for_something_with": "Шукаць {search_term} у:",
+    "search_button": "Шукаць",
+    "search_header": "Шукаць у {search_engine_name}",
+    "search_web_placeholder": "Пошук у Інтэрнэце",
+    "search_settings": "Змяніць налады пошуку",
+    "welcome_title": "Калі ласка ў новую картку",
+    "welcome_body": "Firefox будзе выкарыстоўваць гэта месца, каб адлюстроўваць самыя актуальныя закладкі, артыкулы, відэа і старонкі, якія вы нядаўна наведалі, каб вы змаглі лёгка трапіць на іх зноў.",
+    "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_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": "Адхіліць гэты сайт"
+  },
+  "bg": {
+    "newtab_page_title": "Нов раздел",
+    "default_label_loading": "Зареждане…",
+    "header_top_sites": "Най-посещавани",
+    "header_highlights": "Акценти",
+    "type_label_visited": "Посетена",
+    "type_label_bookmarked": "Отметната",
+    "type_label_synced": "Синхронизирана от друго устройство",
+    "type_label_open": "Отваряне",
+    "type_label_topic": "Тема",
+    "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": "Премахване от историята",
+    "search_for_something_with": "Търсене на {search_term} с:",
+    "search_button": "Търсене",
+    "search_header": "Търсене с {search_engine_name}",
+    "search_web_placeholder": "Търсене в интернет",
+    "search_settings": "Настройки на търсене",
+    "welcome_title": "Добре дошли в нов раздел",
+    "welcome_body": "Firefox ще използва това място, за да ви покаже най-подходящите отметки, статии, видео и страници, които сте посетили наскоро, така че да се върнете към тях лесно.",
+    "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_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": "Изтриване"
+  },
+  "bn-BD": {
+    "newtab_page_title": "নতুন ট্যাব",
+    "default_label_loading": "লোড হচ্ছে…",
+    "header_top_sites": "শীর্ঘ সাইট",
+    "header_highlights": "হাইলাইট",
+    "type_label_visited": "পরিদর্শিত",
+    "type_label_bookmarked": "বুকমার্ক করা হয়েছে",
+    "type_label_synced": "অন্য ডিভাইস থেকে সিঙ্ক করা হয়েছে",
+    "type_label_open": "খোলা",
+    "type_label_topic": "টপিক",
+    "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": "ইতিহাস থেকে মুছে ফেলুন",
+    "search_for_something_with": "{search_term} এর জন্য খুঁজুন সাথে:",
+    "search_button": "অনুসন্ধান",
+    "search_header": "{search_engine_name} খুঁজুন",
+    "search_web_placeholder": "ওয়েবে সন্ধান করুন",
+    "search_settings": "সার্চ সেটিংস বদল করুন",
+    "welcome_title": "নতুন ট্যাবে আপনাকে স্বাগতম",
+    "welcome_body": "আপনার সাথে মিলে এমন বুর্কমার্ক, নিবন্ধ, ভিডিও এবং পাতা যেগুলো আপনি সম্প্রতি ভ্রমণ করেছে তা Firefox এই জায়গায় দেখাবে, যাতে আপনি সেগুলো দ্রুত খুঁজে পান।",
+    "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_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": "সাইটটি মুছে দিন"
+  },
+  "bn-IN": {},
+  "br": {},
+  "bs": {},
+  "ca": {
+    "newtab_page_title": "Pestanya nova",
+    "default_label_loading": "S'està carregant…",
+    "header_top_sites": "Llocs principals",
+    "header_highlights": "Destacats",
+    "type_label_visited": "Visitats",
+    "type_label_bookmarked": "A les adreces d'interès",
+    "type_label_synced": "Sincronitzat des d'un altre dispositiu",
+    "type_label_open": "Obert",
+    "type_label_topic": "Tema",
+    "menu_action_bookmark": "Afegeix a les adreces d'interès",
+    "menu_action_remove_bookmark": "Elimina l'adreça d'interès",
+    "menu_action_copy_address": "Copia l'adreça",
+    "menu_action_email_link": "Envia l'enllaç per correu…",
+    "menu_action_open_new_window": "Obre en una finestra nova",
+    "menu_action_open_private_window": "Obre en una finestra privada nova",
+    "menu_action_dismiss": "Descarta",
+    "menu_action_delete": "Elimina de l'historial",
+    "search_for_something_with": "Cerca {search_term} amb:",
+    "search_header": "Cerca de {search_engine_name}",
+    "search_web_placeholder": "Cerca al web",
+    "search_settings": "Canvia els paràmetres de cerca",
+    "welcome_title": "Us donem la benvinguda a la pestanya nova",
+    "welcome_body": "El Firefox utilitzarà aquest espai per mostrar-vos les adreces d'interès, els articles i els vídeos més rellevants, així com les pàgines que heu visitat recentment, per tal que hi pugueu accedir fàcilment.",
+    "welcome_label": "S'estan identificant els vostres llocs destacats",
+    "time_label_less_than_minute": "<1 m",
+    "time_label_minute": "{number} m",
+    "time_label_hour": "{number} h",
+    "time_label_day": "{number} d"
+  },
+  "cak": {},
+  "cs": {
+    "newtab_page_title": "Nový panel",
+    "default_label_loading": "Načítání…",
+    "header_top_sites": "Top stránky",
+    "header_highlights": "Vybrané",
+    "type_label_visited": "Navštívené",
+    "type_label_bookmarked": "V záložkách",
+    "type_label_synced": "Synchronizované z jiného zařízení",
+    "type_label_open": "Otevřené",
+    "type_label_topic": "Téma",
+    "menu_action_bookmark": "Přidat do záložek",
+    "menu_action_remove_bookmark": "Odebrat záložku",
+    "menu_action_copy_address": "Zkopírovat adresu",
+    "menu_action_email_link": "Poslat odkaz…",
+    "menu_action_open_new_window": "Otevřít v novém okně",
+    "menu_action_open_private_window": "Otevřít v novém anonymním okně",
+    "menu_action_dismiss": "Skrýt",
+    "menu_action_delete": "Smazat z historie",
+    "search_for_something_with": "Vyhledat {search_term} s:",
+    "search_button": "Hledat",
+    "search_header": "Vyhledat pomocí {search_engine_name}",
+    "search_web_placeholder": "Hledat na webu",
+    "search_settings": "Změnit nastavení vyhledávání",
+    "welcome_title": "Vítejte na stránce nového panelu",
+    "welcome_body": "Tady Firefox zobrazí nejrelevantnější záložky, články, videa a stránky, které jste nedávno navštívili. Návrat k nim je tak velmi jednoduchý.",
+    "welcome_label": "Rozpoznávání Vybraných stránek",
+    "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": "Přizpůsobení stránky nového panelu",
+    "settings_pane_header": "Předvolby nového panelu",
+    "settings_pane_body": "Vyberte si, co chcete vidět při otevření nového panelu.",
+    "settings_pane_search_header": "Vyhledávání",
+    "settings_pane_search_body": "Vyhledávání na webu rovnou ze stránky nového panelu.",
+    "settings_pane_topsites_header": "Top stránky",
+    "settings_pane_topsites_body": "Přístup ke stránkám, které nejčastěji navštěvujete.",
+    "settings_pane_topsites_options_showmore": "Zobrazit dva řádky",
+    "settings_pane_highlights_header": "Vybrané",
+    "settings_pane_highlights_body": "Pohled zpět na vaši nedávnou historii a nově vytvořené záložky.",
+    "settings_pane_done_button": "Hotovo",
+    "edit_topsites_button_text": "Upravit",
+    "edit_topsites_button_label": "Upravit oddíl Top stránek",
+    "edit_topsites_showmore_button": "Zobrazit více",
+    "edit_topsites_showless_button": "Zobrazit méně",
+    "edit_topsites_done_button": "Hotovo",
+    "edit_topsites_pin_button": "Připnout tuto stránku",
+    "edit_topsites_edit_button": "Upravit tuto stránku",
+    "edit_topsites_dismiss_button": "Skrýt tuto stránku"
+  },
+  "cy": {},
+  "da": {
+    "newtab_page_title": "Nyt faneblad",
+    "default_label_loading": "Indlæser…",
+    "header_top_sites": "Mest besøgte websider",
+    "header_highlights": "Højdepunkter",
+    "type_label_visited": "Besøgt",
+    "type_label_bookmarked": "Bogmærket",
+    "type_label_synced": "Synkroniseret fra en anden enhed",
+    "type_label_open": "Åben",
+    "type_label_topic": "Emne",
+    "menu_action_bookmark": "Bogmærk",
+    "menu_action_remove_bookmark": "Fjern bogmærke",
+    "menu_action_copy_address": "Kopier adresse",
+    "menu_action_email_link": "Send link…",
+    "menu_action_open_new_window": "Åbn i et nyt vindue",
+    "menu_action_open_private_window": "Åbn i et nyt privat vindue",
+    "menu_action_dismiss": "Afvis",
+    "menu_action_delete": "Slet fra historik",
+    "search_for_something_with": "Søg efter {search_term} med:",
+    "search_header": "{search_engine_name}-søgning",
+    "search_web_placeholder": "Søg på internettet",
+    "search_settings": "Skift søgeindstillinger",
+    "welcome_title": "Velkommen til nyt faneblad",
+    "welcome_body": "Firefox vil bruge denne plads til at vise dine mest relevante bogmærker, artikler, videoer og sider, du har besøgt for nylig - så kan du nemmere finde dem.",
+    "welcome_label": "Finder dine højdepunkter",
+    "time_label_less_than_minute": "<1 m.",
+    "time_label_minute": "{number} m.",
+    "time_label_hour": "{number} t.",
+    "time_label_day": "{number} d."
+  },
+  "de": {
+    "newtab_page_title": "Neuer Tab",
+    "default_label_loading": "Wird geladen…",
+    "header_top_sites": "Meistbesuchte Seiten",
+    "header_highlights": "Wichtige Seiten",
+    "type_label_visited": "Besucht",
+    "type_label_bookmarked": "Lesezeichen",
+    "type_label_synced": "Von anderem Gerät synchronisiert",
+    "type_label_open": "Geöffnet",
+    "type_label_topic": "Thema",
+    "menu_action_bookmark": "Lesezeichen",
+    "menu_action_remove_bookmark": "Lesezeichen entfernen",
+    "menu_action_copy_address": "Adresse kopieren",
+    "menu_action_email_link": "Link per E-Mail versenden…",
+    "menu_action_open_new_window": "In neuem Fenster öffnen",
+    "menu_action_open_private_window": "In neuem privaten Fenster öffnen",
+    "menu_action_dismiss": "Schließen",
+    "menu_action_delete": "Aus Chronik löschen",
+    "search_for_something_with": "Nach {search_term} suchen mit:",
+    "search_button": "Suchen",
+    "search_header": "{search_engine_name}-Suche",
+    "search_web_placeholder": "Das Web durchsuchen",
+    "search_settings": "Sucheinstellungen ändern",
+    "welcome_title": "Willkommen im neuen Tab",
+    "welcome_body": "Firefox nutzt diesen Bereich, um Ihnen Ihre wichtigsten Lesezeichen, Artikel, Videos und kürzlich besuchten Seiten anzuzeigen, damit Sie diese einfach wiederfinden.",
+    "welcome_label": "Auswahl Ihrer wichtigsten Seiten",
+    "time_label_less_than_minute": "< 1 min",
+    "time_label_minute": "{number} m",
+    "time_label_hour": "{number} h",
+    "time_label_day": "{number} t",
+    "settings_pane_button_label": "Neuer-Tab-Seite anpassen",
+    "settings_pane_header": "Einstellungen zum neuen Tab",
+    "settings_pane_body": "Entscheiden Sie, was in einem neuen Tab angezeigt wird.",
+    "settings_pane_search_header": "Suche",
+    "settings_pane_search_body": "Suchen Sie aus einem neuen Tab im Internet.",
+    "settings_pane_topsites_header": "Meistbesuchte Seiten",
+    "settings_pane_topsites_body": "Schneller Zugriff auf Ihre meistbesuchten Websites.",
+    "settings_pane_topsites_options_showmore": "Zwei Spalten anzeigen",
+    "settings_pane_highlights_header": "Meistbesuchte Seiten",
+    "settings_pane_highlights_body": "Übersicht über Ihre zuletzt besuchten Seiten und neuen Lesezeichen.",
+    "settings_pane_done_button": "Fertig",
+    "edit_topsites_button_text": "Bearbeiten",
+    "edit_topsites_button_label": "Anpassen der meistbesuchten Seiten",
+    "edit_topsites_showmore_button": "Mehr anzeigen",
+    "edit_topsites_showless_button": "Weniger anzeigen",
+    "edit_topsites_done_button": "Fertig",
+    "edit_topsites_pin_button": "Website immer in aktueller Position anzeigen",
+    "edit_topsites_edit_button": "Diese Website bearbeiten",
+    "edit_topsites_dismiss_button": "Website entfernen"
+  },
+  "dsb": {
+    "newtab_page_title": "Nowy rejtark",
+    "default_label_loading": "Zacytujo se…",
+    "header_top_sites": "Nejcesćej woglědane sedła",
+    "header_highlights": "Wjerški",
+    "type_label_visited": "Woglědany",
+    "type_label_bookmarked": "Ako cytańske znamje skłaźony",
+    "type_label_synced": "Z drugego rěda synchronizěrowany",
+    "type_label_open": "Wócynjony",
+    "type_label_topic": "Tema",
+    "menu_action_bookmark": "Ako cytańske znamje składowaś",
+    "menu_action_remove_bookmark": "Cytańske znamje wótpóraś",
+    "menu_action_copy_address": "Adresu kopěrowaś",
+    "menu_action_email_link": "Wótkaz e-mailowaś…",
+    "menu_action_open_new_window": "W nowem woknje wócyniś",
+    "menu_action_open_private_window": "W nowem priwatnem woknje wócyniś",
+    "menu_action_dismiss": "Zachyśiś",
+    "menu_action_delete": "Z historije lašowaś",
+    "search_for_something_with": "Za {search_term} pytaś z:",
+    "search_button": "Pytaś",
+    "search_header": "Z {search_engine_name} pytaś",
+    "search_web_placeholder": "Web pśepytaś",
+    "search_settings": "Pytańske nastajenja změniś",
+    "welcome_title": "Witajśo k nowemu rejtarkoju",
+    "welcome_body": "Firefox buźo toś ten rum wužywaś, aby waše nejwažnjejše cytańske znamjenja, nastawki, wideo a rowno woglědane boki pokazał, aby mógł se lažko k nim wrośiś.",
+    "welcome_label": "Wuběranje wašych nejwažnjejšych bokow",
+    "time_label_less_than_minute": "<1m",
+    "time_label_minute": "{number} m",
+    "time_label_hour": "{number} h",
+    "time_label_day": "",
+    "settings_pane_button_label": "Bok wašogo nowego rejtarka pśiměriś",
+    "settings_pane_header": "Nastajenja nowego rejtarka składowaś",
+    "settings_pane_body": "Wubjeŕśo, což cośo wiźeś, gaž nowy rejtark wócynjaśo.",
+    "settings_pane_search_header": "Pytaś",
+    "settings_pane_search_body": "Pśepytajśo web ze swójogo nowego rejtarka.",
+    "settings_pane_topsites_header": "Nejcesćej woglědane sedła",
+    "settings_pane_topsites_body": "Wócyńśo websedła, kótarež sćo se nejcesćej woglědał.",
+    "settings_pane_topsites_options_showmore": "Dwě smužki pokazaś",
+    "settings_pane_highlights_header": "Wjerški",
+    "settings_pane_highlights_body": "Woglědajśo se nejnowšu pśeglědowańsku historiju a nowo napórane cytańske znamjenja.",
+    "settings_pane_done_button": "Gótowo",
+    "edit_topsites_button_text": "Wobźěłaś",
+    "edit_topsites_button_label": "Pśiměrśo wótrězk swójich nejcesćej woglědanych sedłow",
+    "edit_topsites_showmore_button": "Wěcej pokazaś",
+    "edit_topsites_showless_button": "Mjenjej pokazaś",
+    "edit_topsites_done_button": "Gótowo",
+    "edit_topsites_pin_button": "Sedło pśipěś",
+    "edit_topsites_edit_button": "Toś to sedło wobźěłaś",
+    "edit_topsites_dismiss_button": "Sedło zachyśiś"
+  },
+  "el": {
+    "newtab_page_title": "Νέα καρτέλα",
+    "default_label_loading": "Φόρτωση…",
+    "header_top_sites": "Κορυφαίες ιστοσελίδες",
+    "header_highlights": "Κορυφαίες στιγμές",
+    "type_label_visited": "Από ιστορικό",
+    "type_label_bookmarked": "Από σελιδοδείκτες",
+    "type_label_synced": "Συγχρονισμένα από άλλη συσκευή",
+    "type_label_open": "Ανοικτό",
+    "type_label_topic": "Θέμα",
+    "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": "Διαγραφή από ιστορικό",
+    "search_for_something_with": "Αναζήτηση για {search_term} με:",
+    "search_button": "Αναζήτηση",
+    "search_header": "Αναζήτηση {search_engine_name}",
+    "search_web_placeholder": "Αναζήτηση στον ιστό",
+    "search_settings": "Αλλαγή ρυθμίσεων αναζήτησης",
+    "welcome_title": "Καλώς ορίσατε στη νέα καρτέλα",
+    "welcome_body": "Το Firefox θα χρησιμοποιήσει αυτό το χώρο για να εμφανίσει τους πιο σχετικούς σελιδοδείκτες, άρθρα, βίντεο και σελίδες που επισκεφθήκατε πρόσφατα, ώστε να έχετε εύκολη πρόσβαση.",
+    "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_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": "Απόρριψη ιστοσελίδας"
+  },
+  "en-GB": {
+    "newtab_page_title": "New Tab",
+    "default_label_loading": "Loading…",
+    "header_top_sites": "Top Sites",
+    "header_highlights": "Highlights",
+    "type_label_visited": "Visited",
+    "type_label_bookmarked": "Bookmarked",
+    "type_label_synced": "Synchronised from another device",
+    "type_label_open": "Open",
+    "type_label_topic": "Topic",
+    "menu_action_bookmark": "Bookmark",
+    "menu_action_remove_bookmark": "Remove Bookmark",
+    "menu_action_copy_address": "Copy Address",
+    "menu_action_email_link": "Email Link…",
+    "menu_action_open_new_window": "Open in a New Window",
+    "menu_action_open_private_window": "Open in a New Private Window",
+    "menu_action_dismiss": "Dismiss",
+    "menu_action_delete": "Delete from History",
+    "search_for_something_with": "Search for {search_term} with:",
+    "search_button": "Search",
+    "search_header": "{search_engine_name} Search",
+    "search_web_placeholder": "Search the Web",
+    "search_settings": "Change Search Settings",
+    "welcome_title": "Welcome to new tab",
+    "welcome_body": "Firefox will use this space to show your most relevant bookmarks, articles, videos, and pages you’ve recently visited, so you can get back to them easily.",
+    "welcome_label": "Identifying your Highlights",
+    "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": "Customise your New Tab page",
+    "settings_pane_header": "New Tab Preferences",
+    "settings_pane_body": "Choose what you see when you open a new tab.",
+    "settings_pane_search_header": "Search",
+    "settings_pane_search_body": "Search the Web from your new tab.",
+    "settings_pane_topsites_header": "Top Sites",
+    "settings_pane_topsites_body": "Access the web sites you visit most.",
+    "settings_pane_topsites_options_showmore": "Show two rows",
+    "settings_pane_highlights_header": "Highlights",
+    "settings_pane_highlights_body": "Look back at your recent browsing history and newly created bookmarks.",
+    "settings_pane_done_button": "Done",
+    "edit_topsites_button_text": "Edit",
+    "edit_topsites_button_label": "Customise your Top Sites section",
+    "edit_topsites_showmore_button": "Show more",
+    "edit_topsites_showless_button": "Show less",
+    "edit_topsites_done_button": "Done",
+    "edit_topsites_pin_button": "Pin this site",
+    "edit_topsites_edit_button": "Edit this site",
+    "edit_topsites_dismiss_button": "Dismiss this site"
+  },
+  "en-US": {
+    "newtab_page_title": "New Tab",
+    "default_label_loading": "Loading…",
+    "header_top_sites": "Top Sites",
+    "header_highlights": "Highlights",
+    "header_stories": "Top Stories",
+    "header_stories_from": "from",
+    "type_label_visited": "Visited",
+    "type_label_bookmarked": "Bookmarked",
+    "type_label_synced": "Synced from another device",
+    "type_label_recommended": "Trending",
+    "type_label_open": "Open",
+    "type_label_topic": "Topic",
+    "menu_action_bookmark": "Bookmark",
+    "menu_action_remove_bookmark": "Remove Bookmark",
+    "menu_action_copy_address": "Copy Address",
+    "menu_action_email_link": "Email Link…",
+    "menu_action_open_new_window": "Open in a New Window",
+    "menu_action_open_private_window": "Open in a New Private Window",
+    "menu_action_dismiss": "Dismiss",
+    "menu_action_delete": "Delete from History",
+    "menu_action_save_to_pocket": "Save to Pocket",
+    "search_for_something_with": "Search for {search_term} with:",
+    "search_button": "Search",
+    "search_header": "{search_engine_name} Search",
+    "search_web_placeholder": "Search the Web",
+    "search_settings": "Change Search Settings",
+    "welcome_title": "Welcome to new tab",
+    "welcome_body": "Firefox will use this space to show your most relevant bookmarks, articles, videos, and pages you’ve recently visited, so you can get back to them easily.",
+    "welcome_label": "Identifying your Highlights",
+    "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": "Customize your New Tab page",
+    "settings_pane_header": "New Tab Preferences",
+    "settings_pane_body": "Choose what you see when you open a new tab.",
+    "settings_pane_search_header": "Search",
+    "settings_pane_search_body": "Search the Web from your new tab.",
+    "settings_pane_topsites_header": "Top Sites",
+    "settings_pane_topsites_body": "Access the websites you visit most.",
+    "settings_pane_topsites_options_showmore": "Show two rows",
+    "settings_pane_highlights_header": "Highlights",
+    "settings_pane_highlights_body": "Look back at your recent browsing history and newly created bookmarks.",
+    "settings_pane_pocketstories_header": "Top Stories",
+    "settings_pane_pocketstories_body": "Pocket, a part of the Mozilla family, will help connect you to high-quality content that you may not have found otherwise.",
+    "settings_pane_done_button": "Done",
+    "edit_topsites_button_text": "Edit",
+    "edit_topsites_button_label": "Customize your Top Sites section",
+    "edit_topsites_showmore_button": "Show more",
+    "edit_topsites_showless_button": "Show less",
+    "edit_topsites_done_button": "Done",
+    "edit_topsites_pin_button": "Pin this site",
+    "edit_topsites_unpin_button": "Unpin this site",
+    "edit_topsites_edit_button": "Edit this site",
+    "edit_topsites_dismiss_button": "Dismiss this site",
+    "pocket_read_more": "Popular Topics:",
+    "pocket_read_even_more": "View More Stories",
+    "pocket_feedback_header": "The best of the web, curated by over 25 million people.",
+    "pocket_feedback_body": "Pocket, a part of the Mozilla family, will help connect you to high-quality content that you may not have found otherwise.",
+    "pocket_send_feedback": "Send Feedback"
+  },
+  "en-ZA": {},
+  "eo": {
+    "newtab_page_title": "Nova legosigno",
+    "default_label_loading": "Ŝargado…",
+    "header_top_sites": "Plej vizititaj",
+    "header_highlights": "Elstaraĵoj",
+    "type_label_visited": "Vizititaj",
+    "type_label_bookmarked": "Kun legosigno",
+    "type_label_synced": "Spegulitaj el alia aparato",
+    "type_label_open": "Malfermita",
+    "type_label_topic": "Temo",
+    "menu_action_bookmark": "Aldoni legosignon",
+    "menu_action_remove_bookmark": "Forigi legosignon",
+    "menu_action_copy_address": "Kopii adreson",
+    "menu_action_email_link": "Sendi ligilon retpoŝte…",
+    "menu_action_open_new_window": "Malfermi en nova fenestro",
+    "menu_action_open_private_window": "Malfermi en nova privata fenestro",
+    "menu_action_dismiss": "Ignori",
+    "menu_action_delete": "Forigi el historio",
+    "search_for_something_with": "Serĉi {search_term} per:",
+    "search_header": "Serĉo de {search_engine_name}",
+    "search_web_placeholder": "Serĉi la Teksaĵon",
+    "search_settings": "Modifi serĉajn agordojn",
+    "welcome_title": "Bonvenon al nova langeto",
+    "welcome_body": "Firefox uzos tiun ĉi spacon por montri al vi viaj plej gravajn legosignojn, artikolojn, filmetojn kaj paĝojn, kiujn vi vizitis antaŭ nelonge, tiel ke vi povos reiri al ili facile.",
+    "welcome_label": "Elstaraĵoj identigataj",
+    "time_label_less_than_minute": "<1m",
+    "time_label_minute": "{number}m",
+    "time_label_hour": "{number}h",
+    "time_label_day": "{number}t"
+  },
+  "es-AR": {
+    "newtab_page_title": "Nueva pestaña",
+    "default_label_loading": "Cargando…",
+    "header_top_sites": "Más visitados",
+    "header_highlights": "Destacados",
+    "type_label_visited": "Visitados",
+    "type_label_bookmarked": "Marcados",
+    "type_label_synced": "Sincronizados de otro dispositivo",
+    "type_label_open": "Abrir",
+    "type_label_topic": "Tópico",
+    "menu_action_bookmark": "Marcador",
+    "menu_action_remove_bookmark": "Eliminar marcador",
+    "menu_action_copy_address": "Copiar dirección",
+    "menu_action_email_link": "Enlace por correo electrónico…",
+    "menu_action_open_new_window": "Abrir en nueva ventana",
+    "menu_action_open_private_window": "Abrir en nueva ventana privada",
+    "menu_action_dismiss": "Descartar",
+    "menu_action_delete": "Borrar del historial",
+    "search_for_something_with": "Buscar {search_term} con:",
+    "search_button": "Buscar",
+    "search_header": "Buscar con {search_engine_name}",
+    "search_web_placeholder": "Buscar en la web",
+    "search_settings": "Cambiar opciones de búsqueda",
+    "welcome_title": "Bienvenido a una nueva pestaña",
+    "welcome_body": "Firefox usará este espacio para mostrar sus marcadores, artículos, videos y páginas más relevantes que se hayan visitado para poder volver más fácilmente.",
+    "welcome_label": "Identificar los destacados",
+    "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": "Personalizar la página nueva pestaña",
+    "settings_pane_header": "Preferencia de nueva pestaña",
+    "settings_pane_body": "Elegir que se verá al abrir una nueva pestaña.",
+    "settings_pane_search_header": "Buscar",
+    "settings_pane_search_body": "Buscar en la Web desde nueva pestaña.",
+    "settings_pane_topsites_header": "Más visitados",
+    "settings_pane_topsites_body": "Acceder a los sitios web más visitados.",
+    "settings_pane_topsites_options_showmore": "Mostrar dos filas",
+    "settings_pane_highlights_header": "Destacados",
+    "settings_pane_highlights_body": "Mirar hacia atrás el historial de navegación reciente y los marcadores recién creados.",
+    "settings_pane_done_button": "Listo",
+    "edit_topsites_button_text": "Editar",
+    "edit_topsites_button_label": "Personalizar la sección de sitios más visitados",
+    "edit_topsites_showmore_button": "Mostrar más",
+    "edit_topsites_showless_button": "Mostrar menos",
+    "edit_topsites_done_button": "Listo",
+    "edit_topsites_pin_button": "Pegar este sitio",
+    "edit_topsites_edit_button": "Editar este sitio",
+    "edit_topsites_dismiss_button": "Descartar este sitio"
+  },
+  "es-CL": {
+    "newtab_page_title": "Nueva pestaña",
+    "default_label_loading": "Cargando…",
+    "header_top_sites": "Sitios frecuentes",
+    "header_highlights": "Destacados",
+    "type_label_visited": "Visitado",
+    "type_label_bookmarked": "Marcado",
+    "type_label_synced": "Sacado de otro dispositivo",
+    "type_label_open": "Abrir",
+    "type_label_topic": "Tema",
+    "menu_action_bookmark": "Marcador",
+    "menu_action_remove_bookmark": "Remover marcador",
+    "menu_action_copy_address": "Copiar dirección",
+    "menu_action_email_link": "Enviar enlace por correo",
+    "menu_action_open_new_window": "Abrir en una nueva ventana",
+    "menu_action_open_private_window": "Abrir en una nueva ventana privada",
+    "menu_action_dismiss": "Descartar",
+    "menu_action_delete": "Eliminar del historial",
+    "search_for_something_with": "Buscar {search_term} con:",
+    "search_button": "Buscar",
+    "search_header": "Búsqueda de {search_engine_name}",
+    "search_web_placeholder": "Buscar en la Web",
+    "search_settings": "Cambiar ajustes de búsqueda",
+    "welcome_title": "Bienvenido a la nueva pestaña",
+    "welcome_body": "Firefox usará este espacio para mostrarte los marcadores, artículos, videos y páginas visitadas recientemente más relevantes, para que puedas regresar a ellos de una.",
+    "welcome_label": "Identificando tus destacados",
+    "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": "Personaliza tu página de Nueva pestaña",
+    "settings_pane_header": "Preferencias de Nueva pestaña",
+    "settings_pane_body": "Elige que ver cuando abras una nueva pestaña.",
+    "settings_pane_search_header": "Buscar",
+    "settings_pane_search_body": "Busca en la Web desde tu nueva pestaña.",
+    "settings_pane_topsites_header": "Sitios frecuentes",
+    "settings_pane_topsites_body": "Accede a los sitios que más visitas.",
+    "settings_pane_topsites_options_showmore": "Mostrar dos filas",
+    "settings_pane_highlights_header": "Destacados",
+    "settings_pane_highlights_body": "Dale un vistazo a tu historial de navegación y marcadores recientes.",
+    "settings_pane_done_button": "Hecho",
+    "edit_topsites_button_text": "Editar",
+    "edit_topsites_button_label": "Personaliza tu sección de sitios frecuentes",
+    "edit_topsites_showmore_button": "Mostrar más",
+    "edit_topsites_showless_button": "Mostrar menos",
+    "edit_topsites_done_button": "Hecho",
+    "edit_topsites_pin_button": "Fijar este sitio",
+    "edit_topsites_edit_button": "Editar este sitio",
+    "edit_topsites_dismiss_button": "Sacar este sitio"
+  },
+  "es-ES": {
+    "newtab_page_title": "Nueva pestaña",
+    "default_label_loading": "Cargando…",
+    "header_top_sites": "Sitios favoritos",
+    "header_highlights": "Destacados",
+    "type_label_visited": "Visitados",
+    "type_label_bookmarked": "En marcadores",
+    "type_label_synced": "Sincronizado desde otro dispositivo",
+    "type_label_open": "Abrir",
+    "type_label_topic": "Tema",
+    "menu_action_bookmark": "Marcador",
+    "menu_action_remove_bookmark": "Eliminar marcador",
+    "menu_action_copy_address": "Copiar dirección",
+    "menu_action_email_link": "Enviar enlace…",
+    "menu_action_open_new_window": "Abrir en una nueva ventana",
+    "menu_action_open_private_window": "Abrir en una nueva ventana privada",
+    "menu_action_dismiss": "Ignorar",
+    "menu_action_delete": "Eliminar del historial",
+    "search_for_something_with": "Buscar {search_term} con:",
+    "search_button": "Buscar",
+    "search_header": "Búsqueda de {search_engine_name}",
+    "search_web_placeholder": "Buscar en la Web",
+    "search_settings": "Cambiar ajustes de búsqueda",
+    "welcome_title": "Bienvenido a la nueva pestaña",
+    "welcome_body": "Firefox utilizará este espacio para mostrarte los marcadores, artículos y vídeos más relevantes y las páginas que has visitado recientemente, para que puedas acceder más rápido.",
+    "welcome_label": "Identificar lo más destacado para ti",
+    "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": "Personalizar la página Nueva pestaña",
+    "settings_pane_header": "Preferencias de nueva pestaña",
+    "settings_pane_body": "Elige qué quieres ver al abrir una nueva pestaña",
+    "settings_pane_search_header": "Buscar",
+    "settings_pane_search_body": "Busca en la Web desde tu nueva pestaña.",
+    "settings_pane_topsites_header": "Sitios populares",
+    "settings_pane_topsites_body": "Accede a las páginas que más visitas.",
+    "settings_pane_topsites_options_showmore": "Mostrar dos líneas",
+    "settings_pane_highlights_header": "Resaltados",
+    "settings_pane_highlights_body": "Échale un vistazo al historial de navegación y marcadores más recientes.",
+    "settings_pane_done_button": "Hecho",
+    "edit_topsites_button_text": "Editar",
+    "edit_topsites_button_label": "Personalizar la sección de Sitios populares",
+    "edit_topsites_showmore_button": "Mostrar más",
+    "edit_topsites_showless_button": "Mostrar menos",
+    "edit_topsites_done_button": "Hecho",
+    "edit_topsites_pin_button": "Fijar este sitio",
+    "edit_topsites_edit_button": "Editar este sitio",
+    "edit_topsites_dismiss_button": "Olvidar este sitio"
+  },
+  "es-MX": {
+    "newtab_page_title": "Nueva pestaña",
+    "default_label_loading": "Cargando…",
+    "header_top_sites": "Sitios favoritos",
+    "header_highlights": "Destacados",
+    "type_label_visited": "Visitados",
+    "type_label_bookmarked": "Marcados",
+    "type_label_synced": "Sincronizado desde otro dispositivo",
+    "type_label_open": "Abrir",
+    "type_label_topic": "Tema",
+    "menu_action_bookmark": "Marcador",
+    "menu_action_remove_bookmark": "Eliminar marcador",
+    "menu_action_copy_address": "Copiar dirección",
+    "menu_action_email_link": "Enlace por correo electrónico…",
+    "menu_action_open_new_window": "Abrir en una Nueva Ventana",
+    "menu_action_open_private_window": "Abrir en una Nueva Ventana Privada",
+    "menu_action_dismiss": "Descartar",
+    "menu_action_delete": "Eliminar del historial",
+    "search_for_something_with": "Buscar {search_term} con:",
+    "search_button": "Buscar",
+    "search_header": "Buscar {search_engine_name}",
+    "search_web_placeholder": "Buscar en la Web",
+    "search_settings": "Cambiar configuraciones de búsqueda",
+    "welcome_title": "Bienvenido a una nueva pestaña",
+    "welcome_body": "Firefox usará este espacio para mostrar tus marcadores, artículos, videos y páginas más relevantes que se hayan visitado para poder volver más fácilmente.",
+    "welcome_label": "Identificando tus destacados",
+    "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": "Personalizar tu página de nueva pestaña",
+    "settings_pane_header": "Preferencias de nueva pestaña",
+    "settings_pane_body": "Elige lo que ves al abrir una nueva pestaña.",
+    "settings_pane_search_header": "Buscar",
+    "settings_pane_search_body": "Busca en la web de tu nueva pestaña.",
+    "settings_pane_topsites_header": "Sitios populares",
+    "settings_pane_topsites_body": "Accede a los sitios web que más visitas.",
+    "settings_pane_topsites_options_showmore": "Mostrar dos filas",
+    "settings_pane_highlights_header": "Destacados",
+    "settings_pane_highlights_body": "Ve tu historial de navegación reciente y tus marcadores recién creados.",
+    "settings_pane_done_button": "Listo",
+    "edit_topsites_button_text": "Editar",
+    "edit_topsites_button_label": "Personalizar la sección de tus sitios preferidos",
+    "edit_topsites_showmore_button": "Mostrar más",
+    "edit_topsites_showless_button": "Mostrar menos",
+    "edit_topsites_done_button": "Listo",
+    "edit_topsites_pin_button": "Fijar este sitio",
+    "edit_topsites_edit_button": "Editar este sitio",
+    "edit_topsites_dismiss_button": "Descartar este sitio"
+  },
+  "et": {
+    "newtab_page_title": "Uus kaart",
+    "default_label_loading": "Laadimine…",
+    "header_top_sites": "Top saidid",
+    "header_highlights": "Esiletõstetud",
+    "type_label_visited": "Külastatud",
+    "type_label_bookmarked": "Järjehoidjatest",
+    "type_label_synced": "Sünkroniseeritud teisest seadmest",
+    "type_label_open": "Avatud",
+    "type_label_topic": "Teema",
+    "menu_action_bookmark": "Lisa järjehoidjatesse",
+    "menu_action_remove_bookmark": "Eemalda järjehoidja",
+    "menu_action_copy_address": "Kopeeri aadress",
+    "menu_action_email_link": "Saada link e-postiga…",
+    "menu_action_open_new_window": "Ava uues aknas",
+    "menu_action_open_private_window": "Ava uues privaatses aknas",
+    "menu_action_dismiss": "Peida",
+    "menu_action_delete": "Kustuta ajaloost",
+    "search_for_something_with": "Otsi fraasi {search_term}, kasutades otsingumootorit:",
+    "search_header": "{search_engine_name}",
+    "search_web_placeholder": "Otsi veebist",
+    "search_settings": "Muuda otsingu sätteid",
+    "welcome_title": "Tere tulemast uuele kaardile",
+    "welcome_body": "Firefox kasutab seda lehte, et kuvada sulle kõige olulisemaid järjehoidjaid, artikleid, videoid ja lehti, mida oled hiljuti külastanud, nii et pääseksid kergelt nende juurde tagasi.",
+    "welcome_label": "Esiletõstetava sisu tuvastamine",
+    "time_label_less_than_minute": "<1m",
+    "time_label_minute": "{number}m",
+    "time_label_hour": "{number}t",
+    "time_label_day": "{number}p"
+  },
+  "eu": {},
+  "fa": {
+    "newtab_page_title": "زبانه جدید",
+    "default_label_loading": "در حال بارگیری…",
+    "header_top_sites": "سایت‌های برتر",
+    "header_highlights": "برجسته‌ها",
+    "type_label_visited": "مشاهده شده",
+    "type_label_bookmarked": "نشانک شده",
+    "type_label_synced": "هم‌گام شده از دستگاهی دیگر",
+    "type_label_open": "باز کردن",
+    "type_label_topic": "موضوع",
+    "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": "حذف از تاریخچه",
+    "search_for_something_with": "جست‌وجو برای {search_term} با:",
+    "search_button": "جست‌وجو",
+    "search_header": "جست‌وجو {search_engine_name}",
+    "search_web_placeholder": "جست‌وجوی وب",
+    "search_settings": "تغییر تنظیمات جست‌وجو",
+    "welcome_title": "به زبانه جدید خوش‌آمدید",
+    "welcome_body": "فایرفاکس از این فضا برای نمایش نشانک‌ها، مقالات، ویدئوها و صفحات مرتبطی که به‌تازگی مشاهده کرده‌اید استفاده می‌کند، تا شما به راحتی دوباره به آنها دسترسی داشته باشید.",
+    "welcome_label": "شناسایی گزینه‌های برجسته شما",
+    "time_label_less_than_minute": "> ۱ دقیقه",
+    "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_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": "نادیده گرفتن این سایت"
+  },
+  "ff": {},
+  "fi": {
+    "newtab_page_title": "Uusi välilehti",
+    "default_label_loading": "Ladataan…",
+    "header_top_sites": "Ykkössivustot",
+    "header_highlights": "Nostot",
+    "type_label_visited": "Vierailtu",
+    "type_label_bookmarked": "Kirjanmerkki",
+    "type_label_synced": "Synkronoitu toiselta laitteelta",
+    "type_label_open": "Avoin",
+    "type_label_topic": "Aihe",
+    "menu_action_bookmark": "Lisää kirjanmerkki",
+    "menu_action_remove_bookmark": "Poista kirjanmerkki",
+    "menu_action_copy_address": "Kopioi osoite",
+    "menu_action_email_link": "Lähetä linkki…",
+    "menu_action_open_new_window": "Avaa uuteen ikkunaan",
+    "menu_action_open_private_window": "Avaa uuteen yksityiseen ikkunaan",
+    "menu_action_dismiss": "Hylkää",
+    "menu_action_delete": "Poista historiasta",
+    "search_for_something_with": "Hae {search_term} palvelusta:",
+    "search_header": "{search_engine_name}-haku",
+    "search_web_placeholder": "Verkkohaku",
+    "search_settings": "Muuta hakuasetuksia",
+    "welcome_title": "Tervetuloa uuteen välilehteen",
+    "welcome_body": "Firefox käyttää tätä tilaa näyttämään olennaisimmat kirjanmerkit, artikkelit, videot ja sivut, joita olet katsellut, jotta pääset niihin takaisin nopeasti.",
+    "welcome_label": "Tunnistetaan nostojasi",
+    "time_label_less_than_minute": "<1 min",
+    "time_label_minute": "{number} min",
+    "time_label_hour": "{number} h",
+    "time_label_day": "{number} pv"
+  },
+  "fr": {
+    "newtab_page_title": "Nouvel onglet",
+    "default_label_loading": "Chargement…",
+    "header_top_sites": "Sites les plus visités",
+    "header_highlights": "Éléments-clés",
+    "type_label_visited": "Visité",
+    "type_label_bookmarked": "Ajouté aux marque-pages",
+    "type_label_synced": "Synchronisé depuis un autre appareil",
+    "type_label_open": "Ouvert",
+    "type_label_topic": "Thème",
+    "menu_action_bookmark": "Marquer cette page",
+    "menu_action_remove_bookmark": "Supprimer le marque-page",
+    "menu_action_copy_address": "Copier l’adresse",
+    "menu_action_email_link": "Envoyer un lien par courriel…",
+    "menu_action_open_new_window": "Ouvrir dans une nouvelle fenêtre",
+    "menu_action_open_private_window": "Ouvrir dans une nouvelle fenêtre privée",
+    "menu_action_dismiss": "Retirer",
+    "menu_action_delete": "Supprimer de l’historique",
+    "search_for_something_with": "Recherche pour {search_term} avec :",
+    "search_button": "Rechercher",
+    "search_header": "Recherche {search_engine_name}",
+    "search_web_placeholder": "Rechercher sur le Web",
+    "search_settings": "Paramètres de recherche",
+    "welcome_title": "Bienvenue sur la page Nouvel onglet",
+    "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_body": "Choisissez ce qui s’affiche à l’ouverture d’un nouvel onglet.",
+    "settings_pane_search_header": "Recherche",
+    "settings_pane_search_body": "Effectuez une recherche sur le Web à partir du 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_highlights_header": "Éléments-clés",
+    "settings_pane_highlights_body": "Revenir sur votre historique de navigation récent et sur vos marque-pages nouvellement créés.",
+    "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_done_button": "Terminé",
+    "edit_topsites_pin_button": "Épingler ce site",
+    "edit_topsites_edit_button": "Modifier ce site",
+    "edit_topsites_dismiss_button": "Retirer ce site"
+  },
+  "fy-NL": {
+    "newtab_page_title": "Nij ljepblêd",
+    "default_label_loading": "Lade…",
+    "header_top_sites": "Topwebsites",
+    "header_highlights": "Hichtepunten",
+    "type_label_visited": "Besocht",
+    "type_label_bookmarked": "Blêdwizer makke",
+    "type_label_synced": "Syngronisearre fan oar apparaat ôf",
+    "type_label_open": "Iepene",
+    "type_label_topic": "Underwerp",
+    "menu_action_bookmark": "Blêdwizer",
+    "menu_action_remove_bookmark": "Blêdwizer fuortsmite",
+    "menu_action_copy_address": "Adres kopiearje",
+    "menu_action_email_link": "Keppeling e-maile…",
+    "menu_action_open_new_window": "Iepenje yn in nij finster",
+    "menu_action_open_private_window": "Iepenje yn in nij priveefinster",
+    "menu_action_dismiss": "Fuortsmite",
+    "menu_action_delete": "Fuortsmite út skiednis",
+    "search_for_something_with": "Sykje nei {search_term} mei:",
+    "search_button": "Sykje",
+    "search_header": "{search_engine_name} trochsykje",
+    "search_web_placeholder": "Sykje op it web",
+    "search_settings": "Sykynstellingen wizigje",
+    "welcome_title": "Wolkom by it nije ljepblêd",
+    "welcome_body": "Firefox brûkt dizze romte om jo meast relevante blêdwizers, artikelen, fideo’s en siden dy't jo koartlyn besocht hawwe wer te jaan, sadat jo dizze ienfâldichwei weromfine kinne.",
+    "welcome_label": "Jo hichtepunten oantsjutte",
+    "time_label_less_than_minute": "< 1 m",
+    "time_label_minute": "{number} m",
+    "time_label_hour": "{number} o",
+    "time_label_day": "{number} d",
+    "settings_pane_button_label": "Jo side foar nije ljepblêden oanpasse",
+    "settings_pane_header": "Nij ljepblêdfoarkarren",
+    "settings_pane_body": "Kies wat jo sjogge as jo in nij ljepblêd iepenje.",
+    "settings_pane_search_header": "Sykje",
+    "settings_pane_search_body": "Sykje op it web fan jo nije ljepblêd út.",
+    "settings_pane_topsites_header": "Topwebsites",
+    "settings_pane_topsites_body": "Benaderje de websites dy't jo it meast besykje.",
+    "settings_pane_topsites_options_showmore": "Twa rigen toane",
+    "settings_pane_highlights_header": "Hichtepunten",
+    "settings_pane_highlights_body": "Sjoch werom nei jo resinte sneupskiednis en nij makke blêdwizers.",
+    "settings_pane_done_button": "Dien",
+    "edit_topsites_button_text": "Bewurkje",
+    "edit_topsites_button_label": "Jo seksje Topwebsites oanpasse",
+    "edit_topsites_showmore_button": "Mear toane",
+    "edit_topsites_showless_button": "Minder toane",
+    "edit_topsites_done_button": "Dien",
+    "edit_topsites_pin_button": "Dizze side fêstsette",
+    "edit_topsites_edit_button": "Dizze side bewurkje",
+    "edit_topsites_dismiss_button": "Dizze side fuortsmite"
+  },
+  "ga-IE": {
+    "newtab_page_title": "Cluaisín Nua",
+    "default_label_loading": "Á Luchtú…",
+    "header_top_sites": "Barrshuímh",
+    "header_highlights": "Buaicphointí",
+    "type_label_visited": "Feicthe",
+    "type_label_bookmarked": "Leabharmharcáilte",
+    "type_label_synced": "Sioncronaithe ó ghléas eile",
+    "type_label_open": "Oscailte",
+    "type_label_topic": "Ábhar",
+    "menu_action_bookmark": "Cruthaigh leabharmharc",
+    "menu_action_remove_bookmark": "Scrios Leabharmharc",
+    "menu_action_copy_address": "Cóipeáil an Seoladh",
+    "menu_action_email_link": "Seol an Nasc trí Ríomhphost…",
+    "menu_action_open_new_window": "Oscail i bhFuinneog Nua",
+    "menu_action_open_private_window": "Oscail i bhFuinneog Nua Phríobháideach",
+    "menu_action_dismiss": "Ruaig",
+    "menu_action_delete": "Scrios ón Stair",
+    "search_for_something_with": "Déan cuardach ar {search_term} le:",
+    "search_header": "Cuardach {search_engine_name}",
+    "search_web_placeholder": "Cuardaigh an Gréasán",
+    "search_settings": "Socruithe Cuardaigh",
+    "welcome_title": "Fáilte go dtí cluaisín nua",
+    "welcome_body": "Úsáidfidh Firefox an spás seo chun na leabharmharcanna, ailt, físeáin, agus leathanaigh is tábhachtaí a thaispeáint duit, ionas go mbeidh tú in ann filleadh orthu gan stró.",
+    "welcome_label": "Buaicphointí á lorg",
+    "time_label_less_than_minute": "< 1 n",
+    "time_label_minute": "{number}n",
+    "time_label_hour": "{number}u",
+    "time_label_day": "{number}l"
+  },
+  "gd": {
+    "newtab_page_title": "Taba ùr",
+    "default_label_loading": "’Ga luchdadh…",
+    "header_top_sites": "Brod nan làrach",
+    "header_highlights": "Highlights",
+    "type_label_visited": "Na thadhail thu air",
+    "type_label_bookmarked": "’Nan comharran-lìn",
+    "type_label_synced": "Sioncronaichte o uidheam eile",
+    "type_label_open": "Fosgailte",
+    "type_label_topic": "Cuspair",
+    "menu_action_bookmark": "Comharra-lìn",
+    "menu_action_remove_bookmark": "Thoir an comharra-lìn air falbh",
+    "menu_action_copy_address": "Dèan lethbhreac dhen t-seòladh",
+    "menu_action_email_link": "Cuir an ceangal air a’ phost-d…",
+    "menu_action_open_new_window": "Fosgail ann an uinneag ùr",
+    "menu_action_open_private_window": "Fosgail ann an uinneag phrìobhaideach ùr",
+    "menu_action_dismiss": "Leig seachad",
+    "menu_action_delete": "Sguab às an eachdraidh",
+    "search_for_something_with": "Lorg {search_term} le:",
+    "search_header": "Lorg le {search_engine_name}",
+    "search_web_placeholder": "Lorg air an lìon",
+    "search_settings": "Atharraich roghainnean an luirg",
+    "welcome_title": "Fàilte gun taba ùr",
+    "welcome_body": "Seallaidh Firefox na comharran-lìn, artaigealan, videothan is duilleagan as iomchaidhe dhut, an fheadhainn air an do thadhail thu o chionn goirid, ach an ruig thu iad gu luath.",
+    "welcome_label": "Ag aithneachadh nan highlights agad",
+    "time_label_less_than_minute": "<1m",
+    "time_label_minute": "{number}m",
+    "time_label_hour": "{number}u",
+    "time_label_day": "{number}l"
+  },
+  "gl": {},
+  "gn": {},
+  "gu-IN": {
+    "newtab_page_title": "નવું ટૅબ",
+    "default_label_loading": "લોડ કરી રહ્યું છે...",
+    "header_top_sites": "ટોપ સાઇટ્સ",
+    "header_highlights": "હાઇલાઇટ્સ",
+    "type_label_visited": "જોવામા આવેલ:",
+    "type_label_bookmarked": "બુકમાર્ક્સ",
+    "type_label_synced": "બીજા ઉપકરણ થી સમન્વયિત કરેલ છે",
+    "type_label_open": "ખોલો",
+    "type_label_topic": "વિષય",
+    "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": "ઇતિહાસમાંથી દૂર કરો",
+    "search_for_something_with": "શોધ કરો {search_term} ની સાથે:",
+    "search_header": "{search_engine_name} શોધ કરો",
+    "search_web_placeholder": "વેબ પર શોધો",
+    "search_settings": "શોધ ના સેટિંગ્સ બદલો",
+    "welcome_title": "નવી વિન્ડોમાં આપનું સ્વાગત છે",
+    "welcome_body": "ફાયરફોક્સ, તમારા સૌથી સંબંધિત બુકમાર્ક્સ, લેખો, વિડિઓઝ, અને પૃષ્ઠો જે તમે તાજેતરમાં મુલાકાત લીધી એ બતાવવા માટે આ જગ્યાનો ઉપયોગ કરશે જેથી તમે પાછા તેમને સરળતાથી મેળવી શકો છો.",
+    "welcome_label": "તમારા હાઇલાઇટ્સ ઓળખવા",
+    "time_label_less_than_minute": "<1મિનિટ",
+    "time_label_minute": "{number}મિનિટ",
+    "time_label_hour": "{number}કલાક",
+    "time_label_day": "{number}દિવસ"
+  },
+  "he": {
+    "newtab_page_title": "לשונית חדשה",
+    "default_label_loading": "בטעינה…",
+    "header_top_sites": "אתרים מובילים",
+    "header_highlights": "המלצות",
+    "type_label_visited": "ביקורים קודמים",
+    "type_label_bookmarked": "נוצרה סימניה",
+    "type_label_synced": "סונכרן מהתקן אחר",
+    "type_label_open": "פתיחה",
+    "type_label_topic": "נושא",
+    "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": "מחיקה מההיסטוריה",
+    "search_for_something_with": "חיפוש אחר {search_term} עם:",
+    "search_header": "חיפוש ב־{search_engine_name}",
+    "search_web_placeholder": "חיפוש ברשת",
+    "search_settings": "שינוי הגדרות חיפוש",
+    "welcome_title": "ברוכים הבאים לדף הלשונית החדשה",
+    "welcome_body": "Firefox ישתמש באזור זה כדי להציג את הסימניות הרלוונטיות ביותר, מאמרים, סרטוני וידאו ודפים שביקרת בהם לאחרונה, כך שניתן יהיה לגשת אליהם שוב בקלות.",
+    "time_label_less_than_minute": "פחות מדקה",
+    "time_label_minute": "{number} דקות",
+    "time_label_hour": "{number} שעות",
+    "time_label_day": "{number} ימים"
+  },
+  "hi-IN": {},
+  "hr": {
+    "newtab_page_title": "Nova kartica",
+    "default_label_loading": "Učitavanje…",
+    "header_top_sites": "Najbolje stranice",
+    "header_highlights": "Istaknuto",
+    "type_label_visited": "Posjećeno",
+    "type_label_bookmarked": "Zabilježeno",
+    "type_label_synced": "Sinkronizirano s drugog uređaja",
+    "type_label_open": "Otvori",
+    "type_label_topic": "Tema",
+    "menu_action_bookmark": "Zabilježi stranicu",
+    "menu_action_remove_bookmark": "Ukloni zabilješku",
+    "menu_action_copy_address": "Kopiraj adresu",
+    "menu_action_email_link": "Pošalji poveznicu e-poštom…",
+    "menu_action_open_new_window": "Otvori u novom prozoru",
+    "menu_action_open_private_window": "Otvori u novom privatnom prozoru",
+    "menu_action_dismiss": "Odbaci",
+    "menu_action_delete": "Obriši iz povijesti",
+    "search_for_something_with": "Traži {search_term} s:",
+    "search_header": "{search_engine_name} pretraživanje",
+    "search_web_placeholder": "Pretraži web",
+    "search_settings": "Promijeni postavke pretraživanja",
+    "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"
+  },
+  "hsb": {
+    "newtab_page_title": "Nowy rajtark",
+    "default_label_loading": "Začituje so…",
+    "header_top_sites": "Najhusćišo wopytane sydła",
+    "header_highlights": "Wjerški",
+    "type_label_visited": "Wopytany",
+    "type_label_bookmarked": "Jako zapołožka składowany",
+    "type_label_synced": "Z druheho grata synchronizowany",
+    "type_label_open": "Wočinjeny",
+    "type_label_topic": "Tema",
+    "menu_action_bookmark": "Zapołožki składować",
+    "menu_action_remove_bookmark": "Zapołožku wotstronić",
+    "menu_action_copy_address": "Adresu kopěrować",
+    "menu_action_email_link": "Wotkaz e-mejlować…",
+    "menu_action_open_new_window": "W nowym woknje wočinić",
+    "menu_action_open_private_window": "W nowym priwatnym woknje wočinić",
+    "menu_action_dismiss": "Zaćisnyć",
+    "menu_action_delete": "Z historije zhašeć",
+    "search_for_something_with": "Za {search_term} pytać z:",
+    "search_button": "Pytać",
+    "search_header": "Z {search_engine_name} pytać",
+    "search_web_placeholder": "Web přepytać",
+    "search_settings": "Pytanske nastajenja změnić",
+    "welcome_title": "Witajće k nowemu rajtarkej",
+    "welcome_body": "Firefox budźe tutón rum wužiwać, zo by waše najwažniše zapołožki, nastawki, wideja a runje wopytane strony pokazał, zo byšće móhł so lochko k nim wróćić.",
+    "welcome_label": "Wuběranje wašich najwažnišich stronow",
+    "time_label_less_than_minute": "< 1 min",
+    "time_label_minute": "{number} m",
+    "time_label_hour": "{number} h",
+    "time_label_day": "",
+    "settings_pane_button_label": "Stronu wašeho noweho rajtarka přiměrić",
+    "settings_pane_header": "Nastajenja noweho rajtarka",
+    "settings_pane_body": "Wubjerće, štož chceće widźeć, hdyž nowy rajtark wočinjeće.",
+    "settings_pane_search_header": "Pytać",
+    "settings_pane_search_body": "Přepytajće web ze swojeho noweho rajtarka.",
+    "settings_pane_topsites_header": "Najhusćišo wopytane sydła",
+    "settings_pane_topsites_body": "Wočińće websydła, kotrež sće najhusćišo wopytał.",
+    "settings_pane_topsites_options_showmore": "Dwě lince pokazać",
+    "settings_pane_highlights_header": "Wjerški",
+    "settings_pane_highlights_body": "Wobhladajće sej najnowšu přehladowansku historiju a nowo wutworjene zapołožki.",
+    "settings_pane_done_button": "Hotowo",
+    "edit_topsites_button_text": "Wobdźěłać",
+    "edit_topsites_button_label": "Přiměrće wotrězk swojich najhusćišo wopytanych sydłow",
+    "edit_topsites_showmore_button": "Wjace pokazać",
+    "edit_topsites_showless_button": "Mjenje pokazać",
+    "edit_topsites_done_button": "Hotowo",
+    "edit_topsites_pin_button": "Tute sydło připjeć",
+    "edit_topsites_edit_button": "Tute sydło wobdźěłać",
+    "edit_topsites_dismiss_button": "Sydło zaćisnyć"
+  },
+  "hu": {
+    "newtab_page_title": "Új lap",
+    "default_label_loading": "Betöltés…",
+    "header_top_sites": "Népszerű oldalak",
+    "header_highlights": "Kiemelések",
+    "type_label_visited": "Látogatott",
+    "type_label_bookmarked": "Könyvjelzőzött",
+    "type_label_synced": "Másik eszközről szinkronizálva",
+    "type_label_open": "Megnyitás",
+    "type_label_topic": "Téma",
+    "menu_action_bookmark": "Könyvjelzőzés",
+    "menu_action_remove_bookmark": "Könyvjelző eltávolítása",
+    "menu_action_copy_address": "Cím másolása",
+    "menu_action_email_link": "Hivatkozás küldése e-mailben…",
+    "menu_action_open_new_window": "Megnyitás új ablakban",
+    "menu_action_open_private_window": "Megnyitás új privát ablakban",
+    "menu_action_dismiss": "Elutasítás",
+    "menu_action_delete": "Törlés az előzményekből",
+    "search_for_something_with": "„{search_term}” keresése ezzel:",
+    "search_button": "Keresés",
+    "search_header": "{search_engine_name} keresés",
+    "search_web_placeholder": "Keresés a weben",
+    "search_settings": "Keresési beállítások módosítása",
+    "welcome_title": "Üdvözöljük az új lapon",
+    "welcome_body": "A Firefox ezt a területet a leginkább releváns könyvjelzők, cikkek, videók és nemrég látogatott oldalak megjelenítésére fogja használni, így könnyedén visszatalálhat hozzájuk.",
+    "welcome_label": "A kiemeléseinek azonosítása",
+    "time_label_less_than_minute": "<1 p",
+    "time_label_minute": "{number} p",
+    "time_label_hour": "{number} ó",
+    "time_label_day": "{number} n",
+    "settings_pane_button_label": "Az Új lap oldal személyre szabása",
+    "settings_pane_header": "Új lap beállításai",
+    "settings_pane_body": "Válassza ki, hogy mit lát, amikor megnyit egy új lapot.",
+    "settings_pane_search_header": "Keresés",
+    "settings_pane_search_body": "Keresés a weben az új lapon.",
+    "settings_pane_topsites_header": "Népszerű oldalak",
+    "settings_pane_topsites_body": "A leggyakrabban látogatott webhelyek elérése.",
+    "settings_pane_topsites_options_showmore": "Két sor megjelenítése",
+    "settings_pane_highlights_header": "Kiemelések",
+    "settings_pane_highlights_body": "A böngészési előzmények, és az újonnan létrehozott könyvjelzők visszanézése.",
+    "settings_pane_done_button": "Kész",
+    "edit_topsites_button_text": "Szerkesztés",
+    "edit_topsites_button_label": "A Népszerű oldalak rész testreszabása",
+    "edit_topsites_showmore_button": "Több megjelenítése",
+    "edit_topsites_showless_button": "Kevesebb megjelenítése",
+    "edit_topsites_done_button": "Kész",
+    "edit_topsites_pin_button": "Webhely rögzítése",
+    "edit_topsites_edit_button": "Webhely szerkesztése",
+    "edit_topsites_dismiss_button": "Webhely eltávolítása"
+  },
+  "hy-AM": {
+    "newtab_page_title": "Նոր ներդիր",
+    "default_label_loading": "Բեռնվում է...",
+    "header_top_sites": "Լավագույն կայքեր",
+    "header_highlights": "Գունանշում",
+    "type_label_visited": "Այցելած",
+    "type_label_bookmarked": "Էջանշված",
+    "type_label_synced": "Համաժամեցված այլ սարքից",
+    "type_label_open": "Բացել",
+    "type_label_topic": "Թեմա",
+    "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": "Ջնջել Պատմությունից",
+    "search_for_something_with": "Որոնել {search_term}-ը հետևյալով՝",
+    "search_header": "{search_engine_name}-ի որոնում",
+    "search_web_placeholder": "Որոնել առցանց",
+    "search_settings": "Փոխել որոնման կարգավորումները",
+    "welcome_title": "Բարի գալուստ նոր ներդիր",
+    "welcome_body": "Firefox-ը կօգտագործի այս բացատը՝ ցուցադրելու ձեզ համար առավել կարևոր էջանիշերը, հոդվածները և ձեր այցելած վերջին էջերը, որպեսզի հեշտությամբ վերադառնաք դրանց:",
+    "welcome_label": "Նույնացնում է ձեր գունանշումը",
+    "time_label_less_than_minute": "<1 ր",
+    "time_label_minute": "{number} ր",
+    "time_label_hour": "{number} ժ",
+    "time_label_day": "{number} օր"
+  },
+  "id": {
+    "newtab_page_title": "Tab Baru",
+    "default_label_loading": "Memuat…",
+    "header_top_sites": "Situs Teratas",
+    "header_highlights": "Sorotan",
+    "type_label_visited": "Dikunjungi",
+    "type_label_bookmarked": "Dimarkahi",
+    "type_label_synced": "Disinkronkan dari perangkat lain",
+    "type_label_open": "Buka",
+    "type_label_topic": "Topik",
+    "menu_action_bookmark": "Markah",
+    "menu_action_remove_bookmark": "Hapus Markah",
+    "menu_action_copy_address": "Salin Alamat",
+    "menu_action_email_link": "Emailkan Tautan…",
+    "menu_action_open_new_window": "Buka di Jendela Baru",
+    "menu_action_open_private_window": "Buka di Jendela Penjelajahan Pribadi Baru",
+    "menu_action_dismiss": "Tutup",
+    "menu_action_delete": "Hapus dari Riwayat",
+    "search_for_something_with": "Cari {search_term} lewat:",
+    "search_button": "Cari",
+    "search_header": "Pencarian {search_engine_name}",
+    "search_web_placeholder": "Cari di Web",
+    "search_settings": "Ubah Pengaturan Pencarian",
+    "welcome_title": "Selamat datang di tab baru",
+    "welcome_body": "Firefox akan menggunakan ruang ini untuk menampilkan markah, artikel, video, dan laman yang baru-baru ini dikunjungi, yang paling relevan agar Anda bisa kembali mengunjunginya dengan mudah.",
+    "welcome_label": "Mengidentifikasi Sorotan Anda",
+    "time_label_less_than_minute": "<1 mnt",
+    "time_label_minute": "{number} mnt",
+    "time_label_hour": "{number} jam",
+    "time_label_day": "{number} hr",
+    "settings_pane_button_label": "Ubahsuai laman Tab Baru Anda",
+    "settings_pane_header": "Preferensi Tab Baru",
+    "settings_pane_body": "Pilih apa yang Anda lihat ketika Anda membuka tab baru.",
+    "settings_pane_search_header": "Pencarian",
+    "settings_pane_search_body": "Cari Web dari tab baru Anda.",
+    "settings_pane_topsites_header": "Situs Teratas",
+    "settings_pane_topsites_body": "Mengakses situs web yang paling sering Anda kunjungi.",
+    "settings_pane_topsites_options_showmore": "Tampilkan dua baris",
+    "settings_pane_highlights_header": "Sorotan",
+    "settings_pane_highlights_body": "Melihat kembali pada riwayat peramban terbaru dan markah yang baru dibuat.",
+    "settings_pane_done_button": "Selesai",
+    "edit_topsites_button_text": "Sunting",
+    "edit_topsites_button_label": "Ubahsuai bagian Situs Teratas Anda",
+    "edit_topsites_showmore_button": "Tampilkan lainnya",
+    "edit_topsites_showless_button": "Tampilkan lebih sedikit",
+    "edit_topsites_done_button": "Selesai",
+    "edit_topsites_pin_button": "Sematkan situs ini",
+    "edit_topsites_edit_button": "Sunting situs ini",
+    "edit_topsites_dismiss_button": "Abaikan situs ini"
+  },
+  "is": {},
+  "it": {
+    "newtab_page_title": "Nuova scheda",
+    "default_label_loading": "Caricamento…",
+    "header_top_sites": "Siti principali",
+    "header_highlights": "In evidenza",
+    "type_label_visited": "Visitato",
+    "type_label_bookmarked": "Nei segnalibri",
+    "type_label_synced": "Sincronizzato da un altro dispositivo",
+    "type_label_open": "Apri",
+    "type_label_topic": "Argomento",
+    "menu_action_bookmark": "Aggiungi ai segnalibri",
+    "menu_action_remove_bookmark": "Elimina segnalibro",
+    "menu_action_copy_address": "Copia indirizzo",
+    "menu_action_email_link": "Invia link per email…",
+    "menu_action_open_new_window": "Apri in una nuova finestra",
+    "menu_action_open_private_window": "Apri in una nuova finestra anonima",
+    "menu_action_dismiss": "Rimuovi",
+    "menu_action_delete": "Elimina dalla cronologia",
+    "search_for_something_with": "Cerca {search_term} con:",
+    "search_button": "Cerca",
+    "search_header": "Ricerca {search_engine_name}",
+    "search_web_placeholder": "Cerca sul Web",
+    "search_settings": "Cambia impostazioni di ricerca",
+    "welcome_title": "Benvenuto nella nuova scheda",
+    "welcome_body": "Firefox utilizzerà questo spazio per visualizzare gli elementi più significativi, come segnalibri, articoli, video e pagine visitate di recente, in modo che siano sempre facili da raggiungere.",
+    "welcome_label": "Identificazione elementi in evidenza…",
+    "time_label_less_than_minute": "<1m",
+    "time_label_minute": "{number}m",
+    "time_label_hour": "{number}h",
+    "time_label_day": "{number}g",
+    "settings_pane_button_label": "Personalizza la pagina Nuova scheda",
+    "settings_pane_header": "Preferenze Nuova scheda",
+    "settings_pane_body": "Scegli quali elementi visualizzare all’apertura di una nuova scheda.",
+    "settings_pane_search_header": "Ricerca",
+    "settings_pane_search_body": "Avvia ricerche in una nuova scheda.",
+    "settings_pane_topsites_header": "Siti principali",
+    "settings_pane_topsites_body": "Accedi ai siti che visiti più spesso.",
+    "settings_pane_topsites_options_showmore": "Visualizza due righe",
+    "settings_pane_highlights_header": "In evidenza",
+    "settings_pane_highlights_body": "Visualizza gli elementi più recenti nella cronologia e gli ultimi segnalibri memorizzati.",
+    "settings_pane_done_button": "Fatto",
+    "edit_topsites_button_text": "Modifica",
+    "edit_topsites_button_label": "Personalizza la sezione Siti principali",
+    "edit_topsites_showmore_button": "Visualizza altri",
+    "edit_topsites_showless_button": "Nascondi altri",
+    "edit_topsites_done_button": "Fatto",
+    "edit_topsites_pin_button": "Aggiungi sito alla bacheca",
+    "edit_topsites_edit_button": "Modifica questo sito",
+    "edit_topsites_dismiss_button": "Ignora questo sito"
+  },
+  "ja": {
+    "newtab_page_title": "新しいタブ",
+    "default_label_loading": "読み込み中...",
+    "header_top_sites": "トップサイト",
+    "header_highlights": "ハイライト",
+    "type_label_visited": "訪問済み",
+    "type_label_bookmarked": "ブックマーク",
+    "type_label_synced": "他の端末から同期",
+    "type_label_open": "開く",
+    "type_label_topic": "トピック",
+    "menu_action_bookmark": "ブックマーク",
+    "menu_action_remove_bookmark": "ブックマークを削除",
+    "menu_action_copy_address": "URL をコピー",
+    "menu_action_email_link": "URL をメールで送信...",
+    "menu_action_open_new_window": "新しいウィンドウで開く",
+    "menu_action_open_private_window": "新しいプライベートウィンドウで開く",
+    "menu_action_dismiss": "閉じる",
+    "menu_action_delete": "履歴から削除",
+    "search_for_something_with": "{search_term} を検索:",
+    "search_button": "検索",
+    "search_header": "{search_engine_name} 検索",
+    "search_web_placeholder": "ウェブを検索",
+    "search_settings": "検索設定を変更",
+    "welcome_title": "新しいタブへようこそ",
+    "welcome_body": "Firefox はこのスペースを使って、関連性の高いブックマーク、記事、動画、最近訪れたページを表示し、それらのコンテンツへ簡単に戻れるようにします。",
+    "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": "2 行で表示",
+    "settings_pane_highlights_header": "ハイライト",
+    "settings_pane_highlights_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_edit_button": "このサイトを編集",
+    "edit_topsites_dismiss_button": "このサイトを削除"
+  },
+  "ka": {},
+  "kab": {
+    "newtab_page_title": "Iccer amaynut",
+    "default_label_loading": "Asali…",
+    "header_top_sites": "Ismal ifazen",
+    "header_highlights": "Iferdisen tisura",
+    "type_label_visited": "Yettwarza",
+    "type_label_bookmarked": "Yettwacreḍ",
+    "type_label_synced": "Yemtawi seg ibenk-nniḍen",
+    "type_label_open": "Yeldi",
+    "type_label_topic": "Asentel",
+    "menu_action_bookmark": "Creḍ asebter-agi",
+    "menu_action_remove_bookmark": "Kkes tacreṭ-agi",
+    "menu_action_copy_address": "Nγel tansa",
+    "menu_action_email_link": "Azen aseγwen s yimayl…",
+    "menu_action_open_new_window": "Ldei deg usfaylu amaynut",
+    "menu_action_open_private_window": "Ldi deg usfaylu uslig amaynut",
+    "menu_action_dismiss": "Kkes",
+    "menu_action_delete": "Kkes seg umazray",
+    "search_for_something_with": "Nadi γef {search_term} s:",
+    "search_button": "Nadi",
+    "search_header": "Anadi {search_engine_name}",
+    "search_web_placeholder": "Nadi di Web",
+    "search_settings": "Snifel iγewwaṛen n unadi",
+    "welcome_title": "Ansuf ar yiccer amaynut",
+    "welcome_body": "Firefox ad iseqdec tallunt akken ad d-yesken akk ticraḍ n isebtar iwulmen, imagraden, tividyutin, akked isebtar aniɣer terziḍ melmi kan, ihi tzemreḍ ad d-uɣaleḍ ɣer-sen s wudem fessusen.",
+    "welcome_label": "Asulu n iferdisen tisura",
+    "time_label_less_than_minute": "<1 n tesdat",
+    "time_label_minute": "{number} n tesdatin",
+    "time_label_hour": "{number} n isragen",
+    "time_label_day": "{number}n wussan",
+    "settings_pane_button_label": "Sagen asebter n yiccer-ik amaynut",
+    "settings_pane_header": "Ismenyifen n yiccer amaynut",
+    "settings_pane_body": "Fren ayen ara twaliḍ ticki teldiḍ iccer imaynut.",
+    "settings_pane_search_header": "Nadi",
+    "settings_pane_search_body": "Nadi di Web seg iccer-ik amaynut.",
+    "settings_pane_topsites_header": "Ismal ifazen",
+    "settings_pane_topsites_body": "Kcem ar yesmal web i trezzuḍ s waṭas.",
+    "settings_pane_topsites_options_showmore": "Sken sin izirigen",
+    "settings_pane_highlights_header": "Asebrureq",
+    "settings_pane_highlights_body": "Wali ar deffir ar umazray n tunigin yezrin akked tecraḍ i terniḍ melmi kan.",
+    "settings_pane_done_button": "Immed",
+    "edit_topsites_button_text": "Ẓreg",
+    "edit_topsites_button_label": "Sagen tigezmi n ismal ifazen",
+    "edit_topsites_showmore_button": "Sken ugar",
+    "edit_topsites_showless_button": "Sken qel",
+    "edit_topsites_done_button": "Immed",
+    "edit_topsites_pin_button": "Ṭṭef asmel-agi",
+    "edit_topsites_edit_button": "Ẓreg asmel-agi",
+    "edit_topsites_dismiss_button": "Anef i usmel-agi"
+  },
+  "kk": {
+    "newtab_page_title": "Жаңа бет",
+    "default_label_loading": "Жүктелуде…",
+    "header_top_sites": "Топ сайттар",
+    "header_highlights": "Бастысы",
+    "type_label_visited": "Қаралған",
+    "type_label_bookmarked": "Бетбелгілерде",
+    "type_label_synced": "Басқа құрылғыдан синхрондалған",
+    "type_label_open": "Ашу",
+    "type_label_topic": "Тақырып",
+    "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": "Тарихтан өшіру",
+    "search_for_something_with": "{search_term} ұғымын көмегімен іздеу:",
+    "search_button": "Іздеу",
+    "search_header": "{search_engine_name} іздеуі",
+    "search_web_placeholder": "Интернетте іздеу",
+    "search_settings": "Іздеу баптауларын өзгерту",
+    "welcome_title": "Жаңа бетке қош келдіңіз",
+    "welcome_body": "Firefox бұл орында ең маңызды бетбелгілер, мақалалар, видеолар және жуырда қаралған беттерді көрсетеді, оның көмегімен сіз оларға оңай түрде орала аласыз.",
+    "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_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": "Бұл сайтты тайдыру"
+  },
+  "km": {
+    "newtab_page_title": "ផ្ទាំង​ថ្មី",
+    "default_label_loading": "កំពុង​ផ្ទុក...",
+    "header_top_sites": "វិបសាយ​លើ​គេ",
+    "header_highlights": "ការ​រំលេច",
+    "type_label_visited": "បាន​ចូល​មើល",
+    "type_label_bookmarked": "បាន​ចំណាំ",
+    "type_label_synced": "បាន​ធ្វើ​សមកាលកម្ម​ពី​ឧបករណ៍​ផ្សេង​ទៀត",
+    "type_label_open": "បើក",
+    "type_label_topic": "ប្រធានបទ",
+    "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": "លុប​ពី​ប្រវត្តិ",
+    "search_for_something_with": "ស្វែងរក {search_term} ជាមួយ៖",
+    "search_header": "{search_engine_name} ស្វែងរក",
+    "search_web_placeholder": "ស្វែងរក​បណ្ដាញ",
+    "search_settings": "ផ្លាស់ប្ដូរ​ការ​កំណត់​ស្វែងរក",
+    "welcome_title": "ស្វាគមន៍​មក​កាន់​ផ្ទាំង​ថ្មី",
+    "welcome_body": "Firefox នឹង​ប្រើប្រាស់​កន្លែង​ទំនេរ​នេះ ដើម្បី​បង្ហាញ​ចំណាំ អត្ថបទ វីដេអូ និង​ទំព័រ​ដែល​ទាក់ទង​អ្នក​បំផុត ដែល​អ្នក​បាន​ចូល​មើល​ថ្មីៗ​នេះ ដូច្នេះ​អ្នក​អាច​ត្រឡប់​ទៅ​​កាន់​​វា​​វិញ​បាន​យ៉ាងងាយស្រួល។",
+    "welcome_label": "កំពុង​បញ្ជាក់​ការ​រំលេច​របស់​អ្នក",
+    "time_label_less_than_minute": "<1 នាទី",
+    "time_label_minute": "{number} នាទី",
+    "time_label_hour": "{number} ម៉ោង",
+    "time_label_day": "{number} ថ្ងៃ"
+  },
+  "kn": {},
+  "ko": {
+    "newtab_page_title": "새 탭",
+    "default_label_loading": "읽는 중…",
+    "header_top_sites": "상위 사이트",
+    "header_highlights": "하이라이트",
+    "type_label_visited": "방문한 사이트",
+    "type_label_bookmarked": "즐겨찾기",
+    "type_label_synced": "다른 기기에서 동기화",
+    "type_label_open": "열기",
+    "type_label_topic": "주제",
+    "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": "방문 기록에서 삭제",
+    "search_for_something_with": "다음에서 {search_term} 검색:",
+    "search_header": "{search_engine_name} 검색",
+    "search_web_placeholder": "웹 검색",
+    "search_settings": "검색 설정 바꾸기",
+    "welcome_title": "새 탭을 소개합니다",
+    "welcome_body": "최근에 방문한 관련있는 즐겨찾기나 글, 동영상, 페이지를 Firefox가 여기에 표시해서 쉽게 다시 찾아볼 수 있게 할 것입니다.",
+    "welcome_label": "하이라이트 확인",
+    "time_label_less_than_minute": "<1분",
+    "time_label_minute": "{number}분",
+    "time_label_hour": "{number}시",
+    "time_label_day": "{number}일"
+  },
+  "ku": {},
+  "lij": {
+    "newtab_page_title": "Neuvo Feuggio",
+    "default_label_loading": "Carego…",
+    "header_top_sites": "I megio sciti",
+    "header_highlights": "In evidensa",
+    "type_label_visited": "Vixitou",
+    "type_label_bookmarked": "Azonto a-i segnalibbri",
+    "type_label_synced": "Scincronizou da 'n atro dispoxitivo",
+    "type_label_open": "Arvi",
+    "type_label_topic": "Argomento",
+    "menu_action_bookmark": "Azonzi a-i segnalibbri",
+    "menu_action_remove_bookmark": "Scancella segnalibbro",
+    "menu_action_copy_address": "Còpia indirisso",
+    "menu_action_email_link": "Manda colegamento…",
+    "menu_action_open_new_window": "Arvi in neuvo barcon",
+    "menu_action_open_private_window": "Arvi in neuvo barcon privou",
+    "menu_action_dismiss": "Scancella",
+    "menu_action_delete": "Scancella da-a stöia",
+    "search_for_something_with": "Çerca {search_term} con:",
+    "search_button": "Çerca",
+    "search_header": "Riçerca {search_engine_name}",
+    "search_web_placeholder": "Çerca inta Ræ",
+    "search_settings": "Cangia inpostaçioin de riçerca",
+    "welcome_title": "Benvegnuo into neuvo feuggio",
+    "welcome_body": "Firefox o deuviâ sto spaçio pe mostrâ i elementi ciù scignificativi, comme segnalibbri, articoli, video e pagine vixitatæ da pöco in sa, in mòddo che segian de longo ciù façili da razonze.",
+    "welcome_label": "Identificaçion elementi in evidensa",
+    "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": "Personalizza a teu pagina Neuvo feuggio",
+    "settings_pane_header": "Preferense neuvo feuggio",
+    "settings_pane_body": "Çerni cöse ti veu vedde quande t'arvi 'n neuvo feuggio.",
+    "settings_pane_search_header": "Çerca",
+    "settings_pane_search_body": "Çerca inta Ræ da-o teu neuvo feuggio.",
+    "settings_pane_topsites_header": "I megio sciti",
+    "settings_pane_topsites_body": "Acedi a-i sciti che ti vixiti ciù de spesso.",
+    "settings_pane_topsites_options_showmore": "Fanni vedde doe righe",
+    "settings_pane_highlights_header": "In evidensa",
+    "settings_pane_highlights_body": "Veddi i elementi ciù neuvi inta stöia e i urtimi segnalibbri creæ.",
+    "settings_pane_done_button": "Fæto",
+    "edit_topsites_button_text": "Cangia",
+    "edit_topsites_button_label": "Personalizza a seçion I Megio Sciti",
+    "edit_topsites_showmore_button": "Fanni vedde de ciù",
+    "edit_topsites_showless_button": "Fanni vedde de meno",
+    "edit_topsites_done_button": "Fæto",
+    "edit_topsites_pin_button": "Azonzi sto scito",
+    "edit_topsites_edit_button": "Cangia sto scito",
+    "edit_topsites_dismiss_button": "Ignòra sto scito"
+  },
+  "lo": {
+    "newtab_page_title": "ແທັບໃຫມ່",
+    "default_label_loading": "ກຳລັງໂຫລດ…",
+    "header_top_sites": "ເວັບໄຊຕ໌ຍອດນິຍົມ",
+    "header_highlights": "ຈຸດເດັ່ນ",
+    "type_label_visited": "ເຂົ້າໄປເບິງມາແລ້ວ",
+    "type_label_bookmarked": "ບຸກມາກໄວ້ແລ້ວ",
+    "type_label_synced": "ໄດ້ Sync ມາຈາກອຸປະກອນອື່ນ",
+    "type_label_open": "ເປີດ",
+    "type_label_topic": "ຫົວ​ຂໍ້",
+    "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": "ລຶບອອກຈາກປະຫວັດການນຳໃຊ້",
+    "search_for_something_with": "ຄົ້ນຫາສໍາລັບ {search_term} ດ້ວຍ:",
+    "search_header": "ຄົ້ນຫາ {search_engine_name}",
+    "search_web_placeholder": "ຄົ້ນຫາເວັບ",
+    "search_settings": "ປ່ຽນການຕັ້ງຄ່າການຄົ້ນຫາ",
+    "welcome_title": "ຍິນດີຕອນຮັບເຂົ້າສູ່ແຖບໃຫມ່",
+    "welcome_label": "ກໍາລັງລະບຸລາຍການເດັ່ນຂອງທ່ານ",
+    "time_label_less_than_minute": "<1 ນາທີ",
+    "time_label_minute": "{number} ນາທີ",
+    "time_label_hour": "{number} ຊົ່ວໂມງ",
+    "time_label_day": "{number} ມື້"
+  },
+  "lt": {
+    "newtab_page_title": "Nauja kortelė",
+    "default_label_loading": "Įkeliama…",
+    "header_top_sites": "Lankomiausios svetainės",
+    "header_highlights": "Akcentai",
+    "type_label_visited": "Aplankyti",
+    "type_label_bookmarked": "Adresyne",
+    "type_label_synced": "Sinchronizuoti iš kito įrenginio",
+    "type_label_open": "Atviri",
+    "type_label_topic": "Tema",
+    "menu_action_bookmark": "Įrašyti į adresyną",
+    "menu_action_remove_bookmark": "Pašalinti iš adresyno",
+    "menu_action_copy_address": "Kopijuoti adresą",
+    "menu_action_email_link": "Siųsti saitą el. paštu…",
+    "menu_action_open_new_window": "Atverti naujame lange",
+    "menu_action_open_private_window": "Atverti naujame privačiajame lange",
+    "menu_action_dismiss": "Paslėpti",
+    "menu_action_delete": "Pašalinti iš istorijos",
+    "search_for_something_with": "Ieškoti „{search_term}“ per:",
+    "search_button": "Ieškoti",
+    "search_header": "{search_engine_name} paieška",
+    "search_web_placeholder": "Ieškokite saityne",
+    "search_settings": "Keisti paieškos nuostatas",
+    "welcome_title": "Sveiki, čia nauja kortelė",
+    "welcome_body": "„Firefox“ naudos šią vietą jums aktualiausių adresyno įrašų, straipsnių, vaizdo įrašų bei neseniai lankytų tinklalapių rodymui, kad galėtumėte lengvai į juos sugrįžti.",
+    "welcome_label": "Nustatomi jūsų akcentai",
+    "time_label_less_than_minute": "<1 min.",
+    "time_label_minute": "{number} min.",
+    "time_label_hour": "{number} val.",
+    "time_label_day": "{number} d.",
+    "settings_pane_button_label": "Tinkinkite savo naujos kortelės puslapį",
+    "settings_pane_header": "Naujos kortelės nuostatos",
+    "settings_pane_body": "Pasirinkite, ką matysite atvėrę naują kortelę.",
+    "settings_pane_search_header": "Paieška",
+    "settings_pane_search_body": "Ieškokite saityne tiesiai iš naujos kortelės.",
+    "settings_pane_topsites_header": "Lankomiausios svetainės",
+    "settings_pane_topsites_body": "Pasiekite jūsų dažniausiai lankomas svetaines.",
+    "settings_pane_topsites_options_showmore": "Rodyti dvi eilutes",
+    "settings_pane_highlights_header": "Akcentai",
+    "settings_pane_highlights_body": "Pažvelkite į savo naujausią naršymo istoriją bei paskiausiai pridėtus adresyno įrašus.",
+    "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_edit_button": "Redaguoti šią svetainę",
+    "edit_topsites_dismiss_button": "Paslėpti šią svetainę"
+  },
+  "ltg": {},
+  "lv": {},
+  "mai": {},
+  "mk": {},
+  "ml": {},
+  "mn": {},
+  "mr": {},
+  "ms": {
+    "newtab_page_title": "Tab Baru",
+    "default_label_loading": "Memuatkan…",
+    "header_top_sites": "Laman Teratas",
+    "header_highlights": "Serlahan",
+    "type_label_visited": "Dilawati",
+    "type_label_bookmarked": "Ditandabuku",
+    "type_label_synced": "Sync dari peranti lain",
+    "type_label_open": "Buka",
+    "type_label_topic": "Topik",
+    "menu_action_bookmark": "Tandabuku",
+    "menu_action_remove_bookmark": "Alihkeluar Tandabuku",
+    "menu_action_copy_address": "Salin Alamat",
+    "menu_action_email_link": "Pautan E-mel…",
+    "menu_action_open_new_window": "Buka dalam Tetingkap Baru",
+    "menu_action_open_private_window": "Buka dalam Tetingkap Peribadi Baru",
+    "menu_action_dismiss": "Abai",
+    "menu_action_delete": "Hapuskan sejarah",
+    "search_for_something_with": "Cari {search_term} dengan:",
+    "search_button": "Cari",
+    "search_header": "{search_engine_name} Cari",
+    "search_web_placeholder": "Cari dalam Web",
+    "search_settings": "Ubah Tetapan Carian",
+    "welcome_title": "Selamat Datang ke tab baru",
+    "welcome_body": "Firefox akan menggunakan ruang ini untuk mempamerkan tandabuku, artikel, video dan halaman yang paling berkaitan dan terkini anda lawati supaya anda boleh mendapatkannya semula dengan mudah.",
+    "welcome_label": "Mengenalpasti Serlahan anda",
+    "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": "Sesuaikan halaman Tab Baru anda",
+    "settings_pane_header": "Keutamaan Tab Baru",
+    "settings_pane_body": "Pilih paparan apabila anda buka tab baru.",
+    "settings_pane_search_header": "Cari",
+    "settings_pane_search_body": "Carian Web dari tab baru anda.",
+    "settings_pane_topsites_header": "Laman Teratas",
+    "settings_pane_topsites_body": "Akses laman web yang paling banyak dilawati.",
+    "settings_pane_topsites_options_showmore": "Papar dua baris",
+    "settings_pane_highlights_header": "Serlahan",
+    "settings_pane_highlights_body": "Papar semula sejarah pelayaran terkini dan tandabuku yang baru diwujudkan.",
+    "settings_pane_done_button": "Siap",
+    "edit_topsites_button_text": "Edit",
+    "edit_topsites_button_label": "Sesuaikan bahagian Laman Teratas anda",
+    "edit_topsites_showmore_button": "Papar selanjutnya",
+    "edit_topsites_showless_button": "Papar minima",
+    "edit_topsites_done_button": "Siap",
+    "edit_topsites_pin_button": "Pin laman ini",
+    "edit_topsites_edit_button": "Edit laman ini",
+    "edit_topsites_dismiss_button": "Buang laman ini"
+  },
+  "my": {},
+  "nb-NO": {
+    "newtab_page_title": "Ny fane",
+    "default_label_loading": "Laster …",
+    "header_top_sites": "Mest besøkte nettsider",
+    "header_highlights": "Høydepunkter",
+    "type_label_visited": "Besøkt",
+    "type_label_bookmarked": "Bokmerket",
+    "type_label_synced": "Synkronisert fra annen enhet",
+    "type_label_open": "Åpne",
+    "type_label_topic": "Emne",
+    "menu_action_bookmark": "Bokmerke",
+    "menu_action_remove_bookmark": "Fjern bokmerke",
+    "menu_action_copy_address": "Kopier adresse",
+    "menu_action_email_link": "Send lenke på e-post …",
+    "menu_action_open_new_window": "Åpne i nytt vindu",
+    "menu_action_open_private_window": "Åpne i nytt privat vindu",
+    "menu_action_dismiss": "Avslå",
+    "menu_action_delete": "Slett fra historikk",
+    "search_for_something_with": "Søk etter {search_term} med:",
+    "search_header": "{search_engine_name}-søk",
+    "search_web_placeholder": "Søk på nettet",
+    "search_settings": "Endre søkeinnstillinger",
+    "welcome_title": "Velkommen til ny fane",
+    "welcome_body": "Firefox vil bruke denne plassen til å vise deg de mest relevante bokmerkene, artiklene, videoene og sidene du nettopp har besøkt, slik at du enkelt kan finne tilbake til de.",
+    "welcome_label": "Identifiserer dine høydepunkter",
+    "time_label_less_than_minute": "<1 m",
+    "time_label_minute": "{number} m",
+    "time_label_hour": "{number} t",
+    "time_label_day": "{number} d"
+  },
+  "ne-NP": {
+    "newtab_page_title": "नयाँ ट्याब",
+    "default_label_loading": "लोड हुदैँछ...",
+    "header_top_sites": "शीर्ष साइटहरु",
+    "header_highlights": "विशेषताहरू",
+    "type_label_visited": "भ्रमण गरिएको",
+    "type_label_bookmarked": "पुस्तकचिनो लागाइएको",
+    "type_label_synced": "अर्को यण्त्रबाट समक्रमण गरिएको",
+    "type_label_open": "खोल्नुहोस्",
+    "type_label_topic": "शीर्षक",
+    "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": "इतिहासबाट मेट्नुहोस्",
+    "search_for_something_with": "{search_term} खोज्न प्रयोग गर्नुहोस्:",
+    "search_header": "{search_engine_name} खोजी",
+    "search_web_placeholder": "वेबमा खोज्नुहोस्",
+    "search_settings": "खोजी सेटिङ परिवर्तन गर्नुहोस्",
+    "welcome_title": "नयाँ ट्याबमा स्वागत छ",
+    "welcome_label": "तपाईँका विशेषताहरु पत्ता लगाउँदै",
+    "time_label_less_than_minute": "< १ मिनेट",
+    "time_label_minute": "{number} मिनेट",
+    "time_label_hour": "{number} घण्टा",
+    "time_label_day": "{number} दिन"
+  },
+  "nl": {
+    "newtab_page_title": "Nieuw tabblad",
+    "default_label_loading": "Laden…",
+    "header_top_sites": "Topwebsites",
+    "header_highlights": "Highlights",
+    "type_label_visited": "Bezocht",
+    "type_label_bookmarked": "Bladwijzer gemaakt",
+    "type_label_synced": "Gesynchroniseerd vanaf ander apparaat",
+    "type_label_open": "Open",
+    "type_label_topic": "Onderwerp",
+    "menu_action_bookmark": "Bladwijzer maken",
+    "menu_action_remove_bookmark": "Bladwijzer verwijderen",
+    "menu_action_copy_address": "Adres kopiëren",
+    "menu_action_email_link": "Koppeling e-mailen…",
+    "menu_action_open_new_window": "Openen in een nieuw venster",
+    "menu_action_open_private_window": "Openen in een nieuw privévenster",
+    "menu_action_dismiss": "Verwijderen",
+    "menu_action_delete": "Verwijderen uit geschiedenis",
+    "search_for_something_with": "Zoeken naar {search_term} met:",
+    "search_button": "Zoeken",
+    "search_header": "{search_engine_name} doorzoeken",
+    "search_web_placeholder": "Zoeken op het web",
+    "search_settings": "Zoekinstellingen wijzigen",
+    "welcome_title": "Welkom bij het nieuwe tabblad",
+    "welcome_body": "Firefox gebruikt deze ruimte om uw meest relevante bladwijzers, artikelen, video’s en pagina’s die u onlangs hebt bezocht weer te geven, zodat u deze eenvoudig kunt terugvinden.",
+    "welcome_label": "Uw highlights aanduiden",
+    "time_label_less_than_minute": "< 1 m",
+    "time_label_minute": "{number} m",
+    "time_label_hour": "{number} u",
+    "time_label_day": "{number} d",
+    "settings_pane_button_label": "Uw Nieuw-tabbladpagina aanpassen",
+    "settings_pane_header": "Nieuw-tabbladvoorkeuren",
+    "settings_pane_body": "Kiezen wat u ziet bij het openen van een nieuw tabblad.",
+    "settings_pane_search_header": "Zoeken",
+    "settings_pane_search_body": "Het web doorzoeken vanaf uw nieuwe tabblad.",
+    "settings_pane_topsites_header": "Topwebsites",
+    "settings_pane_topsites_body": "De websites benaderen die u het vaakst bezoekt.",
+    "settings_pane_topsites_options_showmore": "Twee rijen tonen",
+    "settings_pane_highlights_header": "Highlights",
+    "settings_pane_highlights_body": "Terugkijken naar uw recente navigatiegeschiedenis en nieuw aangemaakte bladwijzers.",
+    "settings_pane_done_button": "Gereed",
+    "edit_topsites_button_text": "Bewerken",
+    "edit_topsites_button_label": "Uw sectie Topwebsites aanpassen",
+    "edit_topsites_showmore_button": "Meer tonen",
+    "edit_topsites_showless_button": "Minder tonen",
+    "edit_topsites_done_button": "Gereed",
+    "edit_topsites_pin_button": "Deze website vastmaken",
+    "edit_topsites_edit_button": "Deze website bewerken",
+    "edit_topsites_dismiss_button": "Deze website verwijderen"
+  },
+  "nn-NO": {
+    "newtab_page_title": "Ny flik",
+    "default_label_loading": "Lastar…",
+    "header_top_sites": "Mest vitja",
+    "header_highlights": "Høgdepunkt",
+    "type_label_visited": "Vitja",
+    "type_label_bookmarked": "Bokmerkte",
+    "type_label_synced": "Synkronisert frå ei anna eining",
+    "type_label_open": "Opna",
+    "type_label_topic": "Emne",
+    "menu_action_bookmark": "Bokmerke",
+    "menu_action_remove_bookmark": "Fjern bokmerke",
+    "menu_action_copy_address": "Kopier adresse",
+    "menu_action_email_link": "E-postlenke…",
+    "menu_action_open_new_window": "Opna i nytt vindauge",
+    "menu_action_open_private_window": "Opna i eit nytt privat vindauge",
+    "menu_action_dismiss": "Avslå",
+    "menu_action_delete": "Slett frå historikk",
+    "search_for_something_with": "Søk etter {search_term} med:",
+    "search_button": "Søk",
+    "search_header": "{search_engine_name}",
+    "search_web_placeholder": "Søk på nettet",
+    "search_settings": "Endra søkjeinnstillingar",
+    "welcome_title": "Velkomen til ny fane",
+    "welcome_body": "Firefox vil bruka denne plassen til å visa deg dei mest relevante bokmerka, artiklane, videoane og sidene du nettopp har vitja, slik at du enkelt kan finna tilbake til dei.",
+    "welcome_label": "Identifiserer høgdepunkta dine",
+    "time_label_less_than_minute": "<1 min.",
+    "time_label_minute": "{number} m",
+    "time_label_hour": "{number} t",
+    "time_label_day": "{number} d",
+    "settings_pane_button_label": "Tilpass sida for Ny fane",
+    "settings_pane_header": "Innstillingar for Ny fane",
+    "settings_pane_body": "Vel kva som skal visast når du opnar ei ny fane.",
+    "settings_pane_search_header": "Søk",
+    "settings_pane_search_body": "Søk på nettet frå den nye fana di.",
+    "settings_pane_topsites_header": "Mest besøkte",
+    "settings_pane_topsites_body": "Tilgang til nettsidene du besøker mest.",
+    "settings_pane_topsites_options_showmore": "Vis to rader",
+    "settings_pane_highlights_header": "Høgdepunkt",
+    "settings_pane_highlights_body": "Sjå tilbake på nyleg nettlesarhistorikk og nyleg oppretta bokmerke.",
+    "settings_pane_done_button": "Ferdig",
+    "edit_topsites_button_text": "Rediger",
+    "edit_topsites_button_label": "Tilpass seksjonen Mest besøkte",
+    "edit_topsites_showmore_button": "Vis meir",
+    "edit_topsites_showless_button": "Vis mindre",
+    "edit_topsites_done_button": "Ferdig",
+    "edit_topsites_pin_button": "Fest sida",
+    "edit_topsites_edit_button": "Rediger denne nettsida",
+    "edit_topsites_dismiss_button": "Avvis denne nettsida"
+  },
+  "or": {},
+  "pa-IN": {
+    "newtab_page_title": "ਨਵੀਂ ਟੈਬ",
+    "default_label_loading": "…ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ",
+    "header_top_sites": "ਸਿਖਰਲੀਆਂ ਸਾਈਟਾਂ",
+    "header_highlights": "ਹਾਈਲਾਈਟ",
+    "type_label_visited": "ਖੋਲ੍ਹੀਆਂ",
+    "type_label_bookmarked": "ਬੁੱਕਮਾਰਕ ਕੀਤੀਆਂ",
+    "type_label_synced": "ਹੋਰ ਡਿਵਾਈਸ ਤੋਂ ਸਿੰਕ ਕੀਤੀਆਂ",
+    "type_label_open": "ਖੋਲ੍ਹੋ",
+    "type_label_topic": "ਵਿਸ਼ੇ",
+    "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": "ਅਤੀਤ ਵਿੱਚੋਂ ਹਟਾਓ",
+    "search_for_something_with": "{search_term} ਨੂੰ ਇਸ ਨਾਲ ਖੋਜੋ:",
+    "search_button": "ਖੋਜੋ",
+    "search_header": "{search_engine_name} ਖੋਜ",
+    "search_web_placeholder": "ਵੈੱਬ ਨੂੰ ਖੋਜੋ",
+    "search_settings": "ਖੋਜ ਸੈਟਿੰਗਾਂ ਨੂੰ ਬਦਲੋ",
+    "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_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": "ਇਸ ਸਾਈਟ ਰੱਦ ਕਰੋ"
+  },
+  "pl": {
+    "newtab_page_title": "Nowa karta",
+    "default_label_loading": "Wczytywanie…",
+    "header_top_sites": "Popularne",
+    "header_highlights": "Wyróżnione",
+    "type_label_visited": "Odwiedzone",
+    "type_label_bookmarked": "Zakładka",
+    "type_label_synced": "Z innego urządzenia",
+    "type_label_open": "Otwarte",
+    "type_label_topic": "Temat",
+    "menu_action_bookmark": "Dodaj zakładkę",
+    "menu_action_remove_bookmark": "Usuń zakładkę",
+    "menu_action_copy_address": "Kopiuj adres",
+    "menu_action_email_link": "Wyślij odnośnik…",
+    "menu_action_open_new_window": "Otwórz w nowym oknie",
+    "menu_action_open_private_window": "Otwórz w nowym oknie prywatnym",
+    "menu_action_dismiss": "Odrzuć",
+    "menu_action_delete": "Usuń z historii",
+    "search_for_something_with": "Szukaj „{search_term}” w:",
+    "search_button": "Szukaj",
+    "search_header": "Wyszukiwanie w {search_engine_name}",
+    "search_web_placeholder": "Szukaj",
+    "search_settings": "Zmień ustawienia wyszukiwania",
+    "welcome_title": "Witamy w nowej karcie",
+    "welcome_body": "W tym miejscu Firefox będzie wyświetlał najciekawsze zakładki, artykuły, filmy i niedawno odwiedzone strony, aby można było do nich łatwo wrócić.",
+    "welcome_label": "Wykrywanie ulubionych treści użytkownika",
+    "time_label_less_than_minute": "<1 min",
+    "time_label_minute": "{number} min",
+    "time_label_hour": "{number} godz.",
+    "time_label_day": "{number} d.",
+    "settings_pane_button_label": "Dostosuj stronę nowej karty",
+    "settings_pane_header": "Preferencje nowej karty",
+    "settings_pane_body": "Wybierz, co widać po otwarciu nowej karty.",
+    "settings_pane_search_header": "Wyszukiwanie",
+    "settings_pane_search_body": "Szukaj w Internecie na nowej karcie.",
+    "settings_pane_topsites_header": "Popularne",
+    "settings_pane_topsites_body": "Otwieraj najczęściej odwiedzane strony.",
+    "settings_pane_topsites_options_showmore": "Dwa rzędy",
+    "settings_pane_highlights_header": "Wyróżnione",
+    "settings_pane_highlights_body": "Przeglądaj historię i nowo dodane zakładki.",
+    "settings_pane_done_button": "Gotowe",
+    "edit_topsites_button_text": "Edytuj",
+    "edit_topsites_button_label": "Dostosuj często odwiedzane strony",
+    "edit_topsites_showmore_button": "Więcej",
+    "edit_topsites_showless_button": "Mniej",
+    "edit_topsites_done_button": "Gotowe",
+    "edit_topsites_pin_button": "Przypnij tę stronę",
+    "edit_topsites_edit_button": "Edytuj tę stronę",
+    "edit_topsites_dismiss_button": "Odrzuć tę stronę"
+  },
+  "pt-BR": {
+    "newtab_page_title": "Nova aba",
+    "default_label_loading": "Carregando…",
+    "header_top_sites": "Sites preferidos",
+    "header_highlights": "Destaques",
+    "type_label_visited": "Visitado",
+    "type_label_bookmarked": "Favorito",
+    "type_label_synced": "Sincronizado a partir de outro dispositivo",
+    "type_label_open": "Abrir",
+    "type_label_topic": "Tópico",
+    "menu_action_bookmark": "Favoritos",
+    "menu_action_remove_bookmark": "Remover favorito",
+    "menu_action_copy_address": "Copiar endereço",
+    "menu_action_email_link": "Enviar link por e-mail…",
+    "menu_action_open_new_window": "Abrir em uma nova janela",
+    "menu_action_open_private_window": "Abrir em uma nova janela privativa",
+    "menu_action_dismiss": "Dispensar",
+    "menu_action_delete": "Excluir do histórico",
+    "search_for_something_with": "Pesquisar por {search_term} com:",
+    "search_button": "Pesquisar",
+    "search_header": "Pesquisa {search_engine_name}",
+    "search_web_placeholder": "Pesquisar na Web",
+    "search_settings": "Alterar configurações de pesquisa",
+    "welcome_title": "Bem-vindo a nova aba",
+    "welcome_body": "O Firefox irá usar este espaço para lhe mostrar os seus favoritos, artigos, vídeos, e páginas mais relevantes que visitou recentemente, para que possa regressar a estes mais facilmente.",
+    "welcome_label": "Identificando seus destaques",
+    "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": "Personalize sua página de nova aba",
+    "settings_pane_header": "Preferências de novas abas",
+    "settings_pane_body": "Escolha o que ver quando abrir uma nova aba.",
+    "settings_pane_search_header": "Pesquisar",
+    "settings_pane_search_body": "Pesquise na Web a partir da sua nova aba.",
+    "settings_pane_topsites_header": "Sites preferidos",
+    "settings_pane_topsites_body": "Acesse os sites que você mais visita.",
+    "settings_pane_topsites_options_showmore": "Mostrar duas linhas",
+    "settings_pane_highlights_header": "Destaques",
+    "settings_pane_highlights_body": "Veja o seu histórico de navegação recente e favoritos recentemente criados.",
+    "settings_pane_done_button": "Concluir",
+    "edit_topsites_button_text": "Editar",
+    "edit_topsites_button_label": "Personalizar a sua seção de sites preferidos",
+    "edit_topsites_showmore_button": "Mostrar mais",
+    "edit_topsites_showless_button": "Mostrar menos",
+    "edit_topsites_done_button": "Concluir",
+    "edit_topsites_pin_button": "Fixar este site",
+    "edit_topsites_edit_button": "Editar este site",
+    "edit_topsites_dismiss_button": "Descartar este site"
+  },
+  "pt-PT": {
+    "newtab_page_title": "Novo separador",
+    "default_label_loading": "A carregar…",
+    "header_top_sites": "Sites mais visitados",
+    "header_highlights": "Destaques",
+    "type_label_visited": "Visitados",
+    "type_label_bookmarked": "Guardados nos marcadores",
+    "type_label_synced": "Sincronizado a partir de outro dispositivo",
+    "type_label_open": "Abertos",
+    "type_label_topic": "Tópico",
+    "menu_action_bookmark": "Adicionar aos marcadores",
+    "menu_action_remove_bookmark": "Remover marcador",
+    "menu_action_copy_address": "Copiar endereço",
+    "menu_action_email_link": "Enviar ligação por email…",
+    "menu_action_open_new_window": "Abrir em nova janela",
+    "menu_action_open_private_window": "Abrir em nova janela privada",
+    "menu_action_dismiss": "Dispensar",
+    "menu_action_delete": "Eliminar do histórico",
+    "search_for_something_with": "Pesquisar por {search_term} com:",
+    "search_button": "Pesquisar",
+    "search_header": "Pesquisa {search_engine_name}",
+    "search_web_placeholder": "Pesquisar na Web",
+    "search_settings": "Alterar definições de pesquisa",
+    "welcome_title": "Bem-vindo ao novo separador",
+    "welcome_body": "O Firefox irá utilizar este espaço para lhe mostrar os seus marcadores, artigos, vídeos, e páginas mais relevantes que visitou recentemente, para que possa regressar a estes mais facilmente.",
+    "welcome_label": "A identificar os seus destaques",
+    "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": "Personalizar a sua página de novo separador",
+    "settings_pane_header": "Novas preferências de separador",
+    "settings_pane_body": "Escolha o que ver quando abre um novo separador.",
+    "settings_pane_search_header": "Pesquisar",
+    "settings_pane_search_body": "Pesquise na Web a partir do seu novo separador.",
+    "settings_pane_topsites_header": "Sites mais visitados",
+    "settings_pane_topsites_body": "Aceda aos websites que mais visita.",
+    "settings_pane_topsites_options_showmore": "Mostrar duas linhas",
+    "settings_pane_highlights_header": "Destaques",
+    "settings_pane_highlights_body": "Veja o seu histórico de navegação recente e marcadores recentemente criados.",
+    "settings_pane_done_button": "Feito",
+    "edit_topsites_button_text": "Editar",
+    "edit_topsites_button_label": "Personalizar a sua secção de sites mais visitados",
+    "edit_topsites_showmore_button": "Mostrar mais",
+    "edit_topsites_showless_button": "Mostrar menos",
+    "edit_topsites_done_button": "Feito",
+    "edit_topsites_pin_button": "Afixar este site",
+    "edit_topsites_edit_button": "Editar este site",
+    "edit_topsites_dismiss_button": "Descartar este site"
+  },
+  "rm": {
+    "newtab_page_title": "Nov tab",
+    "default_label_loading": "Chargiar…",
+    "header_top_sites": "Paginas preferidas",
+    "header_highlights": "Accents",
+    "type_label_visited": "Visità",
+    "type_label_bookmarked": "Cun segnapagina",
+    "type_label_synced": "Sincronisà dad auters apparats",
+    "type_label_open": "Avert",
+    "type_label_topic": "Tema",
+    "menu_action_bookmark": "Marcar sco segnapagina",
+    "menu_action_remove_bookmark": "Allontanar il segnapagina",
+    "menu_action_copy_address": "Copiar l'adressa",
+    "menu_action_email_link": "Trametter la colliaziun per e-mail…",
+    "menu_action_open_new_window": "Avrir en ina nova fanestra",
+    "menu_action_open_private_window": "Avrir en ina nova fanestra privata",
+    "menu_action_dismiss": "Serrar",
+    "menu_action_delete": "Stizzar da la cronologia",
+    "search_for_something_with": "Tschertgar {search_term} cun:",
+    "search_button": "Tschertgar",
+    "search_header": "Tschertga da {search_engine_name}",
+    "search_web_placeholder": "Tschertgar en il Web",
+    "search_settings": "Midar las preferenzas per tschertgar",
+    "welcome_title": "Bainvegni sin in nov tab",
+    "welcome_body": "Firefox utilisescha quest plaz per ta mussar ils segnapaginas, ils artitgels, ils videos e las paginas las pli relevantas che ti has visità dacurt, uschè che ti pos turnar a moda simpla tar quellas.",
+    "welcome_label": "Identifitgar tes accents",
+    "time_label_less_than_minute": "< 1 min",
+    "time_label_minute": "{number} min",
+    "time_label_hour": "{number} uras",
+    "time_label_day": "{number} dis",
+    "settings_pane_button_label": "Persunalisar tia pagina per novs tabs",
+    "settings_pane_header": "Preferenzas per novs tabs",
+    "settings_pane_body": "Tscherna tge che ti vesas sche ti avras in nov tab.",
+    "settings_pane_search_header": "Tschertgar",
+    "settings_pane_search_body": "Tschertgar en l'internet da tes nov tab.",
+    "settings_pane_topsites_header": "Paginas preferidas",
+    "settings_pane_topsites_body": "Acceder las websites che ti visitas il pli savens.",
+    "settings_pane_topsites_options_showmore": "Mussar duas colonnas",
+    "settings_pane_highlights_header": "Accents",
+    "settings_pane_highlights_body": "Dar in sguard enavos sin websites visitadas dacurt e sin segnapaginas creads dacurt.",
+    "settings_pane_done_button": "Finì",
+    "edit_topsites_button_text": "Modifitgar",
+    "edit_topsites_button_label": "Persunalisar la secziun da paginas preferidas",
+    "edit_topsites_showmore_button": "Mussar dapli",
+    "edit_topsites_showless_button": "Mussar pli pauc",
+    "edit_topsites_done_button": "Finì",
+    "edit_topsites_pin_button": "Fixar questa pagina",
+    "edit_topsites_edit_button": "Modifitgar questa pagina",
+    "edit_topsites_dismiss_button": "Allontanar questa pagina"
+  },
+  "ro": {
+    "newtab_page_title": "Filă nouă",
+    "default_label_loading": "Se încarcă…",
+    "header_top_sites": "Site-uri de top",
+    "header_highlights": "Evidențieri",
+    "type_label_visited": "Vizitate",
+    "type_label_bookmarked": "Însemnat",
+    "type_label_synced": "Sincronizat de pe alt dispozitiv",
+    "type_label_open": "Deschise",
+    "type_label_topic": "Subiect",
+    "menu_action_bookmark": "Însemnează",
+    "menu_action_remove_bookmark": "Elimină semnul de carte",
+    "menu_action_copy_address": "Copiază adresa",
+    "menu_action_email_link": "Deschide linkul…",
+    "menu_action_open_new_window": "Deschide într-o fereastră nouă",
+    "menu_action_open_private_window": "Deschide într-o fereastră privată nouă",
+    "menu_action_dismiss": "Înlătură",
+    "menu_action_delete": "Șterge din istoric",
+    "search_for_something_with": "Caută {search_term} cu: ",
+    "search_header": "Căutare {search_engine_name}",
+    "search_web_placeholder": "Caută pe web",
+    "search_settings": "Schimbă setările de căutare",
+    "welcome_title": "Bun venit în noua filă",
+    "welcome_body": "Firefox va folosi acest spațiu pentru a arăta cele mai relevante semne de carte, articole, videouri și pagini vizitate recent pentru a reveni la acestea ușor.",
+    "welcome_label": "Se identifică evidențierile tale",
+    "time_label_less_than_minute": "<1m",
+    "time_label_minute": "{number}m",
+    "time_label_hour": "{number}h",
+    "time_label_day": "{number}d"
+  },
+  "ru": {
+    "newtab_page_title": "Новая вкладка",
+    "default_label_loading": "Загрузка…",
+    "header_top_sites": "Топ сайтов",
+    "header_highlights": "Избранные",
+    "type_label_visited": "Посещено",
+    "type_label_bookmarked": "В закладках",
+    "type_label_synced": "Синхронизировано с другого устройства",
+    "type_label_open": "Открыта",
+    "type_label_topic": "Тема",
+    "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": "Удалить из истории",
+    "search_for_something_with": "Искать {search_term} в:",
+    "search_button": "Искать",
+    "search_header": "Искать в {search_engine_name}",
+    "search_web_placeholder": "Искать в Интернете",
+    "search_settings": "Изменить настройки поиска",
+    "welcome_title": "Добро пожаловать на новую вкладку",
+    "welcome_body": "Firefox будет использовать это место, чтобы отображать самые актуальные закладки, статьи, видео и страницы, которые вы недавно посетили, чтобы вы смогли легко попасть на них снова.",
+    "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_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": "Скрыть этот сайт"
+  },
+  "si": {},
+  "sk": {
+    "newtab_page_title": "Nová karta",
+    "default_label_loading": "Načítava sa…",
+    "header_top_sites": "Top stránky",
+    "header_highlights": "Vybrané stránky",
+    "type_label_visited": "Navštívené",
+    "type_label_bookmarked": "V záložkách",
+    "type_label_synced": "Synchronizované z ďalšieho zariadenia",
+    "type_label_open": "Otvorené",
+    "type_label_topic": "Téma",
+    "menu_action_bookmark": "Pridať medzi záložky",
+    "menu_action_remove_bookmark": "Odstrániť záložku",
+    "menu_action_copy_address": "Kopírovať adresu",
+    "menu_action_email_link": "Odoslať odkaz e-mailom…",
+    "menu_action_open_new_window": "Otvoriť v novom okne",
+    "menu_action_open_private_window": "Otvoriť v novom okne režimu Súkromné prehliadanie",
+    "menu_action_dismiss": "Skryť",
+    "menu_action_delete": "Odstrániť z histórie",
+    "search_for_something_with": "Hľadať {search_term} pomocou:",
+    "search_button": "Hľadať",
+    "search_header": "Vyhľadávanie pomocou {search_engine_name}",
+    "search_web_placeholder": "Vyhľadávanie na webe",
+    "search_settings": "Zmeniť nastavenia vyhľadávania",
+    "welcome_title": "Vitajte na stránke novej karty",
+    "welcome_body": "Firefox bude na tomto mieste zobrazovať často zobrazované záložky, články, videá a stránky, ktoré ste nedávno navštívili. Váš prístup k nim je tak omnoho ľahší.",
+    "welcome_label": "Identifikácia vybraných stránok",
+    "time_label_less_than_minute": "< 1 min",
+    "time_label_minute": "{number} min",
+    "time_label_hour": "{number} hod",
+    "time_label_day": "{number} d",
+    "settings_pane_button_label": "Prispôsobte si svoju stránku Nová karta",
+    "settings_pane_header": "Nastavenia Novej karty",
+    "settings_pane_body": "Vyberte si, čo chcete vidieť keď otvoríte novú kartu.",
+    "settings_pane_search_header": "Vyhľadávanie",
+    "settings_pane_search_body": "Vyhľadávanie zo stránky novej karty.",
+    "settings_pane_topsites_header": "Top stránky",
+    "settings_pane_topsites_body": "Prístup k webovým stránkam, ktoré navštevujete najčastejšie.",
+    "settings_pane_topsites_options_showmore": "Zobraziť dva riadky",
+    "settings_pane_highlights_header": "Vybrané stránky",
+    "settings_pane_highlights_body": "Pozrite sa na vašu nedávnu históriu prehliadania a na novovytvorené záložky.",
+    "settings_pane_done_button": "Hotovo",
+    "edit_topsites_button_text": "Upraviť",
+    "edit_topsites_button_label": "Upravte sekciu Top stránky",
+    "edit_topsites_showmore_button": "Zobraziť viac",
+    "edit_topsites_showless_button": "Zobraziť menej",
+    "edit_topsites_done_button": "Hotovo",
+    "edit_topsites_pin_button": "Pripnúť túto stránku",
+    "edit_topsites_edit_button": "Upraviť túto stránku",
+    "edit_topsites_dismiss_button": "Odstrániť túto stránku"
+  },
+  "sl": {
+    "newtab_page_title": "Nov zavihek",
+    "default_label_loading": "Nalaganje …",
+    "header_top_sites": "Glavne strani",
+    "header_highlights": "Poudarki",
+    "type_label_visited": "Obiskano",
+    "type_label_bookmarked": "Med zaznamki",
+    "type_label_synced": "Sinhronizirano z druge naprave",
+    "type_label_open": "Odpri",
+    "type_label_topic": "Tema",
+    "menu_action_bookmark": "Dodaj med zaznamke",
+    "menu_action_remove_bookmark": "Odstrani zaznamek",
+    "menu_action_copy_address": "Kopiraj naslov",
+    "menu_action_email_link": "Pošlji povezavo po e-pošti …",
+    "menu_action_open_new_window": "Odpri v novem oknu",
+    "menu_action_open_private_window": "Odpri v novem zasebnem oknu",
+    "menu_action_dismiss": "Opusti",
+    "menu_action_delete": "Izbriši iz zgodovine",
+    "search_for_something_with": "Išči \"{search_term}\" z iskalnikom:",
+    "search_button": "Iskanje",
+    "search_header": "Iskanje {search_engine_name}",
+    "search_web_placeholder": "Iskanje po spletu",
+    "search_settings": "Spremeni nastavitve iskanja",
+    "welcome_title": "Dobrodošli v novem zavihku",
+    "welcome_body": "Na tem prostoru bo Firefox prikazoval najustreznejše zaznamke, članke, videoposnetke in nedavno obiskane strani, tako da jih lahko pozneje znova hitro najdete.",
+    "welcome_label": "Zbiranje poudarkov",
+    "time_label_less_than_minute": "<1 min",
+    "time_label_minute": "{number} min",
+    "time_label_hour": "{number} ur",
+    "time_label_day": "{number} dni",
+    "settings_pane_button_label": "Prilagodite stran novega zavihka",
+    "settings_pane_header": "Nastavitve novega zavihka",
+    "settings_pane_body": "Izberite, kaj naj se prikaže, ko odprete nov zavihek.",
+    "settings_pane_search_header": "Išči",
+    "settings_pane_search_body": "Iščite po spletu s strani novega zavihka.",
+    "settings_pane_topsites_header": "Glavne strani",
+    "settings_pane_topsites_body": "Priročen dostop do najbolj obiskanih strani.",
+    "settings_pane_topsites_options_showmore": "Prikaži dve vrsti",
+    "settings_pane_highlights_header": "Poudarki",
+    "settings_pane_highlights_body": "Pogled nazaj na nedavno zgodovino brskanja in novo ustvarjene zaznamke.",
+    "settings_pane_done_button": "Končano",
+    "edit_topsites_button_text": "Uredi",
+    "edit_topsites_button_label": "Prilagodite odsek Glavne strani",
+    "edit_topsites_showmore_button": "Prikaži več",
+    "edit_topsites_showless_button": "Prikaži manj",
+    "edit_topsites_done_button": "Končano",
+    "edit_topsites_pin_button": "Pripni to stran",
+    "edit_topsites_edit_button": "Uredi to stran",
+    "edit_topsites_dismiss_button": "Odstrani to stran"
+  },
+  "son": {},
+  "sq": {
+    "newtab_page_title": "Skedë e Re",
+    "default_label_loading": "Po ngarkohet…",
+    "header_top_sites": "Sajte Kryesues",
+    "header_highlights": "Highlights",
+    "type_label_visited": "Të vizituara",
+    "type_label_bookmarked": "Të faqeruajtura",
+    "type_label_synced": "Njëkohësuar prej pajisjeje tjetër",
+    "type_label_open": "Hape",
+    "type_label_topic": "Temë",
+    "menu_action_bookmark": "Faqerojtës",
+    "menu_action_remove_bookmark": "Hiqe Faqerojtësin",
+    "menu_action_copy_address": "Kopjoje Adresën",
+    "menu_action_email_link": "Dërgoni Lidhje me Email…",
+    "menu_action_open_new_window": "Hape në Dritare të Re",
+    "menu_action_open_private_window": "Hape në Dritare të Re Private",
+    "menu_action_dismiss": "Hidhe tej",
+    "menu_action_delete": "Fshije prej Historiku",
+    "search_for_something_with": "Kërko për {search_term} me:",
+    "search_header": "Kërkim me {search_engine_name}",
+    "search_web_placeholder": "Kërkoni në Web",
+    "search_settings": "Ndryshoji Rregullimet e Kërkimit",
+    "welcome_title": "Mirë se vini te skedë e re",
+    "welcome_body": "Firefox-i do ta përdorë këtë hapësirë për t’ju shfaqur faqerojtësit, artikujt, videot dhe faqet më me peshë që keni vizituar së fundi, që kështu të mund të ktheheni lehtë në to.",
+    "welcome_label": "Po identifikohen Highlights tuaj",
+    "time_label_less_than_minute": "<1m",
+    "time_label_minute": "{number}m",
+    "time_label_hour": "{number}h",
+    "time_label_day": "{number}d"
+  },
+  "sr": {
+    "newtab_page_title": "Нови језичак",
+    "default_label_loading": "Учитавање…",
+    "header_top_sites": "Популарни сајтови",
+    "header_highlights": "Истакнути",
+    "type_label_visited": "Посећене",
+    "type_label_bookmarked": "Забележено",
+    "type_label_synced": "Синхронизовано са другог уређаја",
+    "type_label_open": "Отвори",
+    "type_label_topic": "Тема",
+    "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": "Уклони из историјата",
+    "search_for_something_with": "Претражите {search_term} са:",
+    "search_button": "Претражи",
+    "search_header": "{search_engine_name} претрага",
+    "search_web_placeholder": "Претражујте веб",
+    "search_settings": "Измените подешавања претраге",
+    "welcome_title": "Добродошли на нови језичак",
+    "welcome_body": "Firefox ће користити овај простор да вам приказује најрелевантне језичке, чланке, видео клипове и странице које сте недавно посетили, како бисте им се лако могли вратити.",
+    "welcome_label": "Учитавам ваше истакнуте ставке",
+    "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": "Прилагодите страницу новог језичка",
+    "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_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": "Одбаци овај сајт"
+  },
+  "sv-SE": {
+    "newtab_page_title": "Ny flik",
+    "default_label_loading": "Laddar…",
+    "header_top_sites": "Mest besökta",
+    "header_highlights": "Höjdpunkter",
+    "type_label_visited": "Besökta",
+    "type_label_bookmarked": "Bokmärkta",
+    "type_label_synced": "Synkroniserade från en annan enhet",
+    "type_label_open": "Öppna",
+    "type_label_topic": "Ämne",
+    "menu_action_bookmark": "Bokmärke",
+    "menu_action_remove_bookmark": "Ta bort bokmärke",
+    "menu_action_copy_address": "Kopiera adress",
+    "menu_action_email_link": "E-posta länk…",
+    "menu_action_open_new_window": "Öppna i nytt fönster",
+    "menu_action_open_private_window": "Öppna i nytt privat fönster",
+    "menu_action_dismiss": "Avfärda",
+    "menu_action_delete": "Ta bort från historik",
+    "search_for_something_with": "Sök efter {search_term} med:",
+    "search_button": "Sök",
+    "search_header": "{search_engine_name}",
+    "search_web_placeholder": "Sök på webben",
+    "search_settings": "Ändra sökinställningar",
+    "welcome_title": "Välkommen till ny flik",
+    "welcome_body": "Firefox kommer att använda detta utrymme för att visa dina mest relevanta bokmärken, artiklar, videor och sidor du nyligen besökt, så du kan hitta dem lätt.",
+    "welcome_label": "Identifierar dina höjdpunkter",
+    "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": "Anpassa sidan för Ny flik",
+    "settings_pane_header": "Inställningar Ny flik",
+    "settings_pane_body": "Välj vad som ska visas när du öppnar en ny flik.",
+    "settings_pane_search_header": "Sök",
+    "settings_pane_search_body": "Sök på webben från din nya flik.",
+    "settings_pane_topsites_header": "Mest besökta",
+    "settings_pane_topsites_body": "Åtkomst till de webbplatser du besökt mest.",
+    "settings_pane_topsites_options_showmore": "Visa två rader",
+    "settings_pane_highlights_header": "Höjdpunkter",
+    "settings_pane_highlights_body": "Titta tillbaka på din senaste webbhistorik och nyskapade bokmärken.",
+    "settings_pane_done_button": "Klar",
+    "edit_topsites_button_text": "Redigera",
+    "edit_topsites_button_label": "Anpassa avsnittet Mest besökta",
+    "edit_topsites_showmore_button": "Visa mer",
+    "edit_topsites_showless_button": "Visa mindre",
+    "edit_topsites_done_button": "Klar",
+    "edit_topsites_pin_button": "Fäst denna webbplats",
+    "edit_topsites_edit_button": "Redigera denna webbplats",
+    "edit_topsites_dismiss_button": "Avfärda denna webbplats"
+  },
+  "ta": {},
+  "ta-LK": {},
+  "te": {
+    "newtab_page_title": "కొత్త ట్యాబు",
+    "default_label_loading": "వస్తోంది…",
+    "header_top_sites": "మేటి సైట్లు",
+    "header_highlights": "ముఖ్యాంశాలు",
+    "type_label_visited": "సందర్శించినవి",
+    "type_label_bookmarked": "ఇష్టాంశము చేయబడినది",
+    "type_label_synced": "మరో పరికరం నుంచి సమకాలీకరించి తెచ్చుకున్నవి",
+    "type_label_open": "తెరువు",
+    "type_label_topic": "విషయం",
+    "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": "చరిత్ర నుంచి తీసివేయి",
+    "search_for_something_with": "{search_term} కోసం దీని సాయంతో వెతుకు:",
+    "search_header": "{search_engine_name} శోధన",
+    "search_web_placeholder": "వెబ్ లో వెతకండి",
+    "search_settings": "శోధన అమరికలు మార్చు",
+    "welcome_title": "కొత్త ట్యాబుకు స్వాగతం",
+    "welcome_body": "సముచితమైన మీ ఇష్టాంశాలను, వ్యాసాలను, వీడియోలను, ఇంకా మీరు ఇటీవలే చూసిన పేజీలను మీకు తేలిగ్గా అందుబాటులో ఉంచేందుకు Firefox ఈ జాగాని వాడుకుంటుంది.",
+    "welcome_label": "మీ ముఖ్యాంశాలను గుర్తిస్తున్నది",
+    "time_label_less_than_minute": "<1ని",
+    "time_label_minute": "{number}ని",
+    "time_label_hour": "{number}గం",
+    "time_label_day": "{number}రో"
+  },
+  "th": {
+    "newtab_page_title": "แท็บใหม่",
+    "default_label_loading": "กำลังโหลด…",
+    "header_top_sites": "ไซต์เด่น",
+    "header_highlights": "รายการเด่น",
+    "type_label_visited": "เยี่ยมชมแล้ว",
+    "type_label_bookmarked": "คั่นหน้าแล้ว",
+    "type_label_synced": "ซิงค์จากอุปกรณ์อื่น",
+    "type_label_open": "เปิด",
+    "type_label_topic": "หัวข้อ",
+    "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": "ลบออกจากประวัติ",
+    "search_for_something_with": "ค้นหาสำหรับ {search_term} ด้วย:",
+    "search_button": "ค้นหา",
+    "search_header": "ค้นหา {search_engine_name}",
+    "search_web_placeholder": "ค้นหาเว็บ",
+    "search_settings": "เปลี่ยนการตั้งค่าการค้นหา",
+    "welcome_title": "ยินดีต้อนรับสู่แท็บใหม่",
+    "welcome_body": "Firefox จะใช้พื้นที่นี้เพื่อแสดงที่คั่นหน้า, บทความ, วิดีโอ และหน้าที่คุณเพิ่งเยี่ยมชมที่เกี่ยวข้องกับคุณมากที่สุด เพื่อให้คุณสามารถกลับมาชมได้อย่างง่ายดาย",
+    "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_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": "ไม่สนใจไซต์นี้"
+  },
+  "tl": {
+    "newtab_page_title": "Bagong Tab",
+    "default_label_loading": "Pagkarga…",
+    "header_top_sites": "Tuktok na mga Site",
+    "header_highlights": "Highlights",
+    "type_label_visited": "Binisita",
+    "type_label_bookmarked": "Bookmarked",
+    "type_label_synced": "Naka-sync mula sa ibang kagamitan",
+    "type_label_open": "Bukas",
+    "type_label_topic": "Topiko",
+    "menu_action_bookmark": "Bookmark",
+    "menu_action_remove_bookmark": "Alisin ang Bookmark",
+    "menu_action_copy_address": "Kopyahin ang Address",
+    "menu_action_email_link": "Email Link…",
+    "menu_action_open_new_window": "Buksan sa isang Bagong Window",
+    "menu_action_open_private_window": "Buksan sa isang Pribadong Bago na Window",
+    "menu_action_dismiss": "Paalisin",
+    "menu_action_delete": "Tanggalin mula History",
+    "search_for_something_with": "Maghanap ng mga {search_term} na may:",
+    "search_button": "Hanapin",
+    "search_header": "{search_engine_name} Hanapin",
+    "search_web_placeholder": "Hanapin sa Web",
+    "search_settings": "Baguhin ang mga Setting ng Paghahanap",
+    "welcome_title": "Maligayang pagdating sa bagong tab",
+    "welcome_body": "Firefox ay gagamit ng puwang upang ipakita ang iyong mga pinaka-kaugnay na bookmark, artikulo, video, at mga pahina ng kamakailan na iyong binisita, kaya maaari kang bumalik sa mga ito ng madali.",
+    "welcome_label": "Ang pagkilala sa iyong Highlights",
+    "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": "I-customize ang iyong pahina ng Bagong Tab",
+    "settings_pane_header": "Bagong Kagustuhan na Tab",
+    "settings_pane_body": "Piliin kung ano ang makikita mo kapag binuksan mo ang isang bagong tab.",
+    "settings_pane_search_header": "Paghahanap",
+    "settings_pane_search_body": "Hanapin sa Web mula sa iyong bagong tab.",
+    "settings_pane_topsites_header": "Tuktok na mga Site",
+    "settings_pane_topsites_body": "Ma-access ang mga website na karamihang binibisita.",
+    "settings_pane_topsites_options_showmore": "Ipakita ang dalawang mga hanay",
+    "settings_pane_highlights_header": "Highlights",
+    "settings_pane_highlights_body": "Titingnan mo ang iyong kamakailang kasaysayan ng pagba-browse at nilikhang bagong bookmark.",
+    "settings_pane_done_button": "Tapos",
+    "edit_topsites_button_text": "I-edit",
+    "edit_topsites_button_label": "I-customize ang iyong Tuktok na mga seksyon ng Sites",
+    "edit_topsites_showmore_button": "Magpakita ng higit pa",
+    "edit_topsites_showless_button": "Magpakita ng mas kaunti",
+    "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_highlights": "Öne Çıkanlar",
+    "type_label_visited": "Ziyaret edildi",
+    "type_label_bookmarked": "Yer imlerine eklendi",
+    "type_label_synced": "Başka bir cihazdan eşitlendi",
+    "type_label_open": "Açık",
+    "type_label_topic": "Konu",
+    "menu_action_bookmark": "Yer imlerine ekle",
+    "menu_action_remove_bookmark": "Yer imini sil",
+    "menu_action_copy_address": "Adresi kopyala",
+    "menu_action_email_link": "Bağlantıyı e-postayla gönder…",
+    "menu_action_open_new_window": "Yeni pencerede aç",
+    "menu_action_open_private_window": "Yeni gizli pencerede aç",
+    "menu_action_dismiss": "Kapat",
+    "menu_action_delete": "Geçmişten sil",
+    "search_for_something_with": "{search_term} terimini şununla ara:",
+    "search_button": "Ara",
+    "search_header": "{search_engine_name} Araması",
+    "search_web_placeholder": "Web'de ara",
+    "search_settings": "Arama ayarlarını değiştir",
+    "welcome_title": "Yeni sekmeye hoş geldiniz",
+    "welcome_body": "Firefox son zamanlarda ziyaret ettiğiniz ve sık kullandığınız yer imlerini, makaleleri, videoları ve sayfaları onlara tekrar kolayca geri dönebilmeniz için bu alanda gösterecektir.",
+    "welcome_label": "Öne Çıkanlar'ınızı tanıyın",
+    "time_label_less_than_minute": "<1 dk",
+    "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_body": "Yeni bir sekme açtığınızda neleri göreceğinizi 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_body": "En sık ziyaret ettiğiniz web sitelerine erişin.",
+    "settings_pane_topsites_options_showmore": "İki satır göster",
+    "settings_pane_highlights_header": "Öne Çıkanlar",
+    "settings_pane_highlights_body": "Yakın zamandaki gezinti geçmişinize ve yeni eklediğiniz yer imlerine göz atın.",
+    "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_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_edit_button": "Bu siteyi düzenle",
+    "edit_topsites_dismiss_button": "Bu siteyi görmezden gel"
+  },
+  "uk": {
+    "newtab_page_title": "Нова вкладка",
+    "default_label_loading": "Завантаження…",
+    "header_top_sites": "Популярні сайти",
+    "header_highlights": "Обране",
+    "type_label_visited": "Відвідано",
+    "type_label_bookmarked": "Закладено",
+    "type_label_synced": "Синхронізовано з іншого пристрою",
+    "type_label_open": "Відкрито",
+    "type_label_topic": "Тема",
+    "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": "Видалити з історії",
+    "search_for_something_with": "Шукати {search_term} з:",
+    "search_button": "Пошук",
+    "search_header": "Шукати з {search_engine_name}",
+    "search_web_placeholder": "Пошук в Інтернеті",
+    "search_settings": "Змінити налаштування пошуку",
+    "welcome_title": "Вітаємо на новій вкладці",
+    "welcome_body": "Firefox буде використовувати її для показу найважливіших закладок, статей, відео, а також нещодавно відвіданих сторінок, щоб ви могли з легкістю повернутися до них.",
+    "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_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": "Відхилити цей сайт"
+  },
+  "ur": {
+    "newtab_page_title": "نیا ٹیب",
+    "default_label_loading": "لوڈ کر رہا ہے…",
+    "header_top_sites": "بہترین سائٹیں",
+    "header_highlights": "شہ سرخياں",
+    "type_label_visited": "دورہ شدہ",
+    "type_label_bookmarked": "نشان شدہ",
+    "type_label_synced": "کسی دوسرے آلے سے ہمہ وقت ساز کیا گیا ہے",
+    "type_label_open": "کھولیں",
+    "type_label_topic": "عنوان",
+    "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": "تاریخ سے حذف کریں",
+    "search_for_something_with": "ساتھ {search_term} کے لئے تلاش کریں:",
+    "search_button": "تلاش",
+    "search_header": "{search_engine_name} پر تلاش کریں",
+    "search_web_placeholder": "ويب پر تلاش کريں",
+    "search_settings": "تلاش  کی سیٹکگیں تبدیل کریں",
+    "welcome_title": "نئے ٹیب میں خوش آمدید",
+    "welcome_body": "اس جگہ کا استعمال کرنے ہوئے Firefox آپکی متعلقہ نشانیاں، عبارات، وڈیوز اور صفحات جن کا حال ہی میں ص آُپ نے دورہ کیا ہے دکھائے گا۔ تاکہ آپ ان تک واپس آسانی سے پہنچ سکیں۔",
+    "welcome_label": "آپکی جھلکیوں کی نشاندہی کر رہا ہے",
+    "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": "اپنے نئے ٹیب کہ صفحہ کی تخصیص کریں",
+    "settings_pane_search_header": "تلاش",
+    "settings_pane_search_body": "اپنے نئے ٹیب سے وہب پر تلاش کریں۔",
+    "settings_pane_topsites_header": "بہترین سائٹیں",
+    "settings_pane_topsites_options_showmore": "دو قطاریں دکھائیں",
+    "settings_pane_highlights_header": "شہ سرخياں",
+    "settings_pane_done_button": "ہوگیا",
+    "edit_topsites_button_text": "تدوین",
+    "edit_topsites_done_button": "ہوگیا",
+    "edit_topsites_edit_button": "اس سائٹ کی تدوین کریں",
+    "edit_topsites_dismiss_button": "اس سائٹ کو برخاست کریں"
+  },
+  "uz": {},
+  "vi": {},
+  "wo": {},
+  "xh": {},
+  "zh-CN": {
+    "newtab_page_title": "新标签页",
+    "default_label_loading": "载入中…",
+    "header_top_sites": "常用网站",
+    "header_highlights": "集锦",
+    "type_label_visited": "访问过",
+    "type_label_bookmarked": "加了书签",
+    "type_label_synced": "从其他设备同步过来的",
+    "type_label_open": "打开",
+    "type_label_topic": "主题",
+    "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": "从历史记录中删除",
+    "search_for_something_with": "搜索 {search_term},使用:",
+    "search_button": "搜索",
+    "search_header": "{search_engine_name} 搜索",
+    "search_web_placeholder": "在网络上搜索",
+    "search_settings": "更改搜索设置",
+    "welcome_title": "欢迎使用新标签页",
+    "welcome_body": "Firefox 会在这里显示对您最有用的书签、文章、视频和访问过的页面,便于您回到这些网站。",
+    "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_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": "隐藏此网站"
+  },
+  "zh-TW": {
+    "newtab_page_title": "新分頁",
+    "default_label_loading": "載入中…",
+    "header_top_sites": "熱門網站",
+    "header_highlights": "精選網站",
+    "type_label_visited": "造訪過的網站",
+    "type_label_bookmarked": "已加入書籤",
+    "type_label_synced": "從其他裝置同步過來",
+    "type_label_open": "開啟",
+    "type_label_topic": "主題",
+    "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": "從瀏覽紀錄刪除",
+    "search_for_something_with": "搜尋 {search_term} 使用:",
+    "search_button": "搜尋",
+    "search_header": "{search_engine_name} 搜尋",
+    "search_web_placeholder": "搜尋 Web",
+    "search_settings": "變更搜尋選項",
+    "welcome_title": "歡迎來到新分頁",
+    "welcome_body": "Firefox 會使用此空間來顯示與您最相關的書籤、文章、影片以及您最近造訪的頁面,這樣您就可以快速回到這些網站。",
+    "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_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": "忽略此網站"
+  },
+  "zu": {}
+}
\ No newline at end of file
--- a/browser/extensions/activity-stream/jar.mn
+++ b/browser/extensions/activity-stream/jar.mn
@@ -4,11 +4,12 @@
 
 [features/activity-stream@mozilla.org] chrome.jar:
 % resource activity-stream %content/
   content/lib/ (./lib/*)
   content/common/ (./common/*)
   content/vendor/Redux.jsm (./vendor/Redux.jsm)
   content/vendor/react.js (./vendor/react.js)
   content/vendor/react-dom.js (./vendor/react-dom.js)
+  content/vendor/react-intl.js (./vendor/react-intl.js)
   content/vendor/redux.js (./vendor/redux.js)
   content/vendor/react-redux.js (./vendor/react-redux.js)
   content/data/ (./data/*)
--- a/browser/extensions/activity-stream/lib/ActivityStream.jsm
+++ b/browser/extensions/activity-stream/lib/ActivityStream.jsm
@@ -1,61 +1,77 @@
 /* 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/. */
-/* globals XPCOMUtils, NewTabInit, TopSitesFeed, SearchFeed */
-
+/* globals LocalizationFeed, NewTabInit, SearchFeed, TelemetryFeed, TopSitesFeed, XPCOMUtils */
 "use strict";
 
 const {utils: Cu} = Components;
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 const {Store} = Cu.import("resource://activity-stream/lib/Store.jsm", {});
 const {actionTypes: at} = Cu.import("resource://activity-stream/common/Actions.jsm", {});
 
 // Feeds
+XPCOMUtils.defineLazyModuleGetter(this, "LocalizationFeed",
+  "resource://activity-stream/lib/LocalizationFeed.jsm");
+
 XPCOMUtils.defineLazyModuleGetter(this, "NewTabInit",
   "resource://activity-stream/lib/NewTabInit.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesFeed",
+  "resource://activity-stream/lib/PlacesFeed.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "SearchFeed",
+  "resource://activity-stream/lib/SearchFeed.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "TelemetryFeed",
+  "resource://activity-stream/lib/TelemetryFeed.jsm");
+
 XPCOMUtils.defineLazyModuleGetter(this, "TopSitesFeed",
   "resource://activity-stream/lib/TopSitesFeed.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "SearchFeed",
-  "resource://activity-stream/lib/SearchFeed.jsm");
 
 const feeds = {
   // When you add a feed here:
   // 1. The key in this object should directly refer to a pref, not including the
   //    prefix (so "feeds.newtabinit" refers to the
   //    "browser.newtabpage.activity-stream.feeds.newtabinit" pref)
   // 2. The value should be a function that returns a feed.
   // 3. You should use XPCOMUtils.defineLazyModuleGetter to import the Feed,
   //    so it isn't loaded until the feed is enabled.
+  "feeds.localization": () => new LocalizationFeed(),
   "feeds.newtabinit": () => new NewTabInit(),
-  "feeds.topsites": () => new TopSitesFeed(),
-  "feeds.search": () => new SearchFeed()
+  "feeds.places": () => new PlacesFeed(),
+  "feeds.search": () => new SearchFeed(),
+  "feeds.telemetry": () => new TelemetryFeed(),
+  "feeds.topsites": () => new TopSitesFeed()
 };
 
 this.ActivityStream = class ActivityStream {
 
   /**
    * constructor - Initializes an instance of ActivityStream
    *
    * @param  {object} options Options for the ActivityStream instance
    * @param  {string} options.id Add-on ID. e.g. "activity-stream@mozilla.org".
    * @param  {string} options.version Version of the add-on. e.g. "0.1.0"
    * @param  {string} options.newTabURL URL of New Tab page on which A.S. is displayed. e.g. "about:newtab"
    */
-  constructor(options) {
+  constructor(options = {}) {
     this.initialized = false;
     this.options = options;
     this.store = new Store();
     this.feeds = feeds;
   }
   init() {
     this.initialized = true;
     this.store.init(this.feeds);
-    this.store.dispatch({type: at.INIT});
+    this.store.dispatch({
+      type: at.INIT,
+      data: {version: this.options.version}
+    });
   }
   uninit() {
     this.store.dispatch({type: at.UNINIT});
     this.store.uninit();
     this.initialized = false;
   }
 };
 
--- a/browser/extensions/activity-stream/lib/ActivityStreamMessageChannel.jsm
+++ b/browser/extensions/activity-stream/lib/ActivityStreamMessageChannel.jsm
@@ -84,17 +84,17 @@ this.ActivityStreamMessageChannel = clas
 
   /**
    * onActionFromContent - Handler for actions from a content processes
    *
    * @param  {object} action  A Redux action
    * @param  {string} targetId The portID of the port that sent the message
    */
   onActionFromContent(action, targetId) {
-    this.dispatch(ac.SendToMain(action, {fromTarget: targetId}));
+    this.dispatch(ac.SendToMain(action, targetId));
   }
 
   /**
    * broadcast - Sends an action to all ports
    *
    * @param  {object} action A Redux action
    */
   broadcast(action) {
@@ -191,12 +191,12 @@ this.ActivityStreamMessageChannel = clas
     }
     let action = {};
     Object.assign(action, msg.data);
     // target is used to access a browser reference that came from the content
     // and should only be used in feeds (not reducers)
     action._target = msg.target;
     this.onActionFromContent(action, portID);
   }
-}
+};
 
 this.DEFAULT_OPTIONS = DEFAULT_OPTIONS;
 this.EXPORTED_SYMBOLS = ["ActivityStreamMessageChannel", "DEFAULT_OPTIONS"];
new file mode 100644
--- /dev/null
+++ b/browser/extensions/activity-stream/lib/LocalizationFeed.jsm
@@ -0,0 +1,74 @@
+/* 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/. */
+ /* globals Services, XPCOMUtils */
+"use strict";
+
+const {utils: Cu} = Components;
+const {actionTypes: at, actionCreators: ac} = Cu.import("resource://activity-stream/common/Actions.jsm", {});
+
+Cu.importGlobalProperties(["fetch"]);
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "Services",
+  "resource://gre/modules/Services.jsm");
+
+// What is our default locale for the app?
+const DEFAULT_LOCALE = "en-US";
+// Event from LocaleService when locales are assigned
+const LOCALES_CHANGE_TOPIC = "intl:requested-locales-changed";
+// Where is the packaged locales json with all strings?
+const LOCALES_FILE = "resource://activity-stream/data/locales.json";
+
+this.LocalizationFeed = class LocalizationFeed {
+  async init() {
+    Services.obs.addObserver(this, LOCALES_CHANGE_TOPIC);
+
+    let response = await fetch(LOCALES_FILE);
+    this.allStrings = await response.json();
+
+    this.updateLocale();
+  }
+  uninit() {
+    Services.obs.removeObserver(this, LOCALES_CHANGE_TOPIC);
+  }
+
+  updateLocale() {
+    let locale = Services.locale.getRequestedLocale() || DEFAULT_LOCALE;
+    let strings = this.allStrings[locale];
+
+    // Use the default strings for any that are missing
+    if (locale !== DEFAULT_LOCALE) {
+      strings = Object.assign({}, this.allStrings[DEFAULT_LOCALE], strings || {});
+    }
+
+    this.store.dispatch(ac.BroadcastToContent({
+      type: at.LOCALE_UPDATED,
+      data: {
+        locale,
+        strings
+      }
+    }));
+  }
+
+  observe(subject, topic, data) {
+    switch (topic) {
+      case LOCALES_CHANGE_TOPIC:
+        this.updateLocale();
+        break;
+    }
+  }
+
+  onAction(action) {
+    switch (action.type) {
+      case at.INIT:
+        this.init();
+        break;
+      case at.UNINIT:
+        this.uninit();
+        break;
+    }
+  }
+};
+
+this.EXPORTED_SYMBOLS = ["LocalizationFeed"];
new file mode 100644
--- /dev/null
+++ b/browser/extensions/activity-stream/lib/PlacesFeed.jsm
@@ -0,0 +1,213 @@
+/* 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/. */
+ /* globals ContentSearch, XPCOMUtils, PlacesUtils, NewTabUtils, Services */
+"use strict";
+
+const {utils: Cu, interfaces: Ci} = Components;
+const {actionTypes: at, actionCreators: ac} = Cu.import("resource://activity-stream/common/Actions.jsm", {});
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
+  "resource://gre/modules/NewTabUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
+  "resource://gre/modules/PlacesUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Services",
+  "resource://gre/modules/Services.jsm");
+
+const LINK_BLOCKED_EVENT = "newtab-linkBlocked";
+
+/**
+ * Observer - a wrapper around history/bookmark observers to add the QueryInterface.
+ */
+class Observer {
+  constructor(dispatch, observerInterface) {
+    this.dispatch = dispatch;
+    this.QueryInterface = XPCOMUtils.generateQI([observerInterface, Ci.nsISupportsWeakReference]);
+  }
+}
+
+/**
+ * HistoryObserver - observes events from PlacesUtils.history
+ */
+class HistoryObserver extends Observer {
+  constructor(dispatch) {
+    super(dispatch, Ci.nsINavHistoryObserver);
+  }
+
+  /**
+   * onDeleteURI - Called when an link is deleted from history.
+   *
+   * @param  {obj} uri        A URI object representing the link's url
+   *         {str} uri.spec   The URI as a string
+   */
+  onDeleteURI(uri) {
+    this.dispatch({
+      type: at.PLACES_LINK_DELETED,
+      data: {url: uri.spec}
+    });
+  }
+
+  /**
+   * onClearHistory - Called when the user clears their entire history.
+   */
+  onClearHistory() {
+    this.dispatch({type: at.PLACES_HISTORY_CLEARED});
+  }
+}
+
+/**
+ * BookmarksObserver - observes events from PlacesUtils.bookmarks
+ */
+class BookmarksObserver extends Observer {
+  constructor(dispatch) {
+    super(dispatch, Ci.nsINavBookmarkObserver);
+  }
+
+  /**
+   * onItemAdded - Called when a bookmark is added
+   *
+   * @param  {str} id
+   * @param  {str} folderId
+   * @param  {int} index
+   * @param  {int} type       Indicates if the bookmark is an actual bookmark,
+   *                          a folder, or a separator.
+   * @param  {str} uri
+   * @param  {str} title
+   * @param  {int} dateAdded
+   * @param  {str} guid      The unique id of the bookmark
+   */
+  async onItemAdded(...args) {
+    const type = args[3];
+    const guid = args[7];
+    if (type !== PlacesUtils.bookmarks.TYPE_BOOKMARK) {
+      return;
+    }
+    try {
+      // bookmark: {bookmarkGuid, bookmarkTitle, lastModified, url}
+      const bookmark = await NewTabUtils.activityStreamProvider.getBookmark(guid);
+      this.dispatch({type: at.PLACES_BOOKMARK_ADDED, data: bookmark});
+    } catch (e) {
+      Cu.reportError(e);
+    }
+  }
+
+  /**
+   * onItemRemoved - Called when a bookmark is removed
+   *
+   * @param  {str} id
+   * @param  {str} folderId
+   * @param  {int} index
+   * @param  {int} type       Indicates if the bookmark is an actual bookmark,
+   *                          a folder, or a separator.
+   * @param  {str} uri
+   * @param  {str} guid      The unique id of the bookmark
+   */
+  onItemRemoved(id, folderId, index, type, uri, guid) {
+    if (type === PlacesUtils.bookmarks.TYPE_BOOKMARK) {
+      this.dispatch({
+        type: at.PLACES_BOOKMARK_REMOVED,
+        data: {url: uri.spec, bookmarkGuid: guid}
+      });
+    }
+  }
+
+  /**
+   * onItemChanged - Called when a bookmark is modified
+   *
+   * @param  {str} id           description
+   * @param  {str} property     The property that was modified (e.g. uri, title)
+   * @param  {bool} isAnnotation
+   * @param  {any} value
+   * @param  {int} lastModified
+   * @param  {int} type         Indicates if the bookmark is an actual bookmark,
+   *                             a folder, or a separator.
+   * @param  {int} parent
+   * @param  {str} guid         The unique id of the bookmark
+   */
+  async onItemChanged(...args) {
+    const property = args[1];
+    const type = args[5];
+    const guid = args[7];
+
+    // Only process this event if it is a TYPE_BOOKMARK, and uri or title was the property changed.
+    if (type !== PlacesUtils.bookmarks.TYPE_BOOKMARK || !["uri", "title"].includes(property)) {
+      return;
+    }
+    try {
+      // bookmark: {bookmarkGuid, bookmarkTitle, lastModified, url}
+      const bookmark = await NewTabUtils.activityStreamProvider.getBookmark(guid);
+      this.dispatch({type: at.PLACES_BOOKMARK_CHANGED, data: bookmark});
+    } catch (e) {
+      Cu.reportError(e);
+    }
+  }
+}
+
+class PlacesFeed {
+  constructor() {
+    this.historyObserver = new HistoryObserver(action => this.store.dispatch(ac.BroadcastToContent(action)));
+    this.bookmarksObserver = new BookmarksObserver(action => this.store.dispatch(ac.BroadcastToContent(action)));
+  }
+
+  addObservers() {
+    PlacesUtils.history.addObserver(this.historyObserver, true);
+    PlacesUtils.bookmarks.addObserver(this.bookmarksObserver, true);
+    Services.obs.addObserver(this, LINK_BLOCKED_EVENT);
+  }
+
+  removeObservers() {
+    PlacesUtils.history.removeObserver(this.historyObserver);
+    PlacesUtils.bookmarks.removeObserver(this.bookmarksObserver);
+    Services.obs.removeObserver(this, LINK_BLOCKED_EVENT);
+  }
+
+  /**
+   * observe - An observer for the LINK_BLOCKED_EVENT.
+   *           Called when a link is blocked.
+   *
+   * @param  {null} subject
+   * @param  {str} topic   The name of the event
+   * @param  {str} value   The data associated with the event
+   */
+  observe(subject, topic, value) {
+    if (topic === LINK_BLOCKED_EVENT) {
+      this.store.dispatch(ac.BroadcastToContent({
+        type: at.PLACES_LINK_BLOCKED,
+        data: {url: value}
+      }));
+    }
+  }
+
+  onAction(action) {
+    switch (action.type) {
+      case at.INIT:
+        this.addObservers();
+        break;
+      case at.UNINIT:
+        this.removeObservers();
+        break;
+      case at.BLOCK_URL:
+        NewTabUtils.activityStreamLinks.blockURL({url: action.data});
+        break;
+      case at.BOOKMARK_URL:
+        NewTabUtils.activityStreamLinks.addBookmark(action.data);
+        break;
+      case at.DELETE_BOOKMARK_BY_ID:
+        NewTabUtils.activityStreamLinks.deleteBookmark(action.data);
+        break;
+      case at.DELETE_HISTORY_URL:
+        NewTabUtils.activityStreamLinks.deleteHistoryEntry(action.data);
+        break;
+    }
+  }
+}
+
+this.PlacesFeed = PlacesFeed;
+
+// Exported for testing only
+PlacesFeed.HistoryObserver = HistoryObserver;
+PlacesFeed.BookmarksObserver = BookmarksObserver;
+
+this.EXPORTED_SYMBOLS = ["PlacesFeed"];
--- a/browser/extensions/activity-stream/lib/SearchFeed.jsm
+++ b/browser/extensions/activity-stream/lib/SearchFeed.jsm
@@ -13,50 +13,62 @@ Cu.import("resource://gre/modules/XPCOMU
 XPCOMUtils.defineLazyModuleGetter(this, "ContentSearch",
   "resource:///modules/ContentSearch.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
   "resource://gre/modules/Services.jsm");
 
 this.SearchFeed = class SearchFeed {
   addObservers() {
     Services.obs.addObserver(this, SEARCH_ENGINE_TOPIC);
+
+    // Notice when ContentSearch.init would be lazily loaded from nsBrowserGlue
+    this.contentSearch = new Promise(resolve => Services.mm.addMessageListener(
+      "ContentSearch", (this._onMessage = () => {
+        Services.mm.removeMessageListener("ContentSearch", this._onMessage);
+        resolve(ContentSearch);
+      })));
   }
   removeObservers() {
     Services.obs.removeObserver(this, SEARCH_ENGINE_TOPIC);
+    Services.mm.removeMessageListener("ContentSearch", this._onMessage);
   }
+
   observe(subject, topic, data) {
     switch (topic) {
       case SEARCH_ENGINE_TOPIC:
         if (data !== "engine-default") {
           this.getState();
         }
         break;
     }
   }
+
   async getState() {
-    const state = await ContentSearch.currentStateObj(true);
+    // Wait for ContentSearch to be lazily loaded before getting state
+    const state = await (await this.contentSearch).currentStateObj(true);
     const engines = state.engines.map(engine => ({
       name: engine.name,
       icon: engine.iconBuffer
     }));
     const currentEngine = {
       name: state.currentEngine.name,
       icon: state.currentEngine.iconBuffer
     };
     const action = {type: at.SEARCH_STATE_UPDATED, data: {engines, currentEngine}};
     this.store.dispatch(ac.BroadcastToContent(action));
   }
   performSearch(browser, data) {
     ContentSearch.performSearch({target: browser}, data);
   }
-  onAction(action) {
+
+  async onAction(action) {
     switch (action.type) {
       case at.INIT:
         this.addObservers();
-        this.getState();
+        await this.getState();
         break;
       case at.PERFORM_SEARCH:
         this.performSearch(action._target.browser, action.data);
         break;
       case at.UNINIT:
         this.removeObservers();
         break;
     }
--- a/browser/extensions/activity-stream/lib/Store.jsm
+++ b/browser/extensions/activity-stream/lib/Store.jsm
@@ -26,19 +26,19 @@ this.Store = class Store {
    * constructor - The redux store and message manager are created here,
    *               but no listeners are added until "init" is called.
    */
   constructor() {
     this._middleware = this._middleware.bind(this);
     // Bind each redux method so we can call it directly from the Store. E.g.,
     // store.dispatch() will call store._store.dispatch();
     ["dispatch", "getState", "subscribe"].forEach(method => {
-      this[method] = (...args) => {
+      this[method] = function(...args) {
         return this._store[method](...args);
-      };
+      }.bind(this);
     });
     this.feeds = new Map();
     this._feedFactories = null;
     this._prefHandlers = new Map();
     this._messageChannel = new ActivityStreamMessageChannel({dispatch: this.dispatch});
     this._store = redux.createStore(
       redux.combineReducers(reducers),
       redux.applyMiddleware(this._middleware, this._messageChannel.middleware)
new file mode 100644
--- /dev/null
+++ b/browser/extensions/activity-stream/lib/TelemetryFeed.jsm
@@ -0,0 +1,162 @@
+/* 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/. */
+/* globals XPCOMUtils, gUUIDGenerator, ClientID */
+
+"use strict";
+
+const {utils: Cu} = Components;
+const {actionTypes: at, actionUtils: au} = Cu.import("resource://activity-stream/common/Actions.jsm", {});
+
+Cu.import("resource://gre/modules/ClientID.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
+  "@mozilla.org/uuid-generator;1",
+  "nsIUUIDGenerator");
+XPCOMUtils.defineLazyModuleGetter(this, "TelemetrySender",
+  "resource://activity-stream/lib/TelemetrySender.jsm");
+
+this.TelemetryFeed = class TelemetryFeed {
+  constructor(options) {
+    this.sessions = new Map();
+    this.telemetryClientId = null;
+    this.telemetrySender = null;
+  }
+
+  async init() {
+    // TelemetrySender adds pref observers, so we initialize it after INIT
+    this.telemetrySender = new TelemetrySender();
+
+    const id = await ClientID.getClientID();
+    this.telemetryClientId = id;
+  }
+
+  /**
+   * addSession - Start tracking a new session
+   *
+   * @param  {string} id the portID of the open session
+   */
+  addSession(id) {
+    this.sessions.set(id, {
+      start_time: Components.utils.now(),
+      session_id: String(gUUIDGenerator.generateUUID()),
+      page: "about:newtab" // TODO: Handle about:home
+    });
+  }
+
+  /**
+   * endSession - Stop tracking a session
+   *
+   * @param  {string} portID the portID of the session that just closed
+   */
+  endSession(portID) {
+    const session = this.sessions.get(portID);
+
+    if (!session) {
+      // It's possible the tab was never visible – in which case, there was no user session.
+      return;
+    }
+
+    session.session_duration = Math.round(Components.utils.now() - session.start_time);
+    this.sendEvent(this.createSessionEndEvent(session));
+    this.sessions.delete(portID);
+  }
+
+  /**
+   * createPing - Create a ping with common properties
+   *
+   * @param  {string} id The portID of the session, if a session is relevant (optional)
+   * @return {obj}    A telemetry ping
+   */
+  createPing(portID) {
+    const appInfo = this.store.getState().App;
+    const ping = {
+      client_id: this.telemetryClientId,
+      addon_version: appInfo.version,
+      locale: appInfo.locale
+    };
+
+    // If the ping is part of a user session, add session-related info
+    if (portID) {
+      const session = this.sessions.get(portID);
+      Object.assign(ping, {
+        session_id: session.session_id,
+        page: session.page
+      });
+    }
+    return ping;
+  }
+
+  createUserEvent(action) {
+    return Object.assign(
+      this.createPing(au.getPortIdOfSender(action)),
+      action.data,
+      {action: "activity_stream_user_event"}
+    );
+  }
+
+  createUndesiredEvent(action) {
+    return Object.assign(
+      this.createPing(au.getPortIdOfSender(action)),
+      {value: 0}, // Default value
+      action.data,
+      {action: "activity_stream_undesired_event"}
+    );
+  }
+
+  createPerformanceEvent(action) {
+    return Object.assign(
+      this.createPing(au.getPortIdOfSender(action)),
+      action.data,
+      {action: "activity_stream_performance_event"}
+    );
+  }
+
+  createSessionEndEvent(session) {
+    return Object.assign(
+      this.createPing(),
+      {
+        session_id: session.session_id,
+        page: session.page,
+        session_duration: session.session_duration,
+        action: "activity_stream_session"
+      }
+    );
+  }
+
+  sendEvent(event) {
+    this.telemetrySender.sendPing(event);
+  }
+
+  onAction(action) {
+    switch (action.type) {
+      case at.INIT:
+        this.init();
+        break;
+      case at.NEW_TAB_VISIBLE:
+        this.addSession(au.getPortIdOfSender(action));
+        break;
+      case at.NEW_TAB_UNLOAD:
+        this.endSession(au.getPortIdOfSender(action));
+        break;
+      case at.TELEMETRY_UNDESIRED_EVENT:
+        this.sendEvent(this.createUndesiredEvent(action));
+        break;
+      case at.TELEMETRY_USER_EVENT:
+        this.sendEvent(this.createUserEvent(action));
+        break;
+      case at.TELEMETRY_PERFORMANCE_EVENT:
+        this.sendEvent(this.createPerformanceEvent(action));
+        break;
+    }
+  }
+
+  uninit() {
+    this.telemetrySender.uninit();
+    this.telemetrySender = null;
+    // TODO: Send any unfinished sessions
+  }
+};
+
+this.EXPORTED_SYMBOLS = ["TelemetryFeed"];
new file mode 100644
--- /dev/null
+++ b/browser/extensions/activity-stream/lib/TelemetrySender.jsm
@@ -0,0 +1,99 @@
+/* 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/. */
+/* globals Preferences, Services, XPCOMUtils */
+
+const {interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Preferences.jsm");
+Cu.importGlobalProperties(["fetch"]);
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Console.jsm"); // eslint-disable-line no-console
+
+// This is intentionally a different pref-branch than the SDK-based add-on
+// used, to avoid extra weirdness for people who happen to have the SDK-based
+// installed.  Though maybe we should just forcibly disable the old add-on?
+const PREF_BRANCH = "browser.newtabpage.activity-stream.";
+
+const ENDPOINT_PREF = "telemetry.ping.endpoint";
+const TELEMETRY_PREF = "telemetry";
+const LOGGING_PREF = "telemetry.log";
+
+/**
+ * Observe various notifications and send them to a telemetry endpoint.
+ *
+ * @param {Object} args - optional arguments
+ * @param {Function} args.prefInitHook - if present, will be called back
+ *                   inside the Prefs constructor. Typically used from tests
+ *                   to save off a pointer to a fake Prefs instance so that
+ *                   stubs and spies can be inspected by the test code.
+ *
+ */
+function TelemetrySender(args) {
+  let prefArgs = {branch: PREF_BRANCH};
+  if (args) {
+    if ("prefInitHook" in args) {
+      prefArgs.initHook = args.prefInitHook;
+    }
+  }
+
+  this._prefs = new Preferences(prefArgs);
+
+  this.enabled = this._prefs.get(TELEMETRY_PREF);
+  this._onTelemetryPrefChange = this._onTelemetryPrefChange.bind(this);
+  this._prefs.observe(TELEMETRY_PREF, this._onTelemetryPrefChange);
+
+  this.logging = this._prefs.get(LOGGING_PREF);
+  this._onLoggingPrefChange = this._onLoggingPrefChange.bind(this);
+  this._prefs.observe(LOGGING_PREF, this._onLoggingPrefChange);
+
+  this._pingEndpoint = this._prefs.get(ENDPOINT_PREF);
+}
+
+TelemetrySender.prototype = {
+
+  _onLoggingPrefChange(prefVal) {
+    this.logging = prefVal;
+  },
+
+  _onTelemetryPrefChange(prefVal) {
+    this.enabled = prefVal;
+  },
+
+  async sendPing(data) {
+    if (this.logging) {
+      // performance related pings cause a lot of logging, so we mute them
+      if (data.action !== "activity_stream_performance") {
+        console.log(`TELEMETRY PING: ${JSON.stringify(data)}\n`); // eslint-disable-line no-console
+      }
+    }
+    if (!this.enabled) {
+      return Promise.resolve();
+    }
+    return fetch(this._pingEndpoint, {method: "POST", body: data}).then(response => {
+      if (!response.ok) {
+        Cu.reportError(`Ping failure with HTTP response code: ${response.status}`);
+      }
+    }).catch(e => {
+      Cu.reportError(`Ping failure with error: ${e}`);
+    });
+  },
+
+  uninit() {
+    try {
+      this._prefs.ignore(TELEMETRY_PREF, this._onTelemetryPrefChange);
+      this._prefs.ignore(LOGGING_PREF, this._onLoggingPrefChange);
+    } catch (e) {
+      Cu.reportError(e);
+    }
+  }
+};
+
+this.TelemetrySender = TelemetrySender;
+this.TelemetrySenderConstants = {
+  ENDPOINT_PREF,
+  TELEMETRY_PREF,
+  LOGGING_PREF
+};
+this.EXPORTED_SYMBOLS = ["TelemetrySender", "TelemetrySenderConstants"];
--- a/browser/extensions/activity-stream/lib/TopSitesFeed.jsm
+++ b/browser/extensions/activity-stream/lib/TopSitesFeed.jsm
@@ -53,31 +53,42 @@ this.TopSitesFeed = class TopSitesFeed {
     this.store.dispatch(ac.SendToContent(newAction, action.meta.fromTarget));
     this.lastUpdated = Date.now();
 
     // Now, get a screenshot for every item
     for (let link of links) {
       this.getScreenshot(link.url);
     }
   }
+  openNewWindow(action, isPrivate = false) {
+    const win = action._target.browser.ownerGlobal;
+    win.openLinkIn(action.data.url, "window", {private: isPrivate});
+  }
   onAction(action) {
     let realRows;
     switch (action.type) {
       case at.NEW_TAB_LOAD:
         // Only check against real rows returned from history, not default ones.
         realRows = this.store.getState().TopSites.rows.filter(row => !row.isDefault);
         // When a new tab is opened, if we don't have enough top sites yet, refresh the data.
         if (realRows.length < TOP_SITES_SHOWMORE_LENGTH) {
           this.refresh(action);
         } else if (Date.now() - this.lastUpdated >= UPDATE_TIME) {
           // When a new tab is opened, if the last time we refreshed the data
           // is greater than 15 minutes, refresh the data.
           this.refresh(action);
         }
         break;
+      case at.OPEN_NEW_WINDOW:
+        this.openNewWindow(action);
+        break;
+      case at.OPEN_PRIVATE_WINDOW: {
+        this.openNewWindow(action, true);
+        break;
+      }
     }
   }
 };
 
 this.UPDATE_TIME = UPDATE_TIME;
 this.TOP_SITES_SHOWMORE_LENGTH = TOP_SITES_SHOWMORE_LENGTH;
 this.DEFAULT_TOP_SITES = DEFAULT_TOP_SITES;
 this.EXPORTED_SYMBOLS = ["TopSitesFeed", "UPDATE_TIME", "DEFAULT_TOP_SITES", "TOP_SITES_SHOWMORE_LENGTH"];
new file mode 100644
--- /dev/null
+++ b/browser/extensions/activity-stream/test/schemas/pings.js
@@ -0,0 +1,57 @@
+const Joi = require("joi-browser");
+
+const baseKeys = {
+  client_id: Joi.string().required(),
+  addon_version: Joi.string().required(),
+  locale: Joi.string().required(),
+  session_id: Joi.string(),
+  page: Joi.valid(["about:home", "about:newtab"])
+};
+
+const BasePing = Joi.object().keys(baseKeys).options({allowUnknown: true});
+
+const UserEventPing = Joi.object().keys(Object.assign({}, baseKeys, {
+  session_id: baseKeys.session_id.required(),
+  page: baseKeys.page.required(),
+  source: Joi.string().required(),
+  event: Joi.string().required(),
+  action: Joi.valid("activity_stream_user_event").required(),
+  metadata_source: Joi.string(),
+  highlight_type: Joi.valid(["bookmarks", "recommendation", "history"]),
+  recommender_type: Joi.string()
+}));
+
+const UndesiredPing = Joi.object().keys(Object.assign({}, baseKeys, {
+  source: Joi.string().required(),
+  event: Joi.string().required(),
+  action: Joi.valid("activity_stream_undesired_event").required(),
+  value: Joi.number().required()
+}));
+
+const PerfPing = Joi.object().keys(Object.assign({}, baseKeys, {
+  source: Joi.string(),
+  event: Joi.string().required(),
+  action: Joi.valid("activity_stream_performance_event").required(),
+  value: Joi.number().required()
+}));
+
+const SessionPing = Joi.object().keys(Object.assign({}, baseKeys, {
+  session_id: baseKeys.session_id.required(),
+  page: baseKeys.page.required(),
+  session_duration: Joi.number().integer().required(),
+  action: Joi.valid("activity_stream_session").required()
+}));
+
+function assertMatchesSchema(ping, schema) {
+  assert.isNull(Joi.validate(ping, schema).error);
+}
+
+module.exports = {
+  baseKeys,
+  BasePing,
+  UndesiredPing,
+  UserEventPing,
+  PerfPing,
+  SessionPing,
+  assertMatchesSchema
+};
--- a/browser/extensions/activity-stream/test/unit/common/Actions.test.js
+++ b/browser/extensions/activity-stream/test/unit/common/Actions.test.js
@@ -1,15 +1,31 @@
 const {
+  actionTypes: at,
   actionCreators: ac,
   actionUtils: au,
   MAIN_MESSAGE_TYPE,
-  CONTENT_MESSAGE_TYPE
+  CONTENT_MESSAGE_TYPE,
+  UI_CODE,
+  BACKGROUND_PROCESS,
+  globalImportContext
 } = require("common/Actions.jsm");
 
+describe("Actions", () => {
+  it("should set globalImportContext to UI_CODE", () => {
+    assert.equal(globalImportContext, UI_CODE);
+  });
+});
+
+describe("ActionTypes", () => {
+  it("should be in alpha order", () => {
+    assert.equal(Object.keys(at).join(", "), Object.keys(at).sort().join(", "));
+  });
+});
+
 describe("ActionCreators", () => {
   describe("_RouteMessage", () => {
     it("should throw if options are not passed as the second param", () => {
       assert.throws(() => {
         au._RouteMessage({type: "FOO"});
       });
     });
     it("should set all defined options on the .meta property of the new action", () => {
@@ -28,16 +44,21 @@ describe("ActionCreators", () => {
       const action = {type: "FOO", data: "BAR"};
       const newAction = ac.SendToMain(action);
       assert.deepEqual(newAction, {
         type: "FOO",
         data: "BAR",
         meta: {from: CONTENT_MESSAGE_TYPE, to: MAIN_MESSAGE_TYPE}
       });
     });
+    it("should add the fromTarget if it was supplied", () => {
+      const action = {type: "FOO", data: "BAR"};
+      const newAction = ac.SendToMain(action, "port123");
+      assert.equal(newAction.meta.fromTarget, "port123");
+    });
     describe("isSendToMain", () => {
       it("should return true if action is SendToMain", () => {
         const newAction = ac.SendToMain({type: "FOO"});
         assert.isTrue(au.isSendToMain(newAction));
       });
       it("should return false if action is not SendToMain", () => {
         assert.isFalse(au.isSendToMain({type: "FOO"}));
       });
@@ -85,9 +106,55 @@ describe("ActionCreators", () => {
         assert.isTrue(au.isBroadcastToContent(ac.BroadcastToContent({type: "FOO"})));
       });
       it("should return false if action is not BroadcastToContent", () => {
         assert.isFalse(au.isBroadcastToContent({type: "FOO"}));
         assert.isFalse(au.isBroadcastToContent(ac.SendToContent({type: "FOO"}, "foo123")));
       });
     });
   });
+  describe("UserEvent", () => {
+    it("should include the given data", () => {
+      const data = {action: "foo"};
+      assert.equal(ac.UserEvent(data).data, data);
+    });
+    it("should wrap with SendToMain", () => {
+      const action = ac.UserEvent({action: "foo"});
+      assert.isTrue(au.isSendToMain(action), "isSendToMain");
+    });
+  });
+  describe("UndesiredEvent", () => {
+    it("should include the given data", () => {
+      const data = {action: "foo"};
+      assert.equal(ac.UndesiredEvent(data).data, data);
+    });
+    it("should wrap with SendToMain if in UI code", () => {
+      assert.isTrue(au.isSendToMain(ac.UndesiredEvent({action: "foo"})), "isSendToMain");
+    });
+    it("should not wrap with SendToMain if in UI code", () => {
+      const action = ac.UndesiredEvent({action: "foo"}, BACKGROUND_PROCESS);
+      assert.isFalse(au.isSendToMain(action), "isSendToMain");
+    });
+  });
+  describe("PerfEvent", () => {
+    it("should include the right data", () => {
+      const data = {action: "foo"};
+      assert.equal(ac.UndesiredEvent(data).data, data);
+    });
+    it("should wrap with SendToMain if in UI code", () => {
+      assert.isTrue(au.isSendToMain(ac.PerfEvent({action: "foo"})), "isSendToMain");
+    });
+    it("should not wrap with SendToMain if in UI code", () => {
+      const action = ac.PerfEvent({action: "foo"}, BACKGROUND_PROCESS);
+      assert.isFalse(au.isSendToMain(action), "isSendToMain");
+    });
+  });
 });
+
+describe("ActionUtils", () => {
+  describe("getPortIdOfSender", () => {
+    it("should return the PortID from a SendToMain action", () => {
+      const portID = "foo123";
+      const result = au.getPortIdOfSender(ac.SendToMain({type: "FOO"}, portID));
+      assert.equal(result, portID);
+    });
+  });
+});
--- a/browser/extensions/activity-stream/test/unit/common/Reducers.test.js
+++ b/browser/extensions/activity-stream/test/unit/common/Reducers.test.js
@@ -1,13 +1,39 @@
 const {reducers, INITIAL_STATE} = require("common/Reducers.jsm");
-const {TopSites, Search} = reducers;
+const {TopSites, Search, App} = reducers;
 const {actionTypes: at} = require("common/Actions.jsm");
 
 describe("Reducers", () => {
+  describe("App", () => {
+    it("should return the initial state", () => {
+      const nextState = App(undefined, {type: "FOO"});
+      assert.equal(nextState, INITIAL_STATE.App);
+    });
+    it("should not set initialized to true on INIT", () => {
+      const nextState = App(undefined, {type: "INIT"});
+      assert.propertyVal(nextState, "initialized", true);
+    });
+    it("should set initialized, version, and locale on INIT", () => {
+      const action = {type: "INIT", data: {version: "1.2.3"}};
+      const nextState = App(undefined, action);
+      assert.propertyVal(nextState, "version", "1.2.3");
+    });
+    it("should not update state for empty action.data on LOCALE_UPDATED", () => {
+      const nextState = App(undefined, {type: at.LOCALE_UPDATED});
+      assert.equal(nextState, INITIAL_STATE.App);
+    });
+    it("should set locale, strings on LOCALE_UPDATE", () => {
+      const strings = {};
+      const action = {type: "LOCALE_UPDATED", data: {locale: "zh-CN", strings}};
+      const nextState = App(undefined, action);
+      assert.propertyVal(nextState, "locale", "zh-CN");
+      assert.propertyVal(nextState, "strings", strings);
+    });
+  });
   describe("TopSites", () => {
     it("should return the initial state", () => {
       const nextState = TopSites(undefined, {type: "FOO"});
       assert.equal(nextState, INITIAL_STATE.TopSites);
     });
     it("should add top sites on TOP_SITES_UPDATED", () => {
       const newRows = [{url: "foo.com"}, {url: "bar.com"}];
       const nextState = TopSites(undefined, {type: at.TOP_SITES_UPDATED, data: newRows});
@@ -24,16 +50,68 @@ describe("Reducers", () => {
       assert.deepEqual(nextState.rows, [{url: "foo.com"}, {url: "bar.com", screenshot: "data:123"}]);
     });
     it("should not modify rows if nothing matches the url for SCREENSHOT_UPDATED", () => {
       const oldState = {rows: [{url: "foo.com"}, {url: "bar.com"}]};
       const action = {type: at.SCREENSHOT_UPDATED, data: {url: "baz.com", screenshot: "data:123"}};
       const nextState = TopSites(oldState, action);
       assert.deepEqual(nextState, oldState);
     });
+    it("should bookmark an item on PLACES_BOOKMARK_ADDED", () => {
+      const oldState = {rows: [{url: "foo.com"}, {url: "bar.com"}]};
+      const action = {
+        type: at.PLACES_BOOKMARK_ADDED,
+        data: {
+          url: "bar.com",
+          bookmarkGuid: "bookmark123",
+          bookmarkTitle: "Title for bar.com",
+          lastModified: 1234567
+        }
+      };
+      const nextState = TopSites(oldState, action);
+      const newRow = nextState.rows[1];
+      // new row has bookmark data
+      assert.equal(newRow.url, action.data.url);
+      assert.equal(newRow.bookmarkGuid, action.data.bookmarkGuid);
+      assert.equal(newRow.bookmarkTitle, action.data.bookmarkTitle);
+      assert.equal(newRow.bookmarkDateCreated, action.data.lastModified);
+
+      // old row is unchanged
+      assert.equal(nextState.rows[0], oldState.rows[0]);
+    });
+    it("should remove a bookmark on PLACES_BOOKMARK_REMOVED", () => {
+      const oldState = {
+        rows: [{url: "foo.com"}, {
+          url: "bar.com",
+          bookmarkGuid: "bookmark123",
+          bookmarkTitle: "Title for bar.com",
+          lastModified: 123456
+        }]
+      };
+      const action = {type: at.PLACES_BOOKMARK_REMOVED, data: {url: "bar.com"}};
+      const nextState = TopSites(oldState, action);
+      const newRow = nextState.rows[1];
+      // new row no longer has bookmark data
+      assert.equal(newRow.url, oldState.rows[1].url);
+      assert.isUndefined(newRow.bookmarkGuid);
+      assert.isUndefined(newRow.bookmarkTitle);
+      assert.isUndefined(newRow.bookmarkDateCreated);
+
+      // old row is unchanged
+      assert.deepEqual(nextState.rows[0], oldState.rows[0]);
+    });
+    it("should remove a link on PLACES_LINK_BLOCKED and PLACES_LINK_DELETED", () => {
+      const events = [at.PLACES_LINK_BLOCKED, at.PLACES_LINK_DELETED];
+      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"}]);
+      });
+    });
   });
   describe("Search", () => {
     it("should return the initial state", () => {
       const nextState = Search(undefined, {type: "FOO"});
       assert.equal(nextState, INITIAL_STATE.Search);
     });
     it("should not update state for empty action.data on Search", () => {
       const nextState = Search(undefined, {type: at.SEARCH_STATE_UPDATED});
--- a/browser/extensions/activity-stream/test/unit/lib/ActivityStream.test.js
+++ b/browser/extensions/activity-stream/test/unit/lib/ActivityStream.test.js
@@ -1,23 +1,24 @@
 const injector = require("inject!lib/ActivityStream.jsm");
 
 describe("ActivityStream", () => {
   let sandbox;
   let as;
   let ActivityStream;
-  function NewTabInit() {}
-  function TopSitesFeed() {}
-  function SearchFeed() {}
+  function Fake() {}
   before(() => {
     sandbox = sinon.sandbox.create();
     ({ActivityStream} = injector({
-      "lib/NewTabInit.jsm": {NewTabInit},
-      "lib/TopSitesFeed.jsm": {TopSitesFeed},
-      "lib/SearchFeed.jsm": {SearchFeed}
+      "lib/LocalizationFeed.jsm": {LocalizationFeed: Fake},
+      "lib/NewTabInit.jsm": {NewTabInit: Fake},
+      "lib/PlacesFeed.jsm": {PlacesFeed: Fake},
+      "lib/SearchFeed.jsm": {SearchFeed: Fake},
+      "lib/TelemetryFeed.jsm": {TelemetryFeed: Fake},
+      "lib/TopSitesFeed.jsm": {TopSitesFeed: Fake}
     }));
   });
 
   afterEach(() => sandbox.restore());
 
   beforeEach(() => {
     as = new ActivityStream();
     sandbox.stub(as.store, "init");
@@ -35,36 +36,59 @@ describe("ActivityStream", () => {
       as.init();
     });
     it("should set .initialized to true", () => {
       assert.isTrue(as.initialized, ".initialized");
     });
     it("should call .store.init", () => {
       assert.calledOnce(as.store.init);
     });
+    it("should emit an INIT event with the right version", () => {
+      as = new ActivityStream({version: "1.2.3"});
+      sandbox.stub(as.store, "init");
+      sandbox.stub(as.store, "dispatch");
+
+      as.init();
+
+      assert.calledOnce(as.store.dispatch);
+      const action = as.store.dispatch.firstCall.args[0];
+      assert.propertyVal(action.data, "version", "1.2.3");
+    });
   });
   describe("#uninit", () => {
     beforeEach(() => {
       as.init();
       as.uninit();
     });
     it("should set .initialized to false", () => {
       assert.isFalse(as.initialized, ".initialized");
     });
     it("should call .store.uninit", () => {
       assert.calledOnce(as.store.uninit);
     });
   });
   describe("feeds", () => {
+    it("should create a Localization feed", () => {
+      const feed = as.feeds["feeds.localization"]();
+      assert.instanceOf(feed, Fake);
+    });
     it("should create a NewTabInit feed", () => {
       const feed = as.feeds["feeds.newtabinit"]();
-      assert.instanceOf(feed, NewTabInit);
+      assert.instanceOf(feed, Fake);
+    });
+    it("should create a Places feed", () => {
+      const feed = as.feeds["feeds.places"]();
+      assert.instanceOf(feed, Fake);
     });
     it("should create a TopSites feed", () => {
       const feed = as.feeds["feeds.topsites"]();
-      assert.instanceOf(feed, TopSitesFeed);
+      assert.instanceOf(feed, Fake);
+    });
+    it("should create a Telemetry feed", () => {
+      const feed = as.feeds["feeds.telemetry"]();
+      assert.instanceOf(feed, Fake);
     });
     it("should create a Search feed", () => {
       const feed = as.feeds["feeds.search"]();
-      assert.instanceOf(feed, SearchFeed);
+      assert.instanceOf(feed, Fake);
     });
   });
 });
new file mode 100644
--- /dev/null
+++ b/browser/extensions/activity-stream/test/unit/lib/LocalizationFeed.test.js
@@ -0,0 +1,128 @@
+"use strict";
+const {LocalizationFeed} = require("lib/LocalizationFeed.jsm");
+const {GlobalOverrider} = require("test/unit/utils");
+const {actionTypes: at} = require("common/Actions.jsm");
+
+const DEFAULT_LOCALE = "en-US";
+const TEST_STRINGS = {
+  [DEFAULT_LOCALE]: {
+    foo: "Foo",
+    too: "Too"
+  },
+  "it": {
+    foo: "Bar",
+    too: "Boo"
+  },
+  "ru": {foo: "Baz"}
+};
+
+describe("Localization Feed", () => {
+  let feed;
+  let globals;
+  before(() => {
+    globals = new GlobalOverrider();
+  });
+  beforeEach(() => {
+    feed = new LocalizationFeed();
+    feed.store = {dispatch: sinon.spy()};
+  });
+  afterEach(() => {
+    globals.restore();
+  });
+
+  it("should fetch strings on init", async () => {
+    sinon.stub(feed, "updateLocale");
+    fetch.returns(Promise.resolve({json() { return Promise.resolve(TEST_STRINGS); }}));
+
+    await feed.init();
+
+    assert.deepEqual(feed.allStrings, TEST_STRINGS);
+    assert.calledOnce(feed.updateLocale);
+  });
+
+  describe("#updateLocale", () => {
+    beforeEach(() => {
+      feed.allStrings = TEST_STRINGS;
+    });
+
+    it("should dispatch with locale and strings for default", () => {
+      const locale = DEFAULT_LOCALE;
+      feed.updateLocale();
+
+      assert.calledOnce(feed.store.dispatch);
+      const arg = feed.store.dispatch.firstCall.args[0];
+      assert.propertyVal(arg, "type", at.LOCALE_UPDATED);
+      assert.propertyVal(arg.data, "locale", locale);
+      assert.deepEqual(arg.data.strings, TEST_STRINGS[locale]);
+    });
+    it("should use strings for other locale", () => {
+      const locale = "it";
+      global.Services.locale.getRequestedLocale.returns(locale);
+
+      feed.updateLocale();
+
+      assert.calledOnce(feed.store.dispatch);
+      const arg = feed.store.dispatch.firstCall.args[0];
+      assert.propertyVal(arg, "type", at.LOCALE_UPDATED);
+      assert.propertyVal(arg.data, "locale", locale);
+      assert.deepEqual(arg.data.strings, TEST_STRINGS[locale]);
+    });
+    it("should use some fallback strings for partial locale", () => {
+      const locale = "ru";
+      global.Services.locale.getRequestedLocale.returns(locale);
+
+      feed.updateLocale();
+
+      assert.calledOnce(feed.store.dispatch);
+      const arg = feed.store.dispatch.firstCall.args[0];
+      assert.propertyVal(arg, "type", at.LOCALE_UPDATED);
+      assert.propertyVal(arg.data, "locale", locale);
+      assert.deepEqual(arg.data.strings, {
+        foo: TEST_STRINGS[locale].foo,
+        too: TEST_STRINGS[DEFAULT_LOCALE].too
+      });
+    });
+    it("should use all default strings for unknown locale", () => {
+      const locale = "xyz";
+      global.Services.locale.getRequestedLocale.returns(locale);
+
+      feed.updateLocale();
+
+      assert.calledOnce(feed.store.dispatch);
+      const arg = feed.store.dispatch.firstCall.args[0];
+      assert.propertyVal(arg, "type", at.LOCALE_UPDATED);
+      assert.propertyVal(arg.data, "locale", locale);
+      assert.deepEqual(arg.data.strings, TEST_STRINGS[DEFAULT_LOCALE]);
+    });
+  });
+
+  describe("#observe", () => {
+    it("should update locale on locale change event", () => {
+      sinon.stub(feed, "updateLocale");
+
+      feed.observe(null, "intl:requested-locales-changed");
+
+      assert.calledOnce(feed.updateLocale);
+    });
+    it("shouldn't update locale on other event", () => {
+      sinon.stub(feed, "updateLocale");
+
+      feed.observe(null, "some-other-notification");
+
+      assert.notCalled(feed.updateLocale);
+    });
+  });
+
+  describe("#onAction", () => {
+    it("should addObserver on INIT", () => {
+      feed.onAction({type: at.INIT});
+
+      assert.calledOnce(global.Services.obs.addObserver);
+    });
+    it("should removeObserver on UNINIT", () => {
+      feed.onAction({type: at.UNINIT});
+
+      assert.calledOnce(global.Services.obs.removeObserver);
+    });
+  });
+});
new file mode 100644
--- /dev/null
+++ b/browser/extensions/activity-stream/test/unit/lib/PlacesFeed.test.js
@@ -0,0 +1,208 @@
+const {PlacesFeed} = require("lib/PlacesFeed.jsm");
+const {HistoryObserver, BookmarksObserver} = PlacesFeed;
+const {GlobalOverrider} = require("test/unit/utils");
+const {actionTypes: at} = require("common/Actions.jsm");
+
+const FAKE_BOOKMARK = {bookmarkGuid: "xi31", bookmarkTitle: "Foo", lastModified: 123214232, url: "foo.com"};
+const TYPE_BOOKMARK = 0; // This is fake, for testing
+
+const BLOCKED_EVENT = "newtab-linkBlocked"; // The event dispatched in NewTabUtils when a link is blocked;
+
+describe("PlacesFeed", () => {
+  let globals;
+  let sandbox;
+  let feed;
+  beforeEach(() => {
+    globals = new GlobalOverrider();
+    sandbox = globals.sandbox;
+    globals.set("NewTabUtils", {
+      activityStreamProvider: {getBookmark() {}},
+      activityStreamLinks: {
+        addBookmark: sandbox.spy(),
+        deleteBookmark: sandbox.spy(),
+        deleteHistoryEntry: sandbox.spy(),
+        blockURL: sandbox.spy()
+      }
+    });
+    globals.set("PlacesUtils", {
+      history: {addObserver: sandbox.spy(), removeObserver: sandbox.spy()},
+      bookmarks: {TYPE_BOOKMARK, addObserver: sandbox.spy(), removeObserver: sandbox.spy()}
+    });
+
+    feed = new PlacesFeed();
+    feed.store = {dispatch: sinon.spy()};
+  });
+  afterEach(() => globals.restore());
+
+  it("should have a HistoryObserver that dispatches to the store", () => {
+    assert.instanceOf(feed.historyObserver, HistoryObserver);
+    const action = {type: "FOO"};
+
+    feed.historyObserver.dispatch(action);
+
+    assert.calledOnce(feed.store.dispatch);
+    assert.equal(feed.store.dispatch.firstCall.args[0].type, action.type);
+  });
+
+  it("should have a BookmarksObserver that dispatch to the store", () => {
+    assert.instanceOf(feed.bookmarksObserver, BookmarksObserver);
+    const action = {type: "FOO"};
+
+    feed.bookmarksObserver.dispatch(action);
+
+    assert.calledOnce(feed.store.dispatch);
+    assert.equal(feed.store.dispatch.firstCall.args[0].type, action.type);
+  });
+
+  describe("#onAction", () => {
+    it("should add bookmark, history, blocked observers on INIT", () => {
+      feed.onAction({type: at.INIT});
+
+      assert.calledWith(global.PlacesUtils.history.addObserver, feed.historyObserver, true);
+      assert.calledWith(global.PlacesUtils.bookmarks.addObserver, feed.bookmarksObserver, true);
+      assert.calledWith(global.Services.obs.addObserver, feed, BLOCKED_EVENT);
+    });
+    it("should remove bookmark, history, blocked observers on UNINIT", () => {
+      feed.onAction({type: at.UNINIT});
+
+      assert.calledWith(global.PlacesUtils.history.removeObserver, feed.historyObserver);
+      assert.calledWith(global.PlacesUtils.bookmarks.removeObserver, feed.bookmarksObserver);
+      assert.calledWith(global.Services.obs.removeObserver, feed, BLOCKED_EVENT);
+    });
+    it("should block a url on BLOCK_URL", () => {
+      feed.onAction({type: at.BLOCK_URL, data: "apple.com"});
+      assert.calledWith(global.NewTabUtils.activityStreamLinks.blockURL, {url: "apple.com"});
+    });
+    it("should bookmark a url on BOOKMARK_URL", () => {
+      feed.onAction({type: at.BOOKMARK_URL, data: "pear.com"});
+      assert.calledWith(global.NewTabUtils.activityStreamLinks.addBookmark, "pear.com");
+    });
+    it("should delete a bookmark on DELETE_BOOKMARK_BY_ID", () => {
+      feed.onAction({type: at.DELETE_BOOKMARK_BY_ID, data: "g123kd"});
+      assert.calledWith(global.NewTabUtils.activityStreamLinks.deleteBookmark, "g123kd");
+    });
+    it("should delete a history entry on DELETE_HISTORY_URL", () => {
+      feed.onAction({type: at.DELETE_HISTORY_URL, data: "guava.com"});
+      assert.calledWith(global.NewTabUtils.activityStreamLinks.deleteHistoryEntry, "guava.com");
+    });
+  });
+
+  describe("#observe", () => {
+    it("should dispatch a PLACES_LINK_BLOCKED action with the url of the blocked link", () => {
+      feed.observe(null, BLOCKED_EVENT, "foo123.com");
+      assert.equal(feed.store.dispatch.firstCall.args[0].type, at.PLACES_LINK_BLOCKED);
+      assert.deepEqual(feed.store.dispatch.firstCall.args[0].data, {url: "foo123.com"});
+    });
+    it("should not call dispatch if the topic is something other than BLOCKED_EVENT", () => {
+      feed.observe(null, "someotherevent");
+      assert.notCalled(feed.store.dispatch);
+    });
+  });
+
+  describe("HistoryObserver", () => {
+    let dispatch;
+    let observer;
+    beforeEach(() => {
+      dispatch = sandbox.spy();
+      observer = new HistoryObserver(dispatch);
+    });
+    it("should have a QueryInterface property", () => {
+      assert.property(observer, "QueryInterface");
+    });
+    describe("#onDeleteURI", () => {
+      it("should dispatch a PLACES_LINK_DELETED action with the right url", () => {
+        observer.onDeleteURI({spec: "foo.com"});
+        assert.calledWith(dispatch, {type: at.PLACES_LINK_DELETED, data: {url: "foo.com"}});
+      });
+    });
+    describe("#onClearHistory", () => {
+      it("should dispatch a PLACES_HISTORY_CLEARED action", () => {
+        observer.onClearHistory();
+        assert.calledWith(dispatch, {type: at.PLACES_HISTORY_CLEARED});
+      });
+    });
+  });
+
+  describe("BookmarksObserver", () => {
+    let dispatch;
+    let observer;
+    beforeEach(() => {
+      dispatch = sandbox.spy();
+      observer = new BookmarksObserver(dispatch);
+    });
+    it("should have a QueryInterface property", () => {
+      assert.property(observer, "QueryInterface");
+    });
+    describe("#onItemAdded", () => {
+      beforeEach(() => {
+        // Make sure getBookmark returns our fake bookmark if it is called with the expected guid
+        sandbox.stub(global.NewTabUtils.activityStreamProvider, "getBookmark")
+          .withArgs(FAKE_BOOKMARK.guid).returns(Promise.resolve(FAKE_BOOKMARK));
+      });
+      it("should dispatch a PLACES_BOOKMARK_ADDED action with the bookmark data", async () => {
+        // Yes, onItemAdded has at least 8 arguments. See function definition for docs.
+        const args = [null, null, null, TYPE_BOOKMARK, null, null, null, FAKE_BOOKMARK.guid];
+        await observer.onItemAdded(...args);
+
+        assert.calledWith(dispatch, {type: at.PLACES_BOOKMARK_ADDED, data: FAKE_BOOKMARK});
+      });
+      it("should catch errors gracefully", async () => {
+        const e = new Error("test error");
+        global.NewTabUtils.activityStreamProvider.getBookmark.restore();
+        sandbox.stub(global.NewTabUtils.activityStreamProvider, "getBookmark")
+          .returns(Promise.reject(e));
+
+        const args = [null, null, null, TYPE_BOOKMARK, null, null, null, FAKE_BOOKMARK.guid];
+        await observer.onItemAdded(...args);
+
+        assert.calledWith(global.Components.utils.reportError, e);
+      });
+      it("should ignore events that are not of TYPE_BOOKMARK", async () => {
+        const args = [null, null, null, "nottypebookmark"];
+        await observer.onItemAdded(...args);
+        assert.notCalled(dispatch);
+      });
+    });
+    describe("#onItemRemoved", () => {
+      it("should ignore events that are not of TYPE_BOOKMARK", async () => {
+        await observer.onItemRemoved(null, null, null, "nottypebookmark", null, "123foo");
+        assert.notCalled(dispatch);
+      });
+      it("should dispatch a PLACES_BOOKMARK_REMOVED action with the right URL and bookmarkGuid", () => {
+        observer.onItemRemoved(null, null, null, TYPE_BOOKMARK, {spec: "foo.com"}, "123foo");
+        assert.calledWith(dispatch, {type: at.PLACES_BOOKMARK_REMOVED, data: {bookmarkGuid: "123foo", url: "foo.com"}});
+      });
+    });
+    describe("#onItemChanged", () => {
+      beforeEach(() => {
+        sandbox.stub(global.NewTabUtils.activityStreamProvider, "getBookmark")
+          .withArgs(FAKE_BOOKMARK.guid).returns(Promise.resolve(FAKE_BOOKMARK));
+      });
+      it("should dispatch a PLACES_BOOKMARK_CHANGED action with the bookmark data", async () => {
+        const args = [null, "title", null, null, null, TYPE_BOOKMARK, null, FAKE_BOOKMARK.guid];
+        await observer.onItemChanged(...args);
+
+        assert.calledWith(dispatch, {type: at.PLACES_BOOKMARK_CHANGED, data: FAKE_BOOKMARK});
+      });
+      it("should catch errors gracefully", async () => {
+        const e = new Error("test error");
+        global.NewTabUtils.activityStreamProvider.getBookmark.restore();
+        sandbox.stub(global.NewTabUtils.activityStreamProvider, "getBookmark")
+          .returns(Promise.reject(e));
+
+        const args = [null, "title", null, null, null, TYPE_BOOKMARK, null, FAKE_BOOKMARK.guid];
+        await observer.onItemChanged(...args);
+
+        assert.calledWith(global.Components.utils.reportError, e);
+      });
+      it("should ignore events that are not of TYPE_BOOKMARK", async () => {
+        await observer.onItemChanged(null, "title", null, null, null, "nottypebookmark");
+        assert.notCalled(dispatch);
+      });
+      it("should ignore events that are not changes to uri/title", async () => {
+        await observer.onItemChanged(null, "tags", null, null, null, TYPE_BOOKMARK);
+        assert.notCalled(dispatch);
+      });
+    });
+  });
+});
--- a/browser/extensions/activity-stream/test/unit/lib/SearchFeed.test.js
+++ b/browser/extensions/activity-stream/test/unit/lib/SearchFeed.test.js
@@ -15,18 +15,19 @@ describe("Search Feed", () => {
   });
   beforeEach(() => {
     feed = new SearchFeed();
     feed.store = {dispatch: sinon.spy()};
   });
   afterEach(() => globals.reset());
   after(() => globals.restore());
 
-  it("should call get state (with true) from the content search provider on INIT", () => {
-    feed.onAction({type: at.INIT});
+  it("should call get state (with true) from the content search provider on INIT", async() => {
+    await feed.onAction({type: at.INIT});
+
     // calling currentStateObj with 'true' allows us to return a data uri for the
     // icon, instead of an array buffer
     assert.calledWith(global.ContentSearch.currentStateObj, true);
   });
   it("should get the the state on INIT", () => {
     sinon.stub(feed, "getState");
     feed.onAction({type: at.INIT});
     assert.calledOnce(feed.getState);
@@ -36,29 +37,35 @@ describe("Search Feed", () => {
     feed.onAction({type: at.INIT});
     assert.calledOnce(feed.addObservers);
   });
   it("should remove observers on UNINIT", () => {
     sinon.stub(feed, "removeObservers");
     feed.onAction({type: at.UNINIT});
     assert.calledOnce(feed.removeObservers);
   });
-  it("should call services.obs.addObserver on INIT", () => {
+  it("should add event handlers on INIT", () => {
     feed.onAction({type: at.INIT});
+
     assert.calledOnce(global.Services.obs.addObserver);
+    assert.calledOnce(global.Services.mm.addMessageListener);
   });
-  it("should call services.obs.removeObserver on UNINIT", () => {
+  it("should remove event handlers on UNINIT", () => {
     feed.onAction({type: at.UNINIT});
+
     assert.calledOnce(global.Services.obs.removeObserver);
+    assert.calledOnce(global.Services.mm.removeMessageListener);
   });
-  it("should dispatch one event with the state", () => (
-    feed.getState().then(() => {
-      assert.calledOnce(feed.store.dispatch);
-    })
-  ));
+  it("should dispatch one event with the state", async() => {
+    feed.contentSearch = Promise.resolve(global.ContentSearch);
+
+    await feed.getState();
+
+    assert.calledOnce(feed.store.dispatch);
+  });
   it("should perform a search on PERFORM_SEARCH", () => {
     sinon.stub(feed, "performSearch");
     feed.onAction({_target: {browser: {}}, type: at.PERFORM_SEARCH});
     assert.calledOnce(feed.performSearch);
   });
   it("should call performSearch with an action", () => {
     const action = {_target: {browser: "browser"}, data: {searchString: "hello"}};
     feed.performSearch(action._target.browser, action.data);
new file mode 100644
--- /dev/null
+++ b/browser/extensions/activity-stream/test/unit/lib/TelemetryFeed.test.js
@@ -0,0 +1,262 @@
+const injector = require("inject!lib/TelemetryFeed.jsm");
+const {GlobalOverrider} = require("test/unit/utils");
+const {actionCreators: ac, actionTypes: at} = require("common/Actions.jsm");
+const {
+  BasePing,
+  UndesiredPing,
+  UserEventPing,
+  PerfPing,
+  SessionPing,
+  assertMatchesSchema
+} = require("test/schemas/pings");
+
+const FAKE_TELEMETRY_ID = "foo123";
+const FAKE_UUID = "{foo-123-foo}";
+
+describe("TelemetryFeed", () => {
+  let globals;
+  let sandbox;
+  let store = {getState() { return {App: {version: "1.0.0", locale: "en-US"}}; }};
+  let instance;
+  class TelemetrySender {sendPing() {} uninit() {}}
+  const {TelemetryFeed} = injector({"lib/TelemetrySender.jsm": {TelemetrySender}});
+
+  function addSession(id) {
+    instance.addSession(id);
+    return instance.sessions.get(id);
+  }
+
+  beforeEach(() => {
+    globals = new GlobalOverrider();
+    sandbox = globals.sandbox;
+    globals.set("ClientID", {getClientID: sandbox.spy(async () => FAKE_TELEMETRY_ID)});
+    globals.set("gUUIDGenerator", {generateUUID: () => FAKE_UUID});
+    instance = new TelemetryFeed();
+    instance.store = store;
+  });
+  afterEach(() => {
+    globals.restore();
+  });
+  describe("#init", () => {
+    it("should add .telemetrySender, a TelemetrySender instance", async () => {
+      assert.isNull(instance.telemetrySender);
+      await instance.init();
+      assert.instanceOf(instance.telemetrySender, TelemetrySender);
+    });
+    it("should add .telemetryClientId from the ClientID module", async () => {
+      assert.isNull(instance.telemetryClientId);
+      await instance.init();
+      assert.equal(instance.telemetryClientId, FAKE_TELEMETRY_ID);
+    });
+  });
+  describe("#addSession", () => {
+    it("should add a session", () => {
+      addSession("foo");
+      assert.isTrue(instance.sessions.has("foo"));
+    });
+    it("should set the start_time", () => {
+      sandbox.spy(Components.utils, "now");
+      const session = addSession("foo");
+      assert.calledOnce(Components.utils.now);
+      assert.equal(session.start_time, Components.utils.now.firstCall.returnValue);
+    });
+    it("should set the session_id", () => {
+      sandbox.spy(global.gUUIDGenerator, "generateUUID");
+      const session = addSession("foo");
+      assert.calledOnce(global.gUUIDGenerator.generateUUID);
+      assert.equal(session.session_id, global.gUUIDGenerator.generateUUID.firstCall.returnValue);
+    });
+    it("should set the page", () => {
+      const session = addSession("foo");
+      assert.equal(session.page, "about:newtab"); // This is hardcoded for now.
+    });
+  });
+  describe("#endSession", () => {
+    it("should not throw if there is no session for the given port ID", () => {
+      assert.doesNotThrow(() => instance.endSession("doesn't exist"));
+    });
+    it("should add a session_duration", () => {
+      sandbox.stub(instance, "sendEvent");
+      const session = addSession("foo");
+      instance.endSession("foo");
+      assert.property(session, "session_duration");
+    });
+    it("should remove the session from .sessions", () => {
+      sandbox.stub(instance, "sendEvent");
+      addSession("foo");
+      instance.endSession("foo");
+      assert.isFalse(instance.sessions.has("foo"));
+    });
+    it("should call createSessionSendEvent and sendEvent with the sesssion", () => {
+      sandbox.stub(instance, "sendEvent");
+      sandbox.stub(instance, "createSessionEndEvent");
+      const session = addSession("foo");
+      instance.endSession("foo");
+
+      // Did we call sendEvent with the result of createSessionEndEvent?
+      assert.calledWith(instance.createSessionEndEvent, session);
+      assert.calledWith(instance.sendEvent, instance.createSessionEndEvent.firstCall.returnValue);
+    });
+  });
+  describe("ping creators", () => {
+    beforeEach(async () => await instance.init());
+    describe("#createPing", () => {
+      it("should create a valid base ping without a session if no portID is supplied", () => {
+        const ping = instance.createPing();
+        assertMatchesSchema(ping, BasePing);
+        assert.notProperty(ping, "session_id");
+      });
+      it("should create a valid base ping with session info if a portID is supplied", () => {
+        // Add a session
+        const portID = "foo";
+        instance.addSession(portID);
+        const sessionID = instance.sessions.get(portID).session_id;
+
+        // Create a ping referencing the session
+        const ping = instance.createPing(portID);
+        assertMatchesSchema(ping, BasePing);
+
+        // Make sure we added the right session-related stuff to the ping
+        assert.propertyVal(ping, "session_id", sessionID);
+        assert.propertyVal(ping, "page", "about:newtab");
+      });
+    });
+    describe("#createUserEvent", () => {
+      it("should create a valid event", () => {
+        const portID = "foo";
+        const data = {source: "TOP_SITES", event: "CLICK"};
+        const action = ac.SendToMain(ac.UserEvent(data), portID);
+        const session = addSession(portID);
+        const ping = instance.createUserEvent(action);
+
+        // Is it valid?
+        assertMatchesSchema(ping, UserEventPing);
+        // Does it have the right session_id?
+        assert.propertyVal(ping, "session_id", session.session_id);
+      });
+    });
+    describe("#createUndesiredEvent", () => {
+      it("should create a valid event without a session", () => {
+        const action = ac.UndesiredEvent({source: "TOP_SITES", event: "MISSING_IMAGE", value: 10});
+        const ping = instance.createUndesiredEvent(action);
+
+        // Is it valid?
+        assertMatchesSchema(ping, UndesiredPing);
+        // Does it have the right value?
+        assert.propertyVal(ping, "value", 10);
+      });
+      it("should create a valid event with a session", () => {
+        const portID = "foo";
+        const data = {source: "TOP_SITES", event: "MISSING_IMAGE", value: 10};
+        const action = ac.SendToMain(ac.UndesiredEvent(data), portID);
+        const session = addSession(portID);
+        const ping = instance.createUndesiredEvent(action);
+
+        // Is it valid?
+        assertMatchesSchema(ping, UndesiredPing);
+        // Does it have the right session_id?
+        assert.propertyVal(ping, "session_id", session.session_id);
+        // Does it have the right value?
+        assert.propertyVal(ping, "value", 10);
+      });
+    });
+    describe("#createPerformanceEvent", () => {
+      it("should create a valid event without a session", () => {
+        const action = ac.PerfEvent({event: "SCREENSHOT_FINISHED", value: 100});
+        const ping = instance.createPerformanceEvent(action);
+
+        // Is it valid?
+        assertMatchesSchema(ping, PerfPing);
+        // Does it have the right value?
+        assert.propertyVal(ping, "value", 100);
+      });
+      it("should create a valid event with a session", () => {
+        const portID = "foo";
+        const data = {event: "PAGE_LOADED", value: 100};
+        const action = ac.SendToMain(ac.PerfEvent(data), portID);
+        const session = addSession(portID);
+        const ping = instance.createPerformanceEvent(action);
+
+        // Is it valid?
+        assertMatchesSchema(ping, PerfPing);
+        // Does it have the right session_id?
+        assert.propertyVal(ping, "session_id", session.session_id);
+        // Does it have the right value?
+        assert.propertyVal(ping, "value", 100);
+      });
+    });
+    describe("#createSessionEndEvent", () => {
+      it("should create a valid event", () => {
+        const ping = instance.createSessionEndEvent({
+          session_id: FAKE_UUID,
+          page: "about:newtab",
+          session_duration: 12345
+        });
+        // Is it valid?
+        assertMatchesSchema(ping, SessionPing);
+        assert.propertyVal(ping, "session_id", FAKE_UUID);
+        assert.propertyVal(ping, "page", "about:newtab");
+        assert.propertyVal(ping, "session_duration", 12345);
+      });
+    });
+  });
+  describe("#sendEvent", () => {
+    it("should call telemetrySender", async () => {
+      await instance.init();
+      sandbox.stub(instance.telemetrySender, "sendPing");
+      const event = {};
+      instance.sendEvent(event);
+      assert.calledWith(instance.telemetrySender.sendPing, event);
+    });
+  });
+  describe("#uninit", () => {
+    it("should call .telemetrySender.uninit and remove it", async () => {
+      await instance.init();
+      const stub = sandbox.stub(instance.telemetrySender, "uninit");
+      instance.uninit();
+      assert.calledOnce(stub);
+      assert.isNull(instance.telemetrySender);
+    });
+  });
+  describe("#onAction", () => {
+    it("should call .init() on an INIT action", () => {
+      const stub = sandbox.stub(instance, "init");
+      instance.onAction({type: at.INIT});
+      assert.calledOnce(stub);
+    });
+    it("should call .addSession() on a NEW_TAB_VISIBLE action", () => {
+      const stub = sandbox.stub(instance, "addSession");
+      instance.onAction(ac.SendToMain({type: at.NEW_TAB_VISIBLE}, "port123"));
+      assert.calledWith(stub, "port123");
+    });
+    it("should call .endSession() on a NEW_TAB_UNLOAD action", () => {
+      const stub = sandbox.stub(instance, "endSession");
+      instance.onAction(ac.SendToMain({type: at.NEW_TAB_UNLOAD}, "port123"));
+      assert.calledWith(stub, "port123");
+    });
+    it("should send an event on an TELEMETRY_UNDESIRED_EVENT action", () => {
+      const sendEvent = sandbox.stub(instance, "sendEvent");
+      const eventCreator = sandbox.stub(instance, "createUndesiredEvent");
+      const action = {type: at.TELEMETRY_UNDESIRED_EVENT};
+      instance.onAction(action);
+      assert.calledWith(eventCreator, action);
+      assert.calledWith(sendEvent, eventCreator.returnValue);
+    });
+    it("should send an event on an TELEMETRY_USER_EVENT action", () => {
+      const sendEvent = sandbox.stub(instance, "sendEvent");
+      const eventCreator = sandbox.stub(instance, "createUserEvent");
+      const action = {type: at.TELEMETRY_USER_EVENT};
+      instance.onAction(action);
+      assert.calledWith(eventCreator, action);
+      assert.calledWith(sendEvent, eventCreator.returnValue);
+    });
+    it("should send an event on an TELEMETRY_PERFORMANCE_EVENT action", () => {
+      const sendEvent = sandbox.stub(instance, "sendEvent");
+      const eventCreator = sandbox.stub(instance, "createPerformanceEvent");
+      const action = {type: at.TELEMETRY_PERFORMANCE_EVENT};
+      instance.onAction(action);
+      assert.calledWith(eventCreator, action);
+      assert.calledWith(sendEvent, eventCreator.returnValue);
+    });
+  });
+});
--- a/browser/extensions/activity-stream/test/unit/lib/TelemetrySender.test.js
+++ b/browser/extensions/activity-stream/test/unit/lib/TelemetrySender.test.js
@@ -1,49 +1,34 @@
 // Any copyright is dedicated to the Public Domain.
 // http://creativecommons.org/publicdomain/zero/1.0/
 
 const {GlobalOverrider, FakePrefs} = require("test/unit/utils");
-const {TelemetrySender} = require("lib/TelemetrySender.jsm");
+const {TelemetrySender, TelemetrySenderConstants} = require("lib/TelemetrySender.jsm");
+const {ENDPOINT_PREF, TELEMETRY_PREF, LOGGING_PREF} = TelemetrySenderConstants;
 
 /**
  * A reference to the fake preferences object created by the TelemetrySender
  * constructor so that we can use the API.
  */
 let fakePrefs;
 const prefInitHook = function() {
   fakePrefs = this; // eslint-disable-line consistent-this
 };
 const tsArgs = {prefInitHook};
 
 describe("TelemetrySender", () => {
   let globals;
   let tSender;
   let fetchStub;
-  const observerTopics = ["user-action-event", "performance-event",
-    "tab-session-complete", "undesired-event"];
   const fakeEndpointUrl = "http://127.0.0.1/stuff";
   const fakePingJSON = JSON.stringify({action: "fake_action", monkey: 1});
   const fakeFetchHttpErrorResponse = {ok: false, status: 400};
   const fakeFetchSuccessResponse = {ok: true, status: 200};
 
-  function assertNotificationObserversAdded() {
-    observerTopics.forEach(topic => {
-      assert.calledWithExactly(
-        global.Services.obs.addObserver, tSender, topic, true);
-    });
-  }
-
-  function assertNotificationObserversRemoved() {
-    observerTopics.forEach(topic => {
-      assert.calledWithExactly(
-        global.Services.obs.removeObserver, tSender, topic);
-    });
-  }
-
   before(() => {
     globals = new GlobalOverrider();
 
     fetchStub = globals.sandbox.stub();
 
     globals.set("Preferences", FakePrefs);
     globals.set("fetch", fetchStub);
   });
@@ -53,219 +38,164 @@ describe("TelemetrySender", () => {
 
   afterEach(() => {
     globals.reset();
     FakePrefs.prototype.prefs = {};
   });
 
   after(() => globals.restore());
 
-  it("should construct the Prefs object with the right branch", () => {
+  it("should construct the Prefs object", () => {
     globals.sandbox.spy(global, "Preferences");
 
     tSender = new TelemetrySender(tsArgs);
 
     assert.calledOnce(global.Preferences);
-    assert.calledWith(global.Preferences,
-      sinon.match.has("branch", "browser.newtabpage.activity-stream"));
   });
 
   it("should set the enabled prop to false if the pref is false", () => {
-    FakePrefs.prototype.prefs = {telemetry: false};
+    FakePrefs.prototype.prefs = {};
+    FakePrefs.prototype.prefs[TELEMETRY_PREF] = false;
 
     tSender = new TelemetrySender(tsArgs);
 
     assert.isFalse(tSender.enabled);
   });
 
-  it("should not add notification observers if the enabled pref is false", () => {
-    FakePrefs.prototype.prefs = {telemetry: false};
-
-    tSender = new TelemetrySender(tsArgs);
-
-    assert.notCalled(global.Services.obs.addObserver);
-  });
-
   it("should set the enabled prop to true if the pref is true", () => {
-    FakePrefs.prototype.prefs = {telemetry: true};
+    FakePrefs.prototype.prefs = {};
+    FakePrefs.prototype.prefs[TELEMETRY_PREF] = true;
 
     tSender = new TelemetrySender(tsArgs);
 
     assert.isTrue(tSender.enabled);
   });
 
-  it("should add all notification observers if the enabled pref is true", () => {
-    FakePrefs.prototype.prefs = {telemetry: true};
-
-    tSender = new TelemetrySender(tsArgs);
-
-    assertNotificationObserversAdded();
-  });
+  describe("#sendPing()", () => {
+    beforeEach(() => {
+      FakePrefs.prototype.prefs = {};
+      FakePrefs.prototype.prefs[TELEMETRY_PREF] = true;
+      FakePrefs.prototype.prefs[ENDPOINT_PREF] = fakeEndpointUrl;
+      tSender = new TelemetrySender(tsArgs);
+    });
 
-  describe("#_sendPing()", () => {
-    beforeEach(() => {
-      FakePrefs.prototype.prefs = {
-        "telemetry": true,
-        "telemetry.ping.endpoint": fakeEndpointUrl
-      };
-      tSender = new TelemetrySender(tsArgs);
+    it("should not send if the TelemetrySender is disabled", async () => {
+      tSender.enabled = false;
+
+      await tSender.sendPing(fakePingJSON);
+
+      assert.notCalled(fetchStub);
     });
 
     it("should POST given ping data to telemetry.ping.endpoint pref w/fetch",
     async () => {
       fetchStub.resolves(fakeFetchSuccessResponse);
-      await tSender._sendPing(fakePingJSON);
+      await tSender.sendPing(fakePingJSON);
 
       assert.calledOnce(fetchStub);
       assert.calledWithExactly(fetchStub, fakeEndpointUrl,
         {method: "POST", body: fakePingJSON});
     });
 
     it("should log HTTP failures using Cu.reportError", async () => {
       fetchStub.resolves(fakeFetchHttpErrorResponse);
 
-      await tSender._sendPing(fakePingJSON);
+      await tSender.sendPing(fakePingJSON);
 
       assert.called(Components.utils.reportError);
     });
 
     it("should log an error using Cu.reportError if fetch rejects", async () => {
       fetchStub.rejects("Oh noes!");
 
-      await tSender._sendPing(fakePingJSON);
+      await tSender.sendPing(fakePingJSON);
 
       assert.called(Components.utils.reportError);
     });
 
     it("should log if logging is on && if action is not activity_stream_performance", async () => {
-      FakePrefs.prototype.prefs = {
-        "telemetry": true,
-        "performance.log": true
-      };
+      globals.sandbox.stub(console, "log");
+      FakePrefs.prototype.prefs = {};
+      FakePrefs.prototype.prefs[TELEMETRY_PREF] = true;
+      FakePrefs.prototype.prefs[LOGGING_PREF] =  true;
       fetchStub.resolves(fakeFetchSuccessResponse);
       tSender = new TelemetrySender(tsArgs);
 
-      await tSender._sendPing(fakePingJSON);
+      await tSender.sendPing(fakePingJSON);
 
       assert.called(console.log); // eslint-disable-line no-console
     });
   });
 
-  describe("#observe()", () => {
-    before(() => {
-      globals.sandbox.stub(TelemetrySender.prototype, "_sendPing");
-    });
-
-    observerTopics.forEach(topic => {
-      it(`should call this._sendPing with data for ${topic}`, () => {
-        const fakeSubject = "fakeSubject";
-        tSender = new TelemetrySender(tsArgs);
-
-        tSender.observe(fakeSubject, topic, fakePingJSON);
-
-        assert.calledOnce(TelemetrySender.prototype._sendPing);
-        assert.calledWithExactly(TelemetrySender.prototype._sendPing,
-          fakePingJSON);
-      });
-    });
-
-    it("should not call this._sendPing for 'nonexistent-topic'", () => {
-      const fakeSubject = "fakeSubject";
-      tSender = new TelemetrySender(tsArgs);
-
-      tSender.observe(fakeSubject, "nonexistent-topic", fakePingJSON);
-
-      assert.notCalled(TelemetrySender.prototype._sendPing);
-    });
-  });
-
   describe("#uninit()", () => {
     it("should remove the telemetry pref listener", () => {
       tSender = new TelemetrySender(tsArgs);
-      assert.property(fakePrefs.observers, "telemetry");
+      assert.property(fakePrefs.observers, TELEMETRY_PREF);
 
       tSender.uninit();
 
-      assert.notProperty(fakePrefs.observers, "telemetry");
+      assert.notProperty(fakePrefs.observers, TELEMETRY_PREF);
     });
 
-    it("should remove all notification observers if telemetry pref is true", () => {
-      FakePrefs.prototype.prefs = {telemetry: true};
+    it("should remove the telemetry log listener", () => {
       tSender = new TelemetrySender(tsArgs);
+      assert.property(fakePrefs.observers, LOGGING_PREF);
 
       tSender.uninit();
 
-      assertNotificationObserversRemoved();
-    });
-
-    it("should not remove notification observers if telemetry pref is false", () => {
-      FakePrefs.prototype.prefs = {telemetry: false};
-      tSender = new TelemetrySender(tsArgs);
-
-      tSender.uninit();
-
-      assert.notCalled(global.Services.obs.removeObserver);
+      assert.notProperty(fakePrefs.observers, TELEMETRY_PREF);
     });
 
     it("should call Cu.reportError if this._prefs.ignore throws", () => {
       globals.sandbox.stub(FakePrefs.prototype, "ignore").throws("Some Error");
       tSender = new TelemetrySender(tsArgs);
 
       tSender.uninit();
 
       assert.called(global.Components.utils.reportError);
     });
   });
 
   describe("Misc pref changes", () => {
     describe("telemetry changes from true to false", () => {
       beforeEach(() => {
-        FakePrefs.prototype.prefs = {"telemetry": true};
+        FakePrefs.prototype.prefs = {};
+        FakePrefs.prototype.prefs[TELEMETRY_PREF] = true;
         tSender = new TelemetrySender(tsArgs);
         assert.propertyVal(tSender, "enabled", true);
       });
 
       it("should set the enabled property to false", () => {
-        fakePrefs.set("telemetry", false);
+        fakePrefs.set(TELEMETRY_PREF, false);
 
         assert.propertyVal(tSender, "enabled", false);
       });
-
-      it("should remove all notification observers", () => {
-        fakePrefs.set("telemetry", false);
-
-        assertNotificationObserversRemoved();
-      });
     });
 
     describe("telemetry changes from false to true", () => {
       beforeEach(() => {
-        FakePrefs.prototype.prefs = {"telemetry": false};
+        FakePrefs.prototype.prefs = {};
+        FakePrefs.prototype.prefs[TELEMETRY_PREF] = false;
         tSender = new TelemetrySender(tsArgs);
         assert.propertyVal(tSender, "enabled", false);
       });
 
       it("should set the enabled property to true", () => {
-        fakePrefs.set("telemetry", true);
+        fakePrefs.set(TELEMETRY_PREF, true);
 
         assert.propertyVal(tSender, "enabled", true);
       });
-
-      it("should add all topic observers", () => {
-        fakePrefs.set("telemetry", true);
-
-        assertNotificationObserversAdded();
-      });
     });
 
     describe("performance.log changes from false to true", () => {
       it("should change this.logging from false to true", () => {
-        FakePrefs.prototype.prefs = {"performance.log": false};
+        FakePrefs.prototype.prefs = {};
+        FakePrefs.prototype.prefs[LOGGING_PREF] = false;
         tSender = new TelemetrySender(tsArgs);
         assert.propertyVal(tSender, "logging", false);
 
-        fakePrefs.set("performance.log", true);
+        fakePrefs.set(LOGGING_PREF, true);
 
         assert.propertyVal(tSender, "logging", true);
       });
     });
   });
 });
--- a/browser/extensions/activity-stream/test/unit/lib/TopSitesFeed.test.js
+++ b/browser/extensions/activity-stream/test/unit/lib/TopSitesFeed.test.js
@@ -107,10 +107,32 @@ describe("Top Sites Feed", () => {
     });
     it("should not call refresh if .lastUpdated is less than update time on NEW_TAB_LOAD", () => {
       feed.lastUpdated = 0;
       clock.tick(UPDATE_TIME - 1);
       sinon.stub(feed, "refresh");
       feed.onAction({type: at.NEW_TAB_LOAD});
       assert.notCalled(feed.refresh);
     });
+    it("should call openNewWindow with the correct url on OPEN_NEW_WINDOW", () => {
+      sinon.stub(feed, "openNewWindow");
+      const openWindowAction = {type: at.OPEN_NEW_WINDOW, data: {url: "foo.com"}};
+      feed.onAction(openWindowAction);
+      assert.calledWith(feed.openNewWindow, openWindowAction);
+    });
+    it("should call openNewWindow with the correct url and privacy args on OPEN_PRIVATE_WINDOW", () => {
+      sinon.stub(feed, "openNewWindow");
+      const openWindowAction = {type: at.OPEN_PRIVATE_WINDOW, data: {url: "foo.com"}};
+      feed.onAction(openWindowAction);
+      assert.calledWith(feed.openNewWindow, openWindowAction, true);
+    });
+    it("should call openNewWindow with the correct url on OPEN_NEW_WINDOW", () => {
+      const openWindowAction = {
+        type: at.OPEN_NEW_WINDOW,
+        data: {url: "foo.com"},
+        _target: {browser: {ownerGlobal: {openLinkIn: () => {}}}}
+      };
+      sinon.stub(openWindowAction._target.browser.ownerGlobal, "openLinkIn");
+      feed.onAction(openWindowAction);
+      assert.calledOnce(openWindowAction._target.browser.ownerGlobal.openLinkIn);
+    });
   });
 });
--- a/browser/extensions/activity-stream/test/unit/unit-entry.js
+++ b/browser/extensions/activity-stream/test/unit/unit-entry.js
@@ -8,27 +8,33 @@ sinon.assert.expose(assert, {prefix: ""}
 
 let overrider = new GlobalOverrider();
 overrider.set({
   Components: {
     interfaces: {},
     utils: {
       import: overrider.sandbox.spy(),
       importGlobalProperties: overrider.sandbox.spy(),
-      reportError: overrider.sandbox.spy()
+      reportError: overrider.sandbox.spy(),
+      now: () => window.performance.now()
     }
   },
   XPCOMUtils: {
     defineLazyModuleGetter: overrider.sandbox.spy(),
     defineLazyServiceGetter: overrider.sandbox.spy(),
     generateQI: overrider.sandbox.stub().returns(() => {})
   },
-  console: {log: overrider.sandbox.spy()},
   dump: overrider.sandbox.spy(),
+  fetch: overrider.sandbox.stub(),
   Services: {
+    locale: {getRequestedLocale: overrider.sandbox.stub()},
+    mm: {
+      addMessageListener: overrider.sandbox.spy((msg, cb) => cb()),
+      removeMessageListener: overrider.sandbox.spy()
+    },
     obs: {
       addObserver: overrider.sandbox.spy(),
       removeObserver: overrider.sandbox.spy()
     }
   }
 });
 
 describe("activity-stream", () => {
--- a/browser/extensions/activity-stream/test/unit/utils.js
+++ b/browser/extensions/activity-stream/test/unit/utils.js
@@ -1,8 +1,15 @@
+const React = require("react");
+const {mount, shallow} = require("enzyme");
+const {IntlProvider, intlShape} = require("react-intl");
+const messages = require("data/locales.json")["en-US"];
+const intlProvider = new IntlProvider({locale: "en", messages});
+const {intl} = intlProvider.getChildContext();
+
 /**
  * GlobalOverrider - Utility that allows you to override properties on the global object.
  *                   See unit-entry.js for example usage.
  */
 class GlobalOverrider {
   constructor() {
     this.originalGlobals = new Map();
     this.sandbox = sinon.sandbox.create();
@@ -110,13 +117,33 @@ FakePrefs.prototype = {
 
 /**
  * addNumberReducer - a simple dummy reducer for testing that adds a number
  */
 function addNumberReducer(prevState = 0, action) {
   return action.type === "ADD" ? prevState + action.data : prevState;
 }
 
+/**
+ * Helper functions to test components that need IntlProvider as an ancestor
+ */
+function nodeWithIntlProp(node) {
+  return React.cloneElement(node, {intl});
+}
+
+function shallowWithIntl(node) {
+  return shallow(nodeWithIntlProp(node), {context: {intl}});
+}
+
+function mountWithIntl(node) {
+  return mount(nodeWithIntlProp(node), {
+    context: {intl},
+    childContextTypes: {intl: intlShape}
+  });
+}
+
 module.exports = {
   FakePrefs,
   GlobalOverrider,
-  addNumberReducer
+  addNumberReducer,
+  mountWithIntl,
+  shallowWithIntl
 };
new file mode 100644
--- /dev/null
+++ b/browser/extensions/activity-stream/vendor/REACT_INTL_LICENSE
@@ -0,0 +1,27 @@
+Copyright 2014 Yahoo Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+    * Neither the name of the Yahoo Inc. nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL YAHOO! INC. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
new file mode 100644
--- /dev/null
+++ b/browser/extensions/activity-stream/vendor/react-intl.js
@@ -0,0 +1,9 @@
+/*
+ * ReactIntl v2.2.3
+ *
+ * Copyright 2017, Yahoo Inc.
+ * Copyrights licensed under the New BSD License.
+ * See the accompanying LICENSE file for terms.
+ */
+!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],e):e(t.ReactIntl=t.ReactIntl||{},t.React)}(this,function(t,e){"use strict";function r(t){var e,r,n,o,a=Array.prototype.slice.call(arguments,1);for(e=0,r=a.length;e<r;e+=1)if(n=a[e])for(o in n)q.call(n,o)&&(t[o]=n[o]);return t}function n(t,e,r){this.locales=t,this.formats=e,this.pluralFn=r}function o(t){this.id=t}function a(t,e,r,n,o){this.id=t,this.useOrdinal=e,this.offset=r,this.options=n,this.pluralFn=o}function i(t,e,r,n){this.id=t,this.offset=e,this.numberFormat=r,this.string=n}function l(t,e){this.id=t,this.options=e}function u(t,e,r){var n="string"==typeof t?u.__parse(t):t;if(!n||"messageFormatPattern"!==n.type)throw new TypeError("A message must be provided as a String or AST.");r=this._mergeFormats(u.formats,r),W(this,"_locale",{value:this._resolveLocale(e)});var o=this._findPluralRuleFunction(this._locale),a=this._compilePattern(n,e,r,o),i=this;this.format=function(t){return i._format(a,t)}}function s(t){return 400*t/146097}function c(t,e){e=e||{},et(t)&&(t=t.concat()),X(this,"_locale",{value:this._resolveLocale(t)}),X(this,"_options",{value:{style:this._resolveStyle(e.style),units:this._isValidUnits(e.units)&&e.units}}),X(this,"_locales",{value:t}),X(this,"_fields",{value:this._findFields(this._locale)}),X(this,"_messages",{value:Y(null)});var r=this;this.format=function(t,e){return r._format(t,e)}}function f(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],e=Array.isArray(t)?t:[t];e.forEach(function(t){t&&t.locale&&(u.__addLocaleData(t),c.__addLocaleData(t))})}function p(t){for(var e=(t||"").split("-");e.length>0;){if(h(e.join("-")))return!0;e.pop()}return!1}function h(t){var e=t&&t.toLowerCase();return!(!u.__localeData__[e]||!c.__localeData__[e])}function m(t){return(""+t).replace(Ut,function(t){return St[t]})}function d(t,e){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return e.reduce(function(e,n){return t.hasOwnProperty(n)?e[n]=t[n]:r.hasOwnProperty(n)&&(e[n]=r[n]),e},{})}function y(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=t.intl;Lt(e,"[React Intl] Could not find required `intl` object. <IntlProvider> needs to exist in the component ancestry.")}function v(t,e){if(t===e)return!0;if("object"!==("undefined"==typeof t?"undefined":it(t))||null===t||"object"!==("undefined"==typeof e?"undefined":it(e))||null===e)return!1;var r=Object.keys(t),n=Object.keys(e);if(r.length!==n.length)return!1;for(var o=Object.prototype.hasOwnProperty.bind(e),a=0;a<r.length;a++)if(!o(r[a])||t[r[a]]!==e[r[a]])return!1;return!0}function g(t,e,r){var n=t.props,o=t.state,a=t.context,i=void 0===a?{}:a,l=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},u=i.intl,s=void 0===u?{}:u,c=l.intl,f=void 0===c?{}:c;return!v(e,n)||!v(r,o)||!(f===s||v(d(f,It),d(s,It)))}function _(t){return t.displayName||t.name||"Component"}function b(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=r.intlPropName,o=void 0===n?"intl":n,a=r.withRef,i=void 0!==a&&a,l=function(e){function r(t,e){lt(this,r);var n=ht(this,(r.__proto__||Object.getPrototypeOf(r)).call(this,t,e));return y(e),n}return ft(r,e),ut(r,[{key:"getWrappedInstance",value:function(){return Lt(i,"[React Intl] To access the wrapped instance, the `{withRef: true}` option must be set when calling: `injectIntl()`"),this.refs.wrappedInstance}},{key:"render",value:function(){return U.createElement(t,ct({},this.props,st({},o,this.context.intl),{ref:i?"wrappedInstance":null}))}}]),r}(e.Component);return l.displayName="InjectIntl("+_(t)+")",l.contextTypes={intl:At},l.WrappedComponent=t,l}function w(t){return t}function F(t){return u.prototype._resolveLocale(t)}function O(t){return u.prototype._findPluralRuleFunction(t)}function x(t){var e=Zt(null);return function(){var r=Array.prototype.slice.call(arguments),n=P(r),o=n&&e[n];return o||(o=new(qt.apply(t,[null].concat(r))),n&&(e[n]=o)),o}}function P(t){if("undefined"!=typeof JSON){var e,r,n,o=[];for(e=0,r=t.length;e<r;e+=1)n=t[e],n&&"object"==typeof n?o.push(T(n)):o.push(n);return JSON.stringify(o)}}function T(t){var e,r,n,o,a=[],i=[];for(e in t)t.hasOwnProperty(e)&&i.push(e);var l=i.sort();for(r=0,n=l.length;r<n;r+=1)e=l[r],o={},o[e]=t[e],a[r]=o;return a}function j(t){var e=c.thresholds;e.second=t.second,e.minute=t.minute,e.hour=t.hour,e.day=t.day,e.month=t.month}function C(t,e,r){var n=t&&t[e]&&t[e][r];if(n)return n}function A(t,e,r){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},o=t.locale,a=t.formats,i=n.format,l=new Date(r),u=i&&C(a,"date",i),s=d(n,Bt,u);try{return e.getDateTimeFormat(o,s).format(l)}catch(t){}return String(l)}function N(t,e,r){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},o=t.locale,a=t.formats,i=n.format,l=new Date(r),u=i&&C(a,"time",i),s=d(n,Bt,u);s.hour||s.minute||s.second||(s=ct({},s,{hour:"numeric",minute:"numeric"}));try{return e.getDateTimeFormat(o,s).format(l)}catch(t){}return String(l)}function M(t,e,r){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},o=t.locale,a=t.formats,i=n.format,l=new Date(r),u=new Date(n.now),s=i&&C(a,"relative",i),f=d(n,$t,s),p=ct({},c.thresholds);j(Kt);try{return e.getRelativeFormat(o,f).format(l,{now:isFinite(u)?u:e.now()})}catch(t){}finally{j(p)}return String(l)}function R(t,e,r){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},o=t.locale,a=t.formats,i=n.format,l=i&&C(a,"number",i),u=d(n,Jt,l);try{return e.getNumberFormat(o,u).format(r)}catch(t){}return String(r)}function k(t,e,r){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},o=t.locale,a=d(n,zt);try{return e.getPluralFormat(o,a).format(r)}catch(t){}return"other"}function D(t,e){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},o=t.locale,a=t.formats,i=t.messages,l=t.defaultLocale,u=t.defaultFormats,s=r.id,c=r.defaultMessage;Lt(s,"[React Intl] An `id` must be provided to format a message.");var f=i&&i[s],p=Object.keys(n).length>0;if(!p)return f||c||s;var h=void 0;if(f)try{var m=e.getMessageFormat(f,o,a);h=m.format(n)}catch(t){}if(!h&&c)try{var d=e.getMessageFormat(c,l,u);h=d.format(n)}catch(t){}return h||f||c||s}function E(t,e,r){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},o=Object.keys(n).reduce(function(t,e){var r=n[e];return t[e]="string"==typeof r?m(r):r,t},{});return D(t,e,r,o)}function L(t){var e=Math.abs(t);return e<ae?"second":e<ie?"minute":e<le?"hour":"day"}function I(t){switch(t){case"second":return oe;case"minute":return ae;case"hour":return ie;case"day":return le;default:return ue}}function S(t,e){if(t===e)return!0;var r=new Date(t).getTime(),n=new Date(e).getTime();return isFinite(r)&&isFinite(n)&&r===n}if("undefined"==typeof e)throw new ReferenceError("React must be loaded before ReactIntl.");var U="default"in e?e.default:e,G={locale:"en",pluralRuleFunction:function(t,e){var r=String(t).split("."),n=!r[1],o=Number(r[0])==t,a=o&&r[0].slice(-1),i=o&&r[0].slice(-2);return e?1==a&&11!=i?"one":2==a&&12!=i?"two":3==a&&13!=i?"few":"other":1==t&&n?"one":"other"},fields:{year:{displayName:"year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{one:"in {0} year",other:"in {0} years"},past:{one:"{0} year ago",other:"{0} years ago"}}},month:{displayName:"month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{one:"in {0} month",other:"in {0} months"},past:{one:"{0} month ago",other:"{0} months ago"}}},day:{displayName:"day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{one:"in {0} day",other:"in {0} days"},past:{one:"{0} day ago",other:"{0} days ago"}}},hour:{displayName:"hour",relativeTime:{future:{one:"in {0} hour",other:"in {0} hours"},past:{one:"{0} hour ago",other:"{0} hours ago"}}},minute:{displayName:"minute",relativeTime:{future:{one:"in {0} minute",other:"in {0} minutes"},past:{one:"{0} minute ago",other:"{0} minutes ago"}}},second:{displayName:"second",relative:{0:"now"},relativeTime:{future:{one:"in {0} second",other:"in {0} seconds"},past:{one:"{0} second ago",other:"{0} seconds ago"}}}}},q=Object.prototype.hasOwnProperty,H=function(){try{return!!Object.defineProperty({},"a",{})}catch(t){return!1}}(),W=H?Object.defineProperty:function(t,e,r){"get"in r&&t.__defineGetter__?t.__defineGetter__(e,r.get):(!q.call(t,e)||"value"in r)&&(t[e]=r.value)},V=Object.create||function(t,e){function r(){}var n,o;r.prototype=t,n=new r;for(o in e)q.call(e,o)&&W(n,o,e[o]);return n};n.prototype.compile=function(t){return this.pluralStack=[],this.currentPlural=null,this.pluralNumberFormat=null,this.compileMessage(t)},n.prototype.compileMessage=function(t){if(!t||"messageFormatPattern"!==t.type)throw new Error('Message AST is not of type: "messageFormatPattern"');var e,r,n,o=t.elements,a=[];for(e=0,r=o.length;e<r;e+=1)switch(n=o[e],n.type){case"messageTextElement":a.push(this.compileMessageText(n));break;case"argumentElement":a.push(this.compileArgument(n));break;default:throw new Error("Message element does not have a valid type")}return a},n.prototype.compileMessageText=function(t){return this.currentPlural&&/(^|[^\\])#/g.test(t.value)?(this.pluralNumberFormat||(this.pluralNumberFormat=new Intl.NumberFormat(this.locales)),new i(this.currentPlural.id,this.currentPlural.format.offset,this.pluralNumberFormat,t.value)):t.value.replace(/\\#/g,"#")},n.prototype.compileArgument=function(t){var e=t.format;if(!e)return new o(t.id);var r,n=this.formats,i=this.locales,u=this.pluralFn;switch(e.type){case"numberFormat":return r=n.number[e.style],{id:t.id,format:new Intl.NumberFormat(i,r).format};case"dateFormat":return r=n.date[e.style],{id:t.id,format:new Intl.DateTimeFormat(i,r).format};case"timeFormat":return r=n.time[e.style],{id:t.id,format:new Intl.DateTimeFormat(i,r).format};case"pluralFormat":return r=this.compileOptions(t),new a(t.id,e.ordinal,e.offset,r,u);case"selectFormat":return r=this.compileOptions(t),new l(t.id,r);default:throw new Error("Message element does not have a valid format type")}},n.prototype.compileOptions=function(t){var e=t.format,r=e.options,n={};this.pluralStack.push(this.currentPlural),this.currentPlural="pluralFormat"===e.type?t:null;var o,a,i;for(o=0,a=r.length;o<a;o+=1)i=r[o],n[i.selector]=this.compileMessage(i.value);return this.currentPlural=this.pluralStack.pop(),n},o.prototype.format=function(t){return t?"string"==typeof t?t:String(t):""},a.prototype.getOption=function(t){var e=this.options,r=e["="+t]||e[this.pluralFn(t-this.offset,this.useOrdinal)];return r||e.other},i.prototype.format=function(t){var e=this.numberFormat.format(t-this.offset);return this.string.replace(/(^|[^\\])#/g,"$1"+e).replace(/\\#/g,"#")},l.prototype.getOption=function(t){var e=this.options;return e[t]||e.other};var Z=function(){function t(t,e){function r(){this.constructor=t}r.prototype=e.prototype,t.prototype=new r}function e(t,e,r,n,o,a){this.message=t,this.expected=e,this.found=r,this.offset=n,this.line=o,this.column=a,this.name="SyntaxError"}function r(t){function r(e){function r(e,r,n){var o,a;for(o=r;o<n;o++)a=t.charAt(o),"\n"===a?(e.seenCR||e.line++,e.column=1,e.seenCR=!1):"\r"===a||"\u2028"===a||"\u2029"===a?(e.line++,e.column=1,e.seenCR=!0):(e.column++,e.seenCR=!1)}return zt!==e&&(zt>e&&(zt=0,Kt={line:1,column:1,seenCR:!1}),r(Kt,zt,e),zt=e),Kt}function n(t){Jt<Qt||(Jt>Qt&&(Qt=Jt,Xt=[]),Xt.push(t))}function o(n,o,a){function i(t){var e=1;for(t.sort(function(t,e){return t.description<e.description?-1:t.description>e.description?1:0});e<t.length;)t[e-1]===t[e]?t.splice(e,1):e++}function l(t,e){function r(t){function e(t){return t.charCodeAt(0).toString(16).toUpperCase()}return t.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\x08/g,"\\b").replace(/\t/g,"\\t").replace(/\n/g,"\\n").replace(/\f/g,"\\f").replace(/\r/g,"\\r").replace(/[\x00-\x07\x0B\x0E\x0F]/g,function(t){return"\\x0"+e(t)}).replace(/[\x10-\x1F\x80-\xFF]/g,function(t){return"\\x"+e(t)}).replace(/[\u0180-\u0FFF]/g,function(t){return"\\u0"+e(t)}).replace(/[\u1080-\uFFFF]/g,function(t){return"\\u"+e(t)})}var n,o,a,i=new Array(t.length);for(a=0;a<t.length;a++)i[a]=t[a].description;return n=t.length>1?i.slice(0,-1).join(", ")+" or "+i[t.length-1]:i[0],o=e?'"'+r(e)+'"':"end of input","Expected "+n+" but "+o+" found."}var u=r(a),s=a<t.length?t.charAt(a):null;return null!==o&&i(o),new e(null!==n?n:l(o,s),o,s,a,u.line,u.column)}function a(){var t;return t=i()}function i(){var t,e,r;for(t=Jt,e=[],r=l();r!==N;)e.push(r),r=l();return e!==N&&($t=t,e=k(e)),t=e}function l(){var t;return t=s(),t===N&&(t=f()),t}function u(){var e,r,n,o,a,i;if(e=Jt,r=[],n=Jt,o=F(),o!==N?(a=j(),a!==N?(i=F(),i!==N?(o=[o,a,i],n=o):(Jt=n,n=D)):(Jt=n,n=D)):(Jt=n,n=D),n!==N)for(;n!==N;)r.push(n),n=Jt,o=F(),o!==N?(a=j(),a!==N?(i=F(),i!==N?(o=[o,a,i],n=o):(Jt=n,n=D)):(Jt=n,n=D)):(Jt=n,n=D);else r=D;return r!==N&&($t=e,r=E(r)),e=r,e===N&&(e=Jt,r=w(),r!==N&&(r=t.substring(e,Jt)),e=r),e}function s(){var t,e;return t=Jt,e=u(),e!==N&&($t=t,e=L(e)),t=e}function c(){var e,r,o;if(e=P(),e===N){if(e=Jt,r=[],I.test(t.charAt(Jt))?(o=t.charAt(Jt),Jt++):(o=N,0===Yt&&n(S)),o!==N)for(;o!==N;)r.push(o),I.test(t.charAt(Jt))?(o=t.charAt(Jt),Jt++):(o=N,0===Yt&&n(S));else r=D;r!==N&&(r=t.substring(e,Jt)),e=r}return e}function f(){var e,r,o,a,i,l,u,s,f;return e=Jt,123===t.charCodeAt(Jt)?(r=U,Jt++):(r=N,0===Yt&&n(G)),r!==N?(o=F(),o!==N?(a=c(),a!==N?(i=F(),i!==N?(l=Jt,44===t.charCodeAt(Jt)?(u=H,Jt++):(u=N,0===Yt&&n(W)),u!==N?(s=F(),s!==N?(f=p(),f!==N?(u=[u,s,f],l=u):(Jt=l,l=D)):(Jt=l,l=D)):(Jt=l,l=D),l===N&&(l=q),l!==N?(u=F(),u!==N?(125===t.charCodeAt(Jt)?(s=V,Jt++):(s=N,0===Yt&&n(Z)),s!==N?($t=e,r=B(a,l),e=r):(Jt=e,e=D)):(Jt=e,e=D)):(Jt=e,e=D)):(Jt=e,e=D)):(Jt=e,e=D)):(Jt=e,e=D)):(Jt=e,e=D),e}function p(){var t;return t=h(),t===N&&(t=m(),t===N&&(t=d(),t===N&&(t=y()))),t}function h(){var e,r,o,a,i,l,u;return e=Jt,t.substr(Jt,6)===J?(r=J,Jt+=6):(r=N,0===Yt&&n($)),r===N&&(t.substr(Jt,4)===z?(r=z,Jt+=4):(r=N,0===Yt&&n(K)),r===N&&(t.substr(Jt,4)===Q?(r=Q,Jt+=4):(r=N,0===Yt&&n(X)))),r!==N?(o=F(),o!==N?(a=Jt,44===t.charCodeAt(Jt)?(i=H,Jt++):(i=N,0===Yt&&n(W)),i!==N?(l=F(),l!==N?(u=j(),u!==N?(i=[i,l,u],a=i):(Jt=a,a=D)):(Jt=a,a=D)):(Jt=a,a=D),a===N&&(a=q),a!==N?($t=e,r=Y(r,a),e=r):(Jt=e,e=D)):(Jt=e,e=D)):(Jt=e,e=D),e}function m(){var e,r,o,a,i,l;return e=Jt,t.substr(Jt,6)===tt?(r=tt,Jt+=6):(r=N,0===Yt&&n(et)),r!==N?(o=F(),o!==N?(44===t.charCodeAt(Jt)?(a=H,Jt++):(a=N,0===Yt&&n(W)),a!==N?(i=F(),i!==N?(l=b(),l!==N?($t=e,r=rt(l),e=r):(Jt=e,e=D)):(Jt=e,e=D)):(Jt=e,e=D)):(Jt=e,e=D)):(Jt=e,e=D),e}function d(){var e,r,o,a,i,l;return e=Jt,t.substr(Jt,13)===nt?(r=nt,Jt+=13):(r=N,0===Yt&&n(ot)),r!==N?(o=F(),o!==N?(44===t.charCodeAt(Jt)?(a=H,Jt++):(a=N,0===Yt&&n(W)),a!==N?(i=F(),i!==N?(l=b(),l!==N?($t=e,r=at(l),e=r):(Jt=e,e=D)):(Jt=e,e=D)):(Jt=e,e=D)):(Jt=e,e=D)):(Jt=e,e=D),e}function y(){var e,r,o,a,i,l,u;if(e=Jt,t.substr(Jt,6)===it?(r=it,Jt+=6):(r=N,0===Yt&&n(lt)),r!==N)if(o=F(),o!==N)if(44===t.charCodeAt(Jt)?(a=H,Jt++):(a=N,0===Yt&&n(W)),a!==N)if(i=F(),i!==N){if(l=[],u=g(),u!==N)for(;u!==N;)l.push(u),u=g();else l=D;l!==N?($t=e,r=ut(l),e=r):(Jt=e,e=D)}else Jt=e,e=D;else Jt=e,e=D;else Jt=e,e=D;else Jt=e,e=D;return e}function v(){var e,r,o,a;return e=Jt,r=Jt,61===t.charCodeAt(Jt)?(o=st,Jt++):(o=N,0===Yt&&n(ct)),o!==N?(a=P(),a!==N?(o=[o,a],r=o):(Jt=r,r=D)):(Jt=r,r=D),r!==N&&(r=t.substring(e,Jt)),e=r,e===N&&(e=j()),e}function g(){var e,r,o,a,l,u,s,c,f;return e=Jt,r=F(),r!==N?(o=v(),o!==N?(a=F(),a!==N?(123===t.charCodeAt(Jt)?(l=U,Jt++):(l=N,0===Yt&&n(G)),l!==N?(u=F(),u!==N?(s=i(),s!==N?(c=F(),c!==N?(125===t.charCodeAt(Jt)?(f=V,Jt++):(f=N,0===Yt&&n(Z)),f!==N?($t=e,r=ft(o,s),e=r):(Jt=e,e=D)):(Jt=e,e=D)):(Jt=e,e=D)):(Jt=e,e=D)):(Jt=e,e=D)):(Jt=e,e=D)):(Jt=e,e=D)):(Jt=e,e=D),e}function _(){var e,r,o,a;return e=Jt,t.substr(Jt,7)===pt?(r=pt,Jt+=7):(r=N,0===Yt&&n(ht)),r!==N?(o=F(),o!==N?(a=P(),a!==N?($t=e,r=mt(a),e=r):(Jt=e,e=D)):(Jt=e,e=D)):(Jt=e,e=D),e}function b(){var t,e,r,n,o;if(t=Jt,e=_(),e===N&&(e=q),e!==N)if(r=F(),r!==N){if(n=[],o=g(),o!==N)for(;o!==N;)n.push(o),o=g();else n=D;n!==N?($t=t,e=dt(e,n),t=e):(Jt=t,t=D)}else Jt=t,t=D;else Jt=t,t=D;return t}function w(){var e,r;if(Yt++,e=[],vt.test(t.charAt(Jt))?(r=t.charAt(Jt),Jt++):(r=N,0===Yt&&n(gt)),r!==N)for(;r!==N;)e.push(r),vt.test(t.charAt(Jt))?(r=t.charAt(Jt),Jt++):(r=N,0===Yt&&n(gt));else e=D;return Yt--,e===N&&(r=N,0===Yt&&n(yt)),e}function F(){var e,r,o;for(Yt++,e=Jt,r=[],o=w();o!==N;)r.push(o),o=w();return r!==N&&(r=t.substring(e,Jt)),e=r,Yt--,e===N&&(r=N,0===Yt&&n(_t)),e}function O(){var e;return bt.test(t.charAt(Jt))?(e=t.charAt(Jt),Jt++):(e=N,0===Yt&&n(wt)),e}function x(){var e;return Ft.test(t.charAt(Jt))?(e=t.charAt(Jt),Jt++):(e=N,0===Yt&&n(Ot)),e}function P(){var e,r,o,a,i,l;if(e=Jt,48===t.charCodeAt(Jt)?(r=xt,Jt++):(r=N,0===Yt&&n(Pt)),r===N){if(r=Jt,o=Jt,Tt.test(t.charAt(Jt))?(a=t.charAt(Jt),Jt++):(a=N,0===Yt&&n(jt)),a!==N){for(i=[],l=O();l!==N;)i.push(l),l=O();i!==N?(a=[a,i],o=a):(Jt=o,o=D)}else Jt=o,o=D;o!==N&&(o=t.substring(r,Jt)),r=o}return r!==N&&($t=e,r=Ct(r)),e=r}function T(){var e,r,o,a,i,l,u,s;return At.test(t.charAt(Jt))?(e=t.charAt(Jt),Jt++):(e=N,0===Yt&&n(Nt)),e===N&&(e=Jt,t.substr(Jt,2)===Mt?(r=Mt,Jt+=2):(r=N,0===Yt&&n(Rt)),r!==N&&($t=e,r=kt()),e=r,e===N&&(e=Jt,t.substr(Jt,2)===Dt?(r=Dt,Jt+=2):(r=N,0===Yt&&n(Et)),r!==N&&($t=e,r=Lt()),e=r,e===N&&(e=Jt,t.substr(Jt,2)===It?(r=It,Jt+=2):(r=N,0===Yt&&n(St)),r!==N&&($t=e,r=Ut()),e=r,e===N&&(e=Jt,t.substr(Jt,2)===Gt?(r=Gt,Jt+=2):(r=N,0===Yt&&n(qt)),r!==N&&($t=e,r=Ht()),e=r,e===N&&(e=Jt,t.substr(Jt,2)===Wt?(r=Wt,Jt+=2):(r=N,0===Yt&&n(Vt)),r!==N?(o=Jt,a=Jt,i=x(),i!==N?(l=x(),l!==N?(u=x(),u!==N?(s=x(),s!==N?(i=[i,l,u,s],a=i):(Jt=a,a=D)):(Jt=a,a=D)):(Jt=a,a=D)):(Jt=a,a=D),a!==N&&(a=t.substring(o,Jt)),o=a,o!==N?($t=e,r=Zt(o),e=r):(Jt=e,e=D)):(Jt=e,e=D)))))),e}function j(){var t,e,r;if(t=Jt,e=[],r=T(),r!==N)for(;r!==N;)e.push(r),r=T();else e=D;return e!==N&&($t=t,e=Bt(e)),t=e}var C,A=arguments.length>1?arguments[1]:{},N={},M={start:a},R=a,k=function(t){return{type:"messageFormatPattern",elements:t}},D=N,E=function(t){var e,r,n,o,a,i="";for(e=0,n=t.length;e<n;e+=1)for(o=t[e],r=0,a=o.length;r<a;r+=1)i+=o[r];return i},L=function(t){return{type:"messageTextElement",value:t}},I=/^[^ \t\n\r,.+={}#]/,S={type:"class",value:"[^ \\t\\n\\r,.+={}#]",description:"[^ \\t\\n\\r,.+={}#]"},U="{",G={type:"literal",value:"{",description:'"{"'},q=null,H=",",W={type:"literal",value:",",description:'","'},V="}",Z={type:"literal",value:"}",description:'"}"'},B=function(t,e){return{type:"argumentElement",id:t,format:e&&e[2]}},J="number",$={type:"literal",value:"number",description:'"number"'},z="date",K={type:"literal",value:"date",description:'"date"'},Q="time",X={type:"literal",value:"time",description:'"time"'},Y=function(t,e){return{type:t+"Format",style:e&&e[2]}},tt="plural",et={type:"literal",value:"plural",description:'"plural"'},rt=function(t){return{type:t.type,ordinal:!1,offset:t.offset||0,options:t.options}},nt="selectordinal",ot={type:"literal",value:"selectordinal",description:'"selectordinal"'},at=function(t){return{type:t.type,ordinal:!0,offset:t.offset||0,options:t.options}},it="select",lt={type:"literal",value:"select",description:'"select"'},ut=function(t){return{type:"selectFormat",options:t}},st="=",ct={type:"literal",value:"=",description:'"="'},ft=function(t,e){return{type:"optionalFormatPattern",selector:t,value:e}},pt="offset:",ht={type:"literal",value:"offset:",description:'"offset:"'},mt=function(t){return t},dt=function(t,e){return{type:"pluralFormat",offset:t,options:e}},yt={type:"other",description:"whitespace"},vt=/^[ \t\n\r]/,gt={type:"class",value:"[ \\t\\n\\r]",description:"[ \\t\\n\\r]"},_t={type:"other",description:"optionalWhitespace"},bt=/^[0-9]/,wt={type:"class",value:"[0-9]",description:"[0-9]"},Ft=/^[0-9a-f]/i,Ot={type:"class",value:"[0-9a-f]i",description:"[0-9a-f]i"},xt="0",Pt={type:"literal",value:"0",description:'"0"'},Tt=/^[1-9]/,jt={type:"class",value:"[1-9]",description:"[1-9]"},Ct=function(t){return parseInt(t,10)},At=/^[^{}\\\0-\x1F \t\n\r]/,Nt={type:"class",value:"[^{}\\\\\\0-\\x1F \\t\\n\\r]",description:"[^{}\\\\\\0-\\x1F \\t\\n\\r]"},Mt="\\\\",Rt={type:"literal",value:"\\\\",description:'"\\\\\\\\"'},kt=function(){return"\\"},Dt="\\#",Et={type:"literal",value:"\\#",description:'"\\\\#"'},Lt=function(){return"\\#"},It="\\{",St={type:"literal",value:"\\{",description:'"\\\\{"'},Ut=function(){return"{"},Gt="\\}",qt={type:"literal",value:"\\}",description:'"\\\\}"'},Ht=function(){return"}"},Wt="\\u",Vt={type:"literal",value:"\\u",description:'"\\\\u"'},Zt=function(t){return String.fromCharCode(parseInt(t,16))},Bt=function(t){return t.join("")},Jt=0,$t=0,zt=0,Kt={line:1,column:1,seenCR:!1},Qt=0,Xt=[],Yt=0;if("startRule"in A){if(!(A.startRule in M))throw new Error("Can't start parsing from rule \""+A.startRule+'".');R=M[A.startRule]}if(C=R(),C!==N&&Jt===t.length)return C;throw C!==N&&Jt<t.length&&n({type:"end",description:"end of input"}),o(null,Xt,Qt)}return t(e,Error),{SyntaxError:e,parse:r}}();W(u,"formats",{enumerable:!0,value:{number:{currency:{style:"currency"},percent:{style:"percent"}},date:{short:{month:"numeric",day:"numeric",year:"2-digit"},medium:{month:"short",day:"numeric",year:"numeric"},long:{month:"long",day:"numeric",year:"numeric"},full:{weekday:"long",month:"long",day:"numeric",year:"numeric"}},time:{short:{hour:"numeric",minute:"numeric"},medium:{hour:"numeric",minute:"numeric",second:"numeric"},long:{hour:"numeric",minute:"numeric",second:"numeric",timeZoneName:"short"},full:{hour:"numeric",minute:"numeric",second:"numeric",timeZoneName:"short"}}}}),W(u,"__localeData__",{value:V(null)}),W(u,"__addLocaleData",{value:function(t){if(!t||!t.locale)throw new Error("Locale data provided to IntlMessageFormat is missing a `locale` property");u.__localeData__[t.locale.toLowerCase()]=t}}),W(u,"__parse",{value:Z.parse}),W(u,"defaultLocale",{enumerable:!0,writable:!0,value:void 0}),u.prototype.resolvedOptions=function(){return{locale:this._locale}},u.prototype._compilePattern=function(t,e,r,o){var a=new n(e,r,o);return a.compile(t)},u.prototype._findPluralRuleFunction=function(t){for(var e=u.__localeData__,r=e[t.toLowerCase()];r;){if(r.pluralRuleFunction)return r.pluralRuleFunction;r=r.parentLocale&&e[r.parentLocale.toLowerCase()]}throw new Error("Locale data added to IntlMessageFormat is missing a `pluralRuleFunction` for :"+t)},u.prototype._format=function(t,e){var r,n,o,a,i,l="";for(r=0,n=t.length;r<n;r+=1)if(o=t[r],"string"!=typeof o){if(a=o.id,!e||!q.call(e,a))throw new Error("A value must be provided for: "+a);i=e[a],l+=o.options?this._format(o.getOption(i),e):o.format(i)}else l+=o;return l},u.prototype._mergeFormats=function(t,e){var n,o,a={};for(n in t)q.call(t,n)&&(a[n]=o=V(t[n]),e&&q.call(e,n)&&r(o,e[n]));return a},u.prototype._resolveLocale=function(t){"string"==typeof t&&(t=[t]),t=(t||[]).concat(u.defaultLocale);var e,r,n,o,a=u.__localeData__;for(e=0,r=t.length;e<r;e+=1)for(n=t[e].toLowerCase().split("-");n.length;){if(o=a[n.join("-")])return o.locale;n.pop()}var i=t.pop();throw new Error("No locale data has been added to IntlMessageFormat for: "+t.join(", ")+", or the default locale: "+i)};var B={locale:"en",pluralRuleFunction:function(t,e){var r=String(t).split("."),n=!r[1],o=Number(r[0])==t,a=o&&r[0].slice(-1),i=o&&r[0].slice(-2);return e?1==a&&11!=i?"one":2==a&&12!=i?"two":3==a&&13!=i?"few":"other":1==t&&n?"one":"other"}};u.__addLocaleData(B),u.defaultLocale="en";var J=Math.round,$=function(t,e){t=+t,e=+e;var r=J(e-t),n=J(r/1e3),o=J(n/60),a=J(o/60),i=J(a/24),l=J(i/7),u=s(i),c=J(12*u),f=J(u);return{millisecond:r,second:n,minute:o,hour:a,day:i,week:l,month:c,year:f}},z=Object.prototype.hasOwnProperty,K=Object.prototype.toString,Q=function(){try{return!!Object.defineProperty({},"a",{})}catch(t){return!1}}(),X=Q?Object.defineProperty:function(t,e,r){"get"in r&&t.__defineGetter__?t.__defineGetter__(e,r.get):(!z.call(t,e)||"value"in r)&&(t[e]=r.value)},Y=Object.create||function(t,e){function r(){}var n,o;r.prototype=t,n=new r;for(o in e)z.call(e,o)&&X(n,o,e[o]);return n},tt=Array.prototype.indexOf||function(t,e){var r=this;if(!r.length)return-1;for(var n=e||0,o=r.length;n<o;n++)if(r[n]===t)return n;return-1},et=Array.isArray||function(t){return"[object Array]"===K.call(t)},rt=Date.now||function(){return(new Date).getTime()},nt=["second","minute","hour","day","month","year"],ot=["best fit","numeric"];X(c,"__localeData__",{value:Y(null)}),X(c,"__addLocaleData",{value:function(t){if(!t||!t.locale)throw new Error("Locale data provided to IntlRelativeFormat is missing a `locale` property value");c.__localeData__[t.locale.toLowerCase()]=t,u.__addLocaleData(t)}}),X(c,"defaultLocale",{enumerable:!0,writable:!0,value:void 0}),X(c,"thresholds",{enumerable:!0,value:{second:45,minute:45,hour:22,day:26,month:11}}),c.prototype.resolvedOptions=function(){return{locale:this._locale,style:this._options.style,units:this._options.units}},c.prototype._compileMessage=function(t){var e,r=this._locales,n=(this._locale,this._fields[t]),o=n.relativeTime,a="",i="";for(e in o.future)o.future.hasOwnProperty(e)&&(a+=" "+e+" {"+o.future[e].replace("{0}","#")+"}");for(e in o.past)o.past.hasOwnProperty(e)&&(i+=" "+e+" {"+o.past[e].replace("{0}","#")+"}");var l="{when, select, future {{0, plural, "+a+"}}past {{0, plural, "+i+"}}}";return new u(l,r)},c.prototype._getMessage=function(t){var e=this._messages;return e[t]||(e[t]=this._compileMessage(t)),e[t]},c.prototype._getRelativeUnits=function(t,e){var r=this._fields[e];if(r.relative)return r.relative[t]},c.prototype._findFields=function(t){for(var e=c.__localeData__,r=e[t.toLowerCase()];r;){if(r.fields)return r.fields;r=r.parentLocale&&e[r.parentLocale.toLowerCase()]}throw new Error("Locale data added to IntlRelativeFormat is missing `fields` for :"+t)},c.prototype._format=function(t,e){var r=e&&void 0!==e.now?e.now:rt();if(void 0===t&&(t=r),!isFinite(r))throw new RangeError("The `now` option provided to IntlRelativeFormat#format() is not in valid range.");if(!isFinite(t))throw new RangeError("The date value provided to IntlRelativeFormat#format() is not in valid range.");var n=$(r,t),o=this._options.units||this._selectUnits(n),a=n[o];if("numeric"!==this._options.style){var i=this._getRelativeUnits(a,o);if(i)return i}return this._getMessage(o).format({0:Math.abs(a),when:a<0?"past":"future"})},c.prototype._isValidUnits=function(t){if(!t||tt.call(nt,t)>=0)return!0;if("string"==typeof t){var e=/s$/.test(t)&&t.substr(0,t.length-1);if(e&&tt.call(nt,e)>=0)throw new Error('"'+t+'" is not a valid IntlRelativeFormat `units` value, did you mean: '+e)}throw new Error('"'+t+'" is not a valid IntlRelativeFormat `units` value, it must be one of: "'+nt.join('", "')+'"')},c.prototype._resolveLocale=function(t){"string"==typeof t&&(t=[t]),t=(t||[]).concat(c.defaultLocale);var e,r,n,o,a=c.__localeData__;for(e=0,r=t.length;e<r;e+=1)for(n=t[e].toLowerCase().split("-");n.length;){if(o=a[n.join("-")])return o.locale;n.pop()}var i=t.pop();throw new Error("No locale data has been added to IntlRelativeFormat for: "+t.join(", ")+", or the default locale: "+i)},c.prototype._resolveStyle=function(t){if(!t)return ot[0];if(tt.call(ot,t)>=0)return t;throw new Error('"'+t+'" is not a valid IntlRelativeFormat `style` value, it must be one of: "'+ot.join('", "')+'"')},c.prototype._selectUnits=function(t){var e,r,n;for(e=0,r=nt.length;e<r&&(n=nt[e],!(Math.abs(t[n])<c.thresholds[n]));e+=1);return n};var at={locale:"en",pluralRuleFunction:function(t,e){var r=String(t).split("."),n=!r[1],o=Number(r[0])==t,a=o&&r[0].slice(-1),i=o&&r[0].slice(-2);return e?1==a&&11!=i?"one":2==a&&12!=i?"two":3==a&&13!=i?"few":"other":1==t&&n?"one":"other"},fields:{year:{displayName:"year",relative:{0:"this year",1:"next year","-1":"last year"},relativeTime:{future:{one:"in {0} year",other:"in {0} years"},past:{one:"{0} year ago",other:"{0} years ago"}}},month:{displayName:"month",relative:{0:"this month",1:"next month","-1":"last month"},relativeTime:{future:{one:"in {0} month",other:"in {0} months"},past:{one:"{0} month ago",other:"{0} months ago"}}},day:{displayName:"day",relative:{0:"today",1:"tomorrow","-1":"yesterday"},relativeTime:{future:{one:"in {0} day",other:"in {0} days"},past:{one:"{0} day ago",other:"{0} days ago"}}},hour:{displayName:"hour",relativeTime:{future:{one:"in {0} hour",other:"in {0} hours"},past:{one:"{0} hour ago",other:"{0} hours ago"}}},minute:{displayName:"minute",relativeTime:{future:{one:"in {0} minute",other:"in {0} minutes"},past:{one:"{0} minute ago",other:"{0} minutes ago"}}},second:{displayName:"second",relative:{0:"now"},relativeTime:{future:{one:"in {0} second",other:"in {0} seconds"},past:{one:"{0} second ago",other:"{0} seconds ago"}}}}};c.__addLocaleData(at),c.defaultLocale="en";var it="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},lt=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},ut=function(){function t(t,e){for(var r=0;r<e.length;r++){var n=e[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}return function(e,r,n){return r&&t(e.prototype,r),n&&t(e,n),e}}(),st=function(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t},ct=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(t[n]=r[n])}return t},ft=function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)},pt=function(t,e){var r={};for(var n in t)e.indexOf(n)>=0||Object.prototype.hasOwnProperty.call(t,n)&&(r[n]=t[n]);return r},ht=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e},mt=function(t){if(Array.isArray(t)){for(var e=0,r=Array(t.length);e<t.length;e++)r[e]=t[e];return r}return Array.from(t)},dt=e.PropTypes.bool,yt=e.PropTypes.number,vt=e.PropTypes.string,gt=e.PropTypes.func,_t=e.PropTypes.object,bt=e.PropTypes.oneOf,wt=e.PropTypes.shape,Ft=e.PropTypes.any,Ot=bt(["best fit","lookup"]),xt=bt(["narrow","short","long"]),Pt=bt(["numeric","2-digit"]),Tt=gt.isRequired,jt={locale:vt,formats:_t,messages:_t,textComponent:Ft,defaultLocale:vt,defaultFormats:_t},Ct={formatDate:Tt,formatTime:Tt,formatRelative:Tt,formatNumber:Tt,formatPlural:Tt,formatMessage:Tt,formatHTMLMessage:Tt},At=wt(ct({},jt,Ct,{formatters:_t,now:Tt})),Nt={localeMatcher:Ot,formatMatcher:bt(["basic","best fit"]),timeZone:vt,hour12:dt,weekday:xt,era:xt,year:Pt,month:bt(["numeric","2-digit","narrow","short","long"]),day:Pt,hour:Pt,minute:Pt,second:Pt,timeZoneName:bt(["short","long"])},Mt={localeMatcher:Ot,style:bt(["decimal","currency","percent"]),currency:vt,currencyDisplay:bt(["symbol","code","name"]),useGrouping:dt,minimumIntegerDigits:yt,minimumFractionDigits:yt,maximumFractionDigits:yt,minimumSignificantDigits:yt,maximumSignificantDigits:yt},Rt={style:bt(["best fit","numeric"]),units:bt(["second","minute","hour","day","month","year"])},kt={style:bt(["cardinal","ordinal"])},Dt="production",Et=function(t,e,r,n,o,a,i,l){if("production"!==Dt&&void 0===e)throw new Error("invariant requires an error message argument");if(!t){var u;if(void 0===e)u=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var s=[r,n,o,a,i,l],c=0;u=new Error(e.replace(/%s/g,function(){return s[c++]})),u.name="Invariant Violation";
+}throw u.framesToPop=1,u}},Lt=Et,It=Object.keys(jt),St={"&":"&amp;",">":"&gt;","<":"&lt;",'"':"&quot;","'":"&#x27;"},Ut=/[&><"']/g,Gt=function t(e){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};lt(this,t);var n="ordinal"===r.style,o=O(F(e));this.format=function(t){return o(t,n)}},qt=Function.prototype.bind||function(t){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var e=Array.prototype.slice.call(arguments,1),r=this,n=function(){},o=function(){return r.apply(this instanceof n?this:t,e.concat(Array.prototype.slice.call(arguments)))};return this.prototype&&(n.prototype=this.prototype),o.prototype=new n,o},Ht=Object.prototype.hasOwnProperty,Wt=function(){try{return!!Object.defineProperty({},"a",{})}catch(t){return!1}}(),Vt=Wt?Object.defineProperty:function(t,e,r){"get"in r&&t.__defineGetter__?t.__defineGetter__(e,r.get):(!Ht.call(t,e)||"value"in r)&&(t[e]=r.value)},Zt=Object.create||function(t,e){function r(){}var n,o;r.prototype=t,n=new r;for(o in e)Ht.call(e,o)&&Vt(n,o,e[o]);return n},Bt=Object.keys(Nt),Jt=Object.keys(Mt),$t=Object.keys(Rt),zt=Object.keys(kt),Kt={second:60,minute:60,hour:24,day:30,month:12},Qt=Object.freeze({formatDate:A,formatTime:N,formatRelative:M,formatNumber:R,formatPlural:k,formatMessage:D,formatHTMLMessage:E}),Xt=Object.keys(jt),Yt=Object.keys(Ct),te={formats:{},messages:{},textComponent:"span",defaultLocale:"en",defaultFormats:{}},ee=function(t){function r(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};lt(this,r);var n=ht(this,(r.__proto__||Object.getPrototypeOf(r)).call(this,t,e));Lt("undefined"!=typeof Intl,"[React Intl] The `Intl` APIs must be available in the runtime, and do not appear to be built-in. An `Intl` polyfill should be loaded.\nSee: http://formatjs.io/guides/runtime-environments/");var o=e.intl,a=void 0;a=isFinite(t.initialNow)?Number(t.initialNow):o?o.now():Date.now();var i=o||{},l=i.formatters,s=void 0===l?{getDateTimeFormat:x(Intl.DateTimeFormat),getNumberFormat:x(Intl.NumberFormat),getMessageFormat:x(u),getRelativeFormat:x(c),getPluralFormat:x(Gt)}:l;return n.state=ct({},s,{now:function(){return n._didDisplay?Date.now():a}}),n}return ft(r,t),ut(r,[{key:"getConfig",value:function(){var t=this.context.intl,e=d(this.props,Xt,t);for(var r in te)void 0===e[r]&&(e[r]=te[r]);if(!p(e.locale)){var n=e,o=(n.locale,n.defaultLocale),a=n.defaultFormats;e=ct({},e,{locale:o,formats:a,messages:te.messages})}return e}},{key:"getBoundFormatFns",value:function(t,e){return Yt.reduce(function(r,n){return r[n]=Qt[n].bind(null,t,e),r},{})}},{key:"getChildContext",value:function(){var t=this.getConfig(),e=this.getBoundFormatFns(t,this.state),r=this.state,n=r.now,o=pt(r,["now"]);return{intl:ct({},t,e,{formatters:o,now:n})}}},{key:"shouldComponentUpdate",value:function(){for(var t=arguments.length,e=Array(t),r=0;r<t;r++)e[r]=arguments[r];return g.apply(void 0,[this].concat(e))}},{key:"componentDidMount",value:function(){this._didDisplay=!0}},{key:"render",value:function(){return e.Children.only(this.props.children)}}]),r}(e.Component);ee.displayName="IntlProvider",ee.contextTypes={intl:At},ee.childContextTypes={intl:At.isRequired};var re=function(t){function e(t,r){lt(this,e);var n=ht(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,t,r));return y(r),n}return ft(e,t),ut(e,[{key:"shouldComponentUpdate",value:function(){for(var t=arguments.length,e=Array(t),r=0;r<t;r++)e[r]=arguments[r];return g.apply(void 0,[this].concat(e))}},{key:"render",value:function(){var t=this.context.intl,e=t.formatDate,r=t.textComponent,n=this.props,o=n.value,a=n.children,i=e(o,this.props);return"function"==typeof a?a(i):U.createElement(r,null,i)}}]),e}(e.Component);re.displayName="FormattedDate",re.contextTypes={intl:At};var ne=function(t){function e(t,r){lt(this,e);var n=ht(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,t,r));return y(r),n}return ft(e,t),ut(e,[{key:"shouldComponentUpdate",value:function(){for(var t=arguments.length,e=Array(t),r=0;r<t;r++)e[r]=arguments[r];return g.apply(void 0,[this].concat(e))}},{key:"render",value:function(){var t=this.context.intl,e=t.formatTime,r=t.textComponent,n=this.props,o=n.value,a=n.children,i=e(o,this.props);return"function"==typeof a?a(i):U.createElement(r,null,i)}}]),e}(e.Component);ne.displayName="FormattedTime",ne.contextTypes={intl:At};var oe=1e3,ae=6e4,ie=36e5,le=864e5,ue=2147483647,se=function(t){function e(t,r){lt(this,e);var n=ht(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,t,r));y(r);var o=isFinite(t.initialNow)?Number(t.initialNow):r.intl.now();return n.state={now:o},n}return ft(e,t),ut(e,[{key:"scheduleNextUpdate",value:function(t,e){var r=this,n=t.updateInterval;if(n){var o=new Date(t.value).getTime(),a=o-e.now,i=t.units||L(a),l=I(i),u=Math.abs(a%l),s=a<0?Math.max(n,l-u):Math.max(n,u);clearTimeout(this._timer),this._timer=setTimeout(function(){r.setState({now:r.context.intl.now()})},s)}}},{key:"componentDidMount",value:function(){this.scheduleNextUpdate(this.props,this.state)}},{key:"componentWillReceiveProps",value:function(t){var e=t.value;S(e,this.props.value)||this.setState({now:this.context.intl.now()})}},{key:"shouldComponentUpdate",value:function(){for(var t=arguments.length,e=Array(t),r=0;r<t;r++)e[r]=arguments[r];return g.apply(void 0,[this].concat(e))}},{key:"componentWillUpdate",value:function(t,e){this.scheduleNextUpdate(t,e)}},{key:"componentWillUnmount",value:function(){clearTimeout(this._timer)}},{key:"render",value:function(){var t=this.context.intl,e=t.formatRelative,r=t.textComponent,n=this.props,o=n.value,a=n.children,i=e(o,ct({},this.props,this.state));return"function"==typeof a?a(i):U.createElement(r,null,i)}}]),e}(e.Component);se.displayName="FormattedRelative",se.contextTypes={intl:At},se.defaultProps={updateInterval:1e4};var ce=function(t){function e(t,r){lt(this,e);var n=ht(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,t,r));return y(r),n}return ft(e,t),ut(e,[{key:"shouldComponentUpdate",value:function(){for(var t=arguments.length,e=Array(t),r=0;r<t;r++)e[r]=arguments[r];return g.apply(void 0,[this].concat(e))}},{key:"render",value:function(){var t=this.context.intl,e=t.formatNumber,r=t.textComponent,n=this.props,o=n.value,a=n.children,i=e(o,this.props);return"function"==typeof a?a(i):U.createElement(r,null,i)}}]),e}(e.Component);ce.displayName="FormattedNumber",ce.contextTypes={intl:At};var fe=function(t){function e(t,r){lt(this,e);var n=ht(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,t,r));return y(r),n}return ft(e,t),ut(e,[{key:"shouldComponentUpdate",value:function(){for(var t=arguments.length,e=Array(t),r=0;r<t;r++)e[r]=arguments[r];return g.apply(void 0,[this].concat(e))}},{key:"render",value:function(){var t=this.context.intl,e=t.formatPlural,r=t.textComponent,n=this.props,o=n.value,a=n.other,i=n.children,l=e(o,this.props),u=this.props[l]||a;return"function"==typeof i?i(u):U.createElement(r,null,u)}}]),e}(e.Component);fe.displayName="FormattedPlural",fe.contextTypes={intl:At},fe.defaultProps={style:"cardinal"};var pe=function(t){function r(t,e){lt(this,r);var n=ht(this,(r.__proto__||Object.getPrototypeOf(r)).call(this,t,e));return y(e),n}return ft(r,t),ut(r,[{key:"shouldComponentUpdate",value:function(t){var e=this.props.values,r=t.values;if(!v(r,e))return!0;for(var n=ct({},t,{values:e}),o=arguments.length,a=Array(o>1?o-1:0),i=1;i<o;i++)a[i-1]=arguments[i];return g.apply(void 0,[this,n].concat(a))}},{key:"render",value:function(){var t=this.context.intl,r=t.formatMessage,n=t.textComponent,o=this.props,a=o.id,i=o.description,l=o.defaultMessage,u=o.values,s=o.tagName,c=void 0===s?n:s,f=o.children,p=void 0,h=void 0,m=void 0,d=u&&Object.keys(u).length>0;d&&!function(){var t=Math.floor(1099511627776*Math.random()).toString(16),r=function(){var e=0;return function(){return"ELEMENT-"+t+"-"+(e+=1)}}();p="@__"+t+"__@",h={},m={},Object.keys(u).forEach(function(t){var n=u[t];if(e.isValidElement(n)){var o=r();h[t]=p+o+p,m[o]=n}else h[t]=n})}();var y={id:a,description:i,defaultMessage:l},v=r(y,h||u),g=void 0,_=m&&Object.keys(m).length>0;return g=_?v.split(p).filter(function(t){return!!t}).map(function(t){return m[t]||t}):[v],"function"==typeof f?f.apply(void 0,mt(g)):e.createElement.apply(void 0,[c,null].concat(mt(g)))}}]),r}(e.Component);pe.displayName="FormattedMessage",pe.contextTypes={intl:At},pe.defaultProps={values:{}};var he=function(t){function e(t,r){lt(this,e);var n=ht(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,t,r));return y(r),n}return ft(e,t),ut(e,[{key:"shouldComponentUpdate",value:function(t){var e=this.props.values,r=t.values;if(!v(r,e))return!0;for(var n=ct({},t,{values:e}),o=arguments.length,a=Array(o>1?o-1:0),i=1;i<o;i++)a[i-1]=arguments[i];return g.apply(void 0,[this,n].concat(a))}},{key:"render",value:function(){var t=this.context.intl,e=t.formatHTMLMessage,r=t.textComponent,n=this.props,o=n.id,a=n.description,i=n.defaultMessage,l=n.values,u=n.tagName,s=void 0===u?r:u,c=n.children,f={id:o,description:a,defaultMessage:i},p=e(f,l);if("function"==typeof c)return c(p);var h={__html:p};return U.createElement(s,{dangerouslySetInnerHTML:h})}}]),e}(e.Component);he.displayName="FormattedHTMLMessage",he.contextTypes={intl:At},he.defaultProps={values:{}},f(G),t.addLocaleData=f,t.intlShape=At,t.injectIntl=b,t.defineMessages=w,t.IntlProvider=ee,t.FormattedDate=re,t.FormattedTime=ne,t.FormattedRelative=se,t.FormattedNumber=ce,t.FormattedPlural=fe,t.FormattedMessage=pe,t.FormattedHTMLMessage=he,Object.defineProperty(t,"__esModule",{value:!0})});