]> git.donarmstrong.com Git - dactyl.git/blob - common/modules/messages.jsm
Import 1.0b7.1 supporting Firefox up to 8.*
[dactyl.git] / common / modules / messages.jsm
1 // Copyright (c) 2011 by Kris Maglione <maglione.k@gmail.com>
2 //
3 // This work is licensed for reuse under an MIT license. Details are
4 // given in the LICENSE.txt file included with this file.
5 "use strict";
6
7 try {
8
9 Components.utils.import("resource://dactyl/bootstrap.jsm");
10 defineModule("messages", {
11     exports: ["Messages", "messages", "_"],
12     require: ["services", "util"]
13 }, this);
14
15 // TODO: Lazy instantiation
16 var Messages = Module("messages", {
17
18     init: function init(name) {
19         let self = this;
20         name = name || "messages";
21
22         this.bundles = array.uniq([JSMLoader.getTarget("dactyl://locale/" + name + ".properties"),
23                                    JSMLoader.getTarget("dactyl://locale-local/" + name + ".properties"),
24                                    "resource://dactyl-locale/en-US/" + name + ".properties",
25                                    "resource://dactyl-locale-local/en-US/" + name + ".properties"])
26                             .map(services.stringBundle.createBundle)
27                             .filter(function (bundle) { try { bundle.getSimpleEnumeration(); return true; } catch (e) { return false; } });
28
29         this._ = Class("_", String, {
30             init: function _(message) {
31                 this.args = arguments;
32             },
33             message: Class.memoize(function () {
34                 let message = this.args[0];
35
36                 if (this.args.length > 1) {
37                     let args = Array.slice(this.args, 1);
38                     return self.format(message + "-" + args.length, args, null) || self.format(message, args);
39                 }
40                 return self.get(message);
41             }),
42             valueOf: function valueOf() this.message,
43             toString: function toString() this.message
44         });
45
46         let seen = {};
47         for (let { key } in this.iterate()) {
48             if (!Set.add(seen, key))
49                 this._[key] = this[key] = {
50                     __noSuchMethod__: function __(prop, args) self._.apply(self, [prop].concat(args))
51                 };
52         }
53     },
54
55     iterate: function () let (bundle = this.bundles[0])
56         iter(prop.QueryInterface(Ci.nsIPropertyElement) for (prop in iter(bundle.getSimpleEnumeration()))),
57
58     cleanup: function cleanup() {
59         services.stringBundle.flushBundles();
60     },
61
62     get: function get(value, default_) {
63         for (let bundle in values(this.bundles))
64             try {
65                 return bundle.GetStringFromName(value);
66             }
67             catch (e) {}
68
69         // Report error so tests fail, but don't throw
70         if (arguments.length < 2) // Do *not* localize these strings
71             util.reportError(Error("Invalid locale string: " + value));
72         return arguments.length > 1 ? default_ : value;
73     },
74
75     format: function format(value, args, default_) {
76         for (let bundle in values(this.bundles))
77             try {
78                 return bundle.formatStringFromName(value, args, args.length);
79             }
80             catch (e) {}
81
82         // Report error so tests fail, but don't throw
83         if (arguments.length < 3) // Do *not* localize these strings
84             util.reportError(Error("Invalid locale string: " + value));
85         return arguments.length > 2 ? default_ : value;
86     }
87
88 }, {
89     Localized: Class("Localized", Class.Property, {
90         init: function init(prop, obj) {
91             let _prop = "unlocalized_" + prop;
92             if (this.initialized) {
93                 /*
94                 if (config.locale === "en-US")
95                     return { configurable: true, enumerable: true, value: this.default, writable: true };
96                 */
97
98                 if (!Set.has(obj, "localizedProperties"))
99                     obj.localizedProperties = { __proto__: obj.localizedProperties };
100                 obj.localizedProperties[prop] = true;
101
102                 obj[_prop] = this.default;
103                 return {
104                     get: function get() {
105                         let self = this;
106                         let value = this[_prop];
107
108                         function getter(key, default_) function getter() messages.get([name, key].join("."), default_);
109
110                         if (value != null) {
111                             var name = [this.constructor.className.toLowerCase(), this.identifier || this.name, prop].join(".");
112                             if (!isObject(value))
113                                 value = messages.get(name, value);
114                             else if (isArray(value))
115                                 // Deprecated
116                                 iter(value).forEach(function ([k, v]) {
117                                     if (isArray(v))
118                                         memoize(v, 1, getter(v[0], v[1]));
119                                     else
120                                         memoize(value, k, getter(k, v));
121                                 });
122                             else
123                                 iter(value).forEach(function ([k, v]) {
124                                     memoize(value, k, function () messages.get([name, k].join("."), v));
125                                 });
126                         }
127
128                         return Class.replaceProperty(this, prop, value);
129                     },
130
131                     set: function set(val) this[_prop] = val
132                 };
133             }
134             this.default = prop;
135             this.initialized = true;
136         }
137     })
138 }, {
139     javascript: function initJavascript(dactyl, modules, window) {
140         modules.JavaScript.setCompleter([this._, this.get, this.format], [
141             function (context) {
142                 context.keys = { text: "key", description: "value" };
143                 return messages.iterate();
144             }
145         ]);
146     }
147 });
148
149 var { _ } = messages;
150
151 endModule();
152
153 } catch(e){ if (!e.stack) e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); }
154
155 // vim: set fdm=marker sw=4 ts=4 et ft=javascript: