From 4cfdba9223fe75ac6eb259d403c6f21a36e60679 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Mon, 14 Mar 2011 19:22:43 -0400 Subject: [PATCH] Localitize deprecation warnings. --- common/content/mappings.js | 2 +- common/content/modes.js | 5 ++- common/locale/en-US/messages.properties | 1 + common/modules/base.jsm | 40 ++++++++++++++++++++++-- common/modules/commands.jsm | 29 ++++++++++++----- common/modules/messages.jsm | 41 +++++++++++++++---------- common/modules/options.jsm | 8 +---- 7 files changed, 88 insertions(+), 38 deletions(-) diff --git a/common/content/mappings.js b/common/content/mappings.js index 46f5a2d8..eb2cf78e 100644 --- a/common/content/mappings.js +++ b/common/content/mappings.js @@ -39,7 +39,7 @@ var Map = Class("Map", { Object.freeze(this.modes); if (extraInfo) - update(this, extraInfo); + this.update(extraInfo); }, name: Class.memoize(function () this.names[0]), diff --git a/common/content/modes.js b/common/content/modes.js index a4b88e9b..fba6cd96 100644 --- a/common/content/modes.js +++ b/common/content/modes.js @@ -438,10 +438,9 @@ var Modes = Module("modes", { util.assert(options.bases.every(function (m) m instanceof this, this.constructor), _("mode.invalidBases"), true); - this.description = options.description || name; - - update(this, { + this.update({ id: 1 << Modes.Mode._id++, + description: name, name: name, params: params || {} }, options); diff --git a/common/locale/en-US/messages.properties b/common/locale/en-US/messages.properties index 3edee715..c4524079 100644 --- a/common/locale/en-US/messages.properties +++ b/common/locale/en-US/messages.properties @@ -235,6 +235,7 @@ error.charsOutsideRange-1 = Character list outside the range %S error.invalidCharRange = Invalid character range: %S error.notWriteable-1 = Could not write to %S: %S +warn.deprecated-2 = %S is deprecated: Please use %S instead. warn.notDefaultBranch-2 = You are running %S from a testing branch: %S. Please do not report errors which do not also occur in the default branch. # vim:se ft=jproperties tw=0: diff --git a/common/modules/base.jsm b/common/modules/base.jsm index fca0c9ae..228c7518 100644 --- a/common/modules/base.jsm +++ b/common/modules/base.jsm @@ -331,9 +331,8 @@ deprecated.warn = function warn(func, name, alternative, frame) { frame = frame || Components.stack.caller.caller; let filename = util.fixURI(frame.filename || "unknown"); if (!set.add(func.seenCaller, filename)) - util.dactyl(func).warn( - util.urlPath(filename) + ":" + frame.lineNumber + ": " + - name + " is deprecated: Please use " + alternative + " instead"); + util.dactyl(func).warn([util.urlPath(filename), frame.lineNumber, " "].join(":") + + require("messages")._("warn.deprecated", name, alternative)); } /** @@ -904,6 +903,41 @@ Class.prototype = { util.trapErrors(callback, self); } return services.Timer(timeout_notify, timeout || 0, services.Timer.TYPE_ONE_SHOT); + }, + + /** + * Updates this instance with the properties of the given objects. + * Like the update function, but with special semantics for + * localized properties. + */ + update: function update() { + // XXX: Duplication. + + for (let i = 0; i < arguments.length; i++) { + let src = arguments[i]; + Object.getOwnPropertyNames(src || {}).forEach(function (k) { + let desc = Object.getOwnPropertyDescriptor(src, k); + if (desc.value instanceof Class.Property) + desc = desc.value.init(k, this) || desc.value; + + if (typeof desc.value === "function") { + let func = desc.value.wrapped || desc.value; + func.__defineGetter__("super", function () Object.getPrototypeOf(this)[k]); + func.superapply = function superapply(self, args) + let (meth = Object.getPrototypeOf(this)[k]) + meth && meth.apply(self, args); + func.supercall = function supercall(self) + func.superapply(self, Array.slice(arguments, 1)); + } + try { + if ("value" in desc && set.has(this.localizedProperties, k)) + this[k] = desc.value; + else + Object.defineProperty(this, k, desc); + } + catch (e) {} + }, this); + } } }; Class.makeClosure = function makeClosure() { diff --git a/common/modules/commands.jsm b/common/modules/commands.jsm index 145d885e..bd2c4f6a 100644 --- a/common/modules/commands.jsm +++ b/common/modules/commands.jsm @@ -129,7 +129,7 @@ var Command = Class("Command", { this.action = action; if (extraInfo) - update(this, extraInfo); + this.update(extraInfo); if (this.options) this.options = this.options.map(CommandOption.fromArray, CommandOption); for each (let option in this.options) @@ -155,11 +155,8 @@ var Command = Class("Command", { const { dactyl } = this.modules; let context = args.context; - if (this.deprecated && !set.add(this.complained, context ? context.file : "[Command Line]")) { - let loc = contexts.context ? context.file + ":" + context.line + ": " : ""; - dactyl.echoerr(loc + ":" + this.name + " is deprecated" + - (isString(this.deprecated) ? ": " + this.deprecated : "")); - } + if (this.deprecated) + this.warn(context, "deprecated", _("warn.deprecated", ":" + this.name, this.deprecated)); modifiers = modifiers || {}; @@ -229,6 +226,10 @@ var Command = Class("Command", { /** @property {string} This command's description, as shown in :listcommands */ description: Messages.Localized(""), + + /** @property {string|null} If set, the deprecation message for this command. */ + deprecated: Messages.Localized(null), + /** * @property {function (Args)} The function called to execute this command. */ @@ -356,7 +357,21 @@ var Command = Class("Command", { * @property {string} For commands defined via :command, contains the Ex * command line to be executed upon invocation. */ - replacementText: null + replacementText: null, + + /** + * Warns of a misuse of this command once per warning type per file. + * + * @param {object} context The calling context. + * @param {string} type The type of warning. + * @param {string} warning The warning message. + */ + warn: function warn(context, type, message) { + let loc = !context ? "" : [context.file, context.line, " "].join(":"); + + if (!set.add(this.complained, type + ":" + (context ? context.file : "[Command Line]"))) + this.modules.dactyl.warn(loc + message); + } }, { // TODO: do we really need more than longNames as a convenience anyway? /** diff --git a/common/modules/messages.jsm b/common/modules/messages.jsm index 4b6e4788..c8b20c8b 100644 --- a/common/modules/messages.jsm +++ b/common/modules/messages.jsm @@ -88,13 +88,17 @@ var Messages = Module("messages", { }, { Localized: Class("Localized", Class.Property, { init: function init(prop, obj) { - let _prop = "localized_" + prop; + let _prop = "unlocalized_" + prop; if (this.initialized) { /* if (config.locale === "en-US") - return { configurable: true, enumerable: true, value: null, writable: true }; + return { configurable: true, enumerable: true, value: this.default, writable: true }; */ + if (!set.has(obj, "localizedProperties")) + obj.localizedProperties = { __proto__: obj.localizedProperties }; + obj.localizedProperties[prop] = true; + obj[_prop] = this.default; return { get: function get() { @@ -103,24 +107,27 @@ var Messages = Module("messages", { function getter(key, default_) function getter() messages.get([name, key].join("."), default_); - let name = [this.constructor.className.toLowerCase(), this.identifier || this.name, prop].join("."); - if (!isObject(value)) - value = messages.get(name, value) - else if (isArray(value)) - // Deprecated - iter(value).forEach(function ([k, v]) { - if (isArray(v)) - memoize(v, 1, getter(v[0], v[1])); - else - memoize(value, k, getter(k, v)); - }); - else - iter(value).forEach(function ([k, v]) { - memoize(value, k, function () messages.get([name, k].join("."), v)); - }); + if (value != null) { + let name = [this.constructor.className.toLowerCase(), this.identifier || this.name, prop].join("."); + if (!isObject(value)) + value = messages.get(name, value) + else if (isArray(value)) + // Deprecated + iter(value).forEach(function ([k, v]) { + if (isArray(v)) + memoize(v, 1, getter(v[0], v[1])); + else + memoize(value, k, getter(k, v)); + }); + else + iter(value).forEach(function ([k, v]) { + memoize(value, k, function () messages.get([name, k].join("."), v)); + }); + } return Class.replaceProperty(this, prop, value); }, + set: function set(val) this[_prop] = val } } diff --git a/common/modules/options.jsm b/common/modules/options.jsm index dfa16cb5..cc9303b7 100644 --- a/common/modules/options.jsm +++ b/common/modules/options.jsm @@ -51,14 +51,8 @@ var Option = Class("Option", { this.realNames = names; this.description = description; - // Need to trigger setter - if (extraInfo && "values" in extraInfo && !extraInfo.__lookupGetter__("values")) { - this.values = extraInfo.values; - delete extraInfo.values; - } - if (extraInfo) - update(this, extraInfo); + this.update(extraInfo); if (set.has(this.modules.config.defaults, this.name)) defaultValue = this.modules.config.defaults[this.name];