[tbb-commits] [tor-browser/tor-browser-68.2.0esr-9.5-1] Bug 1581537 - Avoid several browser language leaks r=smaug

gk at torproject.org gk at torproject.org
Wed Nov 6 21:19:43 UTC 2019


commit 79d87f543224b0e9d69a7520e25d9179d4f2c2bc
Author: Alex Catarineu <acat at torproject.org>
Date:   Mon Nov 4 16:56:27 2019 +0000

    Bug 1581537 - Avoid several browser language leaks r=smaug
    
    Spoof dom/dom.properties, layout/xmlparser.properties,
    layout/MediaDocument.properties to en-US if needed.
    
    Differential Revision: https://phabricator.services.mozilla.com/D46034
    
    --HG--
    extra : moz-landing-system : lando
---
 .../browser_misused_characters_in_strings.js       |  6 +++
 browser/installer/package-manifest.in              |  3 ++
 dom/base/Document.cpp                              |  8 ++-
 dom/base/Document.h                                |  5 ++
 dom/base/nsContentUtils.cpp                        | 55 +++++++++++++++-----
 dom/base/nsContentUtils.h                          | 32 +++++++++++-
 dom/html/HTMLInputElement.cpp                      | 40 ++++++++-------
 dom/html/HTMLSelectElement.cpp                     |  4 +-
 dom/html/HTMLTextAreaElement.cpp                   | 18 +++----
 dom/html/ImageDocument.cpp                         |  7 ++-
 dom/html/MediaDocument.cpp                         | 59 ++++++++++++++--------
 dom/html/MediaDocument.h                           |  7 +++
 dom/html/input/CheckableInputTypes.cpp             | 11 ++--
 dom/html/input/DateTimeInputTypes.cpp              | 13 ++---
 dom/html/input/FileInputType.cpp                   |  5 +-
 dom/html/input/InputType.cpp                       | 42 ++++++++-------
 dom/html/input/NumericInputTypes.cpp               | 20 ++++----
 dom/html/input/SingleLineTextInputTypes.cpp        | 15 +++---
 dom/locales/moz.build                              |  6 +++
 layout/base/nsCSSFrameConstructor.cpp              |  9 ++--
 layout/forms/nsFileControlFrame.cpp                |  4 +-
 layout/forms/nsGfxButtonControlFrame.cpp           |  4 +-
 layout/generic/DetailsFrame.cpp                    |  6 +--
 mobile/android/installer/package-manifest.in       |  3 ++
 parser/htmlparser/nsExpatDriver.cpp                | 23 ++++++---
 parser/htmlparser/nsParserMsgUtils.h               |  3 ++
 26 files changed, 272 insertions(+), 136 deletions(-)

diff --git a/browser/base/content/test/static/browser_misused_characters_in_strings.js b/browser/base/content/test/static/browser_misused_characters_in_strings.js
index 4b1d9a75d3bb..a9667b4feb96 100644
--- a/browser/base/content/test/static/browser_misused_characters_in_strings.js
+++ b/browser/base/content/test/static/browser_misused_characters_in_strings.js
@@ -99,6 +99,12 @@ let gWhitelist = [
     key: "PatternAttributeCompileFailure",
     type: "single-quote",
   },
+  // dom.properties is packaged twice so we need to have two exceptions for this string.
+  {
+    file: "dom.properties",
+    key: "PatternAttributeCompileFailure",
+    type: "single-quote",
+  },
   {
     file: "netError.dtd",
     key: "inadequateSecurityError.longDesc",
diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in
index 1a2a24f9b5b9..1825397678d1 100644
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -345,6 +345,9 @@
 @RESPATH@/res/dtd/*
 @RESPATH@/res/language.properties
 @RESPATH@/res/locale/layout/HtmlForm.properties
+ at RESPATH@/res/locale/layout/MediaDocument.properties
+ at RESPATH@/res/locale/layout/xmlparser.properties
+ at RESPATH@/res/locale/dom/dom.properties
 #ifdef XP_MACOSX
 @RESPATH@/res/MainMenu.nib/
 #endif
diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp
index cdeabc4dc7b9..df9e7bd78e72 100644
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -3231,7 +3231,7 @@ bool Document::DocumentSupportsL10n(JSContext* aCx, JSObject* aObject) {
 }
 
 void Document::LocalizationLinkAdded(Element* aLinkElement) {
-  if (!nsContentUtils::PrincipalAllowsL10n(NodePrincipal(), GetDocumentURI())) {
+  if (!AllowsL10n()) {
     return;
   }
 
@@ -3262,7 +3262,7 @@ void Document::LocalizationLinkAdded(Element* aLinkElement) {
 }
 
 void Document::LocalizationLinkRemoved(Element* aLinkElement) {
-  if (!nsContentUtils::PrincipalAllowsL10n(NodePrincipal(), GetDocumentURI())) {
+  if (!AllowsL10n()) {
     return;
   }
 
@@ -3314,6 +3314,10 @@ void Document::InitialDocumentTranslationCompleted() {
   mPendingInitialTranslation = false;
 }
 
+bool Document::AllowsL10n() const {
+  return nsContentUtils::PrincipalAllowsL10n(NodePrincipal(), GetDocumentURI());
+}
+
 bool Document::IsWebAnimationsEnabled(JSContext* aCx, JSObject* /*unused*/) {
   MOZ_ASSERT(NS_IsMainThread());
 
diff --git a/dom/base/Document.h b/dom/base/Document.h
index e65bb95d94c9..9c338b0bb153 100644
--- a/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -3661,6 +3661,11 @@ class Document : public nsINode,
    */
   virtual void InitialDocumentTranslationCompleted();
 
+  /**
+   * Returns whether the document allows localization.
+   */
+  bool AllowsL10n() const;
+
  protected:
   RefPtr<DocumentL10n> mDocumentL10n;
 
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index 9c60c1befe1e..e75fd6c9af8b 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -3574,8 +3574,8 @@ static const char* gPropertiesFiles[nsContentUtils::PropertiesFile_COUNT] = {
     "chrome://global/locale/mathml/mathml.properties",
     "chrome://global/locale/security/security.properties",
     "chrome://necko/locale/necko.properties",
-    "chrome://global/locale/layout/HtmlForm.properties",
-    "resource://gre/res/locale/layout/HtmlForm.properties"};
+    "resource://gre/res/locale/layout/HtmlForm.properties",
+    "resource://gre/res/locale/dom/dom.properties"};
 
 /* static */
 nsresult nsContentUtils::EnsureStringBundle(PropertiesFile aFile) {
@@ -3624,22 +3624,47 @@ void nsContentUtils::AsyncPrecreateStringBundles() {
   }
 }
 
-static bool SpoofLocaleEnglish() {
+/* static */
+bool nsContentUtils::SpoofLocaleEnglish() {
   // 0 - will prompt
   // 1 - don't spoof
   // 2 - spoof
   return StaticPrefs::privacy_spoof_english() == 2;
 }
 
+static nsContentUtils::PropertiesFile GetMaybeSpoofedPropertiesFile(
+    nsContentUtils::PropertiesFile aFile, const char* aKey,
+    Document* aDocument) {
+  // When we spoof English, use en-US properties in strings that are accessible
+  // by content.
+  bool spoofLocale = nsContentUtils::SpoofLocaleEnglish() &&
+                     (!aDocument || !aDocument->AllowsL10n());
+  if (spoofLocale) {
+    switch (aFile) {
+      case nsContentUtils::eFORMS_PROPERTIES:
+        return nsContentUtils::eFORMS_PROPERTIES_en_US;
+      case nsContentUtils::eDOM_PROPERTIES:
+        return nsContentUtils::eDOM_PROPERTIES_en_US;
+      default:
+        break;
+    }
+  }
+  return aFile;
+}
+
+/* static */
+nsresult nsContentUtils::GetMaybeLocalizedString(PropertiesFile aFile,
+                                                 const char* aKey,
+                                                 Document* aDocument,
+                                                 nsAString& aResult) {
+  return GetLocalizedString(
+      GetMaybeSpoofedPropertiesFile(aFile, aKey, aDocument), aKey, aResult);
+}
+
 /* static */
 nsresult nsContentUtils::GetLocalizedString(PropertiesFile aFile,
                                             const char* aKey,
                                             nsAString& aResult) {
-  // When we spoof English, use en-US default strings in HTML forms.
-  if (aFile == eFORMS_PROPERTIES_MAYBESPOOF && SpoofLocaleEnglish()) {
-    aFile = eFORMS_PROPERTIES_en_US;
-  }
-
   nsresult rv = EnsureStringBundle(aFile);
   NS_ENSURE_SUCCESS(rv, rv);
   nsIStringBundle* bundle = sStringBundles[aFile];
@@ -3647,16 +3672,20 @@ nsresult nsContentUtils::GetLocalizedString(PropertiesFile aFile,
 }
 
 /* static */
+nsresult nsContentUtils::FormatMaybeLocalizedString(
+    PropertiesFile aFile, const char* aKey, Document* aDocument,
+    const char16_t** aParams, uint32_t aParamsLength, nsAString& aResult) {
+  return FormatLocalizedString(
+      GetMaybeSpoofedPropertiesFile(aFile, aKey, aDocument), aKey, aParams,
+      aParamsLength, aResult);
+}
+
+/* static */
 nsresult nsContentUtils::FormatLocalizedString(PropertiesFile aFile,
                                                const char* aKey,
                                                const char16_t** aParams,
                                                uint32_t aParamsLength,
                                                nsAString& aResult) {
-  // When we spoof English, use en-US default strings in HTML forms.
-  if (aFile == eFORMS_PROPERTIES_MAYBESPOOF && SpoofLocaleEnglish()) {
-    aFile = eFORMS_PROPERTIES_en_US;
-  }
-
   nsresult rv = EnsureStringBundle(aFile);
   NS_ENSURE_SUCCESS(rv, rv);
   nsIStringBundle* bundle = sStringBundles[aFile];
diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h
index ee23a540871d..5b1eefef3854 100644
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -1117,8 +1117,8 @@ class nsContentUtils {
     eMATHML_PROPERTIES,
     eSECURITY_PROPERTIES,
     eNECKO_PROPERTIES,
-    eFORMS_PROPERTIES_MAYBESPOOF,
     eFORMS_PROPERTIES_en_US,
+    eDOM_PROPERTIES_en_US,
     PropertiesFile_COUNT
   };
   static nsresult ReportToConsole(
@@ -1132,6 +1132,8 @@ class nsContentUtils {
 
   static void LogMessageToConsole(const char* aMsg);
 
+  static bool SpoofLocaleEnglish();
+
   /**
    * Get the localized string named |aKey| in properties file |aFile|.
    */
@@ -1139,6 +1141,15 @@ class nsContentUtils {
                                      nsAString& aResult);
 
   /**
+   * Same as GetLocalizedString, except that it might use en-US locale depending
+   * on SpoofLocaleEnglish() and whether the document is a built-in browser
+   * page.
+   */
+  static nsresult GetMaybeLocalizedString(PropertiesFile aFile,
+                                          const char* aKey, Document* aDocument,
+                                          nsAString& aResult);
+
+  /**
    * A helper function that parses a sandbox attribute (of an <iframe> or a CSP
    * directive) and converts it to the set of flags used internally.
    *
@@ -1210,6 +1221,15 @@ class nsContentUtils {
                                         uint32_t aParamsLength,
                                         nsAString& aResult);
 
+  /**
+   * Same as FormatLocalizedString, except that it might use en-US locale
+   * depending on SpoofLocaleEnglish() and whether the document is a built-in
+   * browser page.
+   */
+  static nsresult FormatMaybeLocalizedString(
+      PropertiesFile aFile, const char* aKey, Document* aDocument,
+      const char16_t** aParams, uint32_t aParamsLength, nsAString& aResult);
+
  public:
   template <uint32_t N>
   static nsresult FormatLocalizedString(PropertiesFile aFile, const char* aKey,
@@ -1218,6 +1238,16 @@ class nsContentUtils {
     return FormatLocalizedString(aFile, aKey, aParams, N, aResult);
   }
 
+  template <uint32_t N>
+  static nsresult FormatMaybeLocalizedString(PropertiesFile aFile,
+                                             const char* aKey,
+                                             Document* aDocument,
+                                             const char16_t* (&aParams)[N],
+                                             nsAString& aResult) {
+    return FormatMaybeLocalizedString(aFile, aKey, aDocument, aParams, N,
+                                      aResult);
+  }
+
   /**
    * Fill (with the parameters given) the localized string named |aKey| in
    * properties file |aFile| consuming an nsTArray of nsString parameters rather
diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp
index dd0365a7646c..3217c78a2757 100644
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -725,15 +725,16 @@ nsresult HTMLInputElement::InitFilePicker(FilePickerType aType) {
   nsAutoString title;
   nsAutoString okButtonLabel;
   if (aType == FILE_PICKER_DIRECTORY) {
-    nsContentUtils::GetLocalizedString(
-        nsContentUtils::eFORMS_PROPERTIES_MAYBESPOOF, "DirectoryUpload", title);
+    nsContentUtils::GetMaybeLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
+                                            "DirectoryUpload", OwnerDoc(),
+                                            title);
 
-    nsContentUtils::GetLocalizedString(
-        nsContentUtils::eFORMS_PROPERTIES_MAYBESPOOF,
-        "DirectoryPickerOkButtonLabel", okButtonLabel);
+    nsContentUtils::GetMaybeLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
+                                            "DirectoryPickerOkButtonLabel",
+                                            OwnerDoc(), okButtonLabel);
   } else {
-    nsContentUtils::GetLocalizedString(
-        nsContentUtils::eFORMS_PROPERTIES_MAYBESPOOF, "FileUpload", title);
+    nsContentUtils::GetMaybeLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
+                                            "FileUpload", OwnerDoc(), title);
   }
 
   nsCOMPtr<nsIFilePicker> filePicker =
@@ -2339,24 +2340,25 @@ void HTMLInputElement::GetDisplayFileName(nsAString& aValue) const {
     if ((IsDirPickerEnabled() && Allowdirs()) ||
         (StaticPrefs::dom_webkitBlink_dirPicker_enabled() &&
          HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory))) {
-      nsContentUtils::GetLocalizedString(
-          nsContentUtils::eFORMS_PROPERTIES_MAYBESPOOF, "NoDirSelected", value);
+      nsContentUtils::GetMaybeLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
+                                              "NoDirSelected", OwnerDoc(),
+                                              value);
     } else if (HasAttr(kNameSpaceID_None, nsGkAtoms::multiple)) {
-      nsContentUtils::GetLocalizedString(
-          nsContentUtils::eFORMS_PROPERTIES_MAYBESPOOF, "NoFilesSelected",
-          value);
+      nsContentUtils::GetMaybeLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
+                                              "NoFilesSelected", OwnerDoc(),
+                                              value);
     } else {
-      nsContentUtils::GetLocalizedString(
-          nsContentUtils::eFORMS_PROPERTIES_MAYBESPOOF, "NoFileSelected",
-          value);
+      nsContentUtils::GetMaybeLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
+                                              "NoFileSelected", OwnerDoc(),
+                                              value);
     }
   } else {
     nsString count;
     count.AppendInt(int(mFileData->mFilesOrDirectories.Length()));
 
     const char16_t* params[] = {count.get()};
-    nsContentUtils::FormatLocalizedString(
-        nsContentUtils::eFORMS_PROPERTIES_MAYBESPOOF, "XFilesSelected", params,
+    nsContentUtils::FormatMaybeLocalizedString(
+        nsContentUtils::eFORMS_PROPERTIES, "XFilesSelected", OwnerDoc(), params,
         value);
   }
 
@@ -5828,8 +5830,8 @@ HTMLInputElement::SubmitNamesValues(HTMLFormSubmission* aFormSubmission) {
       !HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
     // Get our default value, which is the same as our default label
     nsAutoString defaultValue;
-    nsContentUtils::GetLocalizedString(
-        nsContentUtils::eFORMS_PROPERTIES_MAYBESPOOF, "Submit", defaultValue);
+    nsContentUtils::GetMaybeLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
+                                            "Submit", OwnerDoc(), defaultValue);
     value = defaultValue;
   }
 
diff --git a/dom/html/HTMLSelectElement.cpp b/dom/html/HTMLSelectElement.cpp
index 76f21db23b31..a7a93468af02 100644
--- a/dom/html/HTMLSelectElement.cpp
+++ b/dom/html/HTMLSelectElement.cpp
@@ -1538,9 +1538,9 @@ nsresult HTMLSelectElement::GetValidationMessage(nsAString& aValidationMessage,
   switch (aType) {
     case VALIDITY_STATE_VALUE_MISSING: {
       nsAutoString message;
-      nsresult rv = nsContentUtils::GetLocalizedString(
+      nsresult rv = nsContentUtils::GetMaybeLocalizedString(
           nsContentUtils::eDOM_PROPERTIES, "FormValidationSelectMissing",
-          message);
+          OwnerDoc(), message);
       aValidationMessage = message;
       return rv;
     }
diff --git a/dom/html/HTMLTextAreaElement.cpp b/dom/html/HTMLTextAreaElement.cpp
index 0d1ba35c8b59..5a5a81545142 100644
--- a/dom/html/HTMLTextAreaElement.cpp
+++ b/dom/html/HTMLTextAreaElement.cpp
@@ -1000,9 +1000,9 @@ nsresult HTMLTextAreaElement::GetValidationMessage(
       strTextLength.AppendInt(textLength);
 
       const char16_t* params[] = {strMaxLength.get(), strTextLength.get()};
-      rv = nsContentUtils::FormatLocalizedString(
-          nsContentUtils::eDOM_PROPERTIES, "FormValidationTextTooLong", params,
-          message);
+      rv = nsContentUtils::FormatMaybeLocalizedString(
+          nsContentUtils::eDOM_PROPERTIES, "FormValidationTextTooLong",
+          OwnerDoc(), params, message);
       aValidationMessage = message;
     } break;
     case VALIDITY_STATE_TOO_SHORT: {
@@ -1016,16 +1016,16 @@ nsresult HTMLTextAreaElement::GetValidationMessage(
       strTextLength.AppendInt(textLength);
 
       const char16_t* params[] = {strMinLength.get(), strTextLength.get()};
-      rv = nsContentUtils::FormatLocalizedString(
-          nsContentUtils::eDOM_PROPERTIES, "FormValidationTextTooShort", params,
-          message);
+      rv = nsContentUtils::FormatMaybeLocalizedString(
+          nsContentUtils::eDOM_PROPERTIES, "FormValidationTextTooShort",
+          OwnerDoc(), params, message);
       aValidationMessage = message;
     } break;
     case VALIDITY_STATE_VALUE_MISSING: {
       nsAutoString message;
-      rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                              "FormValidationValueMissing",
-                                              message);
+      rv = nsContentUtils::GetMaybeLocalizedString(
+          nsContentUtils::eDOM_PROPERTIES, "FormValidationValueMissing",
+          OwnerDoc(), message);
       aValidationMessage = message;
     } break;
     default:
diff --git a/dom/html/ImageDocument.cpp b/dom/html/ImageDocument.cpp
index 87b70961a386..2de785f5fb51 100644
--- a/dom/html/ImageDocument.cpp
+++ b/dom/html/ImageDocument.cpp
@@ -577,14 +577,13 @@ nsresult ImageDocument::OnLoadComplete(imgIRequest* aRequest,
   UpdateTitleAndCharset();
 
   // mImageContent can be null if the document is already destroyed
-  if (NS_FAILED(aStatus) && mStringBundle && mImageContent) {
+  if (NS_FAILED(aStatus) && mImageContent) {
     nsAutoCString src;
     mDocumentURI->GetSpec(src);
     NS_ConvertUTF8toUTF16 srcString(src);
     const char16_t* formatString[] = {srcString.get()};
     nsAutoString errorMsg;
-    mStringBundle->FormatStringFromName("InvalidImage", formatString, 1,
-                                        errorMsg);
+    FormatStringFromName("InvalidImage", formatString, 1, errorMsg);
 
     mImageContent->SetAttr(kNameSpaceID_None, nsGkAtoms::alt, errorMsg, false);
   }
@@ -788,7 +787,7 @@ void ImageDocument::UpdateTitleAndCharset() {
     ratioStr.AppendInt(NSToCoordFloor(GetRatio() * 100));
 
     const char16_t* formatString[1] = {ratioStr.get()};
-    mStringBundle->FormatStringFromName("ScaledImage", formatString, 1, status);
+    FormatStringFromName("ScaledImage", formatString, 1, status);
   }
 
   static const char* const formatNames[4] = {
diff --git a/dom/html/MediaDocument.cpp b/dom/html/MediaDocument.cpp
index 196adddc0f38..48d209d67b11 100644
--- a/dom/html/MediaDocument.cpp
+++ b/dom/html/MediaDocument.cpp
@@ -121,14 +121,6 @@ nsresult MediaDocument::Init() {
   nsresult rv = nsHTMLDocument::Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Create a bundle for the localization
-  nsCOMPtr<nsIStringBundleService> stringService =
-      mozilla::services::GetStringBundleService();
-  if (stringService) {
-    stringService->CreateBundle(NSMEDIADOCUMENT_PROPERTIES_URI,
-                                getter_AddRefs(mStringBundle));
-  }
-
   mIsSyntheticDocument = true;
 
   return NS_OK;
@@ -327,6 +319,38 @@ nsresult MediaDocument::LinkScript(const nsAString& aScript) {
   return head->AppendChildTo(script, false);
 }
 
+void MediaDocument::FormatStringFromName(const char* aName,
+                                         const char16_t** aParams,
+                                         uint32_t aLength, nsAString& aResult) {
+  bool spoofLocale = nsContentUtils::SpoofLocaleEnglish() && !AllowsL10n();
+  if (!spoofLocale) {
+    if (!mStringBundle) {
+      nsCOMPtr<nsIStringBundleService> stringService =
+          mozilla::services::GetStringBundleService();
+      if (stringService) {
+        stringService->CreateBundle(NSMEDIADOCUMENT_PROPERTIES_URI,
+                                    getter_AddRefs(mStringBundle));
+      }
+    }
+    if (mStringBundle) {
+      mStringBundle->FormatStringFromName(aName, aParams, aLength, aResult);
+    }
+  } else {
+    if (!mStringBundleEnglish) {
+      nsCOMPtr<nsIStringBundleService> stringService =
+          mozilla::services::GetStringBundleService();
+      if (stringService) {
+        stringService->CreateBundle(NSMEDIADOCUMENT_PROPERTIES_URI_en_US,
+                                    getter_AddRefs(mStringBundleEnglish));
+      }
+    }
+    if (mStringBundleEnglish) {
+      mStringBundleEnglish->FormatStringFromName(aName, aParams, aLength,
+                                                 aResult);
+    }
+  }
+}
+
 void MediaDocument::UpdateTitleAndCharset(const nsACString& aTypeStr,
                                           nsIChannel* aChannel,
                                           const char* const* aFormatNames,
@@ -338,7 +362,6 @@ void MediaDocument::UpdateTitleAndCharset(const nsACString& aTypeStr,
   NS_ConvertASCIItoUTF16 typeStr(aTypeStr);
   nsAutoString title;
 
-  if (mStringBundle) {
     // if we got a valid size (not all media have a size)
     if (aWidth != 0 && aHeight != 0) {
       nsAutoString widthStr;
@@ -349,27 +372,24 @@ void MediaDocument::UpdateTitleAndCharset(const nsACString& aTypeStr,
       if (!fileStr.IsEmpty()) {
         const char16_t* formatStrings[4] = {fileStr.get(), typeStr.get(),
                                             widthStr.get(), heightStr.get()};
-        mStringBundle->FormatStringFromName(aFormatNames[eWithDimAndFile],
-                                            formatStrings, 4, title);
+        FormatStringFromName(aFormatNames[eWithDimAndFile], formatStrings, 4,
+                             title);
       } else {
         const char16_t* formatStrings[3] = {typeStr.get(), widthStr.get(),
                                             heightStr.get()};
-        mStringBundle->FormatStringFromName(aFormatNames[eWithDim],
-                                            formatStrings, 3, title);
+        FormatStringFromName(aFormatNames[eWithDim], formatStrings, 3, title);
       }
     } else {
       // If we got a filename, display it
       if (!fileStr.IsEmpty()) {
         const char16_t* formatStrings[2] = {fileStr.get(), typeStr.get()};
-        mStringBundle->FormatStringFromName(aFormatNames[eWithFile],
-                                            formatStrings, 2, title);
+        FormatStringFromName(aFormatNames[eWithFile], formatStrings, 2, title);
       } else {
         const char16_t* formatStrings[1] = {typeStr.get()};
-        mStringBundle->FormatStringFromName(aFormatNames[eWithNoInfo],
-                                            formatStrings, 1, title);
+        FormatStringFromName(aFormatNames[eWithNoInfo], formatStrings, 1,
+                             title);
       }
     }
-  }
 
   // set it on the document
   if (aStatus.IsEmpty()) {
@@ -379,8 +399,7 @@ void MediaDocument::UpdateTitleAndCharset(const nsACString& aTypeStr,
     nsAutoString titleWithStatus;
     const nsPromiseFlatString& status = PromiseFlatString(aStatus);
     const char16_t* formatStrings[2] = {title.get(), status.get()};
-    mStringBundle->FormatStringFromName("TitleWithStatus", formatStrings, 2,
-                                        titleWithStatus);
+    FormatStringFromName("TitleWithStatus", formatStrings, 2, titleWithStatus);
     IgnoredErrorResult ignored;
     SetTitle(titleWithStatus, ignored);
   }
diff --git a/dom/html/MediaDocument.h b/dom/html/MediaDocument.h
index e11fd2ec8551..9c295e70d85f 100644
--- a/dom/html/MediaDocument.h
+++ b/dom/html/MediaDocument.h
@@ -16,6 +16,9 @@
 #define NSMEDIADOCUMENT_PROPERTIES_URI \
   "chrome://global/locale/layout/MediaDocument.properties"
 
+#define NSMEDIADOCUMENT_PROPERTIES_URI_en_US \
+  "resource://gre/res/locale/layout/MediaDocument.properties"
+
 namespace mozilla {
 namespace dom {
 
@@ -60,6 +63,9 @@ class MediaDocument : public nsHTMLDocument {
   nsresult LinkStylesheet(const nsAString& aStylesheet);
   nsresult LinkScript(const nsAString& aScript);
 
+  void FormatStringFromName(const char* aName, const char16_t** aParams,
+                            uint32_t aLength, nsAString& aResult);
+
   // |aFormatNames[]| needs to have four elements in the following order:
   // a format name with neither dimension nor file, a format name with
   // filename but w/o dimension, a format name with dimension but w/o filename,
@@ -77,6 +83,7 @@ class MediaDocument : public nsHTMLDocument {
                              const nsAString& aStatus = EmptyString());
 
   nsCOMPtr<nsIStringBundle> mStringBundle;
+  nsCOMPtr<nsIStringBundle> mStringBundleEnglish;
   static const char* const sFormatNames[4];
 
  private:
diff --git a/dom/html/input/CheckableInputTypes.cpp b/dom/html/input/CheckableInputTypes.cpp
index f55000c766ea..c564c36b884a 100644
--- a/dom/html/input/CheckableInputTypes.cpp
+++ b/dom/html/input/CheckableInputTypes.cpp
@@ -23,14 +23,15 @@ bool CheckboxInputType::IsValueMissing() const {
 }
 
 nsresult CheckboxInputType::GetValueMissingMessage(nsAString& aMessage) {
-  return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                            "FormValidationCheckboxMissing",
-                                            aMessage);
+  return nsContentUtils::GetMaybeLocalizedString(
+      nsContentUtils::eDOM_PROPERTIES, "FormValidationCheckboxMissing",
+      mInputElement->OwnerDoc(), aMessage);
 }
 
 /* input type=radio */
 
 nsresult RadioInputType::GetValueMissingMessage(nsAString& aMessage) {
-  return nsContentUtils::GetLocalizedString(
-      nsContentUtils::eDOM_PROPERTIES, "FormValidationRadioMissing", aMessage);
+  return nsContentUtils::GetMaybeLocalizedString(
+      nsContentUtils::eDOM_PROPERTIES, "FormValidationRadioMissing",
+      mInputElement->OwnerDoc(), aMessage);
 }
diff --git a/dom/html/input/DateTimeInputTypes.cpp b/dom/html/input/DateTimeInputTypes.cpp
index 11dfc9e541b9..6d87313907f4 100644
--- a/dom/html/input/DateTimeInputTypes.cpp
+++ b/dom/html/input/DateTimeInputTypes.cpp
@@ -137,9 +137,9 @@ nsresult DateTimeInputTypeBase::GetRangeOverflowMessage(nsAString& aMessage) {
   mInputElement->GetAttr(kNameSpaceID_None, nsGkAtoms::max, maxStr);
 
   const char16_t* params[] = {maxStr.get()};
-  return nsContentUtils::FormatLocalizedString(
+  return nsContentUtils::FormatMaybeLocalizedString(
       nsContentUtils::eDOM_PROPERTIES, "FormValidationDateTimeRangeOverflow",
-      params, aMessage);
+      mInputElement->OwnerDoc(), params, aMessage);
 }
 
 nsresult DateTimeInputTypeBase::GetRangeUnderflowMessage(nsAString& aMessage) {
@@ -147,9 +147,9 @@ nsresult DateTimeInputTypeBase::GetRangeUnderflowMessage(nsAString& aMessage) {
   mInputElement->GetAttr(kNameSpaceID_None, nsGkAtoms::min, minStr);
 
   const char16_t* params[] = {minStr.get()};
-  return nsContentUtils::FormatLocalizedString(
+  return nsContentUtils::FormatMaybeLocalizedString(
       nsContentUtils::eDOM_PROPERTIES, "FormValidationDateTimeRangeUnderflow",
-      params, aMessage);
+      mInputElement->OwnerDoc(), params, aMessage);
 }
 
 nsresult DateTimeInputTypeBase::MinMaxStepAttrChanged() {
@@ -193,8 +193,9 @@ nsresult DateInputType::GetBadInputMessage(nsAString& aMessage) {
     return NS_ERROR_UNEXPECTED;
   }
 
-  return nsContentUtils::GetLocalizedString(
-      nsContentUtils::eDOM_PROPERTIES, "FormValidationInvalidDate", aMessage);
+  return nsContentUtils::GetMaybeLocalizedString(
+      nsContentUtils::eDOM_PROPERTIES, "FormValidationInvalidDate",
+      mInputElement->OwnerDoc(), aMessage);
 }
 
 bool DateInputType::ConvertStringToNumber(
diff --git a/dom/html/input/FileInputType.cpp b/dom/html/input/FileInputType.cpp
index 2536a875b2ca..856684080825 100644
--- a/dom/html/input/FileInputType.cpp
+++ b/dom/html/input/FileInputType.cpp
@@ -21,6 +21,7 @@ bool FileInputType::IsValueMissing() const {
 }
 
 nsresult FileInputType::GetValueMissingMessage(nsAString& aMessage) {
-  return nsContentUtils::GetLocalizedString(
-      nsContentUtils::eDOM_PROPERTIES, "FormValidationFileMissing", aMessage);
+  return nsContentUtils::GetMaybeLocalizedString(
+      nsContentUtils::eDOM_PROPERTIES, "FormValidationFileMissing",
+      mInputElement->OwnerDoc(), aMessage);
 }
diff --git a/dom/html/input/InputType.cpp b/dom/html/input/InputType.cpp
index 210daeafad14..51dbe9b93527 100644
--- a/dom/html/input/InputType.cpp
+++ b/dom/html/input/InputType.cpp
@@ -166,9 +166,9 @@ nsresult InputType::GetValidationMessage(
       strTextLength.AppendInt(textLength);
 
       const char16_t* params[] = {strMaxLength.get(), strTextLength.get()};
-      rv = nsContentUtils::FormatLocalizedString(
-          nsContentUtils::eDOM_PROPERTIES, "FormValidationTextTooLong", params,
-          message);
+      rv = nsContentUtils::FormatMaybeLocalizedString(
+          nsContentUtils::eDOM_PROPERTIES, "FormValidationTextTooLong",
+          mInputElement->OwnerDoc(), params, message);
       aValidationMessage = message;
       break;
     }
@@ -184,9 +184,9 @@ nsresult InputType::GetValidationMessage(
       strTextLength.AppendInt(textLength);
 
       const char16_t* params[] = {strMinLength.get(), strTextLength.get()};
-      rv = nsContentUtils::FormatLocalizedString(
-          nsContentUtils::eDOM_PROPERTIES, "FormValidationTextTooShort", params,
-          message);
+      rv = nsContentUtils::FormatMaybeLocalizedString(
+          nsContentUtils::eDOM_PROPERTIES, "FormValidationTextTooShort",
+          mInputElement->OwnerDoc(), params, message);
 
       aValidationMessage = message;
       break;
@@ -216,9 +216,9 @@ nsresult InputType::GetValidationMessage(
       nsAutoString title;
       mInputElement->GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);
       if (title.IsEmpty()) {
-        rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                                "FormValidationPatternMismatch",
-                                                message);
+        rv = nsContentUtils::GetMaybeLocalizedString(
+            nsContentUtils::eDOM_PROPERTIES, "FormValidationPatternMismatch",
+            mInputElement->OwnerDoc(), message);
       } else {
         if (title.Length() >
             nsIConstraintValidation::sContentSpecifiedMaxLengthMessage) {
@@ -226,9 +226,10 @@ nsresult InputType::GetValidationMessage(
               nsIConstraintValidation::sContentSpecifiedMaxLengthMessage);
         }
         const char16_t* params[] = {title.get()};
-        rv = nsContentUtils::FormatLocalizedString(
+        rv = nsContentUtils::FormatMaybeLocalizedString(
             nsContentUtils::eDOM_PROPERTIES,
-            "FormValidationPatternMismatchWithTitle", params, message);
+            "FormValidationPatternMismatchWithTitle", mInputElement->OwnerDoc(),
+            params, message);
       }
       aValidationMessage = message;
       break;
@@ -278,23 +279,25 @@ nsresult InputType::GetValidationMessage(
 
         if (valueLowStr.Equals(valueHighStr)) {
           const char16_t* params[] = {valueLowStr.get()};
-          rv = nsContentUtils::FormatLocalizedString(
+          rv = nsContentUtils::FormatMaybeLocalizedString(
               nsContentUtils::eDOM_PROPERTIES,
-              "FormValidationStepMismatchOneValue", params, message);
+              "FormValidationStepMismatchOneValue", mInputElement->OwnerDoc(),
+              params, message);
         } else {
           const char16_t* params[] = {valueLowStr.get(), valueHighStr.get()};
-          rv = nsContentUtils::FormatLocalizedString(
+          rv = nsContentUtils::FormatMaybeLocalizedString(
               nsContentUtils::eDOM_PROPERTIES, "FormValidationStepMismatch",
-              params, message);
+              mInputElement->OwnerDoc(), params, message);
         }
       } else {
         nsAutoString valueLowStr;
         ConvertNumberToString(valueLow, valueLowStr);
 
         const char16_t* params[] = {valueLowStr.get()};
-        rv = nsContentUtils::FormatLocalizedString(
+        rv = nsContentUtils::FormatMaybeLocalizedString(
             nsContentUtils::eDOM_PROPERTIES,
-            "FormValidationStepMismatchOneValue", params, message);
+            "FormValidationStepMismatchOneValue", mInputElement->OwnerDoc(),
+            params, message);
       }
 
       aValidationMessage = message;
@@ -318,8 +321,9 @@ nsresult InputType::GetValidationMessage(
 }
 
 nsresult InputType::GetValueMissingMessage(nsAString& aMessage) {
-  return nsContentUtils::GetLocalizedString(
-      nsContentUtils::eDOM_PROPERTIES, "FormValidationValueMissing", aMessage);
+  return nsContentUtils::GetMaybeLocalizedString(
+      nsContentUtils::eDOM_PROPERTIES, "FormValidationValueMissing",
+      mInputElement->OwnerDoc(), aMessage);
 }
 
 nsresult InputType::GetTypeMismatchMessage(nsAString& aMessage) {
diff --git a/dom/html/input/NumericInputTypes.cpp b/dom/html/input/NumericInputTypes.cpp
index 6332e028c17e..9770ccd416b1 100644
--- a/dom/html/input/NumericInputTypes.cpp
+++ b/dom/html/input/NumericInputTypes.cpp
@@ -72,9 +72,9 @@ nsresult NumericInputTypeBase::GetRangeOverflowMessage(nsAString& aMessage) {
   MOZ_ASSERT(ok, "buf not big enough");
 
   const char16_t* params[] = {maxStr.get()};
-  return nsContentUtils::FormatLocalizedString(
+  return nsContentUtils::FormatMaybeLocalizedString(
       nsContentUtils::eDOM_PROPERTIES, "FormValidationNumberRangeOverflow",
-      params, aMessage);
+      mInputElement->OwnerDoc(), params, aMessage);
 }
 
 nsresult NumericInputTypeBase::GetRangeUnderflowMessage(nsAString& aMessage) {
@@ -89,9 +89,9 @@ nsresult NumericInputTypeBase::GetRangeUnderflowMessage(nsAString& aMessage) {
   MOZ_ASSERT(ok, "buf not big enough");
 
   const char16_t* params[] = {minStr.get()};
-  return nsContentUtils::FormatLocalizedString(
+  return nsContentUtils::FormatMaybeLocalizedString(
       nsContentUtils::eDOM_PROPERTIES, "FormValidationNumberRangeUnderflow",
-      params, aMessage);
+      mInputElement->OwnerDoc(), params, aMessage);
 }
 
 bool NumericInputTypeBase::ConvertStringToNumber(
@@ -150,15 +150,15 @@ bool NumberInputType::HasBadInput() const {
 }
 
 nsresult NumberInputType::GetValueMissingMessage(nsAString& aMessage) {
-  return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                            "FormValidationBadInputNumber",
-                                            aMessage);
+  return nsContentUtils::GetMaybeLocalizedString(
+      nsContentUtils::eDOM_PROPERTIES, "FormValidationBadInputNumber",
+      mInputElement->OwnerDoc(), aMessage);
 }
 
 nsresult NumberInputType::GetBadInputMessage(nsAString& aMessage) {
-  return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
-                                            "FormValidationBadInputNumber",
-                                            aMessage);
+  return nsContentUtils::GetMaybeLocalizedString(
+      nsContentUtils::eDOM_PROPERTIES, "FormValidationBadInputNumber",
+      mInputElement->OwnerDoc(), aMessage);
 }
 
 bool NumberInputType::IsMutable() const {
diff --git a/dom/html/input/SingleLineTextInputTypes.cpp b/dom/html/input/SingleLineTextInputTypes.cpp
index 15cbe65a1941..090de7466fae 100644
--- a/dom/html/input/SingleLineTextInputTypes.cpp
+++ b/dom/html/input/SingleLineTextInputTypes.cpp
@@ -116,8 +116,9 @@ bool URLInputType::HasTypeMismatch() const {
 }
 
 nsresult URLInputType::GetTypeMismatchMessage(nsAString& aMessage) {
-  return nsContentUtils::GetLocalizedString(
-      nsContentUtils::eDOM_PROPERTIES, "FormValidationInvalidURL", aMessage);
+  return nsContentUtils::GetMaybeLocalizedString(
+      nsContentUtils::eDOM_PROPERTIES, "FormValidationInvalidURL",
+      mInputElement->OwnerDoc(), aMessage);
 }
 
 /* input type=email */
@@ -154,13 +155,15 @@ bool EmailInputType::HasBadInput() const {
 }
 
 nsresult EmailInputType::GetTypeMismatchMessage(nsAString& aMessage) {
-  return nsContentUtils::GetLocalizedString(
-      nsContentUtils::eDOM_PROPERTIES, "FormValidationInvalidEmail", aMessage);
+  return nsContentUtils::GetMaybeLocalizedString(
+      nsContentUtils::eDOM_PROPERTIES, "FormValidationInvalidEmail",
+      mInputElement->OwnerDoc(), aMessage);
 }
 
 nsresult EmailInputType::GetBadInputMessage(nsAString& aMessage) {
-  return nsContentUtils::GetLocalizedString(
-      nsContentUtils::eDOM_PROPERTIES, "FormValidationInvalidEmail", aMessage);
+  return nsContentUtils::GetMaybeLocalizedString(
+      nsContentUtils::eDOM_PROPERTIES, "FormValidationInvalidEmail",
+      mInputElement->OwnerDoc(), aMessage);
 }
 
 /* static */
diff --git a/dom/locales/moz.build b/dom/locales/moz.build
index b2bcd271de7c..51f4b88ccd47 100644
--- a/dom/locales/moz.build
+++ b/dom/locales/moz.build
@@ -62,4 +62,10 @@ JAR_MANIFESTS += ['jar.mn']
 
 RESOURCE_FILES.locale.layout += [
     'en-US/chrome/layout/HtmlForm.properties',
+    'en-US/chrome/layout/MediaDocument.properties',
+    'en-US/chrome/layout/xmlparser.properties',
+]
+
+RESOURCE_FILES.locale.dom += [
+    'en-US/chrome/dom/dom.properties',
 ]
diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp
index 7a5a96d1769a..491274c9b2a6 100644
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -1654,8 +1654,8 @@ already_AddRefed<nsIContent> nsCSSFrameConstructor::CreateGeneratedContent(
         }
 
         nsAutoString temp;
-        nsContentUtils::GetLocalizedString(
-            nsContentUtils::eFORMS_PROPERTIES_MAYBESPOOF, "Submit", temp);
+        nsContentUtils::GetMaybeLocalizedString(
+            nsContentUtils::eFORMS_PROPERTIES, "Submit", mDocument, temp);
         return CreateGenConTextNode(aState, temp, nullptr, nullptr);
       }
 
@@ -7899,8 +7899,9 @@ void nsCSSFrameConstructor::GetAlternateTextFor(Element* aElement, nsAtom* aTag,
 
     // If there's no "value" attribute either, then use the localized string for
     // "Submit" as the alternate text.
-    nsContentUtils::GetLocalizedString(
-        nsContentUtils::eFORMS_PROPERTIES_MAYBESPOOF, "Submit", aAltText);
+    nsContentUtils::GetMaybeLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
+                                            "Submit", aElement->OwnerDoc(),
+                                            aAltText);
   }
 }
 
diff --git a/layout/forms/nsFileControlFrame.cpp b/layout/forms/nsFileControlFrame.cpp
index 9be30011aa8e..8da00f76dcea 100644
--- a/layout/forms/nsFileControlFrame.cpp
+++ b/layout/forms/nsFileControlFrame.cpp
@@ -215,8 +215,8 @@ static already_AddRefed<Element> MakeAnonButton(Document* aDoc,
 
   // Set the file picking button text depending on the current locale.
   nsAutoString buttonTxt;
-  nsContentUtils::GetLocalizedString(
-      nsContentUtils::eFORMS_PROPERTIES_MAYBESPOOF, labelKey, buttonTxt);
+  nsContentUtils::GetMaybeLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
+                                          labelKey, aDoc, buttonTxt);
 
   // Set the browse button text. It's a bit of a pain to do because we want to
   // make sure we are not notifying.
diff --git a/layout/forms/nsGfxButtonControlFrame.cpp b/layout/forms/nsGfxButtonControlFrame.cpp
index 03186ef7bf54..fa4219a5308f 100644
--- a/layout/forms/nsGfxButtonControlFrame.cpp
+++ b/layout/forms/nsGfxButtonControlFrame.cpp
@@ -88,8 +88,8 @@ nsresult nsGfxButtonControlFrame::GetDefaultLabel(nsAString& aString) const {
     return NS_OK;
   }
 
-  return nsContentUtils::GetLocalizedString(
-      nsContentUtils::eFORMS_PROPERTIES_MAYBESPOOF, prop, aString);
+  return nsContentUtils::GetMaybeLocalizedString(
+      nsContentUtils::eFORMS_PROPERTIES, prop, mContent->OwnerDoc(), aString);
 }
 
 nsresult nsGfxButtonControlFrame::GetLabel(nsString& aLabel) {
diff --git a/layout/generic/DetailsFrame.cpp b/layout/generic/DetailsFrame.cpp
index e1a9f0c70b2b..20f93b2f328f 100644
--- a/layout/generic/DetailsFrame.cpp
+++ b/layout/generic/DetailsFrame.cpp
@@ -98,9 +98,9 @@ nsresult DetailsFrame::CreateAnonymousContent(
   mDefaultSummary = new HTMLSummaryElement(nodeInfo.forget());
 
   nsAutoString defaultSummaryText;
-  nsContentUtils::GetLocalizedString(
-      nsContentUtils::eFORMS_PROPERTIES_MAYBESPOOF, "DefaultSummary",
-      defaultSummaryText);
+  nsContentUtils::GetMaybeLocalizedString(
+      nsContentUtils::eFORMS_PROPERTIES, "DefaultSummary",
+      GetContent()->OwnerDoc(), defaultSummaryText);
   RefPtr<nsTextNode> description = new nsTextNode(nodeInfoManager);
   description->SetText(defaultSummaryText, false);
   mDefaultSummary->AppendChildTo(description, false);
diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in
index 2002a894fc51..33e0175a624e 100644
--- a/mobile/android/installer/package-manifest.in
+++ b/mobile/android/installer/package-manifest.in
@@ -203,6 +203,9 @@
 @BINPATH@/res/dtd/*
 @BINPATH@/res/language.properties
 @BINPATH@/res/locale/layout/HtmlForm.properties
+ at BINPATH@/res/locale/layout/MediaDocument.properties
+ at BINPATH@/res/locale/layout/xmlparser.properties
+ at BINPATH@/res/locale/dom/dom.properties
 
 #ifndef MOZ_ANDROID_EXCLUDE_FONTS
 @BINPATH@/res/fonts/*
diff --git a/parser/htmlparser/nsExpatDriver.cpp b/parser/htmlparser/nsExpatDriver.cpp
index 73a0e65328f0..0c35f87bc321 100644
--- a/parser/htmlparser/nsExpatDriver.cpp
+++ b/parser/htmlparser/nsExpatDriver.cpp
@@ -673,12 +673,13 @@ static nsresult CreateErrorText(const char16_t* aDescription,
                                 const char16_t* aSourceURL,
                                 const uint32_t aLineNumber,
                                 const uint32_t aColNumber,
-                                nsString& aErrorString) {
+                                nsString& aErrorString, bool spoofEnglish) {
   aErrorString.Truncate();
 
   nsAutoString msg;
   nsresult rv = nsParserMsgUtils::GetLocalizedStringByName(
-      XMLPARSER_PROPERTIES, "XMLParsingError", msg);
+      spoofEnglish ? XMLPARSER_PROPERTIES_en_US : XMLPARSER_PROPERTIES,
+      "XMLParsingError", msg);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // XML Parsing Error: %1$S\nLocation: %2$S\nLine Number %3$u, Column %4$u:
@@ -719,8 +720,15 @@ nsresult nsExpatDriver::HandleError() {
   // Map Expat error code to an error string
   // XXX Deal with error returns.
   nsAutoString description;
-  nsParserMsgUtils::GetLocalizedStringByID(XMLPARSER_PROPERTIES, code,
-                                           description);
+  nsCOMPtr<Document> doc;
+  if (mOriginalSink) {
+    doc = do_QueryInterface(mOriginalSink->GetTarget());
+  }
+  bool spoofEnglish =
+      nsContentUtils::SpoofLocaleEnglish() && (!doc || !doc->AllowsL10n());
+  nsParserMsgUtils::GetLocalizedStringByID(
+      spoofEnglish ? XMLPARSER_PROPERTIES_en_US : XMLPARSER_PROPERTIES, code,
+      description);
 
   if (code == XML_ERROR_TAG_MISMATCH) {
     /**
@@ -756,8 +764,9 @@ nsresult nsExpatDriver::HandleError() {
     tagName.Append(nameStart, (nameEnd ? nameEnd : pos) - nameStart);
 
     nsAutoString msg;
-    nsParserMsgUtils::GetLocalizedStringByName(XMLPARSER_PROPERTIES, "Expected",
-                                               msg);
+    nsParserMsgUtils::GetLocalizedStringByName(
+        spoofEnglish ? XMLPARSER_PROPERTIES_en_US : XMLPARSER_PROPERTIES,
+        "Expected", msg);
 
     // . Expected: </%S>.
     nsAutoString message;
@@ -771,7 +780,7 @@ nsresult nsExpatDriver::HandleError() {
 
   nsAutoString errorText;
   CreateErrorText(description.get(), XML_GetBase(mExpatParser), lineNumber,
-                  colNumber, errorText);
+                  colNumber, errorText, spoofEnglish);
 
   nsAutoString sourceText(mLastLine);
   AppendErrorPointer(colNumber, mLastLine.get(), sourceText);
diff --git a/parser/htmlparser/nsParserMsgUtils.h b/parser/htmlparser/nsParserMsgUtils.h
index b4ec4784d65f..3645610385c1 100644
--- a/parser/htmlparser/nsParserMsgUtils.h
+++ b/parser/htmlparser/nsParserMsgUtils.h
@@ -11,6 +11,9 @@
 #define XMLPARSER_PROPERTIES \
   "chrome://global/locale/layout/xmlparser.properties"
 
+#define XMLPARSER_PROPERTIES_en_US \
+  "resource://gre/res/locale/layout/xmlparser.properties"
+
 class nsParserMsgUtils {
   nsParserMsgUtils();   // Currently this is not meant to be created, use the
                         // static methods



More information about the tbb-commits mailing list