Bug 1086997 - Localize developer warnings issued by the manifest processor. r=baku
authorMarco Castelluccio <mcastelluccio@mozilla.com>
Tue, 02 Feb 2016 16:47:51 -0800
changeset 321046 355b483c2d6c4b89c2cff578d392a20ce70ff2be
parent 321045 7756089b8570a4e6d0e14e95c7e75179e03adf91
child 321047 95b66e9556e585b364389b32db895fefd7f2674a
push id1128
push userjlund@mozilla.com
push dateWed, 01 Jun 2016 01:31:59 +0000
treeherdermozilla-release@fe0d30de989d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1086997
milestone47.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 1086997 - Localize developer warnings issued by the manifest processor. r=baku
dom/locales/en-US/chrome/dom/dom.properties
dom/manifest/ImageObjectProcessor.jsm
dom/manifest/ManifestProcessor.jsm
dom/manifest/ValueExtractor.jsm
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -184,11 +184,21 @@ InterceptedUsedResponseWithURL=Failed to
 BadOpaqueRedirectInterceptionWithURL=Failed to load '%S'. A ServiceWorker passed an opaqueredirect Response to FetchEvent.respondWith() while handling a non-navigation FetchEvent.
 # LOCALIZATION NOTE: Do not translate "ServiceWorker" or "FetchEvent.preventDefault()". %S is a URL.
 InterceptionCanceledWithURL=Failed to load '%S'. A ServiceWorker canceled the load by calling FetchEvent.preventDefault().
 # LOCALIZATION NOTE: Do not translate "ServiceWorker", "promise", or "FetchEvent.respondWith()". %1$S is a URL. %2$S is an error string.
 InterceptionRejectedResponseWithURL=Failed to load '%1$S'. A ServiceWorker passed a promise to FetchEvent.respondWith() that rejected with '%2$S'.
 # LOCALIZATION NOTE: Do not translate "ServiceWorker", "promise", "FetchEvent.respondWith()", or "Response". %1$S is a URL. %2$S is an error string.
 InterceptedNonResponseWithURL=Failed to load '%1$S'. A ServiceWorker passed a promise to FetchEvent.respondWith() that resolved with non-Response value '%2$S'.
 ExecCommandCutCopyDeniedNotInputDriven=document.execCommand('cut'/'copy') was denied because it was not called from inside a short running user-generated event handler.
+ManifestShouldBeObject=Manifest should be an object.
+ManifestScopeURLInvalid=The scope URL is invalid.
+ManifestScopeNotSameOrigin=The scope URL must be same origin as document.
+ManifestStartURLOutsideScope=The start URL is outside the scope, so the scope is invalid.
+ManifestStartURLInvalid=The start URL is invalid.
+ManifestStartURLShouldBeSameOrigin=The start URL must be same origin as document.
+# LOCALIZATION NOTE: %1$S is the name of the object whose property is invalid. %2$S is the name of the invalid property. %3$S is the expected type of the property value. E.g. "Expected the manifest's start_url member to be a string."
+ManifestInvalidType=Expected the %1$S's %2$S member to be a %3$S.
+# LOCALIZATION NOTE: %1$S is the name of the property whose value is invalid. %2$S is the (invalid) value of the property. E.g. "theme_color: 42 is not a valid CSS color."
+ManifestInvalidCSSColor=%1$S: %2$S is not a valid CSS color.
 PatternAttributeCompileFailure=Unable to check <input pattern='%S'> because the pattern is not a valid regexp: %S
 # LOCALIZATION NOTE: Do not translate "postMessage" or DOMWindow. %S values are origins, like https://domain.com:port
 TargetPrincipalDoesNotMatch=Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('%S') does not match the recipient window's origin ('%S').
--- a/dom/manifest/ImageObjectProcessor.jsm
+++ b/dom/manifest/ImageObjectProcessor.jsm
@@ -1,17 +1,17 @@
 /* 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 https://mozilla.org/MPL/2.0/. */
 /*
  * ImageObjectProcessor
  * Implementation of Image Object processing algorithms from:
  * http://www.w3.org/TR/appmanifest/#image-object-and-its-members
  *
- * This is intended to be used in conjunction with ManifestProcessor.js
+ * This is intended to be used in conjunction with ManifestProcessor.jsm
  *
  * Creates an object to process Image Objects as defined by the
  * W3C specification. This is used to process things like the
  * icon member and the splash_screen member.
  *
  * Usage:
  *
  *   .process(aManifest, aBaseURL, aMemberName);
--- a/dom/manifest/ManifestProcessor.jsm
+++ b/dom/manifest/ManifestProcessor.jsm
@@ -28,16 +28,17 @@ Cu.importGlobalProperties(['URL']);
 const displayModes = new Set(['fullscreen', 'standalone', 'minimal-ui',
   'browser'
 ]);
 const orientationTypes = new Set(['any', 'natural', 'landscape', 'portrait',
   'portrait-primary', 'portrait-secondary', 'landscape-primary',
   'landscape-secondary'
 ]);
 Cu.import('resource://gre/modules/Console.jsm');
+Cu.import("resource://gre/modules/Services.jsm");
 // ValueExtractor is used by the various processors to get values
 // from the manifest and to report errors.
 Cu.import('resource://gre/modules/ValueExtractor.jsm');
 // ImageObjectProcessor is used to process things like icons and images
 Cu.import('resource://gre/modules/ImageObjectProcessor.jsm');
 
 this.ManifestProcessor = { // jshint ignore:line
   get defaultDisplayMode() {
@@ -55,31 +56,32 @@ this.ManifestProcessor = { // jshint ign
   //  * jsonText: the JSON string to be processed.
   //  * manifestURL: the URL of the manifest, to resolve URLs.
   //  * docURL: the URL of the owner doc, for security checks
   process({
     jsonText,
     manifestURL: aManifestURL,
     docURL: aDocURL
   }) {
+    const domBundle = Services.strings.createBundle("chrome://global/locale/dom/dom.properties");
+
     const console = new ConsoleAPI({
       prefix: 'Web Manifest'
     });
     const manifestURL = new URL(aManifestURL);
     const docURL = new URL(aDocURL);
     let rawManifest = {};
     try {
       rawManifest = JSON.parse(jsonText);
     } catch (e) {}
     if (typeof rawManifest !== 'object' || rawManifest === null) {
-      let msg = 'Manifest needs to be an object.';
-      console.warn(msg);
+      console.warn(domBundle.GetStringFromName('ManifestShouldBeObject'));
       rawManifest = {};
     }
-    const extractor = new ValueExtractor(console);
+    const extractor = new ValueExtractor(console, domBundle);
     const imgObjProcessor = new ImageObjectProcessor(console, extractor);
     const processedManifest = {
       'lang': processLangMember(),
       'start_url': processStartURLMember(),
       'display': processDisplayMember.call(this),
       'orientation': processOrientationMember.call(this),
       'name': processNameMember(),
       'icons': imgObjProcessor.process(
@@ -160,31 +162,27 @@ this.ManifestProcessor = { // jshint ign
       const startURL = new URL(processedManifest.start_url);
       const value = extractor.extractValue(spec);
       if (value === undefined || value === '') {
         return undefined;
       }
       try {
         scopeURL = new URL(value, manifestURL);
       } catch (e) {
-        let msg = 'The URL of scope is invalid.';
-        console.warn(msg);
+        console.warn(domBundle.GetStringFromName('ManifestScopeURLInvalid'));
         return undefined;
       }
       if (scopeURL.origin !== docURL.origin) {
-        let msg = 'Scope needs to be same-origin as Document.';
-        console.warn(msg);
+        console.warn(domBundle.GetStringFromName('ManifestScopeNotSameOrigin'));
         return undefined;
       }
       // If start URL is not within scope of scope URL:
       let isSameOrigin = startURL && startURL.origin !== scopeURL.origin;
       if (isSameOrigin || !startURL.pathname.startsWith(scopeURL.pathname)) {
-        let msg =
-          'The start URL is outside the scope, so scope is invalid.';
-        console.warn(msg);
+        console.warn(domBundle.GetStringFromName('ManifestStartURLOutsideScope'));
         return undefined;
       }
       return scopeURL.href;
     }
 
     function processStartURLMember() {
       const spec = {
         objectName: 'manifest',
@@ -197,22 +195,21 @@ this.ManifestProcessor = { // jshint ign
       const value = extractor.extractValue(spec);
       if (value === undefined || value === '') {
         return result;
       }
       let potentialResult;
       try {
         potentialResult = new URL(value, manifestURL);
       } catch (e) {
-        console.warn('Invalid URL.');
+        console.warn(domBundle.GetStringFromName('ManifestStartURLInvalid'))
         return result;
       }
       if (potentialResult.origin !== docURL.origin) {
-        let msg = 'start_url must be same origin as document.';
-        console.warn(msg);
+        console.warn(domBundle.GetStringFromName('ManifestStartURLShouldBeSameOrigin'));
       } else {
         result = potentialResult.href;
       }
       return result;
     }
 
     function processThemeColorMember() {
       const spec = {
--- a/dom/manifest/ValueExtractor.jsm
+++ b/dom/manifest/ValueExtractor.jsm
@@ -7,18 +7,19 @@
  */
 /*globals Components*/
 'use strict';
 const {
   classes: Cc,
   interfaces: Ci
 } = Components;
 
-function ValueExtractor(aConsole) {
+function ValueExtractor(aConsole, aBundle) {
   this.console = aConsole;
+  this.domBundle = aBundle;
 }
 
 ValueExtractor.prototype = {
   // This function takes a 'spec' object and destructures
   // it to extract a value. If the value is of th wrong type, it
   // warns the developer and returns undefined.
   //  expectType: is the type of a JS primitive (string, number, etc.)
   //  object: is the object from which to extract the value.
@@ -27,19 +28,19 @@ ValueExtractor.prototype = {
   //  trim: boolean, if the value should be trimmed (used by string type).
   extractValue({expectedType, object, objectName, property, trim}) {
     const value = object[property];
     const isArray = Array.isArray(value);
     // We need to special-case "array", as it's not a JS primitive.
     const type = (isArray) ? 'array' : typeof value;
     if (type !== expectedType) {
       if (type !== 'undefined') {
-        let msg = `Expected the ${objectName}'s ${property} `;
-        msg += `member to be a ${expectedType}.`;
-        this.console.log(msg);
+        this.console.warn(this.domBundle.formatStringFromName("ManifestInvalidType",
+                                                              [objectName, property, expectedType],
+                                                              3));
       }
       return undefined;
     }
     // Trim string and returned undefined if the empty string.
     const shouldTrim = expectedType === 'string' && value && trim;
     if (shouldTrim) {
       return value.trim() || undefined;
     }
@@ -48,16 +49,17 @@ ValueExtractor.prototype = {
   extractColorValue(spec) {
     const value = this.extractValue(spec);
     const DOMUtils = Cc['@mozilla.org/inspector/dom-utils;1']
       .getService(Ci.inIDOMUtils);
     let color;
     if (DOMUtils.isValidCSSColor(value)) {
       color = value;
     } else if (value) {
-      const msg = `${spec.property}: ${value} is not a valid CSS color.`;
-      this.console.warn(msg);
+      this.console.warn(this.domBundle.formatStringFromName("ManifestInvalidCSSColor",
+                                                            [spec.property, value],
+                                                            2));
     }
     return color;
   }
 };
 this.ValueExtractor = ValueExtractor; // jshint ignore:line
 this.EXPORTED_SYMBOLS = ['ValueExtractor']; // jshint ignore:line