Bug 1523741 - Converting legacy aboutTelemetry to Fluent aboutTelemetry, r=jaws,flod,Gijs
☠☠ backed out by dc53fe5c9ced ☠ ☠
authorAvery Berninger <berning5@msu.edu>
Sat, 06 Apr 2019 00:54:52 +0000
changeset 468279 7e40ec0c948d98106fcb558c7650889f10f399a7
parent 468278 6b15d6c337b39b7a6ed533525fe1a565c818031d
child 468280 dc53fe5c9cedaf4b7620ce76b7f72af51f31948f
push id35826
push usernerli@mozilla.com
push dateSat, 06 Apr 2019 21:48:00 +0000
treeherdermozilla-central@dc53fe5c9ced [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws, flod, Gijs
bugs1523741
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1523741 - Converting legacy aboutTelemetry to Fluent aboutTelemetry, r=jaws,flod,Gijs Differential Revision: https://phabricator.services.mozilla.com/D20417
mobile/android/chrome/jar.mn
mobile/android/locales/filter.py
mobile/android/locales/jar.mn
mobile/android/locales/l10n.toml
mobile/locales/filter.py
python/l10n/fluent_migrations/bug_1523741_aboutTelemetry.py
toolkit/content/aboutTelemetry.js
toolkit/content/aboutTelemetry.xhtml
toolkit/locales/en-US/chrome/global/aboutTelemetry.dtd
toolkit/locales/en-US/chrome/global/aboutTelemetry.properties
toolkit/locales/en-US/toolkit/about/aboutTelemetry.ftl
toolkit/locales/jar.mn
--- a/mobile/android/chrome/jar.mn
+++ b/mobile/android/chrome/jar.mn
@@ -55,18 +55,16 @@ chrome.jar:
 % override chrome://global/locale/aboutReader.properties chrome://browser/locale/overrides/aboutReader.properties
 % override chrome://global/locale/charsetMenu.properties chrome://browser/locale/overrides/charsetMenu.properties
 % override chrome://global/locale/commonDialogs.properties chrome://browser/locale/overrides/commonDialogs.properties
 % override chrome://global/locale/intl.properties chrome://browser/locale/overrides/intl.properties
 % override chrome://global/locale/intl.css chrome://browser/locale/overrides/intl.css
 % override chrome://global/locale/search/search.properties chrome://browser/locale/overrides/search/search.properties
 % override chrome://pluginproblem/locale/pluginproblem.dtd chrome://browser/locale/overrides/plugins/pluginproblem.dtd
 % override chrome://global/locale/mozilla.dtd chrome://browser/locale/overrides/global/mozilla.dtd
-% override chrome://global/locale/aboutTelemetry.dtd chrome://browser/locale/overrides/global/aboutTelemetry.dtd
-% override chrome://global/locale/aboutTelemetry.properties chrome://browser/locale/overrides/global/aboutTelemetry.properties
 % override chrome://global/locale/aboutWebrtc.properties chrome://browser/locale/overrides/global/aboutWebrtc.properties
 
 # overrides for dom l10n, also for en-US
 # keep this file list in sync with filter.py
 % override chrome://global/locale/global.dtd chrome://browser/locale/overrides/global.dtd
 % override chrome://global/locale/AccessFu.properties chrome://browser/locale/overrides/AccessFu.properties
 % override chrome://global/locale/dom/dom.properties chrome://browser/locale/overrides/dom/dom.properties
 % override chrome://global/locale/plugins.properties chrome://browser/locale/overrides/plugins.properties
--- a/mobile/android/locales/filter.py
+++ b/mobile/android/locales/filter.py
@@ -21,18 +21,16 @@ def test(mod, path, entity=None):
             "chrome/global/aboutReader.properties",
             "chrome/global/charsetMenu.properties",
             "chrome/global/commonDialogs.properties",
             "chrome/global/intl.properties",
             "chrome/global/intl.css",
             "chrome/search/search.properties",
             "chrome/pluginproblem/pluginproblem.dtd",
             "chrome/global/mozilla.dtd",
-            "chrome/global/aboutTelemetry.dtd",
-            "chrome/global/aboutTelemetry.properties",
             "chrome/global/aboutWebrtc.properties",
         ):
             return "error"
         if re.match(r"crashreporter/[^/]*.ftl", path):
             # error on crashreporter/*.ftl
             return "error"
         if re.match(r"toolkit/about/[^/]*About.ftl", path):
             # error on toolkit/about/*About.ftl
--- a/mobile/android/locales/jar.mn
+++ b/mobile/android/locales/jar.mn
@@ -42,19 +42,16 @@ relativesrcdir toolkit/locales:
   locale/@AB_CD@/browser/overrides/commonDialogs.properties        (%chrome/global/commonDialogs.properties)
   locale/@AB_CD@/browser/overrides/intl.properties                 (%chrome/global/intl.properties)
   locale/@AB_CD@/browser/overrides/intl.css                        (%chrome/global/intl.css)
   locale/@AB_CD@/browser/overrides/search/search.properties        (%chrome/search/search.properties)
 # plugins
   locale/@AB_CD@/browser/overrides/plugins/pluginproblem.dtd       (%chrome/pluginproblem/pluginproblem.dtd)
 #about:mozilla
   locale/@AB_CD@/browser/overrides/global/mozilla.dtd                (%chrome/global/mozilla.dtd)
-#about:telemetry
-  locale/@AB_CD@/browser/overrides/global/aboutTelemetry.dtd         (%chrome/global/aboutTelemetry.dtd)
-  locale/@AB_CD@/browser/overrides/global/aboutTelemetry.properties  (%chrome/global/aboutTelemetry.properties)
 #about:webrtc
   locale/@AB_CD@/browser/overrides/global/aboutWebrtc.properties  (%chrome/global/aboutWebrtc.properties)
 
 # overrides for dom l10n, also for en-US
 # keep this file list in sync with filter.py
 relativesrcdir dom/locales:
   locale/@AB_CD@/browser/overrides/global.dtd                  (%chrome/global.dtd)
   locale/@AB_CD@/browser/overrides/AccessFu.properties         (%chrome/accessibility/AccessFu.properties)
--- a/mobile/android/locales/l10n.toml
+++ b/mobile/android/locales/l10n.toml
@@ -228,24 +228,16 @@ exclude-multi-locale = [
     reference = "toolkit/locales/en-US/crashreporter/crashes.properties"
     l10n = "{l}toolkit/crashreporter/crashes.properties"
 
 [[paths]]
     reference = "toolkit/locales/en-US/chrome/global/mozilla.dtd"
     l10n = "{l}toolkit/chrome/global/mozilla.dtd"
 
 [[paths]]
-    reference = "toolkit/locales/en-US/chrome/global/aboutTelemetry.dtd"
-    l10n = "{l}toolkit/chrome/global/aboutTelemetry.dtd"
-
-[[paths]]
-    reference = "toolkit/locales/en-US/chrome/global/aboutTelemetry.properties"
-    l10n = "{l}toolkit/chrome/global/aboutTelemetry.properties"
-
-[[paths]]
     reference = "toolkit/locales/en-US/chrome/global/aboutWebrtc.properties"
     l10n = "{l}toolkit/chrome/global/aboutWebrtc.properties"
 
 
 [[filters]]
     path = [
         "{l}mobile/android/mobile-l10n.js",
         "{l}mobile/android/defines.inc",
--- a/mobile/locales/filter.py
+++ b/mobile/locales/filter.py
@@ -21,18 +21,16 @@ def test(mod, path, entity=None):
             "chrome/global/aboutReader.properties",
             "chrome/global/charsetMenu.properties",
             "chrome/global/commonDialogs.properties",
             "chrome/global/intl.properties",
             "chrome/global/intl.css",
             "chrome/search/search.properties",
             "chrome/pluginproblem/pluginproblem.dtd",
             "chrome/global/mozilla.dtd",
-            "chrome/global/aboutTelemetry.dtd",
-            "chrome/global/aboutTelemetry.properties",
             "chrome/global/aboutWebrtc.properties",
         ):
             return "error"
         if re.match(r"crashreporter/[^/]*.ftl", path):
             # error on crashreporter/*.ftl
             return "error"
 
         if re.match(r"toolkit/about/[^/]*About.ftl", path):
new file mode 100644
--- /dev/null
+++ b/python/l10n/fluent_migrations/bug_1523741_aboutTelemetry.py
@@ -0,0 +1,303 @@
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import
+import fluent.syntax.ast as FTL
+from fluent.migrate import REPLACE
+from fluent.migrate import COPY
+from fluent.migrate import CONCAT
+from fluent.migrate.helpers import transforms_from
+from fluent.migrate.helpers import TERM_REFERENCE
+from fluent.migrate.helpers import MESSAGE_REFERENCE
+from fluent.migrate.helpers import VARIABLE_REFERENCE
+
+
+def migrate(ctx):
+    """Bug 1523741 - Migrate aboutTelemetry to Fluent, part {index}."""
+
+    ctx.add_transforms(
+        "toolkit/toolkit/about/aboutTelemetry.ftl",
+        "toolkit/toolkit/about/aboutTelemetry.ftl",
+        transforms_from(
+		
+"""
+about-telemetry-ping-data-source = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.pingDataSource") }
+about-telemetry-show-current-ping-data = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.showCurrentPingData") }
+about-telemetry-show-archived-ping-data = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.showArchivedPingData") }
+about-telemetry-show-subsession-data = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.showSubsessionData") }
+about-telemetry-choose-ping = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.choosePing") }
+about-telemetry-archive-ping-type = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.archivePingType") }
+about-telemetry-archive-ping-header = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.archivePingHeader") }
+about-telemetry-option-group-today = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.optionGroupToday") }
+about-telemetry-option-group-yesterday = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.optionGroupYesterday") }
+about-telemetry-option-group-older = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.optionGroupOlder") }
+about-telemetry-previous-ping = { COPY("toolkit/chrome/global/aboutTelemetry.dtd", "aboutTelemetry.previousPing") }
+about-telemetry-next-ping = { COPY("toolkit/chrome/global/aboutTelemetry.dtd", "aboutTelemetry.nextPing") }
+about-telemetry-page-title = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.pageTitle") }
+about-telemetry-more-information = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.moreInformations") }
+about-telemetry-show-in-Firefox-json-viewer = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.showInFirefoxJsonViewer") }
+about-telemetry-home-section = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.homeSection") }
+about-telemetry-general-data-section = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.generalDataSection") }
+about-telemetry-environment-data-section = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.environmentDataSection") }
+about-telemetry-session-info-section = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.sessionInfoSection") }
+about-telemetry-scalar-section = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.scalarsSection") }
+about-telemetry-keyed-scalar-section = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.keyedScalarsSection") }
+about-telemetry-histograms-section = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.histogramsSection") }
+about-telemetry-keyed-histogram-section = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.keyedHistogramsSection") }
+about-telemetry-events-section = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.eventsSection") }
+about-telemetry-simple-measurements-section = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.simpleMeasurementsSection") }
+about-telemetry-slow-sql-section = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.slowSqlSection") }
+about-telemetry-addon-details-section = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.addonDetailsSection") }
+about-telemetry-captured-stacks-section = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.capturedStacksSection") }
+about-telemetry-late-writes-section = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.lateWritesSection") }
+about-telemetry-raw-payload-section = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.rawPayloadSection") }
+about-telemetry-raw = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.raw") }
+about-telemetry-full-sql-warning = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.fullSqlWarning") }
+about-telemetry-fetch-stack-symbols = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.fetchStackSymbols") }
+about-telemetry-hide-stack-symbols = { COPY("toolkit/chrome/global/aboutTelemetry.dtd","aboutTelemetry.hideStackSymbols") }
+about-telemetry-data-type =
+    { $channel ->
+        [release] { COPY("toolkit/chrome/global/aboutTelemetry.properties","releaseData") }
+       *[prerelease] { COPY("toolkit/chrome/global/aboutTelemetry.properties","prereleaseData") }
+    }
+about-telemetry-upload-type =
+    { $uploadcase ->
+        [enabled] { COPY("toolkit/chrome/global/aboutTelemetry.properties","telemetryUploadEnabled") }
+       *[disabled] { COPY("toolkit/chrome/global/aboutTelemetry.properties","telemetryUploadDisabled") }
+    }
+about-telemetry-filter-all-placeholder =
+    .placeholder = { COPY("toolkit/chrome/global/aboutTelemetry.properties","filterAllPlaceholder") }
+about-telemetry-current-ping-sidebar = { COPY("toolkit/chrome/global/aboutTelemetry.properties","currentPingSidebar") }
+about-telemetry-telemetry-ping-type-all = { COPY("toolkit/chrome/global/aboutTelemetry.properties","telemetryPingTypeAll") }
+about-telemetry-histogram-copy = { COPY("toolkit/chrome/global/aboutTelemetry.properties","histogramCopy") }
+about-telemetry-slow-sql-main = { COPY("toolkit/chrome/global/aboutTelemetry.properties","slowSqlMain") }
+about-telemetry-slow-sql-other = { COPY("toolkit/chrome/global/aboutTelemetry.properties","slowSqlOther") }
+about-telemetry-slow-sql-hits = { COPY("toolkit/chrome/global/aboutTelemetry.properties","slowSqlHits") }
+about-telemetry-slow-sql-average = { COPY("toolkit/chrome/global/aboutTelemetry.properties","slowSqlAverage") }
+about-telemetry-slow-sql-statement = { COPY("toolkit/chrome/global/aboutTelemetry.properties","slowSqlStatement") }
+about-telemetry-addon-table-id = { COPY("toolkit/chrome/global/aboutTelemetry.properties","addonTableID") }
+about-telemetry-addon-table-details = { COPY("toolkit/chrome/global/aboutTelemetry.properties","addonTableDetails") }
+about-telemetry-keys-header = { COPY("toolkit/chrome/global/aboutTelemetry.properties","keysHeader") }
+about-telemetry-names-header = { COPY("toolkit/chrome/global/aboutTelemetry.properties","namesHeader") }
+about-telemetry-values-header = { COPY("toolkit/chrome/global/aboutTelemetry.properties","valuesHeader") }
+about-telemetry-stack-title = { COPY("toolkit/chrome/global/aboutTelemetry.properties","stackTitle") }
+about-telemetry-memory-map-title = { COPY("toolkit/chrome/global/aboutTelemetry.properties","memoryMapTitle") }
+about-telemetry-error-fetching-symbols = { COPY("toolkit/chrome/global/aboutTelemetry.properties","errorFetchingSymbols") }
+about-telemetry-time-stamp-header = { COPY("toolkit/chrome/global/aboutTelemetry.properties","timestampHeader") }
+about-telemetry-category-header = { COPY("toolkit/chrome/global/aboutTelemetry.properties","categoryHeader") }
+about-telemetry-method-header = { COPY("toolkit/chrome/global/aboutTelemetry.properties","methodHeader") }
+about-telemetry-object-header = { COPY("toolkit/chrome/global/aboutTelemetry.properties","objectHeader") }
+about-telemetry-extra-header = { COPY("toolkit/chrome/global/aboutTelemetry.properties","extraHeader") }
+"""
+        )
+    )
+    ctx.add_transforms(
+        "toolkit/toolkit/about/aboutTelemetry.ftl",
+        "toolkit/toolkit/about/aboutTelemetry.ftl",
+        [
+			FTL.Message(
+                id=FTL.Identifier("about-telemetry-firefox-data-doc"),
+                value=REPLACE(
+                    "toolkit/chrome/global/aboutTelemetry.dtd",
+                    "aboutTelemetry.firefoxDataDoc",
+                    {
+                        "<a>": FTL.TextElement('<a data-l10n-name="data-doc-link">'),
+                    },
+                )
+            ),
+			FTL.Message(
+                id=FTL.Identifier("about-telemetry-telemetry-client-doc"),
+                value=REPLACE(
+                    "toolkit/chrome/global/aboutTelemetry.dtd",
+                    "aboutTelemetry.telemetryClientDoc",
+                    {
+                        "<a>": FTL.TextElement('<a data-l10n-name="client-doc-link">'),
+                    },
+                )
+            ),
+			FTL.Message(
+                id=FTL.Identifier("about-telemetry-telemetry-dashboard"),
+                value=REPLACE(
+                    "toolkit/chrome/global/aboutTelemetry.dtd",
+                    "aboutTelemetry.telemetryDashboard",
+                    {
+                        "<a>": FTL.TextElement('<a data-l10n-name="dashboard-link">'),
+                    },
+                )
+            ),
+			FTL.Message(
+                id=FTL.Identifier("about-telemetry-telemetry-probe-dictionary"),
+                value=REPLACE(
+                    "toolkit/chrome/global/aboutTelemetry.dtd",
+                    "aboutTelemetry.telemetryProbeDictionary",
+                    {
+                        "<a>": FTL.TextElement('<a data-l10n-name="probe-dictionary-link">'),
+                    },
+                )
+            ),
+            FTL.Message(
+                id=FTL.Identifier("about-telemetry-page-subtitle"),
+                value=REPLACE(
+                    "toolkit/chrome/global/aboutTelemetry.properties",
+                    "pageSubtitle",
+                    {
+                        "%1$S": VARIABLE_REFERENCE("telemetryServerOwner"),
+                        "%2$S": TERM_REFERENCE("brand-full-name"),
+                    },
+                    normalize_printf=True
+                )
+            ),
+            FTL.Message(
+                id=FTL.Identifier("about-telemetry-settings-explanation"),
+                value=REPLACE(
+                    "toolkit/chrome/global/aboutTelemetry.properties",
+                    "settingsExplanation",
+                    {
+                        "%1$S": MESSAGE_REFERENCE("about-telemetry-data-type"),
+                        "%2$S": CONCAT(
+                        FTL.TextElement('<a data-l10n-name="upload-link">'),
+                        MESSAGE_REFERENCE("about-telemetry-upload-type"),
+                        FTL.TextElement("</a>")
+                        ),
+                    },
+                    normalize_printf=True
+                )
+            ),
+            FTL.Message(
+                id=FTL.Identifier("about-telemetry-ping-details"),
+                value=REPLACE(
+                    "toolkit/chrome/global/aboutTelemetry.properties",
+                    "pingDetails",
+                    {
+                        "%1$S": CONCAT(
+                        FTL.TextElement('<a data-l10n-name="ping-link">'),
+                        COPY("toolkit/chrome/global/aboutTelemetry.properties","pingExplanationLink"),
+                        FTL.TextElement("</a>")
+                        ),
+                        "%2$S": REPLACE(
+                            "toolkit/chrome/global/aboutTelemetry.properties",
+                            "namedPing",
+                            {
+                                "%1$S": VARIABLE_REFERENCE("name"),
+                                "%2$S": VARIABLE_REFERENCE("timestamp"),
+                            },
+                            normalize_printf=True
+                        )
+                    },
+                    normalize_printf=True
+                )
+            ),
+            FTL.Message(
+                id=FTL.Identifier("about-telemetry-ping-details-current"),
+                value=REPLACE(
+                    "toolkit/chrome/global/aboutTelemetry.properties",
+                    "pingDetailsCurrent",
+                    {
+                        "%1$S": CONCAT(
+                        FTL.TextElement('<a data-l10n-name="ping-link">'),
+                        COPY("toolkit/chrome/global/aboutTelemetry.properties","pingExplanationLink"),
+                        FTL.TextElement("</a>")
+                        ),
+                        "%2$S": COPY("toolkit/chrome/global/aboutTelemetry.properties","currentPing")
+                    },
+                    normalize_printf=True
+                )
+            ),
+            FTL.Message(
+                id=FTL.Identifier("about-telemetry-filter-placeholder"),
+                attributes=[
+                    FTL.Attribute(
+                        id=FTL.Identifier("placeholder"),
+                        value=REPLACE(
+                        "toolkit/chrome/global/aboutTelemetry.properties",
+                        "filterPlaceholder",
+                            {
+                                "%1$S": VARIABLE_REFERENCE("selectedTitle"),
+                            },
+                            normalize_printf=True
+                        )
+                    )
+                ]
+            ),
+            FTL.Message(
+                id=FTL.Identifier("about-telemetry-results-for-search"),
+                value=REPLACE(
+                    "toolkit/chrome/global/aboutTelemetry.properties",
+                    "resultsForSearch",
+                    {
+                        "%1$S": VARIABLE_REFERENCE("searchTerms"),
+                    },
+                    normalize_printf=True
+                )
+            ),
+            FTL.Message(
+                id=FTL.Identifier("about-telemetry-no-search-results"),
+                value=REPLACE(
+                    "toolkit/chrome/global/aboutTelemetry.properties",
+                    "noSearchResults",
+                    {
+                        "%1$S": VARIABLE_REFERENCE("sectionName"),
+                        "%2$S": VARIABLE_REFERENCE("currentSearchText"),
+                    },
+                    normalize_printf=True
+                )
+            ),
+            FTL.Message(
+                id=FTL.Identifier("about-telemetry-no-search-results-all"),
+                value=REPLACE(
+                    "toolkit/chrome/global/aboutTelemetry.properties",
+                    "noSearchResultsAll",
+                    {
+                        "%1$S": VARIABLE_REFERENCE("searchTerms"),
+                    },
+                    normalize_printf=True
+                )
+            ),
+            FTL.Message(
+                id=FTL.Identifier("about-telemetry-no-data-to-display"),
+                value=REPLACE(
+                    "toolkit/chrome/global/aboutTelemetry.properties",
+                    "noDataToDisplay",
+                    {
+                        "%1$S": VARIABLE_REFERENCE("sectionName"),
+                    },
+                    normalize_printf=True
+                )
+            ),
+            FTL.Message(
+                id=FTL.Identifier("about-telemetry-addon-provider"),
+                value=REPLACE(
+                    "toolkit/chrome/global/aboutTelemetry.properties",
+                    "addonProvider",
+                    {
+                        "%1$S": VARIABLE_REFERENCE("addonProvider"),
+                    },
+                    normalize_printf=True
+                )
+            ),
+
+            FTL.Message(
+                id=FTL.Identifier("about-telemetry-captured-stacks-title"),
+                value=REPLACE(
+                    "toolkit/chrome/global/aboutTelemetry.properties",
+                    "captured-stacks-title",
+                    {
+                        "%1$S": VARIABLE_REFERENCE("stackKey"),
+                        "%2$S": VARIABLE_REFERENCE("capturedStacksCount"),
+                    },
+                    normalize_printf=True
+                )
+            ),
+
+            FTL.Message(
+                id=FTL.Identifier("about-telemetry-late-writes-title"),
+                value=REPLACE(
+                    "toolkit/chrome/global/aboutTelemetry.properties",
+                    "late-writes-title",
+                    {
+                        "%1$S": VARIABLE_REFERENCE("lateWriteCount"),
+                    },
+                    normalize_printf=True
+                )
+            ),
+        ]
+    )
--- a/toolkit/content/aboutTelemetry.js
+++ b/toolkit/content/aboutTelemetry.js
@@ -194,50 +194,44 @@ var Settings = {
   },
 
   detachObservers() {
     for (let setting of this.SETTINGS) {
       Preferences.ignore(setting.pref, this.render, this);
     }
   },
 
-  getStatusString(enabled) {
-    let status = bundle.GetStringFromName(enabled ? "telemetryUploadEnabled" : "telemetryUploadDisabled");
-    return status;
-  },
-
   /**
    * Updates the button & text at the top of the page to reflect Telemetry state.
    */
   render() {
     let settingsExplanation = document.getElementById("settings-explanation");
-    let uploadEnabled = this.getStatusString(TelemetrySend.sendingEnabled());
     let extendedEnabled = Services.telemetry.canRecordExtended;
-    let collectedData = bundle.GetStringFromName(extendedEnabled ? "prereleaseData" : "releaseData");
-    let explanation = bundle.GetStringFromName("settingsExplanation");
 
-    let fragment = BrowserUtils.getLocalizedFragment(document, explanation, collectedData, this.convertStringToLink(uploadEnabled));
-    settingsExplanation.appendChild(fragment);
+    let datacase = extendedEnabled ? "prerelease" : "release";
+    let uploadcase = TelemetrySend.sendingEnabled() ? "enabled" : "disabled";
+
+    document.l10n.setAttributes(settingsExplanation, "about-telemetry-settings-explanation", {datacase, uploadcase});
 
     this.attachObservers();
   },
 
   convertStringToLink(string) {
     let link = document.createElement("a");
     link.setAttribute("href", "#");
     link.setAttribute("class", "change-data-choices-link");
     link.textContent = string;
     return link;
   },
 };
 
 var PingPicker = {
   viewCurrentPingData: null,
   _archivedPings: null,
-  TYPE_ALL: bundle.GetStringFromName("telemetryPingTypeAll"),
+  TYPE_ALL: "all",
 
   attachObservers() {
     let pingSourceElements = document.getElementsByName("choose-ping-source");
     for (let el of pingSourceElements) {
       el.addEventListener("change", () => this.onPingSourceChanged());
     }
 
     let displays = document.getElementsByName("choose-ping-display");
@@ -251,17 +245,16 @@ var PingPicker = {
 
     document.getElementById("choose-ping-id").addEventListener("change", () => {
       this._updateArchivedPingData();
     });
     document.getElementById("choose-ping-type").addEventListener("change", () => {
       this.filterDisplayedPings();
     });
 
-
     document.getElementById("newer-ping")
             .addEventListener("click", () => this._movePingIndex(-1));
     document.getElementById("older-ping")
             .addEventListener("click", () => this._movePingIndex(1));
 
     let pingPickerNeedHide = false;
     let pingPicker = document.getElementById("ping-picker");
     pingPicker.addEventListener("mouseenter", () => pingPickerNeedHide = false);
@@ -289,61 +282,39 @@ var PingPicker = {
     this.update();
   },
 
   onPingDisplayChanged() {
     this.update();
   },
 
   render() {
-    let pings = bundle.GetStringFromName("pingExplanationLink");
-    let pingLink = document.createElement("a");
-    pingLink.setAttribute("href", "https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/telemetry/concepts/pings.html");
-    pingLink.textContent = pings;
-    let pingName = this._getSelectedPingName();
-    let pingNameSpan = document.createElement("span");
-    pingNameSpan.setAttribute("class", "change-ping");
-
     // Display the type and controls if the ping is not current
     let pingDate = document.getElementById("ping-date");
     let pingType = document.getElementById("ping-type");
     let controls = document.getElementById("controls");
-    let fragment;
+    let pingExplanation = document.getElementById("ping-explanation");
+
     if (!this.viewCurrentPingData) {
+      let pingName = this._getSelectedPingName();
       // Change sidebar heading text.
       pingDate.textContent = pingName;
       pingDate.setAttribute("title", pingName);
       let pingTypeText = this._getSelectedPingType();
       controls.classList.remove("hidden");
       pingType.textContent = pingTypeText;
-
-      // Change home page text.
-      pingName = bundle.formatStringFromName("namedPing", [pingName, pingTypeText], 2);
-      pingNameSpan.textContent = pingName;
-      let explanation = bundle.GetStringFromName("pingDetails");
-      fragment = BrowserUtils.getLocalizedFragment(document, explanation, pingLink, pingNameSpan);
+      document.l10n.setAttributes(pingExplanation, "about-telemetry-ping-details", {timestamp: pingTypeText, name: pingName});
     } else {
       // Change sidebar heading text.
       controls.classList.add("hidden");
-      pingType.textContent = bundle.GetStringFromName("currentPingSidebar");
-
+      document.l10n.setAttributes(pingType, "about-telemetry-current-ping-sidebar");
       // Change home page text.
-      pingNameSpan.textContent = pingName;
-      let explanation = bundle.GetStringFromName("pingDetailsCurrent");
-      fragment = BrowserUtils.getLocalizedFragment(document, explanation, pingLink, pingNameSpan);
+      document.l10n.setAttributes(pingExplanation, "about-telemetry-ping-details-current");
     }
 
-    let pingExplanation = document.getElementById("ping-explanation");
-    removeAllChildNodes(pingExplanation);
-    pingExplanation.appendChild(fragment);
-    pingExplanation.querySelector(".change-ping").addEventListener("click", (ev) => {
-      document.getElementById("ping-picker").classList.remove("hidden");
-      ev.stopPropagation();
-    });
-
     GenericSubsection.deleteAllSubSections();
   },
 
   async update() {
     let viewCurrent = document.getElementById("ping-source-current").checked;
     let currentChanged = viewCurrent !== this.viewCurrentPingData;
     this.viewCurrentPingData = viewCurrent;
 
@@ -411,17 +382,17 @@ var PingPicker = {
       delete data.keyedScalars;
       delete data.histograms;
       delete data.keyedHistograms;
     }
     delete ping.payload.histograms;
     delete ping.payload.keyedHistograms;
 
     // augment ping payload with event telemetry
-    let eventSnapshot = Telemetry.snapshotEvents(Telemetry.DATASET_PRERELEASE_CHANNELS, false);
+    let eventSnapshot = Telemetry.snapshotEvents(Telemetry.DATASET_RELEASE_CHANNEL_OPTIN, false);
     for (let process of Object.keys(eventSnapshot)) {
       if (process in ping.payload.processes) {
         ping.payload.processes[process].events = eventSnapshot[process].filter(e => !e[1].startsWith("telemetry.test"));
       }
     }
 
     displayPingData(ping, true);
   },
@@ -547,27 +518,25 @@ var PingPicker = {
     let type = typeSelector.selectedOptions.item(0).value;
     let first = true;
     Array.from(pingSelector.children).forEach((group) => {
       Array.from(group.children).forEach((option) => {
         if (first && option.dataset.type == type) {
           option.selected = true;
           first = false;
         }
-        option.hidden = (type != this.TYPE_ALL) && (option.dataset.type != type);
+        option.hidden = type != this.TYPE_ALL && option.dataset.type != type;
         // Arrow keys should only iterate over visible options
         option.disabled = option.hidden;
       });
     });
     this._updateArchivedPingData();
   },
 
   _getSelectedPingName() {
-    if (this.viewCurrentPingData) return bundle.GetStringFromName("currentPing");
-
     let pingSelector = document.getElementById("choose-ping-id");
     let selected = pingSelector.selectedOptions.item(0);
     return selected.dataset.date;
   },
 
   _getSelectedPingType() {
     let pingSelector = document.getElementById("choose-ping-id");
     let selected = pingSelector.selectedOptions.item(0);
@@ -594,19 +563,19 @@ var GeneralData = {
    * Renders the general data
    */
   render(aPing) {
     setHasData("general-data-section", true);
     let generalDataSection = document.getElementById("general-data");
     removeAllChildNodes(generalDataSection);
 
     const headings = [
-      "namesHeader",
-      "valuesHeader",
-    ].map(h => bundle.GetStringFromName(h));
+      "about-telemetry-names-header",
+      "about-telemetry-values-header",
+    ];
 
     // The payload & environment parts are handled by other renderers.
     let ignoreSections = ["payload", "environment"];
     let data = explodeObject(filterObject(aPing, ignoreSections));
 
     const table = GenericTable.render(data, headings);
     generalDataSection.appendChild(table);
   },
@@ -742,35 +711,26 @@ var EnvironmentData = {
     let colTextElement = document.createTextNode(aColText);
     colElement.appendChild(colTextElement);
     aRowElement.appendChild(colElement);
   },
 };
 
 var SlowSQL = {
 
-  slowSqlHits: bundle.GetStringFromName("slowSqlHits"),
-
-  slowSqlAverage: bundle.GetStringFromName("slowSqlAverage"),
-
-  slowSqlStatement: bundle.GetStringFromName("slowSqlStatement"),
-
-  mainThreadTitle: bundle.GetStringFromName("slowSqlMain"),
-
-  otherThreadTitle: bundle.GetStringFromName("slowSqlOther"),
-
   /**
    * Render slow SQL statistics
    */
   render: function SlowSQL_render(aPing) {
     // We can add the debug SQL data to the current ping later.
     // However, we need to be careful to never send that debug data
     // out due to privacy concerns.
     // We want to show the actual ping data for archived pings,
     // so skip this there.
+
     let debugSlowSql = PingPicker.viewCurrentPingData && Preferences.get(PREF_DEBUG_SLOW_SQL, false);
     let slowSql = debugSlowSql ? Telemetry.debugSlowSQL : aPing.payload.slowSQL;
     if (!slowSql) {
       setHasData("slow-sql-section", false);
       return;
     }
 
     let {mainThread, otherThreads} =
@@ -789,48 +749,54 @@ var SlowSQL = {
     }
 
     let slowSqlDiv = document.getElementById("slow-sql-tables");
     removeAllChildNodes(slowSqlDiv);
 
     // Main thread
     if (mainThreadCount > 0) {
       let table = document.createElement("table");
-      this.renderTableHeader(table, this.mainThreadTitle);
+      this.renderTableHeader(table, "main");
       this.renderTable(table, mainThread);
-
       slowSqlDiv.appendChild(table);
     }
 
     // Other threads
     if (otherThreadCount > 0) {
       let table = document.createElement("table");
-      this.renderTableHeader(table, this.otherThreadTitle);
+      this.renderTableHeader(table, "other");
       this.renderTable(table, otherThreads);
-
       slowSqlDiv.appendChild(table);
     }
   },
 
   /**
    * Creates a header row for a Slow SQL table
    * Tabs & newlines added to cells to make it easier to copy-paste.
    *
    * @param aTable Parent table element
    * @param aTitle Table's title
    */
-  renderTableHeader: function SlowSQL_renderTableHeader(aTable, aTitle) {
+  renderTableHeader: function SlowSQL_renderTableHeader(aTable, threadType) {
     let caption = document.createElement("caption");
-    caption.appendChild(document.createTextNode(aTitle + "\n"));
+    if (threadType == "main") {
+        document.l10n.setAttributes(caption, "about-telemetry-slow-sql-main");
+    }
+
+    if (threadType == "other") {
+        document.l10n.setAttributes(caption, "about-telemetry-slow-sql-other");
+    }
     aTable.appendChild(caption);
 
+
+
     let headings = document.createElement("tr");
-    this.appendColumn(headings, "th", this.slowSqlHits + "\t");
-    this.appendColumn(headings, "th", this.slowSqlAverage + "\t");
-    this.appendColumn(headings, "th", this.slowSqlStatement + "\n");
+    document.l10n.setAttributes(this.appendColumn(headings, "th"), "about-telemetry-slow-sql-hits");
+    document.l10n.setAttributes(this.appendColumn(headings, "th"), "about-telemetry-slow-sql-average");
+    document.l10n.setAttributes(this.appendColumn(headings, "th"), "about-telemetry-slow-sql-statement");
     aTable.appendChild(headings);
   },
 
   /**
    * Fills out the table body
    * Tabs & newlines added to cells to make it easier to copy-paste.
    *
    * @param aTable Parent table element
@@ -852,37 +818,37 @@ var SlowSQL = {
 
   /**
    * Helper function for appending a column to a Slow SQL table.
    *
    * @param aRowElement Parent row element
    * @param aColType Column's tag name
    * @param aColText Column contents
    */
-  appendColumn: function SlowSQL_appendColumn(aRowElement, aColType, aColText) {
+  appendColumn: function SlowSQL_appendColumn(aRowElement, aColType, aColText = "") {
     let colElement = document.createElement(aColType);
-    let colTextElement = document.createTextNode(aColText);
-    colElement.appendChild(colTextElement);
+    if (aColText) {
+      let colTextElement = document.createTextNode(aColText);
+      colElement.appendChild(colTextElement);
+    }
     aRowElement.appendChild(colElement);
+    return colElement;
   },
 };
 
 var StackRenderer = {
-
-  stackTitle: bundle.GetStringFromName("stackTitle"),
-
-  memoryMapTitle: bundle.GetStringFromName("memoryMapTitle"),
-
   /**
    * Outputs the memory map associated with this hang report
    *
    * @param aDiv Output div
    */
-  renderMemoryMap: function StackRenderer_renderMemoryMap(aDiv, memoryMap) {
-    aDiv.appendChild(document.createTextNode(this.memoryMapTitle));
+  renderMemoryMap: async function StackRenderer_renderMemoryMap(aDiv, memoryMap) {
+    let memoryMapTitleElement = document.createElement("span");
+    document.l10n.setAttributes(memoryMapTitleElement, "about-telemetry-memory-map-title");
+    aDiv.appendChild(memoryMapTitleElement);
     aDiv.appendChild(document.createElement("br"));
 
     for (let currentModule of memoryMap) {
       aDiv.appendChild(document.createTextNode(currentModule.join(" ")));
       aDiv.appendChild(document.createElement("br"));
     }
 
     aDiv.appendChild(document.createElement("br"));
@@ -890,17 +856,19 @@ var StackRenderer = {
 
   /**
    * Outputs the raw PCs from the hang's stack
    *
    * @param aDiv Output div
    * @param aStack Array of PCs from the hang stack
    */
   renderStack: function StackRenderer_renderStack(aDiv, aStack) {
-    aDiv.appendChild(document.createTextNode(this.stackTitle));
+    let stackTitleElement = document.createElement("span");
+    document.l10n.setAttributes(stackTitleElement, "about-telemetry-stack-title");
+    aDiv.appendChild(stackTitleElement);
     let stackText = " " + aStack.join(" ");
     aDiv.appendChild(document.createTextNode(stackText));
 
     aDiv.appendChild(document.createElement("br"));
     aDiv.appendChild(document.createElement("br"));
   },
   renderStacks: function StackRenderer_renderStacks(aPrefix, aStacks,
                                                     aMemoryMap, aRenderHeader) {
@@ -977,27 +945,27 @@ function SymbolicationRequest(aPrefix, a
   this.stacks = aStacks;
   this.durations = aDurations;
 }
 /**
  * A callback for onreadystatechange. It replaces the numeric stack with
  * the symbolicated one returned by the symbolication server.
  */
 SymbolicationRequest.prototype.handleSymbolResponse =
-function SymbolicationRequest_handleSymbolResponse() {
+async function SymbolicationRequest_handleSymbolResponse() {
   if (this.symbolRequest.readyState != 4)
     return;
 
   let fetchElement = document.getElementById(this.prefix + "-fetch-symbols");
   fetchElement.hidden = true;
   let hideElement = document.getElementById(this.prefix + "-hide-symbols");
   hideElement.hidden = false;
   let div = document.getElementById(this.prefix);
   removeAllChildNodes(div);
-  let errorMessage = bundle.GetStringFromName("errorFetchingSymbols");
+  let errorMessage = await document.l10n.formatValue("about-telemetry-error-fetching-symbols");
 
   if (this.symbolRequest.status != 200) {
     div.appendChild(document.createTextNode(errorMessage));
     return;
   }
 
   let jsonResponse = {};
   try {
@@ -1066,24 +1034,16 @@ var CapturedStacks = {
     let key = captures[index][0];
     let cardinality = captures[index][2];
     StackRenderer.renderHeader("captured-stacks", [key, cardinality]);
   },
 };
 
 var Histogram = {
 
-  hgramSamplesCaption: bundle.GetStringFromName("histogramSamples"),
-
-  hgramAverageCaption: bundle.GetStringFromName("histogramAverage"),
-
-  hgramSumCaption: bundle.GetStringFromName("histogramSum"),
-
-  hgramCopyCaption: bundle.GetStringFromName("histogramCopy"),
-
   /**
    * Renders a single Telemetry histogram
    *
    * @param aParent Parent element
    * @param aName Histogram name
    * @param aHgram Histogram information
    * @param aOptions Object with render options
    *                 * exponential: bars follow logarithmic scale
@@ -1096,37 +1056,41 @@ var Histogram = {
     outerDiv.className = "histogram";
     outerDiv.id = aName;
 
     let divTitle = document.createElement("div");
     divTitle.classList.add("histogram-title");
     divTitle.appendChild(document.createTextNode(aName));
     outerDiv.appendChild(divTitle);
 
-    let stats = hgram.sample_count + " " + this.hgramSamplesCaption + ", " +
-                this.hgramAverageCaption + " = " + hgram.pretty_average + ", " +
-                this.hgramSumCaption + " = " + hgram.sum;
-
     let divStats = document.createElement("div");
     divStats.classList.add("histogram-stats");
-    divStats.appendChild(document.createTextNode(stats));
-    outerDiv.appendChild(divStats);
+
+    let histogramStatsArgs = {
+        sampleCount: hgram.sample_count,
+        prettyAverage: hgram.pretty_average,
+        sum: hgram.sum,
+    };
+
+    document.l10n.setAttributes(divStats, "about-telemetry-histogram-stats", histogramStatsArgs);
 
     if (isRTL()) {
       hgram.values.reverse();
     }
 
     let textData = this.renderValues(outerDiv, hgram, options);
 
     // The 'Copy' button contains the textual data, copied to clipboard on click
     let copyButton = document.createElement("button");
     copyButton.className = "copy-node";
-    copyButton.appendChild(document.createTextNode(this.hgramCopyCaption));
-    copyButton.histogramText = aName + EOL + stats + EOL + EOL + textData;
-    copyButton.addEventListener("click", function() {
+    document.l10n.setAttributes(copyButton, "about-telemetry-histogram-copy");
+
+    copyButton.addEventListener("click", async function() {
+      let divStatsString = await document.l10n.formatValue("about-telemetry-histogram-stats", histogramStatsArgs);
+      copyButton.histogramText = aName + EOL + divStatsString + EOL + EOL + textData;
       Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper)
                                                  .copyString(this.histogramText);
     });
     outerDiv.appendChild(copyButton);
 
     aParent.appendChild(outerDiv);
     return outerDiv;
   },
@@ -1389,27 +1353,26 @@ var Search = {
       this.updateNoResults(text, noSearchResults);
     }
     return noSearchResults;
   },
 
   updateNoResults(text, noSearchResults) {
     document.getElementById("no-search-results").classList.toggle("hidden", !noSearchResults);
     if (noSearchResults) {
-      let searchStatus;
       let section = document.querySelector(".category.selected > span");
+      let searchResultsText = document.getElementById("no-search-results-text");
       if (section.parentElement.id === "category-home") {
-        searchStatus = bundle.formatStringFromName("noSearchResultsAll", [text], 1);
+        document.l10n.setAttributes(searchResultsText, "about-telemetry-no-search-results-all", {searchTerms: text});
       } else {
         let sectionName = section.textContent.trim();
-        searchStatus = (text === "")
-          ? bundle.formatStringFromName("noDataToDisplay", [sectionName], 1)
-          : bundle.formatStringFromName("noSearchResults", [sectionName, text], 2);
+        (text === "")
+          ? document.l10n.setAttributes(searchResultsText, "about-telemetry-no-data-to-display", {sectionName})
+          : document.l10n.setAttributes(searchResultsText, "about-telemetry-no-search-results", {sectionName, currentSearchText: text});
       }
-      document.getElementById("no-search-results-text").textContent = searchStatus;
     }
   },
 
   resetHome() {
     document.getElementById("main").classList.remove("search");
     document.getElementById("no-search-results").classList.add("hidden");
     adjustHeaderState();
     Array.from(document.querySelectorAll("section")).forEach((section) => {
@@ -1420,18 +1383,17 @@ var Search = {
   homeSearch(text) {
     changeUrlSearch(text);
     removeSearchSectionTitles();
     if (text === "") {
       this.resetHome();
       return;
     }
     document.getElementById("main").classList.add("search");
-    let title = bundle.formatStringFromName("resultsForSearch", [text], 1);
-    adjustHeaderState(title);
+    adjustHeaderState(text);
     let noSearchResults = true;
     Array.from(document.querySelectorAll("section")).forEach((section) => {
       if (section.id == "home-section" || section.id == "raw-payload-section") {
         section.classList.remove("active");
         return;
       }
       section.classList.add("active");
       let sectionHidden = this.search(text, section);
@@ -1534,28 +1496,28 @@ var GenericSubsection = {
       el.parentElement.removeChild(el);
     });
   },
 
 };
 
 var GenericTable = {
 
-  defaultHeadings: [
-    bundle.GetStringFromName("keysHeader"),
-    bundle.GetStringFromName("valuesHeader"),
-  ],
+  // Returns a table with key and value headers
+  defaultHeadings() {
+    return ["about-telemetry-keys-header", "about-telemetry-values-header"];
+  },
 
   /**
    * Returns a n-column table.
    * @param rows An array of arrays, each containing data to render
    *             for one row.
    * @param headings The column header strings.
    */
-  render(rows, headings = this.defaultHeadings) {
+  render(rows, headings = this.defaultHeadings()) {
     let table = document.createElement("table");
     this.renderHeader(table, headings);
     this.renderBody(table, rows);
     return table;
   },
 
   /**
    * Create the table header.
@@ -1564,19 +1526,18 @@ var GenericTable = {
    * @param table Table element
    * @param headings Array of column header strings.
    */
   renderHeader(table, headings) {
     let headerRow = document.createElement("tr");
     table.appendChild(headerRow);
 
     for (let i = 0; i < headings.length; ++i) {
-      let suffix = (i == (headings.length - 1)) ? "\n" : "\t";
       let column = document.createElement("th");
-      column.appendChild(document.createTextNode(headings[i] + suffix));
+      document.l10n.setAttributes(column, headings[i]);
       headerRow.appendChild(column);
     }
   },
 
   /**
    * Create the table body
    * Tabs & newlines added to cells to make it easier to copy-paste.
    *
@@ -1626,39 +1587,35 @@ var KeyedHistogram = {
     }
 
     parent.appendChild(outerDiv);
     return outerDiv;
   },
 };
 
 var AddonDetails = {
-  tableIDTitle: bundle.GetStringFromName("addonTableID"),
-  tableDetailsTitle: bundle.GetStringFromName("addonTableDetails"),
 
   /**
    * Render the addon details section as a series of headers followed by key/value tables
    * @param aPing A ping object to render the data from.
    */
-  render: function AddonDetails_render(aPing) {
+  render(aPing) {
     let addonSection = document.getElementById("addon-details");
     removeAllChildNodes(addonSection);
     let addonDetails = aPing.payload.addonDetails;
     const hasData = addonDetails && Object.keys(addonDetails).length > 0;
     setHasData("addon-details-section", hasData);
     if (!hasData) {
       return;
     }
 
     for (let provider in addonDetails) {
       let providerSection = document.createElement("caption");
-      let titleText = bundle.formatStringFromName("addonProvider", [provider], 1);
-      providerSection.appendChild(document.createTextNode(titleText));
-
-      let headingStrings = [this.tableIDTitle, this.tableDetailsTitle ];
+      document.l10n.setAttributes(providerSection, "about-telemetry-addon-provider", {addonProvider: provider});
+      let headingStrings = ["about-telemetry-addon-table-id", "about-telemetry-addon-table-details"];
       let table = GenericTable.render(explodeObject(addonDetails[provider]),
                                       headingStrings);
       table.appendChild(providerSection);
       addonSection.appendChild(table);
     }
   },
 };
 
@@ -1673,36 +1630,36 @@ var Scalars = {
 
     let processesSelect = document.getElementById("processes");
     let selectedProcess = processesSelect.selectedOptions.item(0).getAttribute("value");
 
     if (!selectedProcess) {
       return;
     }
 
-    const headings = [
-      "namesHeader",
-      "valuesHeader",
-    ].map(h => bundle.GetStringFromName(h));
-
     let payload = aPayload.stores;
     if (payload) { // Check for stores in the current ping data first
       let hasData = false;
       for (const store of Object.keys(payload)) {
         if (!(selectedProcess in payload[store])) {
           continue;
         }
 
         let scalars = payload[store][selectedProcess].scalars || {};
         hasData = hasData || Array.from(processesSelect.options).some((option) => {
           let value = option.getAttribute("value");
           let sclrs = payload[store][value] && payload[store][value].scalars;
           return sclrs && Object.keys(sclrs).length > 0;
         });
         if (Object.keys(scalars).length > 0) {
+          const headings = [
+            "about-telemetry-names-header",
+            "about-telemetry-values-header",
+          ];
+
           let s = GenericSubsection.renderSubsectionHeader(store, true, "scalars-section");
           let table = GenericTable.render(explodeObject(scalars), headings);
           let caption = document.createElement("caption");
           caption.textContent = store;
           table.appendChild(caption);
           s.appendChild(table);
           scalarsSection.appendChild(s);
         }
@@ -1718,59 +1675,43 @@ var Scalars = {
       let hasData = Array.from(processesSelect.options).some((option) => {
         let value = option.getAttribute("value");
         let sclrs = aPayload.processes[value].scalars;
         return sclrs && Object.keys(sclrs).length > 0;
       });
 
       setHasData("scalars-section", hasData);
       if (Object.keys(scalars).length > 0) {
+        const headings = [
+          "about-telemetry-names-header",
+          "about-telemetry-values-header",
+        ];
         const table = GenericTable.render(explodeObject(scalars), headings);
         scalarsSection.appendChild(table);
       }
     }
   },
 };
 
-function createScalarContainer(scalarId, scalarData, headings) {
-  // Add the name of the scalar.
-  let container = document.createElement("div");
-  container.classList.add("keyed-scalar");
-  container.id = scalarId;
-  let scalarNameSection = document.createElement("p");
-  scalarNameSection.classList.add("keyed-title");
-  scalarNameSection.appendChild(document.createTextNode(scalarId));
-  container.appendChild(scalarNameSection);
-  // Populate the section with the key-value pairs from the scalar.
-  const table = GenericTable.render(explodeObject(scalarData), headings);
-  container.appendChild(table);
-  return container;
-}
-
 var KeyedScalars = {
   /**
    * Render the keyed scalar data - if present - from the payload in a simple key-value table.
    * @param aPayload A payload object to render the data from.
    */
   render(aPayload) {
     let scalarsSection = document.getElementById("keyed-scalars");
     removeAllChildNodes(scalarsSection);
 
     let processesSelect = document.getElementById("processes");
     let selectedProcess = processesSelect.selectedOptions.item(0).getAttribute("value");
 
     if (!selectedProcess) {
       return;
     }
 
-    const headings = [
-      "namesHeader",
-      "valuesHeader",
-    ].map(h => bundle.GetStringFromName(h));
-
     let payload = aPayload.stores;
     if (payload) { // Check for stores in the current ping data first
       let hasData = false;
       for (const store of Object.keys(payload)) {
         if (!(selectedProcess in payload[store])) {
           continue;
         }
 
@@ -1784,19 +1725,32 @@ var KeyedScalars = {
           continue;
         }
 
         let s = GenericSubsection.renderSubsectionHeader(store, true, "keyed-scalars-section");
         let heading = document.createElement("h2");
         heading.textContent = store;
         s.appendChild(heading);
 
+        const headings = [
+          "about-telemetry-names-header",
+          "about-telemetry-values-header",
+        ];
         for (let scalar in keyedScalars) {
           // Add the name of the scalar.
-          const container = createScalarContainer(scalar, keyedScalars[scalar], headings);
+          let container = document.createElement("div");
+          container.classList.add("keyed-scalar");
+          container.id = scalar;
+          let scalarNameSection = document.createElement("p");
+          scalarNameSection.classList.add("keyed-title");
+          scalarNameSection.appendChild(document.createTextNode(scalar));
+          container.appendChild(scalarNameSection);
+          // Populate the section with the key-value pairs from the scalar.
+          const table = GenericTable.render(explodeObject(keyedScalars[scalar]), headings);
+          container.appendChild(table);
           s.appendChild(container);
         }
 
         scalarsSection.appendChild(s);
       }
       setHasData("keyed-scalars-section", hasData);
     } else { // Handle archived pings
       if (!aPayload.processes ||
@@ -1811,18 +1765,32 @@ var KeyedScalars = {
         return keyedS && Object.keys(keyedS).length > 0;
       });
 
       setHasData("keyed-scalars-section", hasData);
       if (!Object.keys(keyedScalars).length > 0) {
         return;
       }
 
+      const headings = [
+        "about-telemetry-names-header",
+        "about-telemetry-values-header",
+      ];
       for (let scalar in keyedScalars) {
-        const container = createScalarContainer(scalar, keyedScalars[scalar], headings);
+        // Add the name of the scalar.
+        let container = document.createElement("div");
+        container.classList.add("keyed-scalar");
+        container.id = scalar;
+        let scalarNameSection = document.createElement("p");
+        scalarNameSection.classList.add("keyed-title");
+        scalarNameSection.appendChild(document.createTextNode(scalar));
+        container.appendChild(scalarNameSection);
+        // Populate the section with the key-value pairs from the scalar.
+        const table = GenericTable.render(explodeObject(keyedScalars[scalar]), headings);
+        container.appendChild(table);
         scalarsSection.appendChild(container);
       }
     }
   },
 };
 
 var Events = {
   /**
@@ -1843,33 +1811,26 @@ var Events = {
     }
 
     let events = aPayload.processes[selectedProcess].events || {};
     let hasData = Array.from(processesSelect.options).some((option) => {
       let value = option.getAttribute("value");
       let evts = aPayload.processes[value].events;
       return evts && Object.keys(evts).length > 0;
     });
-
-    // Don't specifically hide the events section if there's no data.
-    // It might be a "main" ping that needs to always show the section.
-    if (hasData) {
-      setHasData("events-section", true);
-    }
-
+    setHasData("events-section", hasData);
     if (Object.keys(events).length > 0) {
       const headings = [
-        "timestampHeader",
-        "categoryHeader",
-        "methodHeader",
-        "objectHeader",
-        "valuesHeader",
-        "extraHeader",
-      ].map(h => bundle.GetStringFromName(h));
-
+        "about-telemetry-timestamp-header",
+        "about-telemetry-category-header",
+        "about-telemetry-method-header",
+        "about-telemetry-object-header",
+        "about-telemetry-values-header",
+        "about-telemetry-extra-header",
+      ];
       const table = GenericTable.render(events, headings);
       eventsSection.appendChild(table);
     }
   },
 };
 
 /**
  * Helper function for showing either the toggle element or "No data collected" message for a section
@@ -1886,33 +1847,18 @@ function setHasData(aSectionID, aHasData
   sectionCategory.classList[aHasData ? "add" : "remove"]("has-data");
 }
 
 /**
  * Sets the text of the page header based on a config pref + bundle strings
  */
 function setupPageHeader() {
   let serverOwner = Preferences.get(PREF_TELEMETRY_SERVER_OWNER, "Mozilla");
-  let brandName = brandBundle.GetStringFromName("brandFullName");
-  let subtitleText = bundle.formatStringFromName(
-    "pageSubtitle", [serverOwner, brandName], 2);
-
   let subtitleElement = document.getElementById("page-subtitle");
-  subtitleElement.appendChild(document.createTextNode(subtitleText));
-
-  let links = [
-    "https://docs.telemetry.mozilla.org/",
-    "https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/telemetry/index.html",
-    "https://telemetry.mozilla.org/",
-    "https://telemetry.mozilla.org/probe-dictionary/",
-  ];
-  let htmlLink = document.querySelectorAll("#home-section > ul > li > a");
-  htmlLink.forEach((a, index) => {
-    a.href = links[index];
-  });
+  document.l10n.setAttributes(subtitleElement, "about-telemetry-page-subtitle", {telemetryServerOwner: serverOwner});
 }
 
 function displayProcessesSelector(selectedSection) {
   let whitelist = [
     "scalars-section",
     "keyed-scalars-section",
     "histograms-section",
     "keyed-histograms-section",
@@ -1952,26 +1898,28 @@ function adjustSection() {
   if (!selectedCategory.classList.contains("has-data")) {
     PingPicker._showStructuredPingData();
   }
 }
 
 function adjustHeaderState(title = null) {
   let selected = document.querySelector(".category.selected .category-name");
   let selectedTitle = selected.textContent.trim();
-  document.getElementById("sectionTitle").textContent = title ? title : selectedTitle;
-
-  let placeholder;
-  if (selected.parentElement.id === "category-home") {
-    placeholder = bundle.GetStringFromName("filterAllPlaceholder");
+  let sectionTitle = document.getElementById("sectionTitle");
+  if (title !== null) {
+      document.l10n.setAttributes(sectionTitle, "about-telemetry-results-for-search", {searchTerms: title});
   } else {
-    placeholder = bundle.formatStringFromName("filterPlaceholder", [ selectedTitle ], 1);
+      sectionTitle.textContent = selectedTitle;
   }
   let search = document.getElementById("search");
-  search.setAttribute("placeholder", placeholder);
+  if (selected.parentElement.id === "category-home") {
+    document.l10n.setAttributes(search, "about-telemetry-filter-all-placeholder");
+  } else {
+    document.l10n.setAttributes(search, "about-telemetry-filter-placeholder", {selectedTitle});
+  }
 }
 
 /**
  * Change the url according to the current section displayed
  * e.g about:telemetry#general-data
  */
 function changeUrlPath(selectedSection, subSection) {
   if (subSection) {
--- a/toolkit/content/aboutTelemetry.xhtml
+++ b/toolkit/content/aboutTelemetry.xhtml
@@ -1,158 +1,154 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
 <!-- 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/. -->
 
-<!DOCTYPE html [
-  <!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"> %htmlDTD;
-  <!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd"> %globalDTD;
-  <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> %brandDTD;
-  <!ENTITY % aboutTelemetryDTD SYSTEM "chrome://global/locale/aboutTelemetry.dtd"> %aboutTelemetryDTD;
-]>
+<!DOCTYPE html>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
-    <title>&aboutTelemetry.pageTitle;</title>
-
+    <title data-l10n-id="about-telemetry-page-title"></title>
     <link rel="stylesheet" href="chrome://global/content/aboutTelemetry.css"
           type="text/css"/>
 
     <script type="application/javascript"
             src="chrome://global/content/aboutTelemetry.js"/>
+    <link rel="localization" href="branding/brand.ftl"/>
+    <link rel="localization" href="toolkit/about/aboutTelemetry.ftl"/>
   </head>
 
-  <body id="body" dir="&locale.dir;">
+  <body id="body">
 
     <div id="categories">
       <div class="heading">
         <span id="ping-type" class="change-ping dropdown"></span>
         <div id="controls" hidden="true">
-          <span id="older-ping">&aboutTelemetry.previousPing;</span>
+          <span id="older-ping" data-l10n-id="about-telemetry-previous-ping"></span>
           <span id="ping-date" class="change-ping"></span>
-          <span id="newer-ping">&aboutTelemetry.nextPing;</span>
+          <span id="newer-ping" data-l10n-id="about-telemetry-next-ping"></span>
         </div>
       </div>
       <div id="category-home" class="category has-data selected" value="home-section">
-        <span class="category-name">&aboutTelemetry.homeSection;</span>
+        <span class="category-name" data-l10n-id="about-telemetry-home-section"></span>
       </div>
       <div class="category" value="general-data-section">
-        <span class="category-name">&aboutTelemetry.generalDataSection;</span>
+        <span class="category-name" data-l10n-id="about-telemetry-general-data-section"></span>
       </div>
       <div class="category" value="environment-data-section">
-        <span class="category-name">&aboutTelemetry.environmentDataSection;</span>
+        <span class="category-name" data-l10n-id="about-telemetry-environment-data-section"></span>
       </div>
       <div class="category" value="session-info-section">
-        <span class="category-name">&aboutTelemetry.sessionInfoSection;</span>
+        <span class="category-name" data-l10n-id="about-telemetry-session-info-section"></span>
       </div>
       <div class="category" value="scalars-section">
-        <span class="category-name">&aboutTelemetry.scalarsSection;</span>
+        <span class="category-name" data-l10n-id="about-telemetry-scalar-section"></span>
       </div>
       <div class="category" value="keyed-scalars-section">
-        <span class="category-name">&aboutTelemetry.keyedScalarsSection;</span>
+        <span class="category-name" data-l10n-id="about-telemetry-keyed-scalar-section"></span>
       </div>
       <div class="category" value="histograms-section">
-        <span class="category-name">&aboutTelemetry.histogramsSection;</span>
+        <span class="category-name" data-l10n-id="about-telemetry-histograms-section"></span>
       </div>
       <div class="category" value="keyed-histograms-section">
-        <span class="category-name">&aboutTelemetry.keyedHistogramsSection;</span>
+        <span class="category-name" data-l10n-id="about-telemetry-keyed-histogram-section"></span>
       </div>
       <div class="category" value="events-section">
-        <span class="category-name">&aboutTelemetry.eventsSection;</span>
+        <span class="category-name" data-l10n-id="about-telemetry-events-section"></span>
       </div>
       <div class="category" value="simple-measurements-section">
-        <span class="category-name">&aboutTelemetry.simpleMeasurementsSection;</span>
+        <span class="category-name" data-l10n-id="about-telemetry-simple-measurements-section"></span>
       </div>
       <div class="category" value="slow-sql-section">
-        <span class="category-name">&aboutTelemetry.slowSqlSection;</span>
+        <span class="category-name" data-l10n-id="about-telemetry-slow-sql-section"></span>
       </div>
       <div class="category" value="addon-details-section">
-        <span class="category-name">&aboutTelemetry.addonDetailsSection;</span>
+        <span class="category-name" data-l10n-id="about-telemetry-addon-details-section"></span>
       </div>
       <div class="category" value="captured-stacks-section">
-        <span class="category-name">&aboutTelemetry.capturedStacksSection;</span>
+        <span class="category-name" data-l10n-id="about-telemetry-captured-stacks-section"></span>
       </div>
       <div class="category" value="late-writes-section">
-        <span class="category-name">&aboutTelemetry.lateWritesSection;</span>
+        <span class="category-name" data-l10n-id="about-telemetry-late-writes-section"></span>
       </div>
       <div class="category has-data" value="raw-payload-section">
-        <span class="category-name">&aboutTelemetry.rawPayloadSection;</span>
+        <span class="category-name" data-l10n-id="about-telemetry-raw-payload-section"></span>
       </div>
       <div id="category-raw" class="category has-data" value="raw-json-viewer">
-          <span class="category-name">&aboutTelemetry.raw;</span>
+          <span class="category-name" data-l10n-id="about-telemetry-raw"></span>
       </div>
     </div>
 
     <div id="main" class="main-content">
 
       <div id="ping-picker" class="hidden">
         <div id="ping-source-picker">
-          <h4 class="title">&aboutTelemetry.pingDataSource;</h4>
+          <h4 class="title" data-l10n-id="about-telemetry-ping-data-source"></h4>
           <div>
             <input type="radio" id="ping-source-current" name="choose-ping-source" value="current" checked="checked" />
-            <label for="ping-source-current">&aboutTelemetry.showCurrentPingData;</label>
+            <label for="ping-source-current" data-l10n-id="about-telemetry-show-current-ping-data"></label>
           </div>
           <div id="ping-source-archive-container">
             <input type="radio" id="ping-source-archive" name="choose-ping-source" value="archive" />
-            <label for="ping-source-archive">&aboutTelemetry.showArchivedPingData;</label>
+            <label for="ping-source-archive" data-l10n-id="about-telemetry-show-archived-ping-data"></label>
           </div>
         </div>
         <div id="current-ping-picker">
-          <input id="show-subsession-data" type="checkbox" checked="checked" />&aboutTelemetry.showSubsessionData;
+          <input id="show-subsession-data" type="checkbox" checked="checked" />
+		  <label for="show-subsession-data" data-l10n-id="about-telemetry-show-subsession-data"></label>
         </div>
         <div id="archived-ping-picker">
-          <h4 class="title">&aboutTelemetry.choosePing;</h4>
+          <h4 class="title" data-l10n-id="about-telemetry-choose-ping"></h4>
           <div>
-            <h4 class="title">&aboutTelemetry.archivePingType;</h4>
+            <h4 class="title" data-l10n-id="about-telemetry-archive-ping-type"></h4>
             <select id="choose-ping-type"></select>
           </div>
           <div>
-            <h4 class="title">&aboutTelemetry.archivePingHeader;</h4>
+            <h4 class="title" data-l10n-id="about-telemetry-archive-ping-header"></h4>
             <select id="choose-ping-id">
-              <optgroup label="&aboutTelemetry.optionGroupToday;">
+              <optgroup data-l10n-id="about-telemetry-option-group-today">
               </optgroup>
-              <optgroup label="&aboutTelemetry.optionGroupYesterday;">
+              <optgroup data-l10n-id="about-telemetry-option-group-yesterday">
               </optgroup>
-              <optgroup label="&aboutTelemetry.optionGroupOlder;">
+              <optgroup data-l10n-id="about-telemetry-option-group-older">
               </optgroup>
             </select>
           </div>
         </div>
       </div>
 
       <div class="header">
-          <div id="sectionTitle" class="header-name">
-              &aboutTelemetry.pageTitle;
+          <div id="sectionTitle" class="header-name" data-l10n-id="about-telemetry-page-title">
           </div>
           <select id="processes" hidden="true"></select>
           <input type="text" id="search" placeholder=""/>
       </div>
 
       <div id="no-search-results" hidden="true" class="hidden">
         <span id="no-search-results-text"></span>
         <div class="no-search-results-image"></div>
       </div>
 
       <section id="home-section" class="active">
         <p id="page-subtitle"></p>
-        <p id="settings-explanation"></p>
-        <p id="ping-explanation"></p>
-        <p>&aboutTelemetry.moreInformations;</p>
+        <p id="settings-explanation"><a id="uploadLink" data-l10n-name="upload-link" href="about:preferences#privacy"></a></p>
+        <p id="ping-explanation"><a id="pingLink" data-l10n-name="ping-link" href="https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/telemetry/concepts/pings.html"></a></p>
+        <p data-l10n-id="about-telemetry-more-information"></p>
         <ul>
-          <li>&aboutTelemetry.firefoxDataDoc;</li>
-          <li>&aboutTelemetry.telemetryClientDoc;</li>
-          <li>&aboutTelemetry.telemetryDashboard;</li>
-          <li>&aboutTelemetry.telemetryProbeDictionary;</li>
+          <li data-l10n-id="about-telemetry-firefox-data-doc"><a id="dataDocLink" data-l10n-name="data-doc-link" href="https://docs.telemetry.mozilla.org/"></a></li>
+          <li data-l10n-id="about-telemetry-telemetry-client-doc"><a id="clientDocLink" data-l10n-name="client-doc-link" href="https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/telemetry/index.html"></a></li>
+          <li data-l10n-id="about-telemetry-telemetry-dashboard"><a id="dashboardLink" data-l10n-name="dashboard-link" href="https://telemetry.mozilla.org/"></a></li>
+          <li data-l10n-id="about-telemetry-telemetry-probe-dictionary"><a id="probeDictionaryLink" data-l10n-name="probe-dictionary-link" href="https://telemetry.mozilla.org/probe-dictionary/"></a></li>
         </ul>
       </section>
 
       <section id="raw-payload-section">
-        <button id="payload-json-viewer">&aboutTelemetry.showInFirefoxJsonViewer;</button>
+        <button id="payload-json-viewer" data-l10n-id="about-telemetry-show-in-Firefox-json-viewer"></button>
         <pre id="raw-payload-data"></pre>
       </section>
 
       <section id="general-data-section">
         <div id="general-data" class="data"></div>
       </section>
 
       <section id="environment-data-section">
@@ -183,32 +179,32 @@
         <div id="events" class="data"></div>
       </section>
 
       <section id="simple-measurements-section">
         <div id="simple-measurements" class="data"></div>
       </section>
 
       <section id="slow-sql-section">
-        <p id="sql-warning">&aboutTelemetry.fullSqlWarning;</p>
+        <p id="sql-warning" data-l10n-id="about-telemetry-full-sql-warning"></p>
         <div id="slow-sql-tables" class="data"></div>
       </section>
 
       <section id="late-writes-section">
-        <a id="late-writes-fetch-symbols" href="">&aboutTelemetry.fetchStackSymbols;</a>
-        <a id="late-writes-hide-symbols" href="">&aboutTelemetry.hideStackSymbols;</a>
+        <a id="late-writes-fetch-symbols" href="" data-l10n-id="about-telemetry-fetch-stack-symbols"></a>
+        <a id="late-writes-hide-symbols" href="" data-l10n-id="about-telemetry-hide-stack-symbols"></a>
         <div id="late-writes" class="data"></div>
       </section>
 
       <section id="addon-details-section">
         <div id="addon-details" class="data"></div>
       </section>
 
       <section id="captured-stacks-section">
-        <a id="captured-stacks-fetch-symbols" href="">&aboutTelemetry.fetchStackSymbols;</a>
-        <a id="captured-stacks-hide-symbols" href="">&aboutTelemetry.hideStackSymbols;</a>
+        <a id="captured-stacks-fetch-symbols" href="" data-l10n-id="about-telemetry-fetch-stack-symbols"></a>
+        <a id="captured-stacks-hide-symbols" href="" data-l10n-id="about-telemetry-hide-stack-symbols"></a>
         <div id="captured-stacks" class="data"></div>
       </section>
     </div>
 
   </body>
 
 </html>
deleted file mode 100644
--- a/toolkit/locales/en-US/chrome/global/aboutTelemetry.dtd
+++ /dev/null
@@ -1,49 +0,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/. -->
-
-<!ENTITY aboutTelemetry.pingDataSource "Ping data source:">
-<!ENTITY aboutTelemetry.showCurrentPingData "Current ping data">
-<!ENTITY aboutTelemetry.showArchivedPingData "Archived ping data">
-<!ENTITY aboutTelemetry.showSubsessionData "Show subsession data">
-<!ENTITY aboutTelemetry.choosePing "Choose ping:">
-<!ENTITY aboutTelemetry.archivePingType "Ping Type">
-<!ENTITY aboutTelemetry.archivePingHeader "Ping">
-<!ENTITY aboutTelemetry.optionGroupToday "Today">
-<!ENTITY aboutTelemetry.optionGroupYesterday "Yesterday">
-<!ENTITY aboutTelemetry.optionGroupOlder "Older">
-<!-- LOCALIZATION NOTE(aboutTelemetry.previousPing, aboutTelemetry.nextPing):
-	These strings are displayed when selecting Archived pings, and they’re
-	used to move to the next or previous ping. -->
-<!ENTITY aboutTelemetry.previousPing "&lt;&lt;">
-<!ENTITY aboutTelemetry.nextPing "&gt;&gt;">
-
-<!ENTITY aboutTelemetry.pageTitle "Telemetry Data">
-<!ENTITY aboutTelemetry.moreInformations "Looking for more information?">
-<!ENTITY aboutTelemetry.firefoxDataDoc "The <a>Firefox Data Documentation</a> contains guides about how to work with our data tools.">
-<!ENTITY aboutTelemetry.telemetryClientDoc "The <a>Firefox Telemetry client documentation</a> includes definitions for concepts, API documentation and data references.">
-<!ENTITY aboutTelemetry.telemetryDashboard "The <a>Telemetry dashboards</a> allow you to visualize the data Mozilla receives via Telemetry.">
-<!ENTITY aboutTelemetry.telemetryProbeDictionary "The <a>Probe Dictionary</a> provides details and descriptions for the probes collected by Telemetry.">
-
-<!ENTITY aboutTelemetry.showInFirefoxJsonViewer "Open in the JSON viewer">
-
-<!ENTITY aboutTelemetry.homeSection "Home">
-<!ENTITY aboutTelemetry.generalDataSection "General Data">
-<!ENTITY aboutTelemetry.environmentDataSection "Environment Data">
-<!ENTITY aboutTelemetry.sessionInfoSection "Session Information">
-<!ENTITY aboutTelemetry.scalarsSection "Scalars">
-<!ENTITY aboutTelemetry.keyedScalarsSection "Keyed Scalars">
-<!ENTITY aboutTelemetry.histogramsSection "Histograms">
-<!ENTITY aboutTelemetry.keyedHistogramsSection "Keyed Histograms">
-<!ENTITY aboutTelemetry.eventsSection "Events">
-<!ENTITY aboutTelemetry.simpleMeasurementsSection "Simple Measurements">
-<!ENTITY aboutTelemetry.slowSqlSection "Slow SQL Statements">
-<!ENTITY aboutTelemetry.addonDetailsSection "Add-on Details">
-<!ENTITY aboutTelemetry.capturedStacksSection "Captured Stacks">
-<!ENTITY aboutTelemetry.lateWritesSection "Late Writes">
-<!ENTITY aboutTelemetry.rawPayloadSection "Raw Payload">
-<!ENTITY aboutTelemetry.raw "Raw JSON">
-
-<!ENTITY aboutTelemetry.fullSqlWarning "NOTE: Slow SQL debugging is enabled. Full SQL strings may be displayed below but they will not be submitted to Telemetry.">
-<!ENTITY aboutTelemetry.fetchStackSymbols "Fetch function names for stacks">
-<!ENTITY aboutTelemetry.hideStackSymbols "Show raw stack data">
deleted file mode 100644
--- a/toolkit/locales/en-US/chrome/global/aboutTelemetry.properties
+++ /dev/null
@@ -1,101 +0,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/.
-
-# LOCALIZATION NOTE(pageSubtitle):
-# - %1$S is replaced by the value of the toolkit.telemetry.server_owner preference
-# - %2$S is replaced by brandFullName
-pageSubtitle = This page shows the information about performance, hardware, usage and customizations collected by Telemetry. This information is submitted to %1$S to help improve %2$S.
-
-# LOCALIZATION NOTE(settingsExplanation):
-# - %1$S is either releaseData or prereleaseData
-# - %2$S is either telemetryUploadEnabled or telemetryUploadDisabled
-settingsExplanation = Telemetry is collecting %1$S and upload is %2$S.
-releaseData = release data
-prereleaseData = pre-release data
-telemetryUploadEnabled = enabled
-telemetryUploadDisabled = disabled
-
-# LOCALIZATION NOTE(pingDetails):
-# - %1$S is replaced by a link with pingExplanationLink as text
-# - %2$S is replaced by namedPing
-pingDetails = Each piece of information is sent bundled into “%1$S”. You are looking at the %2$S ping.
-# LOCALIZATION NOTE(namedPing):
-# - %1$S is replaced by the ping localized timestamp, e.g. “2017/07/08 10:40:46”
-# - %2$S is replaced by the ping name, e.g. “saved-session”
-namedPing = %1$S, %2$S
-# LOCALIZATION NOTE(pingDetailsCurrent):
-# - %1$S is replaced by a link with pingExplanationLink as text
-# - %2$S is replaced by currentPing
-pingDetailsCurrent = Each piece of information is sent bundled into “%1$S“. You are looking at the %2$S ping.
-pingExplanationLink = pings
-currentPing = current
-
-# LOCALIZATION NOTE(filterPlaceholder): string used as a placeholder for the
-# search field, %1$S is replaced by the section name from the structure of the
-# ping. More info about it can be found here:
-# https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/telemetry/data/main-ping.html
-filterPlaceholder = Find in %1$S
-filterAllPlaceholder = Find in all sections
-
-# LOCALIZATION NOTE(resultsForSearch): %1$S is replaced by the searched terms
-resultsForSearch = Results for “%1$S”
-# LOCALIZATION NOTE(noSearchResults):
-# - %1$S is replaced by the section name from the structure of the ping.
-# More info about it can be found here: https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/telemetry/data/main-ping.html
-# - %2$S is replaced by the current text in the search input
-noSearchResults = Sorry! There are no results in %1$S for “%2$S”
-# LOCALIZATION NOTE(noSearchResultsAll): %S is replaced by the searched terms
-noSearchResultsAll = Sorry! There are no results in any sections for “%S”
-# LOCALIZATION NOTE(noDataToDisplay): %S is replaced by the section name.
-# This message is displayed when a section is empty.
-noDataToDisplay = Sorry! There is currently no data available in “%S”
-# LOCALIZATION NOTE(currentPingSidebar): used as a tooltip for the “current”
-# ping title in the sidebar
-currentPingSidebar = current ping
-# LOCALIZATION NOTE(telemetryPingTypeAll): used in the “Ping Type” select
-telemetryPingTypeAll = all
-
-# LOCALIZATION NOTE(histogram*): these strings are used in the “Histograms” section
-histogramSamples = samples
-histogramAverage = average
-histogramSum = sum
-# LOCALIZATION NOTE(histogramCopy): button label to copy the histogram
-histogramCopy = Copy
-
-# LOCALIZATION NOTE(slowSql*): these strings are used in the “Slow SQL Statements” section
-slowSqlMain = Slow SQL Statements on Main Thread
-slowSqlOther = Slow SQL Statements on Helper Threads
-slowSqlHits = Hits
-slowSqlAverage = Avg. Time (ms)
-slowSqlStatement = Statement
-
-# LOCALIZATION NOTE(histogram*): these strings are used in the “Add-on Details” section
-addonTableID = Add-on ID
-addonTableDetails = Details
-# LOCALIZATION NOTE(addonProvider):
-# - %1$S is replaced by the name of an Add-on Provider (e.g. “XPI”, “Plugin”)
-addonProvider = %1$S Provider
-
-keysHeader = Property
-namesHeader = Name
-valuesHeader = Value
-
-# LOCALIZATION NOTE(captured-stacks-title):
-# - %1$S is replaced by the string key for this stack
-# - %2$S is replaced by the number of times this stack was captured
-captured-stacks-title = %1$S (capture count: %2$S)
-# LOCALIZATION NOTE(late-writes-title):
-# - %1$S is replaced by the number of the late write
-late-writes-title = Late Write #%1$S
-
-stackTitle = Stack:
-memoryMapTitle = Memory map:
-
-errorFetchingSymbols = An error occurred while fetching symbols. Check that you are connected to the Internet and try again.
-
-timestampHeader = timestamp
-categoryHeader = category
-methodHeader = method
-objectHeader = object
-extraHeader = extra
new file mode 100644
--- /dev/null
+++ b/toolkit/locales/en-US/toolkit/about/aboutTelemetry.ftl
@@ -0,0 +1,137 @@
+# 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/.
+
+about-telemetry-ping-data-source = Ping data source:
+about-telemetry-show-current-ping-data = Current ping data
+about-telemetry-show-archived-ping-data = Archived ping data
+about-telemetry-show-subsession-data = Show subsession data
+about-telemetry-choose-ping = Choose ping:
+about-telemetry-archive-ping-type = Ping Type
+about-telemetry-archive-ping-header = Ping
+about-telemetry-option-group-today = Today
+about-telemetry-option-group-yesterday = Yesterday
+about-telemetry-option-group-older = Older
+about-telemetry-previous-ping = <<
+about-telemetry-next-ping = >>
+about-telemetry-page-title = Telemetry Data
+about-telemetry-more-information = Looking for more information?
+about-telemetry-firefox-data-doc = The <a data-l10n-name="data-doc-link">Firefox Data Documentation</a> contains guides about how to work with our data tools.
+about-telemetry-telemetry-client-doc = The <a data-l10n-name="client-doc-link">Firefox Telemetry client documentation</a> includes definitions for concepts, API documentation and data references.
+about-telemetry-telemetry-dashboard = The <a data-l10n-name="dashboard-link">Telemetry dashboards</a> allow you to visualize the data Mozilla receives via Telemetry.
+about-telemetry-telemetry-probe-dictionary = The <a data-l10n-name="probe-dictionary-link">Probe Dictionary</a> provides details and descriptions for the probes collected by Telemetry.
+about-telemetry-show-in-Firefox-json-viewer = Open in the JSON viewer
+about-telemetry-home-section = Home
+about-telemetry-general-data-section = General Data
+about-telemetry-environment-data-section = Environment Data
+about-telemetry-session-info-section = Session Information
+about-telemetry-scalar-section = Scalars
+about-telemetry-keyed-scalar-section = Keyed Scalars
+about-telemetry-histograms-section = Histograms
+about-telemetry-keyed-histogram-section = Keyed Histograms
+about-telemetry-events-section = Events
+about-telemetry-simple-measurements-section = Simple Measurements
+about-telemetry-slow-sql-section = Slow SQL Statements
+about-telemetry-addon-details-section = Add-on Details
+about-telemetry-captured-stacks-section = Captured Stacks
+about-telemetry-late-writes-section = Late Writes
+about-telemetry-raw-payload-section = Raw Payload
+about-telemetry-raw = Raw JSON
+about-telemetry-full-sql-warning = NOTE: Slow SQL debugging is enabled. Full SQL strings may be displayed below but they will not be submitted to Telemetry.
+about-telemetry-fetch-stack-symbols = Fetch function names for stacks
+about-telemetry-hide-stack-symbols = Show raw stack data
+# Selects the correct release version
+# Variables:
+#   $channel (String): represents the corresponding release data string
+about-telemetry-data-type =
+    { $channel ->
+        [release] release data
+       *[prerelease] pre-release data
+    }
+# Selects the correct upload string
+# Variables:
+#   $uploadcase (String): represents a corresponding upload string
+about-telemetry-upload-type =
+    { $uploadcase ->
+        [enabled] enabled
+       *[disabled] disabled
+    }
+# Example Output: 1 sample, average = 0, sum = 0
+# Variables:
+#   $sampleCount (Integer): amount of histogram samples
+#   $prettyAverage (Integer): average of histogram samples
+#   $sum (Integer): sum of histogram samples
+about-telemetry-histogram-stats = 
+    { $sampleCount ->
+        [one] { $sampleCount } sample, average = { $prettyAverage }, sum = { $sum }
+       *[other] { $sampleCount } samples, average = { $prettyAverage }, sum = { $sum }
+    }
+# Variables:
+#   $telemetryServerOwner (String): the value of the toolkit.telemetry.server_owner preference
+about-telemetry-page-subtitle = This page shows the information about performance, hardware, usage and customizations collected by Telemetry. This information is submitted to { $telemetryServerOwner } to help improve { -brand-full-name }.
+about-telemetry-settings-explanation = Telemetry is collecting { about-telemetry-data-type } and upload is <a data-l10n-name="upload-link">{ about-telemetry-upload-type }</a>.
+# Variables:
+#   $name (String): ping name, e.g. “saved-session”
+#   $timeStamp (String): ping localized timestamp, e.g. “2017/07/08 10:40:46”
+about-telemetry-ping-details = Each piece of information is sent bundled into “<a data-l10n-name="ping-link">pings</a>”. You are looking at the { $name }, { $timestamp } ping.
+about-telemetry-ping-details-current = Each piece of information is sent bundled into “<a data-l10n-name="ping-link">pings</a>“. You are looking at the current ping.
+# string used as a placeholder for the search field
+# More info about it can be found here:
+# https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/telemetry/data/main-ping.html
+# Variables:
+#   $selectedTitle (String): the section name from the structure of the ping.
+about-telemetry-filter-placeholder =
+    .placeholder = Find in { $selectedTitle }
+about-telemetry-filter-all-placeholder =
+    .placeholder = Find in all sections
+# Variables:
+#   $searchTerms (String): the searched terms
+about-telemetry-results-for-search = Results for “{ $searchTerms }”
+# More info about it can be found here: https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/telemetry/data/main-ping.html
+# Variables:
+#   $sectionName (String): the section name from the structure of the ping.
+#   $currentSearchText (String): the current text in the search input
+about-telemetry-no-search-results = Sorry! There are no results in { $sectionName } for “{ $currentSearchText }”
+# Variables:
+#   $searchTerms (String): the searched terms
+about-telemetry-no-search-results-all = Sorry! There are no results in any sections for “{ $searchTerms }”
+# This message is displayed when a section is empty.
+# Variables:
+#   $sectionName (String): is replaced by the section name.
+about-telemetry-no-data-to-display = Sorry! There is currently no data available in “{ $sectionName }”
+# used as a tooltip for the “current” ping title in the sidebar
+about-telemetry-current-ping-sidebar = current ping
+# used in the “Ping Type” select
+about-telemetry-telemetry-ping-type-all = all
+# button label to copy the histogram
+about-telemetry-histogram-copy = Copy
+# these strings are used in the “Slow SQL Statements” section
+about-telemetry-slow-sql-main = Slow SQL Statements on Main Thread
+about-telemetry-slow-sql-other = Slow SQL Statements on Helper Threads
+about-telemetry-slow-sql-hits = Hits
+about-telemetry-slow-sql-average = Avg. Time (ms)
+about-telemetry-slow-sql-statement = Statement
+# these strings are used in the “Add-on Details” section
+about-telemetry-addon-table-id = Add-on ID
+about-telemetry-addon-table-details = Details
+# Variables:
+#   $addonProvider (String): the name of an Add-on Provider (e.g. “XPI”, “Plugin”)
+about-telemetry-addon-provider = { $addonProvider } Provider
+about-telemetry-keys-header = Property
+about-telemetry-names-header = Name
+about-telemetry-values-header = Value
+# Variables:
+#   $stackKey (String): the string key for this stack
+#   $capturedStacksCount (Integer):  the number of times this stack was captured
+about-telemetry-captured-stacks-title = { $stackKey } (capture count: { $capturedStacksCount })
+# Variables:
+#   $lateWriteCount (Integer): the number of the late writes
+about-telemetry-late-writes-title = Late Write #{ $lateWriteCount }
+about-telemetry-stack-title = Stack:
+about-telemetry-memory-map-title = Memory map:
+about-telemetry-error-fetching-symbols = An error occurred while fetching symbols. Check that you are connected to the Internet and try again.
+about-telemetry-time-stamp-header = timestamp
+about-telemetry-category-header = category
+about-telemetry-method-header = method
+about-telemetry-object-header = object
+about-telemetry-extra-header = extra
--- a/toolkit/locales/jar.mn
+++ b/toolkit/locales/jar.mn
@@ -6,18 +6,16 @@
 [localization] @AB_CD@.jar:
   crashreporter                                    (%crashreporter/**/*.ftl)
   toolkit                                          (%toolkit/**/*.ftl)
 
 @AB_CD@.jar:
 % locale global @AB_CD@ %locale/@AB_CD@/global/
   locale/@AB_CD@/global/aboutReader.properties          (%chrome/global/aboutReader.properties)
   locale/@AB_CD@/global/aboutStudies.properties         (%chrome/global/aboutStudies.properties)
-  locale/@AB_CD@/global/aboutTelemetry.dtd              (%chrome/global/aboutTelemetry.dtd)
-  locale/@AB_CD@/global/aboutTelemetry.properties       (%chrome/global/aboutTelemetry.properties)
   locale/@AB_CD@/global/aboutWebrtc.properties          (%chrome/global/aboutWebrtc.properties)
   locale/@AB_CD@/global/autocomplete.properties         (%chrome/global/autocomplete.properties)
   locale/@AB_CD@/global/appPicker.dtd                   (%chrome/global/appPicker.dtd)
   locale/@AB_CD@/global/browser.properties              (%chrome/global/browser.properties)
   locale/@AB_CD@/global/charsetMenu.dtd                 (%chrome/global/charsetMenu.dtd)
   locale/@AB_CD@/global/charsetMenu.properties          (%chrome/global/charsetMenu.properties)
   locale/@AB_CD@/global/commonDialog.dtd                (%chrome/global/commonDialog.dtd)
   locale/@AB_CD@/global/commonDialogs.properties        (%chrome/global/commonDialogs.properties)