1 // Copyright (c) 2011 by Kris Maglione <maglione.k@gmail.com>
3 // This work is licensed for reuse under an MIT license. Details are
4 // given in the LICENSE.txt file included with this file.
9 Components.utils.import("resource://dactyl/bootstrap.jsm");
10 defineModule("messages", {
11 exports: ["Messages", "messages", "_"],
12 require: ["services", "util"]
15 var Messages = Module("messages", {
17 init: function init(name) {
19 this.name = name || "messages";
21 this._ = Class("_", String, {
22 init: function _(message) {
23 this.args = arguments;
26 message: Class.Memoize(function () {
27 let message = this.args[0];
29 if (this.args.length > 1) {
30 let args = Array.slice(this.args, 1);
31 return self.format(message + "-" + args.length, args, null) || self.format(message, args);
33 return self.get(message);
35 valueOf: function valueOf() this.message,
36 toString: function toString() this.message
40 cleanup: function cleanup() {
41 services.stringBundle.flushBundles();
44 bundles: Class.Memoize(function ()
45 array.uniq([JSMLoader.getTarget("dactyl://locale/" + this.name + ".properties"),
46 JSMLoader.getTarget("dactyl://locale-local/" + this.name + ".properties"),
47 "resource://dactyl-locale/en-US/" + this.name + ".properties",
48 "resource://dactyl-locale-local/en-US/" + this.name + ".properties"])
49 .map(services.stringBundle.createBundle)
50 .filter(function (bundle) { try { bundle.getSimpleEnumeration(); return true; } catch (e) { return false; } })),
52 iterate: function () {
54 for (let bundle in values(this.bundles))
55 for (let { key, value } in iter(bundle.getSimpleEnumeration(), Ci.nsIPropertyElement))
56 if (!Set.add(seen, key))
60 get: function get(value, default_) {
61 for (let bundle in values(this.bundles))
63 let res = bundle.GetStringFromName(value);
64 if (res.slice(0, 2) == "+ ")
65 return res.slice(2).replace(/\s+/g, " ");
70 // Report error so tests fail, but don't throw
71 if (arguments.length < 2) // Do *not* localize these strings
72 util.reportError(Error("Invalid locale string: " + value));
73 return arguments.length > 1 ? default_ : value;
76 format: function format(value, args, default_) {
77 for (let bundle in values(this.bundles))
79 let res = bundle.formatStringFromName(value, args, args.length);
80 if (res.slice(0, 2) == "+ ")
81 return res.slice(2).replace(/\s+/g, " ");
86 // Report error so tests fail, but don't throw
87 if (arguments.length < 3) // Do *not* localize these strings
88 util.reportError(Error("Invalid locale string: " + value));
89 return arguments.length > 2 ? default_ : value;
93 * Exports known localizable strings to a properties file.
95 * @param {string|nsIFile} {file} The file to which to export
98 export: function export_(file) {
99 let { Buffer, commands, hints, io, mappings, modes, options, sanitizer } = overlay.activeModules;
100 file = io.File(file);
102 function properties(base, iter_, prop) iter(function _properties() {
103 function key() [base, obj.identifier || obj.name].concat(Array.slice(arguments)).join(".").replace(/[\\:=]/g, "\\$&");
105 prop = prop || "description";
106 for (var obj in iter_) {
107 if (!obj.hive || obj.hive.name !== "user") {
108 yield key(prop) + " = " + obj[prop];
111 for (let [k, v] in isArray(obj.values) ? array.iterValues(obj.values) : iter(obj.values))
112 yield key("values", k) + " = " + v;
114 for (let opt in values(obj.options))
115 yield key("options", opt.names[0]) + " = " + opt.description;
118 yield key("deprecated") + " = " + obj.deprecated;
124 array(commands.allHives.map(function (h) properties("command", h)))
125 .concat(modes.all.map(function (m)
126 properties("map", values(mappings.builtin.getStack(m)
127 .filter(function (map) map.modes[0] == m)))))
128 .concat(properties("mode", values(modes.all.filter(function (m) !m.hidden))))
129 .concat(properties("option", options))
130 .concat(properties("hintmode", values(hints.modes), "prompt"))
131 .concat(properties("pageinfo", values(Buffer.pageInfo), "title"))
132 .concat(properties("sanitizeitem", values(sanitizer.itemMap)))
133 .flatten().uniq().join("\n"));
136 Localized: Class("Localized", Class.Property, {
137 init: function init(prop, obj) {
138 let _prop = "unlocalized_" + prop;
139 if (this.initialized) {
141 if (config.locale === "en-US")
142 return { configurable: true, enumerable: true, value: this.default, writable: true };
145 if (!Set.has(obj, "localizedProperties"))
146 obj.localizedProperties = { __proto__: obj.localizedProperties };
147 obj.localizedProperties[prop] = true;
149 obj[_prop] = this.default;
151 get: function get() {
153 let value = this[_prop];
155 function getter(key, default_) function getter() messages.get([name, key].join("."), default_);
158 var name = [this.constructor.className.toLowerCase(),
159 this.identifier || this.name,
162 if (!isObject(value))
163 value = messages.get(name, value);
164 else if (isArray(value))
166 iter(value).forEach(function ([k, v]) {
168 memoize(v, 1, getter(v[0], v[1]));
170 memoize(value, k, getter(k, v));
173 iter(value).forEach(function ([k, v]) {
174 memoize(value, k, function () messages.get([name, k].join("."), v));
178 return Class.replaceProperty(this, prop, value);
181 set: function set(val) this[_prop] = val
185 this.initialized = true;
189 javascript: function initJavascript(dactyl, modules, window) {
190 let { JavaScript } = modules;
192 JavaScript.setCompleter([this._, this.get, this.format], [
193 function (context) messages.iterate()
196 JavaScript.setCompleter([this.export],
197 [function (context, obj, args) {
198 context.quote[2] = "";
199 modules.completion.file(context, true);
204 var { _ } = messages;
208 } catch(e){ if (!e.stack) e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); }
210 // vim: set fdm=marker sw=4 ts=4 et ft=javascript: