summaryrefslogtreecommitdiffstats
path: root/comm/suite/chatzilla/js/lib/message-manager.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--comm/suite/chatzilla/js/lib/message-manager.js356
1 files changed, 356 insertions, 0 deletions
diff --git a/comm/suite/chatzilla/js/lib/message-manager.js b/comm/suite/chatzilla/js/lib/message-manager.js
new file mode 100644
index 0000000000..56020d48f6
--- /dev/null
+++ b/comm/suite/chatzilla/js/lib/message-manager.js
@@ -0,0 +1,356 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * 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/. */
+
+//
+function MessageManager(entities)
+{
+ const UC_CTRID = "@mozilla.org/intl/scriptableunicodeconverter";
+ const nsIUnicodeConverter =
+ Components.interfaces.nsIScriptableUnicodeConverter;
+
+ this.ucConverter =
+ Components.classes[UC_CTRID].getService(nsIUnicodeConverter);
+ this.defaultBundle = null;
+ this.bundleList = new Array();
+ // Provide a fallback so we don't break getMsg and related constants later.
+ this.entities = entities || {};
+}
+
+// ISO-2022-JP (often used for Japanese on IRC) doesn't contain any support
+// for hankaku kana (half-width katakana), so we support the option to convert
+// it to zenkaku kana (full-width katakana). This does not affect any other
+// encoding at this time.
+MessageManager.prototype.enableHankakuToZenkaku = false;
+
+MessageManager.prototype.loadBrands =
+function mm_loadbrands()
+{
+ var entities = this.entities;
+ var app = getService("@mozilla.org/xre/app-info;1", "nsIXULAppInfo");
+ if (app)
+ {
+ // Use App info if possible
+ entities.brandShortName = app.name;
+ entities.brandFullName = app.name + " " + app.version;
+ entities.brandVendorName = app.vendor;
+ return;
+ }
+
+ var brandBundle;
+ var path = "chrome://branding/locale/brand.properties";
+ try
+ {
+ brandBundle = this.addBundle(path);
+ }
+ catch (exception)
+ {
+ // May be an older mozilla version, try another location.
+ path = "chrome://global/locale/brand.properties";
+ brandBundle = this.addBundle(path);
+ }
+
+ entities.brandShortName = brandBundle.GetStringFromName("brandShortName");
+ entities.brandVendorName = brandBundle.GetStringFromName("vendorShortName");
+ // Not all versions of Suite / Fx have this defined; Cope:
+ try
+ {
+ entities.brandFullName = brandBundle.GetStringFromName("brandFullName");
+ }
+ catch(exception)
+ {
+ entities.brandFullName = entities.brandShortName;
+ }
+
+ // Remove all of this junk, or it will be the default bundle for getMsg...
+ this.bundleList.pop();
+}
+
+MessageManager.prototype.addBundle =
+function mm_addbundle(bundlePath, targetWindow)
+{
+ var bundle = srGetStrBundle(bundlePath);
+ this.bundleList.push(bundle);
+
+ // The bundle will load if the file doesn't exist. This will fail though.
+ // We want to be clean and remove the bundle again.
+ try
+ {
+ this.importBundle(bundle, targetWindow, this.bundleList.length - 1);
+ }
+ catch (exception)
+ {
+ // Clean up and return the exception.
+ this.bundleList.pop();
+ throw exception;
+ }
+ return bundle;
+}
+
+MessageManager.prototype.importBundle =
+function mm_importbundle(bundle, targetWindow, index)
+{
+ var me = this;
+ function replaceEntities(matched, entity)
+ {
+ if (entity in me.entities)
+ return me.entities[entity];
+
+ return matched;
+ };
+ const nsIPropertyElement = Components.interfaces.nsIPropertyElement;
+
+ if (!targetWindow)
+ targetWindow = window;
+
+ if (typeof index == "undefined")
+ index = arrayIndexOf(this.bundleList, bundle);
+
+ var pfx;
+ if (index == 0)
+ pfx = "";
+ else
+ pfx = index + ":";
+
+ var enumer = bundle.getSimpleEnumeration();
+
+ while (enumer.hasMoreElements())
+ {
+ var prop = enumer.getNext().QueryInterface(nsIPropertyElement);
+ var ary = prop.key.match (/^(msg|msn)/);
+ if (ary)
+ {
+ var constValue;
+ var constName = prop.key.toUpperCase().replace (/\./g, "_");
+ if (ary[1] == "msn" || prop.value.search(/%(\d+\$)?s/i) != -1)
+ constValue = pfx + prop.key;
+ else
+ constValue = prop.value.replace (/^\"/, "").replace (/\"$/, "");
+
+ constValue = constValue.replace(/\&(\w+)\;/g, replaceEntities);
+ targetWindow[constName] = constValue;
+ }
+ }
+
+ if (this.bundleList.length == 1)
+ this.defaultBundle = bundle;
+}
+
+MessageManager.prototype.convertHankakuToZenkaku =
+function mm_converthankakutozenkaku(msg)
+{
+ const basicMapping = [
+ /* 0xFF60 */ 0xFF60,0x3002,0x300C,0x300D,0x3001,0x30FB,0x30F2,0x30A1,
+ /* 0xFF68 */ 0x30A3,0x30A5,0x30A7,0x30A9,0x30E3,0x30E5,0x30E7,0x30C3,
+ /* 0xFF70 */ 0x30FC,0x30A2,0x30A4,0x30A6,0x30A8,0x30AA,0x30AB,0x30AD,
+ /* 0xFF78 */ 0x30AF,0x30B1,0x30B3,0x30B5,0x30B7,0x30B9,0x30BB,0x30BD,
+ /* 0xFF80 */ 0x30BF,0x30C1,0x30C4,0x30C6,0x30C8,0x30CA,0x30CB,0x30CC,
+ /* 0xFF88 */ 0x30CD,0x30CE,0x30CF,0x30D2,0x30D5,0x30D8,0x30DB,0x30DE,
+ /* 0xFF90 */ 0x30DF,0x30E0,0x30E1,0x30E2,0x30E4,0x30E6,0x30E8,0x30E9,
+ /* 0xFF98 */ 0x30EA,0x30EB,0x30EC,0x30ED,0x30EF,0x30F3,0x309B,0x309C
+ ];
+
+ const HANKAKU_BASE1 = 0xFF60;
+ const HANKAKU_BASE2 = 0xFF80;
+ const HANKAKU_MASK = 0xFFE0;
+
+ const MOD_NIGORI = 0xFF9E;
+ const NIGORI_MIN1 = 0xFF76;
+ const NIGORI_MAX1 = 0xFF84;
+ const NIGORI_MIN2 = 0xFF8A;
+ const NIGORI_MAX2 = 0xFF8E;
+ const NIGORI_MODIFIER = 1;
+
+ const MOD_MARU = 0xFF9F;
+ const MARU_MIN = 0xFF8A;
+ const MARU_MAX = 0xFF8E;
+ const MARU_MODIFIER = 2;
+
+ var i, src, srcMod, dest;
+ var rv = "";
+
+ for (i = 0; i < msg.length; i++)
+ {
+ // Get both this character and the next one, which could be a modifier.
+ src = msg.charCodeAt(i);
+ if (i < msg.length - 1)
+ srcMod = msg.charCodeAt(i + 1);
+
+ // Is the source characher hankaku?
+ if ((HANKAKU_BASE1 == (src & HANKAKU_MASK)) ||
+ (HANKAKU_BASE2 == (src & HANKAKU_MASK)))
+ {
+ // Do the basic character mapping first.
+ dest = basicMapping[src - HANKAKU_BASE1];
+
+ // If the source character is in the nigori or maru ranges and
+ // the following character is the associated modifier, we apply
+ // the modification and skip over the modifier.
+ if (i < msg.length - 1)
+ {
+ if ((MOD_NIGORI == srcMod) &&
+ (((src >= NIGORI_MIN1) && (src <= NIGORI_MAX1)) ||
+ ((src >= NIGORI_MIN2) && (src <= NIGORI_MAX2))))
+ {
+ dest += NIGORI_MODIFIER;
+ i++;
+ }
+ else if ((MOD_MARU == srcMod) &&
+ (src >= MARU_MIN) && (src <= MARU_MAX))
+ {
+ dest += MARU_MODIFIER;
+ i++;
+ }
+ }
+
+ rv += String.fromCharCode(dest);
+ }
+ else
+ {
+ rv += msg[i];
+ }
+ }
+
+ return rv;
+}
+
+MessageManager.prototype.checkCharset =
+function mm_checkset(charset)
+{
+ try
+ {
+ this.ucConverter.charset = charset;
+ }
+ catch (ex)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+MessageManager.prototype.toUnicode =
+function mm_tounicode(msg, charset)
+{
+ if (!charset)
+ return msg;
+
+ try
+ {
+ this.ucConverter.charset = charset;
+ msg = this.ucConverter.ConvertToUnicode(msg);
+ }
+ catch (ex)
+ {
+ //dd ("caught exception " + ex + " converting " + msg + " to charset " +
+ // charset);
+ }
+
+ return msg;
+}
+
+MessageManager.prototype.fromUnicode =
+function mm_fromunicode(msg, charset)
+{
+ if (!charset)
+ return msg;
+
+ if (this.enableHankakuToZenkaku && (charset.toLowerCase() == "iso-2022-jp"))
+ msg = this.convertHankakuToZenkaku(msg);
+
+ try
+ {
+ // This can actually fail in bizare cases. Cope.
+ if (charset != this.ucConverter.charset)
+ this.ucConverter.charset = charset;
+
+ if ("Finish" in this.ucConverter)
+ {
+ msg = this.ucConverter.ConvertFromUnicode(msg) +
+ this.ucConverter.Finish();
+ }
+ else
+ {
+ msg = this.ucConverter.ConvertFromUnicode(msg + " ");
+ msg = msg.substr(0, msg.length - 1);
+ }
+ }
+ catch (ex)
+ {
+ //dd ("caught exception " + ex + " converting " + msg + " to charset " +
+ // charset);
+ }
+
+ return msg;
+}
+
+MessageManager.prototype.getMsg =
+function mm_getmsg (msgName, params, deflt)
+{
+ try
+ {
+ var bundle;
+ var ary = msgName.match (/(\d+):(.+)/);
+ if (ary)
+ {
+ return (this.getMsgFrom(this.bundleList[ary[1]], ary[2], params,
+ deflt));
+ }
+
+ return this.getMsgFrom(this.bundleList[0], msgName, params, deflt);
+ }
+ catch (ex)
+ {
+ ASSERT (0, "Caught exception getting message: " + msgName + "/" +
+ params);
+ return deflt ? deflt : msgName;
+ }
+}
+
+MessageManager.prototype.getMsgFrom =
+function mm_getfrom (bundle, msgName, params, deflt)
+{
+ var me = this;
+ function replaceEntities(matched, entity)
+ {
+ if (entity in me.entities)
+ return me.entities[entity];
+
+ return matched;
+ };
+
+ try
+ {
+ var rv;
+
+ if (params && isinstance(params, Array))
+ rv = bundle.formatStringFromName (msgName, params, params.length);
+ else if (params || params == 0)
+ rv = bundle.formatStringFromName (msgName, [params], 1);
+ else
+ rv = bundle.GetStringFromName (msgName);
+
+ /* strip leading and trailing quote characters, see comment at the
+ * top of venkman.properties.
+ */
+ rv = rv.replace(/^\"/, "");
+ rv = rv.replace(/\"$/, "");
+ rv = rv.replace(/\&(\w+)\;/g, replaceEntities);
+
+ return rv;
+ }
+ catch (ex)
+ {
+ if (typeof deflt == "undefined")
+ {
+ ASSERT (0, "caught exception getting value for ``" + msgName +
+ "''\n" + ex + "\n");
+ return msgName;
+ }
+ return deflt;
+ }
+
+ return null;
+}