Bug 1555450 - Remove locale-specific behavior when fully fluent (no longer using properties/json) r=k88hudson
authorEd Lee <edilee@mozilla.com>
Wed, 03 Jul 2019 23:49:07 +0000
changeset 481242 c385e1de2be7392caff3a34e36f8b0b08420ba33
parent 481241 c61360a7302855cce84d8ad75cdc70c01160995a
child 481243 7dcdb13f0c8ebfca8ad8bd49dcb56ccb787c6f2e
push id113603
push userncsoregi@mozilla.com
push dateThu, 04 Jul 2019 09:55:46 +0000
treeherdermozilla-inbound@f01dbf4e5646 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersk88hudson
bugs1555450
milestone69.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 1555450 - Remove locale-specific behavior when fully fluent (no longer using properties/json) r=k88hudson Depends on D36764 Differential Revision: https://phabricator.services.mozilla.com/D36769
.eslintignore
.gitignore
browser/base/content/test/static/browser_all_files_referenced.js
browser/components/newtab/.eslintignore
browser/components/newtab/AboutNewTabService.jsm
browser/components/newtab/bin/render-activity-stream-html.js
browser/components/newtab/jar.mn
browser/components/newtab/nsIAboutNewTabService.idl
browser/components/newtab/prerendered/activity-stream-debug.html
browser/components/newtab/prerendered/activity-stream-noscripts.html
browser/components/newtab/prerendered/activity-stream.html
browser/components/newtab/prerendered/locales/en-US/activity-stream-noscripts.html
browser/components/newtab/prerendered/locales/en-US/activity-stream-strings.js
browser/components/newtab/prerendered/locales/en-US/activity-stream.html
browser/components/newtab/prerendered/static/activity-stream-debug.html
browser/components/newtab/test/xpcshell/test_AboutNewTabService.js
tools/lint/codespell.yml
--- a/.eslintignore
+++ b/.eslintignore
@@ -45,17 +45,16 @@ browser/extensions/pdfjs/content/web**
 # generated or library files in pocket
 browser/components/pocket/content/panels/js/tmpl.js
 browser/components/pocket/content/panels/js/vendor/**
 
 # Ignore newtab files
 # Kept in sync with browser/components/newtab/.eslintignore
 browser/components/newtab/data/
 browser/components/newtab/logs/
-browser/components/newtab/prerendered/
 browser/components/newtab/vendor/
 
 # The only file in browser/locales/ is pre-processed.
 browser/locales/**
 # imported from chromium
 browser/extensions/mortar/**
 # Generated data files
 browser/extensions/formautofill/phonenumberutils/PhoneNumberMetaData.jsm
--- a/.gitignore
+++ b/.gitignore
@@ -39,18 +39,16 @@ security/manager/.nss.checkout
 
 # Build directories
 /obj*/
 
 # gecko.log is generated by various test harnesses
 /gecko.log
 
 # Ignore newtab component build assets
-browser/components/newtab/bin/prerender.js
-browser/components/newtab/bin/prerender.js.map
 browser/components/newtab/data/locales.json
 browser/components/newtab/logs/
 
 # Build directories for js shell
 *_DBG.OBJ/
 *_OPT.OBJ/
 /js/src/*-obj/
 /js/src/obj-*/
--- a/browser/base/content/test/static/browser_all_files_referenced.js
+++ b/browser/base/content/test/static/browser_all_files_referenced.js
@@ -29,18 +29,16 @@ var gExceptionPaths = [
 
   // These resources are referenced using relative paths from html files.
   "resource://payments/",
   "resource://normandy-content/shield-content-frame.js",
   "resource://normandy-content/shield-content-process.js",
 
   // https://github.com/mozilla/activity-stream/issues/3053
   "resource://activity-stream/data/content/tippytop/images/",
-  // https://github.com/mozilla/activity-stream/issues/3758
-  "resource://activity-stream/prerendered/",
 
   // browser/extensions/pdfjs/content/build/pdf.js#1999
   "resource://pdf.js/web/images/",
 
   // Exclude all the metadata paths under the country metadata folder because these
   // paths will be concatenated in FormAutofillUtils.jsm based on different country/region.
   "resource://formautofill/addressmetadata/",
 
--- a/browser/components/newtab/.eslintignore
+++ b/browser/components/newtab/.eslintignore
@@ -1,4 +1,3 @@
 data/
 logs/
-prerendered/
 vendor/
--- a/browser/components/newtab/AboutNewTabService.jsm
+++ b/browser/components/newtab/AboutNewTabService.jsm
@@ -9,38 +9,32 @@
 const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
 const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
 const {E10SUtils} = ChromeUtils.import("resource://gre/modules/E10SUtils.jsm");
 
 ChromeUtils.defineModuleGetter(this, "AboutNewTab",
                                "resource:///modules/AboutNewTab.jsm");
 
 const TOPIC_APP_QUIT = "quit-application-granted";
-const TOPIC_LOCALES_CHANGE = "intl:app-locales-changed";
 const TOPIC_CONTENT_DOCUMENT_INTERACTIVE = "content-document-interactive";
 
-// Automated tests ensure packaged locales are in this list. Copied output of:
-// https://github.com/mozilla/activity-stream/blob/master/bin/render-activity-stream-html.js
-const ACTIVITY_STREAM_BCP47 = "en-US".split(" ");
-
 const ABOUT_URL = "about:newtab";
 const BASE_URL = "resource://activity-stream/";
 const ACTIVITY_STREAM_PAGES = new Set(["home", "newtab", "welcome"]);
 
 const IS_MAIN_PROCESS = Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_DEFAULT;
 const IS_PRIVILEGED_PROCESS = Services.appinfo.remoteType === E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE;
 
 const IS_RELEASE_OR_BETA = AppConstants.RELEASE_OR_BETA;
 
 const PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS = "browser.tabs.remote.separatePrivilegedContentProcess";
 const PREF_ACTIVITY_STREAM_DEBUG = "browser.newtabpage.activity-stream.debug";
 
 function AboutNewTabService() {
   Services.obs.addObserver(this, TOPIC_APP_QUIT);
-  Services.obs.addObserver(this, TOPIC_LOCALES_CHANGE);
   Services.prefs.addObserver(PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS, this);
   if (!IS_RELEASE_OR_BETA) {
     Services.prefs.addObserver(PREF_ACTIVITY_STREAM_DEBUG, this);
   }
 
   // More initialization happens here
   this.toggleActivityStream(true);
   this.initialized = true;
@@ -66,55 +60,52 @@ function AboutNewTabService() {
  *
  * When not overridden, the default URL emitted by the service is "about:newtab".
  * When overridden, it returns the overriden URL.
  *
  * 2. Redirector Access:
  *
  * When the URL loaded is about:newtab, the default behavior, or when entered in the
  * URL bar, the redirector is hit. The service is then called to return the
- * appropriate activity stream url based on prefs and locales.
+ * appropriate activity stream url based on prefs.
  *
  * NOTE: "about:newtab" will always result in a default newtab page, and never an overridden URL.
  *
  * Access patterns:
  *
  * The behavior is different when accessing the service via browser chrome or via redirector
  * largely to maintain compatibility with expectations of add-on developers.
  *
  * Loading a chrome resource, or an about: URL in the redirector with either the
  * LOAD_NORMAL or LOAD_REPLACE flags yield unexpected behaviors, so a roundtrip
  * to the redirector from browser chrome is avoided.
  */
 AboutNewTabService.prototype = {
 
   _newTabURL: ABOUT_URL,
   _activityStreamEnabled: false,
-  _activityStreamPath: "",
   _activityStreamDebug: false,
   _privilegedAboutContentProcess: false,
   _overridden: false,
   willNotifyUser: false,
 
   classID: Components.ID("{dfcd2adc-7867-4d3a-ba70-17501f208142}"),
   QueryInterface: ChromeUtils.generateQI([
     Ci.nsIAboutNewTabService,
     Ci.nsIObserver,
   ]),
 
   observe(subject, topic, data) {
     switch (topic) {
       case "nsPref:changed":
         if (data === PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS) {
           this._privilegedAboutContentProcess = Services.prefs.getBoolPref(PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS);
-          this.updatePrerenderedPath();
           this.notifyChange();
         } else if (!IS_RELEASE_OR_BETA && data === PREF_ACTIVITY_STREAM_DEBUG) {
           this._activityStreamDebug = Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_DEBUG, false);
-          this.updatePrerenderedPath();
           this.notifyChange();
         }
         break;
       case TOPIC_CONTENT_DOCUMENT_INTERACTIVE: {
         const win = subject.defaultView;
 
         // It seems like "content-document-interactive" is triggered multiple
         // times for a single window. The first event always seems to be an
@@ -142,17 +133,16 @@ AboutNewTabService.prototype = {
           const scripts = [
             "chrome://browser/content/contentSearchUI.js",
             "chrome://browser/content/contentTheme.js",
             `${BASE_URL}vendor/react${debugString}.js`,
             `${BASE_URL}vendor/react-dom${debugString}.js`,
             `${BASE_URL}vendor/prop-types.js`,
             `${BASE_URL}vendor/redux.js`,
             `${BASE_URL}vendor/react-redux.js`,
-            `${BASE_URL}prerendered/${this.activityStreamLocale}/activity-stream-strings.js`,
             `${BASE_URL}data/content/activity-stream.bundle.js`,
           ];
 
           for (let script of scripts) {
             Services.scriptloader.loadSubScript(script, win); // Synchronous call
           }
         };
         subject.addEventListener("DOMContentLoaded", onLoaded, {once: true});
@@ -169,20 +159,16 @@ AboutNewTabService.prototype = {
       case TOPIC_APP_QUIT:
         this.uninit();
         if (IS_MAIN_PROCESS) {
           AboutNewTab.uninit();
         } else if (IS_PRIVILEGED_PROCESS) {
           Services.obs.removeObserver(this, TOPIC_CONTENT_DOCUMENT_INTERACTIVE);
         }
         break;
-      case TOPIC_LOCALES_CHANGE:
-        this.updatePrerenderedPath();
-        this.notifyChange();
-        break;
     }
   },
 
   notifyChange() {
     Services.obs.notifyObservers(null, "newtab-url-changed", this._newTabURL);
   },
 
   /**
@@ -204,44 +190,33 @@ AboutNewTabService.prototype = {
       this._activityStreamEnabled = true;
     } else {
       this._activityStreamEnabled = false;
     }
     this._privilegedAboutContentProcess = Services.prefs.getBoolPref(PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS);
     if (!IS_RELEASE_OR_BETA) {
       this._activityStreamDebug = Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_DEBUG, false);
     }
-    this.updatePrerenderedPath();
     this._newtabURL = ABOUT_URL;
     return true;
   },
 
-  /**
-   * Figure out what path under prerendered to use based on current state.
-   */
-  updatePrerenderedPath() {
-    // Debug files are specially packaged in a non-localized directory, but with
-    // dynamic script loading, localized debug is supported.
-    this._activityStreamPath = `${this._activityStreamDebug &&
-      !this._privilegedAboutContentProcess ? "static" : this.activityStreamLocale}/`;
-  },
-
   /*
    * Returns the default URL.
    *
-   * This URL depends on various activity stream prefs and locales. Overriding
+   * This URL depends on various activity stream prefs. Overriding
    * the newtab page has no effect on the result of this function.
    */
   get defaultURL() {
     // Generate the desired activity stream resource depending on state, e.g.,
-    // resource://activity-stream/prerendered/ar/activity-stream.html
-    // resource://activity-stream/prerendered/static/activity-stream-debug.html
+    // "resource://activity-stream/prerendered/activity-stream.html"
+    // "resource://activity-stream/prerendered/activity-stream-debug.html"
+    // "resource://activity-stream/prerendered/activity-stream-noscripts.html"
     return [
       "resource://activity-stream/prerendered/",
-      this._activityStreamPath,
       "activity-stream",
       // Debug version loads dev scripts but noscripts separately loads scripts
       this._activityStreamDebug && !this._privilegedAboutContentProcess ? "-debug" : "",
       this._privilegedAboutContentProcess ? "-noscripts" : "",
       ".html",
     ].join("");
   },
 
@@ -281,31 +256,16 @@ AboutNewTabService.prototype = {
   get activityStreamEnabled() {
     return this._activityStreamEnabled;
   },
 
   get activityStreamDebug() {
     return this._activityStreamDebug;
   },
 
-  get activityStreamLocale() {
-    // Pick the best available locale to match the app locales
-    return Services.locale.negotiateLanguages(
-      // Fix up incorrect BCP47 that are actually lang tags as a workaround for
-      // bug 1479606 returning the wrong values in the content process
-      Services.locale.appLocalesAsBCP47.map(l => l.replace(/^(ja-JP-mac)$/, "$1os")),
-      ACTIVITY_STREAM_BCP47,
-      // defaultLocale's strings aren't necessarily packaged, but en-US' are
-      "en-US",
-      Services.locale.langNegStrategyLookup
-    // Convert the BCP47 to lang tag, which is what is used in our paths, as a
-    // workaround for bug 1478930 negotiating incorrectly with lang tags
-    )[0].replace(/^(ja-JP-mac)os$/, "$1");
-  },
-
   resetNewTabURL() {
     this._overridden = false;
     this._newTabURL = ABOUT_URL;
     this.toggleActivityStream(true, true);
     this.notifyChange();
   },
 
   maybeRecordTopsitesPainted(timestamp) {
@@ -322,17 +282,16 @@ AboutNewTabService.prototype = {
     this.alreadyRecordedTopsitesPainted = true;
   },
 
   uninit() {
     if (!this.initialized) {
       return;
     }
     Services.obs.removeObserver(this, TOPIC_APP_QUIT);
-    Services.obs.removeObserver(this, TOPIC_LOCALES_CHANGE);
     Services.prefs.removeObserver(PREF_SEPARATE_PRIVILEGEDABOUT_CONTENT_PROCESS, this);
     if (!IS_RELEASE_OR_BETA) {
       Services.prefs.removeObserver(PREF_ACTIVITY_STREAM_DEBUG, this);
     }
     this.initialized = false;
   },
 };
 
--- a/browser/components/newtab/bin/render-activity-stream-html.js
+++ b/browser/components/newtab/bin/render-activity-stream-html.js
@@ -1,92 +1,48 @@
  /* eslint-disable no-console */
 const fs = require("fs");
 const {mkdir} = require("shelljs");
 const path = require("path");
 
-const {CENTRAL_LOCALES, DEFAULT_LOCALE} = require("./locales");
-
 // Note: DEFAULT_OPTIONS.baseUrl should match BASE_URL in aboutNewTabService.js
 //       in mozilla-central.
 const DEFAULT_OPTIONS = {
   addonPath: "..",
   baseUrl: "resource://activity-stream/",
 };
 
-// Locales that should be displayed RTL
-const RTL_LIST = ["ar", "he", "fa", "ur"];
-
-/**
- * Get the language part of the locale.
- */
-function getLanguage(locale) {
-  return locale.split("-")[0];
-}
-
-/**
- * Get the best strings for a single provided locale using similar locales and
- * DEFAULT_LOCALE as fallbacks.
- */
-function getStrings(locale, allStrings) {
-  const availableLocales = Object.keys(allStrings);
-
-  const language = getLanguage(locale);
-  const similarLocales = availableLocales.filter(other =>
-    other !== locale && getLanguage(other) === language);
-
-  // Rank locales from least desired to most desired
-  const localeFallbacks = [DEFAULT_LOCALE, ...similarLocales, locale];
-
-  // Get strings from each locale replacing with those from more desired ones
-  const desired = Object.assign({}, ...localeFallbacks.map(l => allStrings[l]));
-
-  // Only include strings that are currently used (defined by default locale)
-  return Object.assign({}, ...Object.keys(allStrings[DEFAULT_LOCALE]).map(
-    key => ({[key]: desired[key]})));
-}
-
-/**
- * Get the text direction of the locale.
- */
-function getTextDirection(locale) {
-  return RTL_LIST.includes(locale.split("-")[0]) ? "rtl" : "ltr";
-}
-
 /**
  * templateHTML - Generates HTML for activity stream, given some options and
  * prerendered HTML if necessary.
  *
  * @param  {obj} options
- *         {str} options.locale         The locale to render in lang="" attribute
- *         {str} options.direction      The language direction to render in dir="" attribute
  *         {str} options.baseUrl        The base URL for all local assets
  *         {bool} options.debug         Should we use dev versions of JS libraries?
  *         {bool} options.noscripts     Should we include scripts in the prerendered files?
  * @return {str}         An HTML document as a string
  */
 function templateHTML(options) {
   const debugString = options.debug ? "-dev" : "";
   const scripts = [
     "chrome://browser/content/contentSearchUI.js",
     "chrome://browser/content/contentTheme.js",
     `${options.baseUrl}vendor/react${debugString}.js`,
     `${options.baseUrl}vendor/react-dom${debugString}.js`,
     `${options.baseUrl}vendor/prop-types.js`,
     `${options.baseUrl}vendor/redux.js`,
     `${options.baseUrl}vendor/react-redux.js`,
-    `${options.baseUrl}prerendered/${options.locale}/activity-stream-strings.js`,
     `${options.baseUrl}data/content/activity-stream.bundle.js`,
   ];
 
   // Add spacing and script tags
   const scriptRender = `\n${scripts.map(script => `    <script src="${script}"></script>`).join("\n")}`;
 
   return `<!doctype html>
-<html lang="${options.locale}" dir="${options.direction}">
+<html>
   <head>
     <meta charset="utf-8">
     <meta http-equiv="Content-Security-Policy" content="default-src 'none'; object-src 'none'; script-src resource: chrome:; connect-src https:; img-src https: data: blob:; style-src 'unsafe-inline';">
     <title data-l10n-id="newtab-page-title"></title>
     <link rel="icon" type="image/png" href="chrome://branding/content/icon32.png"/>
     <link rel="localization" href="browser/branding/brandings.ftl" />
     <link rel="localization" href="browser/newtab/newtab.ftl" />
     <link rel="stylesheet" href="chrome://browser/content/contentSearchUI.css" />
@@ -97,58 +53,33 @@ function templateHTML(options) {
     <div id="root"></div>
     <div id="footer-asrouter-container" role="presentation"></div>${options.noscripts ? "" : scriptRender}
   </body>
 </html>
 `;
 }
 
 /**
- * templateJs - Generates a js file that passes the initial state of the prerendered
- * DOM to the React version. This is necessary to ensure the checksum matches when
- * React mounts so that it can attach to the prerendered elements instead of blowing
- * them away.
- *
- * Note that this may no longer be necessary in React 16 and we should review whether
- * it is still necessary.
- *
- * @param  {string} name The name of the global to expose
- * @param  {string} desc Extra description to include in a js comment
- * @param  {obj}   state The data to expose as a window global
- * @return {str}         The js file as a string
- */
-function templateJs(name, desc, state) {
-  return `// Note - this is a generated ${desc} file.
-window.${name} = ${JSON.stringify(state, null, 2)};
-`;
-}
-
-/**
  * writeFiles - Writes to the desired files the result of a template given
  * various prerendered data and options.
  *
- * @param {string} name          Something to identify in the console
  * @param {string} destPath      Path to write the files to
  * @param {Map}    filesMap      Mapping of a string file name to templater
  * @param {Object} options       Various options for the templater
  */
-function writeFiles(name, destPath, filesMap, options) {
+function writeFiles(destPath, filesMap, options) {
   for (const [file, templater] of filesMap) {
+    console.log("\x1b[32m", `✓ ${file}`, "\x1b[0m");
     fs.writeFileSync(path.join(destPath, file), templater({options}));
   }
-  console.log("\x1b[32m", `✓ ${name}`, "\x1b[0m");
 }
 
 const STATIC_FILES = new Map([
-  ["activity-stream-debug.html", ({options}) => templateHTML(options)],
-]);
-
-const LOCALIZED_FILES = new Map([
-  ["activity-stream-strings.js", ({options: {locale, strings}}) => templateJs("gActivityStreamStrings", locale, strings)],
   ["activity-stream.html", ({options}) => templateHTML(options)],
+  ["activity-stream-debug.html", ({options}) => templateHTML(Object.assign({}, options, {debug: true}))],
   ["activity-stream-noscripts.html", ({options}) => templateHTML(Object.assign({}, options, {noscripts: true}))],
 ]);
 
 /**
  * main - Parses command line arguments, generates html and js with templates,
  *        and writes files to their specified locations.
  */
 function main() { // eslint-disable-line max-statements
@@ -157,79 +88,18 @@ function main() { // eslint-disable-line
   // process.argv are paths
   const args = require("minimist")(process.argv.slice(2), {
     alias: {
       addonPath: "a",
       baseUrl: "b",
     },
   });
 
-  const baseOptions = Object.assign({debug: false}, DEFAULT_OPTIONS, args || {});
-  const addonPath = path.resolve(__dirname, baseOptions.addonPath);
-  const allStrings = require(`${baseOptions.addonPath}/data/locales.json`);
-  const extraLocales = Object.keys(allStrings).filter(locale =>
-    locale !== DEFAULT_LOCALE && !CENTRAL_LOCALES.includes(locale));
-
+  const options = Object.assign({debug: false}, DEFAULT_OPTIONS, args || {});
+  const addonPath = path.resolve(__dirname, options.addonPath);
   const prerenderedPath = path.join(addonPath, "prerendered");
-  console.log(`Writing prerendered files to individual directories under ${prerenderedPath}:`);
-
-  // Save default locale's strings to compare against other locales' strings
-  let defaultStrings;
-  let langStrings;
-  const isSubset = (strings, existing) => existing &&
-    Object.keys(strings).every(key => strings[key] === existing[key]);
-
-  // Process the default locale first then all the ones from mozilla-central
-  const localizedLocales = [];
-  const skippedLocales = [];
-  for (const locale of [DEFAULT_LOCALE, ...CENTRAL_LOCALES]) {
-    // Skip the locale if it would have resulted in duplicate packaged files
-    const strings = getStrings(locale, allStrings);
-    if (isSubset(strings, defaultStrings) || isSubset(strings, langStrings)) {
-      skippedLocales.push(locale);
-      continue;
-    }
-
-    const options = Object.assign({}, baseOptions, {
-      direction: getTextDirection(locale),
-      locale,
-      strings,
-    });
+  console.log(`Writing prerendered files to ${prerenderedPath}:`);
 
-    // Put locale-specific files in their own directory
-    const localePath = path.join(prerenderedPath, "locales", locale);
-    mkdir("-p", localePath);
-    writeFiles(locale, localePath, LOCALIZED_FILES, options);
-
-    // Only write static files once for the default locale
-    if (locale === DEFAULT_LOCALE) {
-      const staticPath = path.join(prerenderedPath, "static");
-      mkdir("-p", staticPath);
-      writeFiles(`${locale} (static)`, staticPath, STATIC_FILES,
-        Object.assign({}, options, {debug: true}));
-
-      // Save the default strings to compare against other locales' strings
-      defaultStrings = strings;
-    }
-
-    // Save the language's strings to maybe reuse for the next similar locales
-    if (getLanguage(locale) === locale) {
-      langStrings = strings;
-    }
-
-    localizedLocales.push(locale);
-  }
-
-  if (skippedLocales.length) {
-    console.log("\x1b[33m", `Skipped the following locales because they use the same strings as ${DEFAULT_LOCALE} or its language locale: ${skippedLocales.join(", ")}`, "\x1b[0m");
-  }
-  if (extraLocales.length) {
-    console.log("\x1b[33m", `Skipped the following locales because they are not in CENTRAL_LOCALES: ${extraLocales.join(", ")}`, "\x1b[0m");
-  }
-
-  // Convert ja-JP-mac lang tag to ja-JP-macos bcp47 to work around bug 1478930
-  const bcp47String = localizedLocales.join(" ").replace(/(ja-JP-mac)/, "$1os");
-
-  // Provide some help to copy/paste locales if tests are failing
-  console.log(`\nIf aboutNewTabService tests are failing for unexpected locales, make sure its list is updated:\nconst ACTIVITY_STREAM_BCP47 = "${bcp47String}".split(" ");`);
+  mkdir("-p", prerenderedPath);
+  writeFiles(prerenderedPath, STATIC_FILES, options);
 }
 
 main();
--- a/browser/components/newtab/jar.mn
+++ b/browser/components/newtab/jar.mn
@@ -21,12 +21,13 @@ browser.jar:
   res/activity-stream/data/content/activity-stream.bundle.js (./data/content/activity-stream.bundle.js)
 #ifdef XP_MACOSX
   res/activity-stream/css/activity-stream.css (./css/activity-stream-mac.css)
 #elifdef XP_WIN
   res/activity-stream/css/activity-stream.css (./css/activity-stream-windows.css)
 #else
   res/activity-stream/css/activity-stream.css (./css/activity-stream-linux.css)
 #endif
+  res/activity-stream/prerendered/activity-stream.html (./prerendered/activity-stream.html)
 #ifndef RELEASE_OR_BETA
-  res/activity-stream/prerendered/static/activity-stream-debug.html (./prerendered/static/activity-stream-debug.html)
+  res/activity-stream/prerendered/activity-stream-debug.html (./prerendered/activity-stream-debug.html)
 #endif
-  res/activity-stream/prerendered/ (./prerendered/locales/*)
+  res/activity-stream/prerendered/activity-stream-noscripts.html (./prerendered/activity-stream-noscripts.html)
--- a/browser/components/newtab/nsIAboutNewTabService.idl
+++ b/browser/components/newtab/nsIAboutNewTabService.idl
@@ -45,21 +45,16 @@ interface nsIAboutNewTabService : nsISup
   readonly attribute bool activityStreamEnabled;
 
   /**
    * Returns true if the the debug pref for activity stream is true
    */
   readonly attribute bool activityStreamDebug;
 
   /**
-   * Returns the locale of the activity stream interface
-   */
-  readonly attribute ACString activityStreamLocale;
-
-  /**
    * Resets to the default resource and also resets the
    * overridden attribute to false.
    */
   void resetNewTabURL();
 
   /**
   * Records a scalar metric for how long it takes to pain Top Sites, this will
   * only record the first timestamp, all the subsequent calls will be ignored.
rename from browser/components/newtab/prerendered/static/activity-stream-debug.html
rename to browser/components/newtab/prerendered/activity-stream-debug.html
--- a/browser/components/newtab/prerendered/static/activity-stream-debug.html
+++ b/browser/components/newtab/prerendered/activity-stream-debug.html
@@ -1,10 +1,10 @@
 <!doctype html>
-<html lang="en-US" dir="ltr">
+<html>
   <head>
     <meta charset="utf-8">
     <meta http-equiv="Content-Security-Policy" content="default-src 'none'; object-src 'none'; script-src resource: chrome:; connect-src https:; img-src https: data: blob:; style-src 'unsafe-inline';">
     <title data-l10n-id="newtab-page-title"></title>
     <link rel="icon" type="image/png" href="chrome://branding/content/icon32.png"/>
     <link rel="localization" href="browser/branding/brandings.ftl" />
     <link rel="localization" href="browser/newtab/newtab.ftl" />
     <link rel="stylesheet" href="chrome://browser/content/contentSearchUI.css" />
@@ -16,12 +16,11 @@
     <div id="footer-asrouter-container" role="presentation"></div>
     <script src="chrome://browser/content/contentSearchUI.js"></script>
     <script src="chrome://browser/content/contentTheme.js"></script>
     <script src="resource://activity-stream/vendor/react-dev.js"></script>
     <script src="resource://activity-stream/vendor/react-dom-dev.js"></script>
     <script src="resource://activity-stream/vendor/prop-types.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/prerendered/en-US/activity-stream-strings.js"></script>
     <script src="resource://activity-stream/data/content/activity-stream.bundle.js"></script>
   </body>
 </html>
rename from browser/components/newtab/prerendered/locales/en-US/activity-stream-noscripts.html
rename to browser/components/newtab/prerendered/activity-stream-noscripts.html
--- a/browser/components/newtab/prerendered/locales/en-US/activity-stream-noscripts.html
+++ b/browser/components/newtab/prerendered/activity-stream-noscripts.html
@@ -1,10 +1,10 @@
 <!doctype html>
-<html lang="en-US" dir="ltr">
+<html>
   <head>
     <meta charset="utf-8">
     <meta http-equiv="Content-Security-Policy" content="default-src 'none'; object-src 'none'; script-src resource: chrome:; connect-src https:; img-src https: data: blob:; style-src 'unsafe-inline';">
     <title data-l10n-id="newtab-page-title"></title>
     <link rel="icon" type="image/png" href="chrome://branding/content/icon32.png"/>
     <link rel="localization" href="browser/branding/brandings.ftl" />
     <link rel="localization" href="browser/newtab/newtab.ftl" />
     <link rel="stylesheet" href="chrome://browser/content/contentSearchUI.css" />
rename from browser/components/newtab/prerendered/locales/en-US/activity-stream.html
rename to browser/components/newtab/prerendered/activity-stream.html
--- a/browser/components/newtab/prerendered/locales/en-US/activity-stream.html
+++ b/browser/components/newtab/prerendered/activity-stream.html
@@ -1,10 +1,10 @@
 <!doctype html>
-<html lang="en-US" dir="ltr">
+<html>
   <head>
     <meta charset="utf-8">
     <meta http-equiv="Content-Security-Policy" content="default-src 'none'; object-src 'none'; script-src resource: chrome:; connect-src https:; img-src https: data: blob:; style-src 'unsafe-inline';">
     <title data-l10n-id="newtab-page-title"></title>
     <link rel="icon" type="image/png" href="chrome://branding/content/icon32.png"/>
     <link rel="localization" href="browser/branding/brandings.ftl" />
     <link rel="localization" href="browser/newtab/newtab.ftl" />
     <link rel="stylesheet" href="chrome://browser/content/contentSearchUI.css" />
@@ -16,12 +16,11 @@
     <div id="footer-asrouter-container" role="presentation"></div>
     <script src="chrome://browser/content/contentSearchUI.js"></script>
     <script src="chrome://browser/content/contentTheme.js"></script>
     <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/prop-types.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/prerendered/en-US/activity-stream-strings.js"></script>
     <script src="resource://activity-stream/data/content/activity-stream.bundle.js"></script>
   </body>
 </html>
deleted file mode 100644
--- a/browser/components/newtab/prerendered/locales/en-US/activity-stream-strings.js
+++ /dev/null
@@ -1,2 +0,0 @@
-// Note - this is a generated en-US file.
-window.gActivityStreamStrings = {};
--- a/browser/components/newtab/test/xpcshell/test_AboutNewTabService.js
+++ b/browser/components/newtab/test/xpcshell/test_AboutNewTabService.js
@@ -24,22 +24,22 @@ function cleanup() {
 }
 
 registerCleanupFunction(cleanup);
 
 let ACTIVITY_STREAM_URL;
 let ACTIVITY_STREAM_DEBUG_URL;
 
 function setExpectedUrlsWithScripts() {
-  ACTIVITY_STREAM_URL = "resource://activity-stream/prerendered/en-US/activity-stream.html";
-  ACTIVITY_STREAM_DEBUG_URL = "resource://activity-stream/prerendered/static/activity-stream-debug.html";
+  ACTIVITY_STREAM_URL = "resource://activity-stream/prerendered/activity-stream.html";
+  ACTIVITY_STREAM_DEBUG_URL = "resource://activity-stream/prerendered/activity-stream-debug.html";
 }
 
 function setExpectedUrlsWithoutScripts() {
-  ACTIVITY_STREAM_URL = "resource://activity-stream/prerendered/en-US/activity-stream-noscripts.html";
+  ACTIVITY_STREAM_URL = "resource://activity-stream/prerendered/activity-stream-noscripts.html";
 
   // Debug urls are the same as non-debug because debug scripts load dynamically
   ACTIVITY_STREAM_DEBUG_URL = ACTIVITY_STREAM_URL;
 }
 
 function nextChangeNotificationPromise(aNewURL, testMessage) {
   return new Promise(resolve => {
     Services.obs.addObserver(function observer(aSubject, aTopic, aData) { // jshint unused:false
@@ -187,21 +187,16 @@ addTestsWithPrivilegedContentProcessPref
       "A notification occurs after changing the debug pref to true.");
     Assert.equal(aboutNewTabService.welcomeURL, ACTIVITY_STREAM_DEBUG_URL,
       "Newtab welcomeURL set to un-prerendered debug AS when debug enabled");
   }
 
   cleanup();
 });
 
-add_task(function test_locale() {
-  Assert.equal(aboutNewTabService.activityStreamLocale, "en-US",
-    "The locale for testing should be en-US");
-});
-
 /**
  * Tests response to updates to prefs
  */
 addTestsWithPrivilegedContentProcessPref(async function test_updates() {
   // Simulates a "cold-boot" situation, with some pref already set before testing a series
   // of changes.
   aboutNewTabService.resetNewTabURL(); // need to set manually because pref notifs are off
   let notificationPromise;
--- a/tools/lint/codespell.yml
+++ b/tools/lint/codespell.yml
@@ -1,16 +1,15 @@
 ---
 codespell:
     description: Check code for common misspellings
     include:
         - browser/base/content/docs/
         - browser/branding/
         - browser/components/newtab/docs/
-        - browser/components/newtab/prerendered/locales/en-US/
         - browser/extensions/formautofill/locales/en-US/
         - browser/extensions/report-site-issue/locales/en-US/
         - browser/installer/windows/docs/
         - browser/locales/en-US/
         - build/docs/
         - devtools/client/locales/en-US/
         - devtools/docs/
         - devtools/shared/locales/en-US/