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 // TODO: Lazy instantiation
16 var Messages = Module("messages", {
18 init: function init(name) {
20 name = name || "messages";
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; } });
29 this._ = Class("_", String, {
30 init: function _(message) {
31 this.args = arguments;
33 message: Class.memoize(function () {
34 let message = this.args[0];
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);
40 return self.get(message);
42 valueOf: function valueOf() this.message,
43 toString: function toString() this.message
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))
55 iterate: function () let (bundle = this.bundles[0])
56 iter(prop.QueryInterface(Ci.nsIPropertyElement) for (prop in iter(bundle.getSimpleEnumeration()))),
58 cleanup: function cleanup() {
59 services.stringBundle.flushBundles();
62 get: function get(value, default_) {
63 for (let bundle in values(this.bundles))
65 return bundle.GetStringFromName(value);
69 // Report error so tests fail, but don't throw
70 if (arguments.length < 2)
71 util.reportError(Error("Invalid locale string: " + value));
72 return arguments.length > 1 ? default_ : value;
75 format: function format(value, args, default_) {
76 for (let bundle in values(this.bundles))
78 return bundle.formatStringFromName(value, args, args.length);
82 // Report error so tests fail, but don't throw
83 if (arguments.length < 3)
84 util.reportError(Error("Invalid locale string: " + value));
85 return arguments.length > 2 ? default_ : value;
89 Localized: Class("Localized", Class.Property, {
90 init: function init(prop, obj) {
91 let _prop = "localized_" + prop;
92 if (this.initialized) {
94 if (config.locale === "en-US")
95 return { configurable: true, enumerable: true, value: null, writable: true };
98 obj[_prop] = this.default;
100 get: function get() {
102 let value = this[_prop];
104 function getter(key, default_) function getter() messages.get([name, key].join("."), default_);
106 let name = [this.constructor.className.toLowerCase(), this.identifier || this.name, prop].join(".");
107 if (!isObject(value))
108 value = messages.get(name, value)
109 else if (isArray(value))
111 iter(value).forEach(function ([k, v]) {
113 memoize(v, 1, getter(v[0], v[1]));
115 memoize(value, k, getter(k, v));
118 iter(value).forEach(function ([k, v]) {
119 memoize(value, k, function () messages.get([name, k].join("."), v));
122 return Class.replaceProperty(this, prop, value);
124 set: function set(val) this[_prop] = val
128 this.initialized = true;
132 javascript: function initJavascript(dactyl, modules, window) {
133 modules.JavaScript.setCompleter([this._, this.get, this.format], [
135 context.keys = { text: "key", description: "value" };
136 return messages.iterate();
142 var { _ } = messages;
146 } catch(e){ if (!e.stack) e = Error(e); dump(e.fileName+":"+e.lineNumber+": "+e+"\n" + e.stack); }
148 // vim: set fdm=marker sw=4 ts=4 et ft=javascript: