Bug 1294220 - part1: Move ellipsis character to a localized string in properties file;r=bgrins draft
authorJulian Descottes <jdescottes@mozilla.com>
Sat, 20 Aug 2016 22:09:03 +0200
changeset 404083 b513f69a00335c63c46e085b0101ca4cf884fb08
parent 403990 935fa9ccdd143a21f4d25608bd7b164e09682c8f
child 404084 f149b09e55105b44f8e36fd2da20efdfbdbd53f0
push id27110
push userjdescottes@mozilla.com
push dateMon, 22 Aug 2016 22:07:41 +0000
reviewersbgrins
bugs1294220
milestone51.0a1
Bug 1294220 - part1: Move ellipsis character to a localized string in properties file;r=bgrins The ellipsis character displayed by devtools is now relying on a localized string in devtools/client/shared.properties instead of a complex preference. The lazy loading of the ellipsis string has been removed, the ellipsis is retrieved once when the client/shared/l10n.js file is loaded. The ellipsis property on the LocalizationHelper instances has been removed in favor of an ELLIPSIS export on the l10n.js module. All the previous callers using either LocalizationHelper::ellipsis or retrieving the intl.ellipsis preference have been migrated to rely on the ELLIPSIS export of l10n.js MozReview-Commit-ID: 4JG0qbJGCw9
devtools/client/debugger/debugger-controller.js
devtools/client/debugger/test/mochitest/browser_dbg_sources-labels.js
devtools/client/debugger/test/mochitest/browser_dbg_variables-view-large-array-buffer.js
devtools/client/debugger/utils.js
devtools/client/debugger/views/global-search-view.js
devtools/client/inspector/breadcrumbs.js
devtools/client/locales/en-US/shared.properties
devtools/client/shared/l10n.js
devtools/client/shared/test/browser_flame-graph-04.js
devtools/client/shared/widgets/FlameGraph.js
devtools/client/shared/widgets/VariablesView.jsm
devtools/client/shared/widgets/VariablesViewController.jsm
devtools/client/storage/ui.js
devtools/client/webconsole/console-output.js
devtools/client/webconsole/test/browser_webconsole_output_05.js
devtools/client/webconsole/test/browser_webconsole_output_06.js
--- a/devtools/client/debugger/debugger-controller.js
+++ b/devtools/client/debugger/debugger-controller.js
@@ -141,17 +141,17 @@ var Services = require("Services");
 var {TargetFactory} = require("devtools/client/framework/target");
 var {Toolbox} = require("devtools/client/framework/toolbox");
 var DevToolsUtils = require("devtools/shared/DevToolsUtils");
 var promise = require("devtools/shared/deprecated-sync-thenables");
 var Editor = require("devtools/client/sourceeditor/editor");
 var DebuggerEditor = require("devtools/client/sourceeditor/debugger");
 var {Tooltip} = require("devtools/client/shared/widgets/Tooltip");
 var FastListWidget = require("devtools/client/shared/widgets/FastListWidget");
-var {LocalizationHelper} = require("devtools/client/shared/l10n");
+var {LocalizationHelper, ELLIPSIS} = require("devtools/client/shared/l10n");
 var {PrefsHelper} = require("devtools/client/shared/prefs");
 var {Task} = require("devtools/shared/task");
 
 XPCOMUtils.defineConstant(this, "EVENTS", EVENTS);
 
 XPCOMUtils.defineLazyModuleGetter(this, "Parser",
   "resource://devtools/shared/Parser.jsm");
 
--- a/devtools/client/debugger/test/mochitest/browser_dbg_sources-labels.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_sources-labels.js
@@ -3,50 +3,50 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests that urls are correctly shortened to unique labels.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
+const { ELLIPSIS } = require("devtools/client/shared/l10n");
 
 function test() {
   let gTab, gPanel, gDebugger;
   let gSources, gUtils;
 
   let options = {
     source: TAB_URL,
     line: 1
   };
   initDebugger(TAB_URL, options).then(Task.async(function* ([aTab,, aPanel]) {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gSources = gDebugger.DebuggerView.Sources;
     gUtils = gDebugger.SourceUtils;
 
-    let ellipsis = gPanel.panelWin.L10N.ellipsis;
     let nananana = new Array(20).join(NaN);
 
     // Test trimming url queries.
 
     let someUrl = "a/b/c.d?test=1&random=4#reference";
     let shortenedUrl = "a/b/c.d";
     is(gUtils.trimUrlQuery(someUrl), shortenedUrl,
       "Trimming the url query isn't done properly.");
 
     // Test trimming long urls with an ellipsis.
 
     let largeLabel = new Array(100).join("Beer can in Jamaican sounds like Bacon!");
     let trimmedLargeLabel = gUtils.trimUrlLength(largeLabel, 1234);
     is(trimmedLargeLabel.length, 1235,
       "Trimming large labels isn't done properly.");
-    ok(trimmedLargeLabel.endsWith(ellipsis),
-      "Trimming large labels should add an ellipsis at the end.");
+    ok(trimmedLargeLabel.endsWith(ELLIPSIS),
+      "Trimming large labels should add an ellipsis at the end : " + ELLIPSIS);
 
     // Test the sources list behaviour with certain urls.
 
     let urls = [
       { href: "http://some.address.com/random/", leaf: "subrandom/" },
       { href: "http://some.address.com/random/", leaf: "suprandom/?a=1" },
       { href: "http://some.address.com/random/", leaf: "?a=1" },
       { href: "https://another.address.org/random/subrandom/", leaf: "page.html" },
@@ -142,17 +142,17 @@ function test() {
       "Source (11) label is incorrect.");
     ok(gSources.getItemForAttachment(e => e.label == "script_t3_1.js"),
       "Source (12) label is incorrect.");
     ok(gSources.getItemForAttachment(e => e.label == "script_t3_2.js"),
       "Source (13) label is incorrect.");
     ok(gSources.getItemForAttachment(e => e.label == "script_t3_3.js"),
       "Source (14) label is incorrect.");
 
-    ok(gSources.getItemForAttachment(e => e.label == nananana + "Batman!" + ellipsis),
+    ok(gSources.getItemForAttachment(e => e.label == nananana + "Batman!" + ELLIPSIS),
       "Source (15) label is incorrect.");
 
     is(gSources.itemCount, urls.filter(({ dupe }) => !dupe).length + 1,
       "Didn't get the correct number of sources in the list.");
 
     is(gSources.getItemByValue(getSourceActor(gSources, "http://some.address.com/random/subrandom/")).attachment.label,
       "random/subrandom/",
       "gSources.getItemByValue isn't functioning properly (0).");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-large-array-buffer.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_variables-view-large-array-buffer.js
@@ -6,34 +6,34 @@
 /**
  * Make sure that the variables view remains responsive when faced with
  * huge ammounts of data.
  */
 
 "use strict";
 
 const TAB_URL = EXAMPLE_URL + "doc_large-array-buffer.html";
+const {ELLIPSIS} = require("devtools/client/shared/l10n");
 
-var gTab, gPanel, gDebugger;
-var gVariables, gEllipsis;
+
+var gTab, gPanel, gDebugger, gVariables;
 
 function test() {
   // this test does a lot of work on large objects, default 45s is not enough
   requestLongerTimeout(4);
 
   let options = {
     source: TAB_URL,
     line: 1
   };
   initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
     gTab = aTab;
     gPanel = aPanel;
     gDebugger = gPanel.panelWin;
     gVariables = gDebugger.DebuggerView.Variables;
-    gEllipsis = Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data;
 
     waitForCaretAndScopes(gPanel, 28, 1)
       .then(() => performTests())
       .then(() => resumeDebuggerThenCloseAndFinish(gPanel))
       .then(null, error => {
         ok(false, "Got an error: " + error.message + "\n" + error.stack);
       });
 
@@ -85,17 +85,17 @@ const VARS_TO_TEST = [
   }
 ];
 
 const PAGE_RANGES = [
   [0, 2499], [2500, 4999], [5000, 7499], [7500, 9999]
 ];
 
 function toPageNames(ranges) {
-  return ranges.map(([ from, to ]) => "[" + from + gEllipsis + to + "]");
+  return ranges.map(([ from, to ]) => "[" + from + ELLIPSIS + to + "]");
 }
 
 function performTests() {
   let localScope = gVariables.getScopeAtIndex(0);
 
   return promise.all(VARS_TO_TEST.map(spec => {
     let { varName, stringified, doNotExpand } = spec;
 
@@ -245,10 +245,9 @@ function verifyNextLevels3(lastPage2, va
   });
 }
 
 registerCleanupFunction(function () {
   gTab = null;
   gPanel = null;
   gDebugger = null;
   gVariables = null;
-  gEllipsis = null;
 });
--- a/devtools/client/debugger/utils.js
+++ b/devtools/client/debugger/utils.js
@@ -202,23 +202,23 @@ var SourceUtils = {
    */
   trimUrlLength: function (aUrl, aLength, aSection) {
     aLength = aLength || SOURCE_URL_DEFAULT_MAX_LENGTH;
     aSection = aSection || "end";
 
     if (aUrl.length > aLength) {
       switch (aSection) {
         case "start":
-          return L10N.ellipsis + aUrl.slice(-aLength);
+          return ELLIPSIS + aUrl.slice(-aLength);
           break;
         case "center":
-          return aUrl.substr(0, aLength / 2 - 1) + L10N.ellipsis + aUrl.slice(-aLength / 2 + 1);
+          return aUrl.substr(0, aLength / 2 - 1) + ELLIPSIS + aUrl.slice(-aLength / 2 + 1);
           break;
         case "end":
-          return aUrl.substr(0, aLength) + L10N.ellipsis;
+          return aUrl.substr(0, aLength) + ELLIPSIS;
           break;
       }
     }
     return aUrl;
   },
 
   /**
    * Trims the query part or reference identifier of a url string, if necessary.
--- a/devtools/client/debugger/views/global-search-view.js
+++ b/devtools/client/debugger/views/global-search-view.js
@@ -661,17 +661,17 @@ LineResults.prototype = {
   },
 
   /**
    * An nsIDOMNode label with an ellipsis value.
    */
   _ellipsis: (function () {
     let label = document.createElement("label");
     label.className = "plain dbg-results-line-contents-string";
-    label.setAttribute("value", L10N.ellipsis);
+    label.setAttribute("value", ELLIPSIS);
     return label;
   })(),
 
   line: 0,
   _sourceResults: null,
   _store: null,
   _target: null
 };
--- a/devtools/client/inspector/breadcrumbs.js
+++ b/devtools/client/inspector/breadcrumbs.js
@@ -1,25 +1,20 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-/* eslint-disable mozilla/reject-some-requires */
-const {Ci} = require("chrome");
-/* eslint-enable mozilla/reject-some-requires */
-const Services = require("Services");
 const promise = require("promise");
 
-const ELLIPSIS = Services.prefs.getComplexValue(
-    "intl.ellipsis",
-    Ci.nsIPrefLocalizedString).data;
+const {ELLIPSIS} = require("devtools/client/shared/l10n");
+
 const MAX_LABEL_LENGTH = 40;
 
 const NS_XHTML = "http://www.w3.org/1999/xhtml";
 const SCROLL_REPEAT_MS = 100;
 
 const EventEmitter = require("devtools/shared/event-emitter");
 const {KeyShortcuts} = require("devtools/client/shared/key-shortcuts");
 
--- a/devtools/client/locales/en-US/shared.properties
+++ b/devtools/client/locales/en-US/shared.properties
@@ -1,11 +1,14 @@
 # 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 (dimensions): This is used to display the dimensions
 # of a node or image, like 100×200.
 dimensions=%S\u00D7%S
 
+# LOCALIZATION NOTE (ellipsis): The ellipsis (three dots) character
+ellipsis=…
+
 # LOCALIZATION NOTE (groupCheckbox.tooltip): This is used in the SideMenuWidget
 # as the default tooltip of a group checkbox
 sideMenu.groupCheckbox.tooltip=Toggle all checkboxes in this group
\ No newline at end of file
--- a/devtools/client/shared/l10n.js
+++ b/devtools/client/shared/l10n.js
@@ -1,28 +1,24 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
-const { Ci } = require("chrome");
 const Services = require("Services");
 
 /**
  * Localization convenience methods.
  *
  * @param string stringBundleName
  *        The desired string bundle's name.
  */
 function LocalizationHelper(stringBundleName) {
   loader.lazyGetter(this, "stringBundle", () =>
     Services.strings.createBundle(stringBundleName));
-  loader.lazyGetter(this, "ellipsis", () =>
-    Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString)
-                  .data);
 }
 
 LocalizationHelper.prototype = {
   /**
    * L10N shortcut function.
    *
    * @param string name
    * @return string
@@ -91,16 +87,19 @@ LocalizationHelper.prototype = {
 
     return number.toLocaleString(undefined, {
       maximumFractionDigits: decimals,
       minimumFractionDigits: decimals
     });
   }
 };
 
+const sharedL10N = new LocalizationHelper("chrome://devtools/locale/shared.properties");
+const ELLIPSIS = sharedL10N.getStr("ellipsis");
+
 /**
  * A helper for having the same interface as LocalizationHelper, but for more
  * than one file. Useful for abstracting l10n string locations.
  */
 function MultiLocalizationHelper(...stringBundleNames) {
   let instances = stringBundleNames.map(bundle => {
     return new LocalizationHelper(bundle);
   });
@@ -126,8 +125,9 @@ function MultiLocalizationHelper(...stri
         }
         return null;
       };
     });
 }
 
 exports.LocalizationHelper = LocalizationHelper;
 exports.MultiLocalizationHelper = MultiLocalizationHelper;
+exports.ELLIPSIS = ELLIPSIS;
--- a/devtools/client/shared/test/browser_flame-graph-04.js
+++ b/devtools/client/shared/test/browser_flame-graph-04.js
@@ -1,21 +1,19 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that text metrics in the flame graph widget work properly.
 
 var HTML_NS = "http://www.w3.org/1999/xhtml";
-var {LocalizationHelper} = require("devtools/client/shared/l10n");
+var {ELLIPSIS} = require("devtools/client/shared/l10n");
 var {FlameGraph} = require("devtools/client/shared/widgets/FlameGraph");
 var {FLAME_GRAPH_BLOCK_TEXT_FONT_SIZE} = require("devtools/client/shared/widgets/FlameGraph");
 var {FLAME_GRAPH_BLOCK_TEXT_FONT_FAMILY} = require("devtools/client/shared/widgets/FlameGraph");
 
-var L10N = new LocalizationHelper();
-
 add_task(function* () {
   yield addTab("about:blank");
   yield performTest();
   gBrowser.removeCurrentTab();
 });
 
 function* performTest() {
   let [host, win, doc] = yield createHost();
@@ -26,17 +24,17 @@ function* performTest() {
 
   yield graph.destroy();
   host.destroy();
 }
 
 function testGraph(graph) {
   is(graph._averageCharWidth, getAverageCharWidth(),
     "The average char width was calculated correctly.");
-  is(graph._overflowCharWidth, getCharWidth(L10N.ellipsis),
+  is(graph._overflowCharWidth, getCharWidth(ELLIPSIS),
     "The ellipsis char width was calculated correctly.");
 
   let text = "This text is maybe overflowing";
   let text1000px = graph._getFittedText(text, 1000);
   let text50px = graph._getFittedText(text, 50);
   let text10px = graph._getFittedText(text, 10);
   let text1px = graph._getFittedText(text, 1);
 
@@ -49,20 +47,20 @@ function testGraph(graph) {
   info("Text at 1px width   : " + text1px);
 
   is(text1000px, text,
     "The fitted text for 1000px width is correct.");
 
   isnot(text50px, text,
     "The fitted text for 50px width is correct (1).");
 
-  ok(text50px.includes(L10N.ellipsis),
+  ok(text50px.includes(ELLIPSIS),
     "The fitted text for 50px width is correct (2).");
 
-  is(graph._getFittedText(text, FLAME_GRAPH_BLOCK_TEXT_FONT_SIZE + 1), L10N.ellipsis,
+  is(graph._getFittedText(text, FLAME_GRAPH_BLOCK_TEXT_FONT_SIZE + 1), ELLIPSIS,
     "The fitted text for text font size width is correct.");
 
   is(graph._getFittedText(text, 1), "",
     "The fitted text for 1px width is correct.");
 }
 
 function getAverageCharWidth() {
   let letterWidthsSum = 0;
--- a/devtools/client/shared/widgets/FlameGraph.js
+++ b/devtools/client/shared/widgets/FlameGraph.js
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const { Task } = require("devtools/shared/task");
 const { ViewHelpers, setNamedTimeout } = require("devtools/client/shared/widgets/view-helpers");
-const { LocalizationHelper } = require("devtools/client/shared/l10n");
+const { ELLIPSIS } = require("devtools/client/shared/l10n");
 
 loader.lazyRequireGetter(this, "defer", "devtools/shared/defer");
 loader.lazyRequireGetter(this, "EventEmitter",
   "devtools/shared/event-emitter");
 
 loader.lazyRequireGetter(this, "getColor",
   "devtools/client/shared/theme", true);
 
@@ -25,18 +25,16 @@ loader.lazyRequireGetter(this, "Abstract
   "devtools/client/shared/widgets/Graphs", true);
 loader.lazyRequireGetter(this, "GraphArea",
   "devtools/client/shared/widgets/Graphs", true);
 loader.lazyRequireGetter(this, "GraphAreaDragger",
   "devtools/client/shared/widgets/Graphs", true);
 
 const GRAPH_SRC = "chrome://devtools/content/shared/widgets/graphs-frame.xhtml";
 
-const L10N = new LocalizationHelper();
-
 // ms
 const GRAPH_RESIZE_EVENTS_DRAIN = 100;
 
 const GRAPH_WHEEL_ZOOM_SENSITIVITY = 0.00035;
 const GRAPH_WHEEL_SCROLL_SENSITIVITY = 0.5;
 const GRAPH_KEYBOARD_ZOOM_SENSITIVITY = 20;
 const GRAPH_KEYBOARD_PAN_SENSITIVITY = 20;
 const GRAPH_KEYBOARD_ACCELERATION = 1.05;
@@ -296,17 +294,17 @@ FlameGraph.prototype = {
    * Overwrite this with your own localized format.
    */
   timelineTickUnits: "",
 
   /**
    * Character used when a block's text is overflowing.
    * Defaults to an ellipsis.
    */
-  overflowChar: L10N.ellipsis,
+  overflowChar: ELLIPSIS,
 
   /**
    * Sets the data source for this graph.
    *
    * @param object data
    *        An object containing the following properties:
    *          - data: the data source; see the constructor for more info
    *          - bounds: the minimum/maximum { start, end }, in ms or px
--- a/devtools/client/shared/widgets/VariablesView.jsm
+++ b/devtools/client/shared/widgets/VariablesView.jsm
@@ -24,16 +24,17 @@ const Services = require("Services");
 const { getSourceNames } = require("devtools/client/shared/source-utils");
 const promise = require("promise");
 const defer = require("devtools/shared/defer");
 const { Heritage, ViewHelpers, setNamedTimeout } =
   require("devtools/client/shared/widgets/view-helpers");
 const { Task } = require("devtools/shared/task");
 const nodeConstants = require("devtools/shared/dom-node-constants");
 const {KeyCodes} = require("devtools/client/shared/keycodes");
+const {ELLIPSIS} = require("devtools/client/shared/l10n");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
   "resource://gre/modules/PluralForm.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
   "@mozilla.org/widget/clipboardhelper;1",
   "nsIClipboardHelper");
 
@@ -2146,20 +2147,16 @@ Scope.prototype = {
 
 // Creating maps and arrays thousands of times for variables or properties
 // with a large number of children fills up a lot of memory. Make sure
 // these are instantiated only if needed.
 DevToolsUtils.defineLazyPrototypeGetter(Scope.prototype, "_store", () => new Map());
 DevToolsUtils.defineLazyPrototypeGetter(Scope.prototype, "_enumItems", Array);
 DevToolsUtils.defineLazyPrototypeGetter(Scope.prototype, "_nonEnumItems", Array);
 
-// An ellipsis symbol (usually "…") used for localization.
-XPCOMUtils.defineLazyGetter(Scope, "ellipsis", () =>
-  Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data);
-
 /**
  * A Variable is a Scope holding Property instances.
  * Iterable via "for (let [name, property] of instance) { }".
  *
  * @param Scope aScope
  *        The scope to contain this variable.
  * @param string aName
  *        The variable's name.
@@ -3458,17 +3455,17 @@ VariablesView.stringifiers.byType = {
   string: function (aGrip, {noStringQuotes}) {
     if (noStringQuotes) {
       return aGrip;
     }
     return '"' + aGrip + '"';
   },
 
   longString: function ({initial}, {noStringQuotes, noEllipsis}) {
-    let ellipsis = noEllipsis ? "" : Scope.ellipsis;
+    let ellipsis = noEllipsis ? "" : ELLIPSIS;
     if (noStringQuotes) {
       return initial + ellipsis;
     }
     let result = '"' + initial + '"';
     if (!ellipsis) {
       return result;
     }
     return result.substr(0, result.length - 1) + ellipsis + '"';
@@ -3809,17 +3806,17 @@ VariablesView.stringifiers.byObjectKind 
           let n = 0, result = "<" + preview.nodeName;
           for (let name in attrs) {
             let value = VariablesView.getString(attrs[name],
                                                 { noStringQuotes: true });
             result += " " + name + '="' + escapeHTML(value) + '"';
             n++;
           }
           if (preview.attributesLength > n) {
-            result += " " + Scope.ellipsis;
+            result += " " + ELLIPSIS;
           }
           return result + ">";
         }
 
         let result = "<" + preview.nodeName;
         if (attrs.id) {
           result += "#" + attrs.id;
         }
--- a/devtools/client/shared/widgets/VariablesViewController.jsm
+++ b/devtools/client/shared/widgets/VariablesViewController.jsm
@@ -8,17 +8,17 @@
 const { utils: Cu } = Components;
 
 var {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
 var {XPCOMUtils} = require("resource://gre/modules/XPCOMUtils.jsm");
 var {VariablesView} = require("resource://devtools/client/shared/widgets/VariablesView.jsm");
 var Services = require("Services");
 var promise = require("promise");
 var defer = require("devtools/shared/defer");
-var {LocalizationHelper} = require("devtools/client/shared/l10n");
+var {LocalizationHelper, ELLIPSIS} = require("devtools/client/shared/l10n");
 
 Object.defineProperty(this, "WebConsoleUtils", {
   get: function () {
     return require("devtools/client/webconsole/utils").Utils;
   },
   configurable: true,
   enumerable: true
 });
@@ -191,17 +191,17 @@ VariablesViewController.prototype = {
         propertyIterator: iterator,
         start: start,
         count: count
       };
 
       // Query the name of the first and last items for this slice
       let deferred = defer();
       iterator.names([start, start + count - 1], ({ names }) => {
-        let label = "[" + names[0] + L10N.ellipsis + names[1] + "]";
+          let label = "[" + names[0] + ELLIPSIS + names[1] + "]";
         let item = aTarget.addItem(label, {}, { internalItem: true });
         item.showArrow();
         this.addExpander(item, sliceGrip);
         deferred.resolve();
       });
       promises.push(deferred.promise);
     }
 
@@ -338,17 +338,17 @@ VariablesViewController.prototype = {
         aTarget.addItem("<handler>", { value: aGrip.proxyHandler }, { internalItem: true }),
         aGrip.proxyHandler);
 
       // Refuse to play the proxy's stupid game and return immediately
       let deferred = defer();
       deferred.resolve();
       return deferred.promise;
     }
-    
+
     if (aGrip.class === "Promise" && aGrip.promiseState) {
       const { state, value, reason } = aGrip.promiseState;
       aTarget.addItem("<state>", { value: state }, { internalItem: true });
       if (state === "fulfilled") {
         this.addExpander(
           aTarget.addItem("<value>", { value }, { internalItem: true }),
           value);
       } else if (state === "rejected") {
--- a/devtools/client/storage/ui.js
+++ b/devtools/client/storage/ui.js
@@ -2,17 +2,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 http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {Task} = require("devtools/shared/task");
 const EventEmitter = require("devtools/shared/event-emitter");
-const {LocalizationHelper} = require("devtools/client/shared/l10n");
+const {LocalizationHelper, ELLIPSIS} = require("devtools/client/shared/l10n");
 const {KeyShortcuts} = require("devtools/client/shared/key-shortcuts");
 const JSOL = require("devtools/client/shared/vendor/jsol");
 const {KeyCodes} = require("devtools/client/shared/keycodes");
 
 loader.lazyRequireGetter(this, "TreeWidget",
                          "devtools/client/shared/widgets/TreeWidget", true);
 loader.lazyRequireGetter(this, "TableWidget",
                          "devtools/client/shared/widgets/TableWidget", true);
@@ -51,17 +51,17 @@ const REASON = {
 };
 
 // Maximum length of item name to show in context menu label - will be
 // trimmed with ellipsis if it's longer.
 const ITEM_NAME_MAX_LENGTH = 32;
 
 function addEllipsis(name) {
   if (name.length > ITEM_NAME_MAX_LENGTH) {
-    return name.substr(0, ITEM_NAME_MAX_LENGTH) + L10N.ellipsis;
+    return name.substr(0, ITEM_NAME_MAX_LENGTH) + ELLIPSIS;
   }
 
   return name;
 }
 
 /**
  * StorageUI is controls and builds the UI of the Storage Inspector.
  *
--- a/devtools/client/webconsole/console-output.js
+++ b/devtools/client/webconsole/console-output.js
@@ -3,18 +3,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {Ci, Cu} = require("chrome");
 
-const Services = require("Services");
-
 loader.lazyImporter(this, "VariablesView", "resource://devtools/client/shared/widgets/VariablesView.jsm");
 loader.lazyImporter(this, "escapeHTML", "resource://devtools/client/shared/widgets/VariablesView.jsm");
 loader.lazyImporter(this, "PluralForm", "resource://gre/modules/PluralForm.jsm");
 
 loader.lazyRequireGetter(this, "promise");
 loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
 loader.lazyRequireGetter(this, "TableWidget", "devtools/client/shared/widgets/TableWidget", true);
 loader.lazyRequireGetter(this, "ObjectClient", "devtools/shared/client/main", true);
@@ -26,17 +24,17 @@ const STRINGS_URI = "chrome://devtools/l
 
 const WebConsoleUtils = require("devtools/client/webconsole/utils").Utils;
 const { getSourceNames } = require("devtools/client/shared/source-utils");
 const {Task} = require("devtools/shared/task");
 const l10n = new WebConsoleUtils.L10n(STRINGS_URI);
 const nodeConstants = require("devtools/shared/dom-node-constants");
 
 const MAX_STRING_GRIP_LENGTH = 36;
-const ELLIPSIS = Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data;
+const {ELLIPSIS} = require("devtools/client/shared/l10n");
 
 const validProtocols = /^(http|https|ftp|data|javascript|resource|chrome):/i;
 
 // Constants for compatibility with the Web Console output implementation before
 // bug 778766.
 // TODO: remove these once bug 778766 is fixed.
 const COMPAT = {
   // The various categories of messages.
--- a/devtools/client/webconsole/test/browser_webconsole_output_05.js
+++ b/devtools/client/webconsole/test/browser_webconsole_output_05.js
@@ -3,18 +3,17 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Test the webconsole output for various types of objects.
 
 "use strict";
 
 const TEST_URI = "data:text/html;charset=utf8,test for console output - 05";
-const ELLIPSIS = Services.prefs.getComplexValue("intl.ellipsis",
-  Ci.nsIPrefLocalizedString).data;
+const {ELLIPSIS} = require("devtools/client/shared/l10n");
 
 // March, 1960: The first implementation of Lisp. From Wikipedia:
 //
 // > Lisp was first implemented by Steve Russell on an IBM 704 computer. Russell
 // > had read McCarthy's paper, and realized (to McCarthy's surprise) that the
 // > Lisp eval function could be implemented in machine code. The result was a
 // > working Lisp interpreter which could be used to run Lisp programs, or more
 // > properly, 'evaluate Lisp expressions.'
--- a/devtools/client/webconsole/test/browser_webconsole_output_06.js
+++ b/devtools/client/webconsole/test/browser_webconsole_output_06.js
@@ -3,18 +3,18 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Test the webconsole output for various arrays.
 
 const TEST_URI = "data:text/html;charset=utf8,test for console output - 06";
-const ELLIPSIS = Services.prefs.getComplexValue("intl.ellipsis",
-  Ci.nsIPrefLocalizedString).data;
+const {ELLIPSIS} = require("devtools/client/shared/l10n");
+
 const testStrIn = "SHOW\\nALL\\nOF\\nTHIS\\nON\\nA\\nSINGLE" +
                   "\\nLINE ONLY. ESCAPE ALL NEWLINE";
 const testStrOut = "SHOW ALL OF THIS ON A SINGLE LINE O" + ELLIPSIS;
 
 var inputTests = [
   // 1 - array with empty slots only
   {
     input: "Array(5)",