Przeglądaj źródła

Merge remote-tracking branch 'origin' into 0.8

Conflicts:
	converse.js
	docs/CHANGES.rst
	index.html
JC Brand 11 lat temu
rodzic
commit
1ce7620b88

+ 11 - 4
README.rst

@@ -29,7 +29,7 @@ It has the following features:
 * Custom status messages
 * Typing notifications
 * Third person messages (/me )
-* Translated into multiple languages  (af, de, es, fr, it, hu, pt-BR, ru)
+* Translated into multiple languages  (af, de, en, es, fr, he, hu, id, it, ja, nl, pt_BR, ru)
 * Off-the-record encryption support (via `OTR.js <http://arlolra.github.io/otr>`_)
 
 -----------
@@ -88,9 +88,16 @@ Licence
 
 ``Converse.js`` is released under both the MIT_ and GPL_ licenses.
 
-------
-Donate
-------
+-------
+Support
+-------
+
+For support queries and discussions, please join the mailing list: conversejs@librelist.com
+Issues can be logged on the `Github issue tracker <https://github.com/jcbrand/converse.js/issues>`_.
+
+---------------------------------
+Donations or tips are appreciated
+---------------------------------
 
 * Bitcoin: 16FsPqE9DhFTryxrUenpsGX4LJ1TPu8GqS
 * Litecoin: LLvLH6qJch7HAamLguHkwobCrxmHLhiwZw

+ 1 - 1
bower.json

@@ -1,6 +1,6 @@
 {
   "name": "converse",
-  "version": "0.7.2",
+  "version": "0.7.3",
   "devDependencies": {
     "jasmine": "https://github.com/jcbrand/jasmine.git#1_3_x",
     "otr": "0.2.7",

Plik diff jest za duży
+ 1 - 1
builds/converse-no-locales-no-otr.min.js


Plik diff jest za duży
+ 1 - 1
builds/converse-no-otr.min.js


Plik diff jest za duży
+ 1 - 1
builds/converse.min.js


+ 4 - 7
converse.css

@@ -333,22 +333,18 @@ you can use the generic selector below, but it's slower:
 
 span.spinner {
     background: url(images/spinner.gif) no-repeat center;
-    width: 22px;
     height: 22px;
     padding: 0 2px 0 2px;
     display: block;
 }
 
 span.spinner.centered {
-    position: absolute;
-    top: 30%;
-    left: 50%;
-    margin: 0 0 0 -25%;
+    text-align: center;
+    padding-top: 5em;
 }
 
 span.spinner.hor_centered {
-    left: 40%;
-    position: absolute;
+    text-align: center;
 }
 
 #toggle-controlbox {
@@ -1157,6 +1153,7 @@ ul.chat-toolbar li {
     list-style: none;
     padding: 0 3px 0 3px;
     cursor: pointer; 
+    margin-top: 1px;
 }
 
 ul.chat-toolbar li:hover {

+ 262 - 152
converse.js

@@ -141,9 +141,12 @@
         this.allow_otr = true;
         this.animate = true;
         this.auto_list_rooms = false;
+        this.auto_reconnect = true;
         this.auto_subscribe = false;
         this.bosh_service_url = undefined; // The BOSH connection manager URL.
+        this.cache_otr_key = false;
         this.debug = false;
+        this.expose_rid_and_sid = false;
         this.hide_muc_server = false;
         this.i18n = locales.en;
         this.prebind = false;
@@ -152,6 +155,7 @@
         this.show_call_button = false;
         this.show_emoticons = true;
         this.show_toolbar = true;
+        this.use_otr_by_default = false;
         this.use_vcards = true;
         this.xhr_custom_status = false;
         this.xhr_custom_status_url = '';
@@ -166,22 +170,26 @@
             'allow_otr',
             'animate',
             'auto_list_rooms',
+            'auto_reconnect',
             'auto_subscribe',
             'bosh_service_url',
+            'cache_otr_key',
             'connection',
             'debug',
+            'expose_rid_and_sid',
             'fullname',
             'hide_muc_server',
             'i18n',
             'jid',
             'prebind',
             'rid',
+            'show_call_button',
             'show_controlbox_by_default',
             'show_emoticons',
             'show_only_online_users',
             'show_toolbar',
-            'show_call_button',
             'sid',
+            'use_otr_by_default',
             'use_vcards',
             'xhr_custom_status',
             'xhr_custom_status_url',
@@ -192,6 +200,9 @@
         // Only allow OTR if we have the capability
         this.allow_otr = this.allow_otr && HAS_CRYPTO;
 
+        // Only use OTR by default if allow OTR is enabled to begin with
+        this.use_otr_by_default = this.use_otr_by_default && this.allow_otr;
+
         // Translation machinery
         // ---------------------
         var __ = $.proxy(function (str) {
@@ -249,13 +260,6 @@
 
         // Module-level functions
         // ----------------------
-        // TODO: REMOVE
-        this.createLinks = function (text) {
-            // Convert URLs into hyperlinks
-            var re = /((http|https|ftp):\/\/[\w?=&.\/\-;#~%\-]+(?![\w\s?&.\/;#~%"=\-]*>))/g;
-            return text.replace(re, '<a target="_blank" href="$1">$1</a>');
-        };
-
         this.giveFeedback = function (message, klass) {
             $('.conn-feedback').text(message);
             $('.conn-feedback').attr('class', 'conn-feedback');
@@ -322,41 +326,63 @@
             );
         };
 
-        this.onConnect = function (status) {
+        this.reconnect = function () {
+            converse.giveFeedback(__('Reconnecting'), 'error');
+            if (!converse.prebind) {
+                this.connection.connect(
+                    this.connection.jid,
+                    this.connection.pass,
+                    function (status, condition) {
+                        converse.onConnect(status, condition, true);
+                    },
+                    this.connection.wait,
+                    this.connection.hold,
+                    this.connection.route
+                );
+            }
+        };
+
+        this.showLoginButton = function () {
+            var view = converse.chatboxesview.views.controlbox;
+            if (typeof view.loginpanel !== 'undefined') {
+                view.loginpanel.showLoginButton();
+            }
+        };
+
+        this.onConnect = function (status, condition, reconnect) {
             var $button, $form;
-            if (status === Strophe.Status.CONNECTED) {
-                converse.log('Connected');
-                converse.onConnected();
+            if ((status === Strophe.Status.CONNECTED) ||
+                (status === Strophe.Status.ATTACHED)) {
+                if ((typeof reconnect !== 'undefined') && (reconnect)) {
+                    converse.log(status === Strophe.Status.CONNECTED ? 'Reconnected' : 'Reattached');
+                    converse.onReconnected();
+                } else {
+                    converse.log(status === Strophe.Status.CONNECTED ? 'Connected' : 'Attached');
+                    converse.onConnected();
+                }
             } else if (status === Strophe.Status.DISCONNECTED) {
-                $form = $('#converse-login');
-                $button = $form.find('input[type=submit]');
-                if ($button) { $button.show().siblings('span').remove(); }
+                // TODO: Handle case where user manually logs out...
                 converse.giveFeedback(__('Disconnected'), 'error');
-                converse.connection.connect(
-                    converse.connection.jid,
-                    converse.connection.pass,
-                    converse.onConnect
-                );
+                if (converse.auto_reconnect) {
+                    converse.reconnect();
+                } else {
+                    converse.showLoginButton();
+                }
             } else if (status === Strophe.Status.Error) {
-                $form = $('#converse-login');
-                $button = $form.find('input[type=submit]');
-                if ($button) { $button.show().siblings('span').remove(); }
+                converse.showLoginButton();
                 converse.giveFeedback(__('Error'), 'error');
             } else if (status === Strophe.Status.CONNECTING) {
                 converse.giveFeedback(__('Connecting'));
             } else if (status === Strophe.Status.CONNFAIL) {
-                converse.chatboxesview.views.controlbox.trigger('connection-fail');
+                converse.showLoginButton();
                 converse.giveFeedback(__('Connection Failed'), 'error');
             } else if (status === Strophe.Status.AUTHENTICATING) {
                 converse.giveFeedback(__('Authenticating'));
             } else if (status === Strophe.Status.AUTHFAIL) {
-                converse.chatboxesview.views.controlbox.trigger('auth-fail');
+                converse.showLoginButton();
                 converse.giveFeedback(__('Authentication Failed'), 'error');
             } else if (status === Strophe.Status.DISCONNECTING) {
                 converse.giveFeedback(__('Disconnecting'), 'error');
-            } else if (status === Strophe.Status.ATTACHED) {
-                converse.log('Attached');
-                converse.onConnected();
             }
         };
 
@@ -381,7 +407,7 @@
         this.parseISO8601 = function (datestr) {
             /* Parses string formatted as 2013-02-14T11:27:08.268Z to a Date obj.
             */
-            var numericKeys = [1, 4, 5, 6, 7, 10, 11],
+            var numericKeys = [1, 4, 5, 6, 7, 10, 11],
                 struct = /^\s*(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}\.?\d*)Z\s*$/.exec(datestr),
                 minutesOffset = 0,
                 i, k;
@@ -434,32 +460,81 @@
             this.xmppstatus.fetch({success: callback, error: callback});
         };
 
-        this.initRoster = function () {
-            // Set up the roster
-            this.roster = new this.RosterItems();
-            this.roster.localStorage = new Backbone.LocalStorage(
-                hex_sha1('converse.rosteritems-'+converse.bare_jid));
-
-            // Register callbacks that depend on the roster
+        this.registerRosterHandler = function () {
+            // Register handlers that depend on the roster
             this.connection.roster.registerCallback(
                 $.proxy(this.roster.rosterHandler, this.roster),
                 null, 'presence', null);
+        };
 
+        this.registerRosterXHandler = function () {
             this.connection.addHandler(
                 $.proxy(this.roster.subscribeToSuggestedItems, this.roster),
                 'http://jabber.org/protocol/rosterx', 'message', null);
+        };
 
+        this.registerPresenceHandler = function () {
             this.connection.addHandler(
                 $.proxy(function (presence) {
                     this.presenceHandler(presence);
                     return true;
                 }, this.roster), null, 'presence', null);
+        };
 
+        this.initRoster = function () {
+            // Set up the roster
+            this.roster = new this.RosterItems();
+            this.roster.localStorage = new Backbone.LocalStorage(
+                hex_sha1('converse.rosteritems-'+converse.bare_jid));
+            this.registerRosterHandler();
+            this.registerRosterXHandler();
+            this.registerPresenceHandler();
             // No create the view which will fetch roster items from
             // localStorage
             this.rosterview = new this.RosterView({'model':this.roster});
         };
 
+        this.registerGlobalEventHandlers = function () {
+            $(document).click(function() {
+                if ($('.toggle-otr ul').is(':visible')) {
+                    $('.toggle-otr ul', this).slideUp();
+                }
+                if ($('.toggle-smiley ul').is(':visible')) {
+                    $('.toggle-smiley ul', this).slideUp();
+                }
+            });
+
+            $(document).on('mousemove', $.proxy(function (ev) {
+                if (!this.resized_chatbox || !this.allow_dragresize) { return true; }
+                ev.preventDefault();
+                this.resized_chatbox.resizeChatbox(ev);
+            }, this));
+
+            $(document).on('mouseup', $.proxy(function (ev) {
+                if (!this.resized_chatbox || !this.allow_dragresize) { return true; }
+                this.resized_chatbox = null;
+            }, this));
+
+            $(window).on("blur focus", $.proxy(function(e) {
+                if ((this.windowState != e.type) && (e.type == 'focus')) {
+                    converse.clearMsgCounter();
+                }
+                this.windowState = e.type;
+            },this));
+        };
+
+        this.onReconnected = function () {
+            // We need to re-register all the event handlers on the newly
+            // created connection.
+            this.initStatus($.proxy(function () {
+                this.registerRosterXHandler();
+                this.registerPresenceHandler();
+                this.chatboxes.registerMessageHandler();
+                converse.xmppstatus.sendPresence();
+                this.giveFeedback(__('Online Contacts'));
+            }, this));
+        };
+
         this.onConnected = function () {
             if (this.debug) {
                 this.connection.xmlInput = function (body) { console.log(body); };
@@ -474,32 +549,7 @@
                 this.initRoster();
                 this.chatboxes.onConnected();
                 this.connection.roster.get(function () {});
-                $(document).click(function() {
-                    if ($('.toggle-otr ul').is(':visible')) {
-                        $('.toggle-otr ul', this).slideUp();
-                    }
-                    if ($('.toggle-smiley ul').is(':visible')) {
-                        $('.toggle-smiley ul', this).slideUp();
-                    }
-                });
-
-                $(document).on('mousemove', $.proxy(function (ev) {
-                    if (!this.resized_chatbox || !this.allow_dragresize) { return true; }
-                    ev.preventDefault();
-                    this.resized_chatbox.resizeChatbox(ev);
-                }, this));
-
-                $(document).on('mouseup', $.proxy(function (ev) {
-                    if (!this.resized_chatbox || !this.allow_dragresize) { return true; }
-                    this.resized_chatbox = null;
-                }, this));
-
-                $(window).on("blur focus", $.proxy(function (e) {
-                    if ((this.windowState != e.type) && (e.type == 'focus')) {
-                        converse.clearMsgCounter();
-                    }
-                    this.windowState = e.type;
-                },this));
+                this.registerGlobalEventHandlers();
                 this.giveFeedback(__('Online Contacts'));
 
                 if (this.callback) {
@@ -524,6 +574,41 @@
 
         // Backbone Models and Views
         // -------------------------
+        this.OTR = Backbone.Model.extend({
+            // A model for managing OTR settings.
+            getSessionPassphrase: function () {
+                if (converse.prebind) {
+                    var key = hex_sha1(converse.connection.jid),
+                        pass = window.sessionStorage[key];
+                    if (typeof pass === 'undefined') {
+                        pass = Math.floor(Math.random()*4294967295).toString();
+                        window.sessionStorage[key] = pass;
+                    }
+                    return pass;
+                } else {
+                    return converse.connection.pass;
+                }
+            },
+
+            generatePrivateKey: function () {
+                var key = new DSA();
+                var jid = converse.connection.jid;
+                if (converse.cache_otr_key) {
+                    var cipher = CryptoJS.lib.PasswordBasedCipher;
+                    var pass = this.getSessionPassphrase();
+                    if (typeof pass !== "undefined") {
+                        // Encrypt the key and set in sessionStorage. Also store instance tag.
+                        window.sessionStorage[hex_sha1(jid+'priv_key')] =
+                            cipher.encrypt(CryptoJS.algo.AES, key.packPrivate(), pass).toString();
+                        window.sessionStorage[hex_sha1(jid+'instance_tag')] = instance_tag;
+                        window.sessionStorage[hex_sha1(jid+'pass_check')] = 
+                            cipher.encrypt(CryptoJS.algo.AES, 'match', pass).toString();
+                    }
+                }
+                return key;
+            }
+        });
+
         this.Message = Backbone.Model.extend();
 
         this.Messages = Backbone.Collection.extend({
@@ -533,9 +618,6 @@
         this.ChatBox = Backbone.Model.extend({
             initialize: function () {
                 if (this.get('box_id') !== 'controlbox') {
-                    if (_.contains([UNVERIFIED, VERIFIED], this.get('otr_status'))) {
-                        this.initiateOTR();
-                    }
                     this.messages = new converse.Messages();
                     this.messages.localStorage = new Backbone.LocalStorage(
                         hex_sha1('converse.messages'+this.get('jid')+converse.bare_jid));
@@ -547,43 +629,43 @@
                 }
             },
 
-            getSession: function () {
-                // XXX: sessionStorage is not supported in IE < 8. Perhaps a
-                // user alert is required here...
-                var saved_key = window.sessionStorage[hex_sha1(this.id+'priv_key')];
-                var instance_tag = window.sessionStorage[hex_sha1(this.id+'instance_tag')];
+            getSession: function (callback) {
                 var cipher = CryptoJS.lib.PasswordBasedCipher;
-                var pass = converse.connection.pass;
-                var pass_check = this.get('pass_check');
-                var result, key;
-                if (saved_key && instance_tag && typeof pass_check !== 'undefined') {
-                    var decrypted = cipher.decrypt(CryptoJS.algo.AES, saved_key, pass);
-                    key = DSA.parsePrivate(decrypted.toString(CryptoJS.enc.Latin1));
-                    if (cipher.decrypt(CryptoJS.algo.AES, pass_check, pass).toString(CryptoJS.enc.Latin1) === 'match') {
-                        // Verified that the user's password is still the same
-                        this.trigger('showHelpMessages', [__('Re-establishing encrypted session')]);
-                        return {
-                            'key': key,
-                            'instance_tag': instance_tag
-                        };
+                var result, pass, instance_tag, saved_key, pass_check;
+                if (converse.cache_otr_key) {
+                    pass = converse.otr.getSessionPassphrase();
+                    if (typeof pass !== "undefined") {
+                        instance_tag = window.sessionStorage[hex_sha1(this.id+'instance_tag')];
+                        saved_key = window.sessionStorage[hex_sha1(this.id+'priv_key')];
+                        pass_check = window.sessionStorage[hex_sha1(this.connection.jid+'pass_check')];
+                        if (saved_key && instance_tag && typeof pass_check !== 'undefined') {
+                            var decrypted = cipher.decrypt(CryptoJS.algo.AES, saved_key, pass);
+                            var key = DSA.parsePrivate(decrypted.toString(CryptoJS.enc.Latin1));
+                            if (cipher.decrypt(CryptoJS.algo.AES, pass_check, pass).toString(CryptoJS.enc.Latin1) === 'match') {
+                                // Verified that the passphrase is still the same
+                                this.trigger('showHelpMessages', [__('Re-establishing encrypted session')]);
+                                callback({
+                                    'key': key,
+                                    'instance_tag': instance_tag
+                                });
+                                return; // Our work is done here
+                            }
+                        }
                     }
                 }
                 // We need to generate a new key and instance tag
-                result = alert(__('Your browser needs to generate a private key, which will be used in your encrypted chat session. This can take up to 30 seconds during which your browser might freeze and become unresponsive.'));
-                instance_tag = OTR.makeInstanceTag();
-                key = new DSA();
-                // Encrypt the key and set in sessionStorage. Also store
-                // instance tag
-                window.sessionStorage[hex_sha1(this.id+'priv_key')] =
-                    cipher.encrypt(CryptoJS.algo.AES, key.packPrivate(), pass).toString();
-                window.sessionStorage[hex_sha1(this.id+'instance_tag')] = instance_tag;
-
-                this.trigger('showHelpMessages', [__('Private key generated.')]);
-                this.save({'pass_check': cipher.encrypt(CryptoJS.algo.AES, 'match', pass).toString()});
-                return {
-                    'key': key,
-                    'instance_tag': instance_tag
-                };
+                this.trigger('showHelpMessages', [
+                    __('Generating private key.'),
+                    __('Your browser might become unresponsive.')],
+                    null,
+                    true // show spinner
+                );
+                setTimeout(function () {
+                    callback({
+                        'key': converse.otr.generatePrivateKey.apply(this),
+                        'instance_tag': OTR.makeInstanceTag()
+                    });
+                }, 500);
             },
 
             updateOTRStatus: function (state) {
@@ -636,32 +718,34 @@
                 // query message from our buddy. Otherwise, it is us who will
                 // send the query message to them.
                 this.save({'otr_status': UNENCRYPTED});
-                var session = this.getSession();
-                this.otr = new OTR({
-                    fragment_size: 140,
-                    send_interval: 200,
-                    priv: session.key,
-                    instance_tag: session.instance_tag,
-                    debug: this.debug
-                });
-                this.otr.on('status', $.proxy(this.updateOTRStatus, this));
-                this.otr.on('smp', $.proxy(this.onSMP, this));
+                var session = this.getSession($.proxy(function (session) {
+                    this.otr = new OTR({
+                        fragment_size: 140,
+                        send_interval: 200,
+                        priv: session.key,
+                        instance_tag: session.instance_tag,
+                        debug: this.debug
+                    });
+                    this.otr.on('status', $.proxy(this.updateOTRStatus, this));
+                    this.otr.on('smp', $.proxy(this.onSMP, this));
 
-                this.otr.on('ui', $.proxy(function (msg) {
-                    this.trigger('showReceivedOTRMessage', msg);
-                }, this));
-                this.otr.on('io', $.proxy(function (msg) {
-                    this.trigger('sendMessageStanza', msg);
-                }, this));
-                this.otr.on('error', $.proxy(function (msg) {
-                    this.trigger('showOTRError', msg);
-                }, this));
+                    this.otr.on('ui', $.proxy(function (msg) {
+                        this.trigger('showReceivedOTRMessage', msg);
+                    }, this));
+                    this.otr.on('io', $.proxy(function (msg) {
+                        this.trigger('sendMessageStanza', msg);
+                    }, this));
+                    this.otr.on('error', $.proxy(function (msg) {
+                        this.trigger('showOTRError', msg);
+                    }, this));
 
-                if (query_msg) {
-                    this.otr.receiveMsg(query_msg);
-                } else {
-                    this.otr.sendQueryMsg();
-                }
+                    this.trigger('showHelpMessages', [__('Exchanging private key with buddy.')]);
+                    if (query_msg) {
+                        this.otr.receiveMsg(query_msg);
+                    } else {
+                        this.otr.sendQueryMsg();
+                    }
+                }, this));
             },
 
             endOTR: function () {
@@ -719,19 +803,22 @@
                 if ((!text) || (!converse.allow_otr)) {
                     return this.createMessage(message);
                 }
-                if (_.contains([UNVERIFIED, VERIFIED], this.get('otr_status'))) {
-                    this.otr.receiveMsg(text);
+                if (text.match(/^\?OTRv23?/)) {
+                    this.initiateOTR(text);
                 } else {
-                    if (text.match(/^\?OTR/)) {
-                        // They want to initiate OTR
-                        if (!this.otr) {
-                            this.initiateOTR(text);
+                    if (_.contains([UNVERIFIED, VERIFIED], this.get('otr_status'))) {
+                        this.otr.receiveMsg(text);
+                    } else {
+                        if (text.match(/^\?OTR/)) {
+                            if (!this.otr) {
+                                this.initiateOTR(text);
+                            } else {
+                                this.otr.receiveMsg(text);
+                            }
                         } else {
-                            this.otr.receiveMsg(text);
+                            // Normal unencrypted message.
+                            this.createMessage(message);
                         }
-                    } else {
-                        // Normal unencrypted message.
-                        this.createMessage(message);
                     }
                 }
             }
@@ -775,13 +862,19 @@
                 this.updateVCard();
                 this.$el.appendTo(converse.chatboxesview.$el);
                 this.render().show().model.messages.fetch({add: true});
+
                 if (this.model.get('status')) {
                     this.showStatusMessage(this.model.get('status'));
                 }
+
                 // Drag to resize values
                 this.chatboxMinHeight = 250;
                 this.chatboxHeight = this.$el.children('.box-flyout').height();
                 this.prevPageY = 0; // To store last known mouse position
+
+                if ((_.contains([UNVERIFIED, VERIFIED], this.model.get('otr_status'))) || converse.use_otr_by_default) {
+                    this.model.initiateOTR();
+                }
             },
 
             render: function () {
@@ -853,12 +946,17 @@
                 return this.scrollDown();
             },
 
-            showHelpMessages: function (msgs, type) {
+            showHelpMessages: function (msgs, type, spinner) {
                 var $chat_content = this.$el.find('.chat-content'), i,
                     msgs_length = msgs.length;
                 for (i=0; i<msgs_length; i++) {
                     $chat_content.append($('<div class="chat-'+(type||'info')+'">'+msgs[i]+'</div>'));
                 }
+                if (spinner === true) {
+                    $chat_content.append('<span class="spinner"/>');
+                } else if (spinner === false) {
+                    $chat_content.find('span.spinner').remove();
+                }
                 return this.scrollDown();
             },
 
@@ -1094,7 +1192,7 @@
                         this.model.save({'otr_status': UNVERIFIED});
                     }
                 } else if (scheme === 'smp') {
-                    alert(__('You will be prompted to provide a security question and then an answer to that question.\n\nYour buddy will then be prompted the same question and if they type the exact same answer (case sensitive), their identity will have been verified.'));
+                    alert(__('You will be prompted to provide a security question and then an answer to that question.\n\nYour buddy will then be prompted the same question and if they type the exact same answer (case sensitive), their identity will be verified.'));
                     question = prompt(__('What is your security question?'));
                     if (question) {
                         answer = prompt(__('What is the answer to the security question?'));
@@ -1218,7 +1316,7 @@
                 } else if (data.otr_status == FINISHED){
                     msgs.push(__("Your buddy has ended encryption on their end, you should do the same."));
                 }
-                return this.showHelpMessages(msgs);
+                return this.showHelpMessages(msgs, 'info', false);
             },
 
             renderToolbar: function () {
@@ -2254,6 +2352,17 @@
         this.ChatBoxes = Backbone.Collection.extend({
             model: converse.ChatBox,
 
+            registerMessageHandler: function () {
+                // TODO: Make this method global to converse, trigger an event
+                // and let messageReceived be called via a handler for that
+                // event.
+                converse.connection.addHandler(
+                    $.proxy(function (message) {
+                        this.messageReceived(message);
+                        return true;
+                    }, this), null, 'message', 'chat');
+            },
+
             onConnected: function () {
                 this.localStorage = new Backbone.LocalStorage(
                     hex_sha1('converse.chatboxes-'+converse.bare_jid));
@@ -2265,16 +2374,9 @@
                 } else {
                     this.get('controlbox').save();
                 }
-                // This will make sure the Roster is set up
+                // This line below will make sure the Roster is set up
                 this.get('controlbox').set({connected:true});
-
-                // Register message handler
-                converse.connection.addHandler(
-                    $.proxy(function (message) {
-                        this.messageReceived(message);
-                        return true;
-                    }, this), null, 'message', 'chat');
-
+                this.registerMessageHandler();
                 // Get cached chatboxes from localstorage
                 this.fetch({
                     add: true,
@@ -2728,8 +2830,7 @@
                                 }, this),
                                 $.proxy(function (jid, fullname, img, img_type, url) {
                                     converse.log("Error while retrieving vcard");
-                                    // XXX: Should vcard_updated be set here as
-                                    // well?
+                                    // XXX: Should vcard_updated be set here as well?
                                     this.add({
                                         jid: bare_jid,
                                         subscription: 'none',
@@ -2752,8 +2853,6 @@
                 var $presence = $(presence),
                     presence_type = $presence.attr('type');
                 if (presence_type === 'error') {
-                    // TODO
-                    // error presence stanzas don't necessarily have a 'from' attr.
                     return true;
                 }
                 var jid = $presence.attr('from'),
@@ -3089,7 +3188,7 @@
                 } else if (stat === 'away') {
                     pretty_status = __('away');
                 } else {
-                    pretty_status = __(stat) || __('online'); // XXX: Is 'online' the right default choice here?
+                    pretty_status = __(stat) || __('online');
                 }
                 return pretty_status;
             },
@@ -3208,7 +3307,7 @@
                 converse.connection.connect(jid, password, converse.onConnect);
             },
 
-            showConnectButton: function () {
+            showLoginButton: function () {
                 var $form = this.$el.find('#converse-login');
                 var $button = $form.find('input[type=submit]');
                 if ($button.length) {
@@ -3225,8 +3324,6 @@
                     })
                 ));
                 this.$tabs = cfg.$parent.parent().find('#controlbox-tabs');
-                this.model.on('connection-fail', function () { this.showConnectButton(); }, this);
-                this.model.on('auth-fail', function () { this.showConnectButton(); }, this);
             },
 
             render: function () {
@@ -3340,6 +3437,7 @@
         this.chatboxes = new this.ChatBoxes();
         this.chatboxesview = new this.ChatBoxesView({model: this.chatboxes});
         this.controlboxtoggle = new this.ControlBoxToggle();
+        this.otr = new this.OTR();
 
         if ((this.prebind) && (!this.connection)) {
             if ((!this.jid) || (!this.sid) || (!this.rid) || (!this.bosh_service_url)) {
@@ -3358,6 +3456,18 @@
         'initialize': function (settings, callback) {
             converse.initialize(settings, callback);
         },
+        'getRID': function () {
+            if (converse.expose_rid_and_sid && typeof converse.connection !== "undefined") {
+                return converse.connection.rid;
+            }
+            return null;
+        },
+        'getSID': function () {
+            if (converse.expose_rid_and_sid && typeof converse.connection !== "undefined") {
+                return converse.connection.sid;
+            }
+            return null;
+        },
         'once': function(evt, handler) {
             converse.once(evt, handler);
         },

Plik diff jest za duży
+ 0 - 0
converse.min.css


+ 8 - 3
docs/CHANGES.rst

@@ -7,11 +7,16 @@ Changelog
 * Chat boxes and rooms can now be resized vertically. [jcbrand]
 * Chat boxes and rooms can be minimized. [jcbrand]
 
-0.7.3 (Unreleased)
+0.7.3 (2014-02-23)
 ------------------
 
-* Option to display a call button in the chatbox toolbar, to allow third-party libraries to provide a calling feature. [Aupajo]
-* #108 Japanese Translations. [mako09]
+* #93 Add API methods exposing the RID and SID values. Can be disabled. [jcbrand]
+* #102 Option to enable OTR by default. [Aupajo]
+* #103 Option to display a call button in the chatbox toolbar, to allow third-party libraries to provide a calling feature. [Aupajo]
+* #108 Japanese Translations [mako09]
+* #111 OTR not working when using converse.js with prebinding. [jseidl, jcbrand]
+* #114, #124 Hewbrew Translations [GreenLunar]
+* #115 Indonesian Translations [priyadi]
 
 0.7.2 (2013-12-18)
 ------------------

BIN
docs/doctrees/index.doctree


+ 1 - 1
docs/html/.buildinfo

@@ -1,4 +1,4 @@
 # Sphinx build info version 1
 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
-config: 652c197d955de4d2c90bb99dc6534a15
+config: 738ca7b60aed811ee1668ad08d26eabb
 tags: fbb0d17656682115ca4d033fb2f83ba1

+ 248 - 135
docs/html/_sources/index.txt

@@ -277,6 +277,17 @@ These values are then passed to converse.js's ``initialize`` method.
    **bosh_service_url** values.
 
 
+Example code for server-side prebinding
+---------------------------------------
+
+* PHP: 
+    See `xmpp-prebind-php <https://github.com/candy-chat/xmpp-prebind-php>`_ by
+    Michael Weibel and the folks from Candy chat.
+
+* Python:
+    See this `example Django application`_ by Jack Moffitt.
+
+
 Setting up a BOSH server
 ------------------------
 
@@ -295,7 +306,6 @@ Facebook integration
     this myself. Feedback and patches from people who have succesfully done this
     will be appreciated.
 
-
 Converse.js uses `Strophe.js <http://strophe.im/strophejs>`_ to connect and
 communicate with the XMPP server. One nice thing about Strophe.js is that it
 can be extended via `plugins <http://github.com/strophe/strophejs-plugins>`_.
@@ -339,6 +349,39 @@ The connection is already created inside Converse.js, so the
 If someone submits a sane patch that does the above, I'll be happy to merge it.
 Until then, people will have to do this themselves.
 
+========
+Features
+========
+
+Off-the-record encryption
+=========================
+
+Converse.js supports `Off-the-record (OTR) <https://otr.cypherpunks.ca/>`_
+encrypted messaging.
+
+The OTR protocol not only **encrypts your messages**, it provides ways to
+**verify the identity** of the person you are talking to,
+**plausible deniability** and **perfect forward secrecy** by generating
+new encryption keys for each conversation.
+
+In its current state, Javascript cryptography is fraught with dangers and
+challenges that make it impossible to reach the same standard of security that
+is available with native "desktop" software.
+
+This is due to its runtime malleability, the way it is "installed" (e.g.
+served) and the browser's lack of cryptographic primitives needed to implement
+secure crypto.
+
+For harsh but fairly valid criticism of Javascript cryptography, read:
+`Javascript Cryptography Considered Harmful <http://www.matasano.com/articles/javascript-cryptography/>`_.
+
+To get an idea on how this applies to OTR support in Converse.js, please read
+`my thoughts on it <https://opkode.com/media/blog/2013/11/11/conversejs-otr-support>`_.
+
+For now, suffice to say that although its useful to have OTR support in
+Converse.js in order to avoid most eavesdroppers, if you need serious
+communications privacy, then you're much better off using native software.
+
 ===========
 Development
 ===========
@@ -387,6 +430,7 @@ If you don't have grunt installed globally, you need to specify the relative
 path:
 
 ::
+
     ./node_modules/.bin/grunt fetch
 
 This will call Bower in the background to fetch all the front-end
@@ -467,6 +511,137 @@ You can run both the tests and jshint in one go by calling:
 
     grunt check
 
+Minification
+============
+
+Minifying Javascript and CSS
+----------------------------
+
+Please make sure to read the section `Development`_ and that you have installed
+all development dependencies (long story short, you can run ``npm install``
+and then ``grunt fetch``).
+
+We  use `require.js`_ to keep track of *Converse.js* and its dependencies and to
+to bundle them together in a single minified file fit for deployment to a
+production site.
+
+To minify the Javascript and CSS, run the following command:
+
+::
+
+    grunt minify
+
+Javascript will be bundled and minified with `require.js`_'s optimization tool,
+using `almond <https://github.com/jrburke/almond>`_.
+
+You can `read more about require.js's optimizer here`_.
+
+CSS is minified via `cssmin <https://github.com/gruntjs/grunt-contrib-cssmin>`_.
+
+Translations
+============
+
+.. Note ::
+   Translations take up a lot of space and will bloat your minified file.
+   At the time of writing, all the translations add about 50KB of extra data to
+   the minified javascript file. Therefore, make sure to only
+   include those languages that you intend to support and remove from
+   ./locale/locales.js those which you don't need. Remember to rebuild the
+   minified file afterwards.
+
+The gettext POT file located in ./locale/converse.pot is the template
+containing all translations and from which for each language an individual PO
+file is generated.
+
+The POT file contains all translateable strings extracted from converse.js.
+
+To make a user facing string translateable, wrap it in the double underscore helper
+function like so:
+
+::
+
+    __('This string will be translated at runtime');
+
+After adding the string, you'll need to regenerate the POT file, like so:
+
+::
+
+    make pot
+
+You can then create or update the PO file for a specific language by doing the following:
+
+::
+
+    msgmerge ./locale/de/LC_MESSAGES/converse.po ./locale/converse.pot -U
+
+To do this for ALL languages, run:
+
+::
+
+    make merge
+
+The resulting PO file is then what gets translated.
+
+If you've created a new PO file, please make sure to add the following
+attributes at the top of the file (under *Content-Transfer-Encoding*). They are
+required as configuration settings for Jed, the Javascript translations library
+that we're using.
+
+::
+
+    "domain: converse\n"
+    "lang: de\n"
+    "plural_forms: nplurals=2; plural=(n != 1);\n"
+
+
+Unfortunately `Jed <http://slexaxton.github.io/Jed>`_ cannot use the PO files directly. We have to generate from it
+a file in JSON format and then put that in a .js file for the specific
+language.
+
+To generate JSON from a PO file, you'll need po2json for node.js. Run the
+following command to install it (npm being the node.js package manager):
+
+::
+
+    npm install po2json
+
+You can then convert the translations into JSON format:
+
+::
+
+    po2json locale/de/LC_MESSAGES/converse.po locale/de/LC_MESSAGES/converse.json
+
+Now from converse.json paste the data as a value for the "locale_data" key in the
+object in the language's .js file.
+
+So, if you are for example translating into German (language code 'de'), you'll
+create or update the file ./locale/LC_MESSAGES/de.js with the following code:
+
+::
+
+    (function (root, factory) {
+        define("de", ['jed'], function () {
+            return factory(new Jed({
+                "domain": "converse",
+                "locale_data": {
+                    // Paste the JSON data from converse.json here
+                }
+            })
+        }
+    }(this, function (i18n) {
+        return i18n;
+    }));
+
+making sure to also paste the JSON data as value to the "locale_data" key.
+
+.. Note ::
+    If you are adding translations for a new language that is not already supported,
+    you'll have to make one more edit in ./locale/locales.js to make sure the
+    language is loaded by require.js.
+
+Congratulations, you've now succesfully added your translations. Sorry for all
+those hoops you had to jump through.
+
 
 ===============
 Troubleshooting
@@ -736,6 +911,14 @@ For each room on the server a query is made to fetch further details (e.g.
 features, number of occupants etc.), so on servers with many rooms this
 option will create lots of extra connection traffic.
 
+auto_reconnect
+--------------
+
+Default = ``true``
+
+Automatically reconnect to the XMPP server if the connection drops
+unexpectedly.
+
 auto_subscribe
 --------------
 
@@ -751,6 +934,30 @@ a middle man between HTTP and XMPP.
 
 See `here <http://metajack.im/2008/09/08/which-bosh-server-do-you-need>`_ for more information.
 
+cache_otr_key
+-------------
+
+Default = ``false``
+
+Let the `OTR (Off-the-record encryption) <https://otr.cypherpunks.ca>`_ private
+key be cached in your browser's session storage.
+
+The browser's session storage persists across page loads but is deleted once
+the tab or window is closed.
+
+If this option is set to ``false``, a new OTR private key will be generated
+for each page load. While more inconvenient, this is a much more secure option.
+
+This setting can only be used together with ``allow_otr = true``.
+
+
+.. Note :: 
+    A browser window's session storage is accessible by all javascript that
+    is served from the same domain. So if there is malicious javascript served by
+    the same server (or somehow injected via an attacker), then they will be able
+    to retrieve your private key and read your all the chat messages in your
+    current session. Previous sessions however cannot be decrypted.
+
 debug
 -----
 
@@ -758,6 +965,16 @@ Default = ``false``
 
 If set to true, debugging output will be logged to the browser console.
 
+expose_rid_and_sid
+------------------
+
+Allow the prebind tokens, RID (request ID) and SID (session ID), to be exposed
+globally via the API. This allows other scripts served on the same page to use
+these values. 
+
+*Beware*: a malicious script could use these tokens to assume your identity
+and inject fake chat messages.
+
 fullname
 --------
 
@@ -813,6 +1030,28 @@ the page with class *toggle-online-users*.
 If this options is set to true, the controlbox will by default be shown upon
 page load.
 
+
+show_call_button
+----------------
+
+Default = ``false``
+
+Enable to display a call button on the chatbox toolbar.
+
+When the call button is pressed, it will emit an event that can be used by a third-party library to initiate a call.
+
+::
+
+    converse.on('onCallButtonClicked', function(event, data) {
+        console.log('Call button was clicked.');
+        console.log('Strophe connection is', data.connection);
+        console.log('Bare buddy JID is', data.model.get('jid'));
+
+        // ... Third-party library code ...
+    });
+
+
+
 show_only_online_users
 ----------------------
 
@@ -821,6 +1060,14 @@ Default = ``false``
 If set to ``true``, only online users will be shown in the contacts roster.
 Users with any other status (e.g. away, busy etc.) will not be shown.
 
+use_otr_by_default
+------------------
+
+Default = ``false``
+
+If set to ``true``, Converse.js will automatically try to initiate an OTR (off-the-record)
+encrypted chat session every time you open a chat box.
+
 use_vcards
 ----------
 
@@ -889,140 +1136,6 @@ Used only in conjunction with ``xhr_user_search``.
 This is the URL to which an AJAX GET request will be made to fetch user data from your remote server.
 The query string will be included in the request with ``q`` as its key.
 
-============
-Minification
-============
-
-Minifying Javascript and CSS
-============================
-
-Please make sure to read the section `Development`_ and that you have installed
-all development dependencies (long story short, you can run ``npm install``
-and then ``grunt fetch``).
-
-We  use `require.js`_ to keep track of *Converse.js* and its dependencies and to
-to bundle them together in a single minified file fit for deployment to a
-production site.
-
-To minify the Javascript and CSS, run the following command:
-
-::
-
-    grunt minify
-
-Javascript will be bundled and minified with `require.js`_'s optimization tool,
-using `almond <https://github.com/jrburke/almond>`_.
-
-You can `read more about require.js's optimizer here`_.
-
-CSS is minified via `cssmin <https://github.com/gruntjs/grunt-contrib-cssmin>`_.
-
-
-============
-Translations
-============
-
-.. Note ::
-   Translations take up a lot of space and will bloat your minified file.
-   At the time of writing, all the translations add about 50KB of extra data to
-   the minified javascript file. Therefore, make sure to only
-   include those languages that you intend to support and remove from
-   ./locale/locales.js those which you don't need. Remember to rebuild the
-   minified file afterwards.
-
-The gettext POT file located in ./locale/converse.pot is the template
-containing all translations and from which for each language an individual PO
-file is generated.
-
-The POT file contains all translateable strings extracted from converse.js.
-
-To make a user facing string translateable, wrap it in the double underscore helper
-function like so:
-
-::
-
-    __('This string will be translated at runtime');
-
-After adding the string, you'll need to regenerate the POT file, like so:
-
-::
-
-    make pot
-
-You can then create or update the PO file for a specific language by doing the following:
-
-::
-
-    msgmerge ./locale/de/LC_MESSAGES/converse.po ./locale/converse.pot -U
-
-To do this for ALL languages, run:
-
-::
-
-    make merge
-
-The resulting PO file is then what gets translated.
-
-If you've created a new PO file, please make sure to add the following
-attributes at the top of the file (under *Content-Transfer-Encoding*). They are
-required as configuration settings for Jed, the Javascript translations library
-that we're using.
-
-::
-
-    "domain: converse\n"
-    "lang: de\n"
-    "plural_forms: nplurals=2; plural=(n != 1);\n"
-
-
-Unfortunately `Jed <http://slexaxton.github.io/Jed>`_ cannot use the PO files directly. We have to generate from it
-a file in JSON format and then put that in a .js file for the specific
-language.
-
-To generate JSON from a PO file, you'll need po2json for node.js. Run the
-following command to install it (npm being the node.js package manager):
-
-::
-
-    npm install po2json
-
-You can then convert the translations into JSON format:
-
-::
-
-    po2json locale/de/LC_MESSAGES/converse.po locale/de/LC_MESSAGES/converse.json
-
-Now from converse.json paste the data as a value for the "locale_data" key in the
-object in the language's .js file.
-
-So, if you are for example translating into German (language code 'de'), you'll
-create or update the file ./locale/LC_MESSAGES/de.js with the following code:
-
-::
-
-    (function (root, factory) {
-        define("de", ['jed'], function () {
-            return factory(new Jed({
-                "domain": "converse",
-                "locale_data": {
-                    // Paste the JSON data from converse.json here
-                }
-            })
-        }
-    }(this, function (i18n) {
-        return i18n;
-    }));
-
-making sure to also paste the JSON data as value to the "locale_data" key.
-
-.. Note ::
-    If you are adding translations for a new language that is not already supported,
-    you'll have to make one more edit in ./locale/locales.js to make sure the
-    language is loaded by require.js.
-
-Congratulations, you've now succesfully added your translations. Sorry for all
-those hoops you had to jump through.
-
 .. _`read more about require.js's optimizer here`: http://requirejs.org/docs/optimization.html
 .. _`HTTP`: https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol
 .. _`XMPP`: https://en.wikipedia.org/wiki/Xmpp

+ 5 - 5
docs/html/genindex.html

@@ -9,7 +9,7 @@
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
     
-    <title>Index &mdash; Converse.js 0.7.1 documentation</title>
+    <title>Index &mdash; Converse.js 0.7.3 documentation</title>
     
     <link rel="stylesheet" href="_static/stylesheet.css" type="text/css" />
     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@@ -17,7 +17,7 @@
     <script type="text/javascript">
       var DOCUMENTATION_OPTIONS = {
         URL_ROOT:    '',
-        VERSION:     '0.7.1',
+        VERSION:     '0.7.3',
         COLLAPSE_INDEX: false,
         FILE_SUFFIX: '.html',
         HAS_SOURCE:  true
@@ -26,7 +26,7 @@
     <script type="text/javascript" src="_static/jquery.js"></script>
     <script type="text/javascript" src="_static/underscore.js"></script>
     <script type="text/javascript" src="_static/doctools.js"></script>
-    <link rel="top" title="Converse.js 0.7.1 documentation" href="index.html" /> 
+    <link rel="top" title="Converse.js 0.7.3 documentation" href="index.html" /> 
   </head>
   <body>
     <div id="header_wrap" class="outer">
@@ -51,7 +51,7 @@
         <li class="right" style="margin-right: 10px">
           <a href="#" title="General Index"
              accesskey="I">index</a></li>
-        <li><a href="index.html">Converse.js 0.7.1 documentation</a> &raquo;</li> 
+        <li><a href="index.html">Converse.js 0.7.3 documentation</a> &raquo;</li> 
       </ul>
     </div>
 <section id="main_content" class="inner">  
@@ -80,7 +80,7 @@
         <li class="right" style="margin-right: 10px">
           <a href="#" title="General Index"
              >index</a></li>
-        <li><a href="index.html">Converse.js 0.7.1 documentation</a> &raquo;</li> 
+        <li><a href="index.html">Converse.js 0.7.3 documentation</a> &raquo;</li> 
       </ul>
     </div>
 </div>

+ 288 - 184
docs/html/index.html

@@ -7,7 +7,7 @@
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
     
-    <title>Quickstart (to get a demo up and running) &mdash; Converse.js 0.7.1 documentation</title>
+    <title>Quickstart (to get a demo up and running) &mdash; Converse.js 0.7.3 documentation</title>
     
     <link rel="stylesheet" href="_static/stylesheet.css" type="text/css" />
     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@@ -15,7 +15,7 @@
     <script type="text/javascript">
       var DOCUMENTATION_OPTIONS = {
         URL_ROOT:    '',
-        VERSION:     '0.7.1',
+        VERSION:     '0.7.3',
         COLLAPSE_INDEX: false,
         FILE_SUFFIX: '.html',
         HAS_SOURCE:  true
@@ -24,7 +24,7 @@
     <script type="text/javascript" src="_static/jquery.js"></script>
     <script type="text/javascript" src="_static/underscore.js"></script>
     <script type="text/javascript" src="_static/doctools.js"></script>
-    <link rel="top" title="Converse.js 0.7.1 documentation" href="#" /> 
+    <link rel="top" title="Converse.js 0.7.3 documentation" href="#" /> 
   </head>
   <body>
     <div id="header_wrap" class="outer">
@@ -49,7 +49,7 @@
         <li class="right" style="margin-right: 10px">
           <a href="genindex.html" title="General Index"
              accesskey="I">index</a></li>
-        <li><a href="#">Converse.js 0.7.1 documentation</a> &raquo;</li> 
+        <li><a href="#">Converse.js 0.7.3 documentation</a> &raquo;</li> 
       </ul>
     </div>
 <section id="main_content" class="inner">  
@@ -75,67 +75,77 @@
 </li>
 <li><a class="reference internal" href="#server-side-authentication" id="id9">Server-side authentication</a><ul>
 <li><a class="reference internal" href="#prebinding-and-single-session-support" id="id10">Prebinding and Single Session Support</a></li>
-<li><a class="reference internal" href="#setting-up-a-bosh-server" id="id11">Setting up a BOSH server</a></li>
+<li><a class="reference internal" href="#example-code-for-server-side-prebinding" id="id11">Example code for server-side prebinding</a></li>
+<li><a class="reference internal" href="#setting-up-a-bosh-server" id="id12">Setting up a BOSH server</a></li>
 </ul>
 </li>
-<li><a class="reference internal" href="#facebook-integration" id="id12">Facebook integration</a></li>
+<li><a class="reference internal" href="#facebook-integration" id="id13">Facebook integration</a></li>
 </ul>
 </li>
-<li><a class="reference internal" href="#development" id="id13">Development</a><ul>
-<li><a class="reference internal" href="#install-node-js-and-development-dependencies" id="id14">Install Node.js and development dependencies</a></li>
-<li><a class="reference internal" href="#install-3rd-party-dependencies" id="id15">Install 3rd party dependencies</a></li>
-<li><a class="reference internal" href="#with-amd-and-require-js-recommended" id="id16">With AMD and require.js (recommended)</a></li>
-<li><a class="reference internal" href="#without-amd-and-require-js" id="id17">Without AMD and require.js</a></li>
-<li><a class="reference internal" href="#before-submitting-a-pull-request" id="id18">Before submitting a pull request</a><ul>
-<li><a class="reference internal" href="#add-tests-for-your-bugfix-or-feature" id="id19">Add tests for your bugfix or feature</a></li>
-<li><a class="reference internal" href="#check-that-the-tests-pass" id="id20">Check that the tests pass</a></li>
-<li><a class="reference internal" href="#check-your-code-for-errors-or-bad-habits-by-running-jshint" id="id21">Check your code for errors or bad habits by running JSHint</a></li>
+<li><a class="reference internal" href="#features" id="id14">Features</a><ul>
+<li><a class="reference internal" href="#off-the-record-encryption" id="id15">Off-the-record encryption</a></li>
 </ul>
 </li>
+<li><a class="reference internal" href="#development" id="id16">Development</a><ul>
+<li><a class="reference internal" href="#install-node-js-and-development-dependencies" id="id17">Install Node.js and development dependencies</a></li>
+<li><a class="reference internal" href="#install-3rd-party-dependencies" id="id18">Install 3rd party dependencies</a></li>
+<li><a class="reference internal" href="#with-amd-and-require-js-recommended" id="id19">With AMD and require.js (recommended)</a></li>
+<li><a class="reference internal" href="#without-amd-and-require-js" id="id20">Without AMD and require.js</a></li>
+<li><a class="reference internal" href="#before-submitting-a-pull-request" id="id21">Before submitting a pull request</a><ul>
+<li><a class="reference internal" href="#add-tests-for-your-bugfix-or-feature" id="id22">Add tests for your bugfix or feature</a></li>
+<li><a class="reference internal" href="#check-that-the-tests-pass" id="id23">Check that the tests pass</a></li>
+<li><a class="reference internal" href="#check-your-code-for-errors-or-bad-habits-by-running-jshint" id="id24">Check your code for errors or bad habits by running JSHint</a></li>
 </ul>
 </li>
-<li><a class="reference internal" href="#troubleshooting" id="id22">Troubleshooting</a><ul>
-<li><a class="reference internal" href="#conflicts-with-other-javascript-libraries" id="id23">Conflicts with other Javascript libraries</a><ul>
-<li><a class="reference internal" href="#problem" id="id24">Problem:</a></li>
-<li><a class="reference internal" href="#solution" id="id25">Solution:</a></li>
+<li><a class="reference internal" href="#minification" id="id25">Minification</a><ul>
+<li><a class="reference internal" href="#minifying-javascript-and-css" id="id26">Minifying Javascript and CSS</a></li>
 </ul>
 </li>
+<li><a class="reference internal" href="#translations" id="id27">Translations</a></li>
 </ul>
 </li>
-<li><a class="reference internal" href="#events" id="id26">Events</a><ul>
-<li><a class="reference internal" href="#event-methods" id="id27">Event Methods</a></li>
-<li><a class="reference internal" href="#event-types" id="id28">Event Types</a></li>
+<li><a class="reference internal" href="#troubleshooting" id="id28">Troubleshooting</a><ul>
+<li><a class="reference internal" href="#conflicts-with-other-javascript-libraries" id="id29">Conflicts with other Javascript libraries</a><ul>
+<li><a class="reference internal" href="#problem" id="id30">Problem:</a></li>
+<li><a class="reference internal" href="#solution" id="id31">Solution:</a></li>
 </ul>
 </li>
-<li><a class="reference internal" href="#configuration" id="id29">Configuration</a><ul>
-<li><a class="reference internal" href="#configuration-variables" id="id30">Configuration variables</a><ul>
-<li><a class="reference internal" href="#allow-contact-requests" id="id31">allow_contact_requests</a></li>
-<li><a class="reference internal" href="#allow-muc" id="id32">allow_muc</a></li>
-<li><a class="reference internal" href="#animate" id="id33">animate</a></li>
-<li><a class="reference internal" href="#auto-list-rooms" id="id34">auto_list_rooms</a></li>
-<li><a class="reference internal" href="#auto-subscribe" id="id35">auto_subscribe</a></li>
-<li><a class="reference internal" href="#bosh-service-url" id="id36">bosh_service_url</a></li>
-<li><a class="reference internal" href="#debug" id="id37">debug</a></li>
-<li><a class="reference internal" href="#fullname" id="id38">fullname</a></li>
-<li><a class="reference internal" href="#hide-muc-server" id="id39">hide_muc_server</a></li>
-<li><a class="reference internal" href="#i18n" id="id40">i18n</a></li>
-<li><a class="reference internal" href="#prebind" id="id41">prebind</a></li>
-<li><a class="reference internal" href="#show-controlbox-by-default" id="id42">show_controlbox_by_default</a></li>
-<li><a class="reference internal" href="#show-only-online-users" id="id43">show_only_online_users</a></li>
-<li><a class="reference internal" href="#use-vcards" id="id44">use_vcards</a></li>
-<li><a class="reference internal" href="#xhr-custom-status" id="id45">xhr_custom_status</a></li>
-<li><a class="reference internal" href="#xhr-custom-status-url" id="id46">xhr_custom_status_url</a></li>
-<li><a class="reference internal" href="#xhr-user-search" id="id47">xhr_user_search</a></li>
-<li><a class="reference internal" href="#xhr-user-search-url" id="id48">xhr_user_search_url</a></li>
 </ul>
 </li>
+<li><a class="reference internal" href="#events" id="id32">Events</a><ul>
+<li><a class="reference internal" href="#event-methods" id="id33">Event Methods</a></li>
+<li><a class="reference internal" href="#event-types" id="id34">Event Types</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#configuration" id="id35">Configuration</a><ul>
+<li><a class="reference internal" href="#configuration-variables" id="id36">Configuration variables</a><ul>
+<li><a class="reference internal" href="#allow-contact-requests" id="id37">allow_contact_requests</a></li>
+<li><a class="reference internal" href="#allow-muc" id="id38">allow_muc</a></li>
+<li><a class="reference internal" href="#animate" id="id39">animate</a></li>
+<li><a class="reference internal" href="#auto-list-rooms" id="id40">auto_list_rooms</a></li>
+<li><a class="reference internal" href="#auto-reconnect" id="id41">auto_reconnect</a></li>
+<li><a class="reference internal" href="#auto-subscribe" id="id42">auto_subscribe</a></li>
+<li><a class="reference internal" href="#bosh-service-url" id="id43">bosh_service_url</a></li>
+<li><a class="reference internal" href="#cache-otr-key" id="id44">cache_otr_key</a></li>
+<li><a class="reference internal" href="#debug" id="id45">debug</a></li>
+<li><a class="reference internal" href="#expose-rid-and-sid" id="id46">expose_rid_and_sid</a></li>
+<li><a class="reference internal" href="#fullname" id="id47">fullname</a></li>
+<li><a class="reference internal" href="#hide-muc-server" id="id48">hide_muc_server</a></li>
+<li><a class="reference internal" href="#i18n" id="id49">i18n</a></li>
+<li><a class="reference internal" href="#prebind" id="id50">prebind</a></li>
+<li><a class="reference internal" href="#show-controlbox-by-default" id="id51">show_controlbox_by_default</a></li>
+<li><a class="reference internal" href="#show-call-button" id="id52">show_call_button</a></li>
+<li><a class="reference internal" href="#show-only-online-users" id="id53">show_only_online_users</a></li>
+<li><a class="reference internal" href="#use-otr-by-default" id="id54">use_otr_by_default</a></li>
+<li><a class="reference internal" href="#use-vcards" id="id55">use_vcards</a></li>
+<li><a class="reference internal" href="#xhr-custom-status" id="id56">xhr_custom_status</a></li>
+<li><a class="reference internal" href="#xhr-custom-status-url" id="id57">xhr_custom_status_url</a></li>
+<li><a class="reference internal" href="#xhr-user-search" id="id58">xhr_user_search</a></li>
+<li><a class="reference internal" href="#xhr-user-search-url" id="id59">xhr_user_search_url</a></li>
 </ul>
 </li>
-<li><a class="reference internal" href="#minification" id="id49">Minification</a><ul>
-<li><a class="reference internal" href="#minifying-javascript-and-css" id="id50">Minifying Javascript and CSS</a></li>
 </ul>
 </li>
-<li><a class="reference internal" href="#translations" id="id51">Translations</a></li>
 </ul>
 </div>
 <div class="section" id="quickstart-to-get-a-demo-up-and-running">
@@ -180,7 +190,7 @@ practical.</p>
 <p>You&#8217;ll most likely want to implement some kind of single-signon solution for
 your website, where users authenticate once in your website and then stay
 logged into their XMPP session upon page reload.</p>
-<p>For more info on this, read: <a href="#id52"><span class="problematic" id="id53">`Pre-binding and Single Session Support`_</span></a>.</p>
+<p>For more info on this, read: <a href="#id60"><span class="problematic" id="id61">`Pre-binding and Single Session Support`_</span></a>.</p>
 <p>You might also want to have more fine-grained control of what gets included in
 the minified Javascript file. Read <a class="reference internal" href="#configuration">Configuration</a> and <a class="reference internal" href="#minification">Minification</a> for more info on how to do
 that.</p>
@@ -338,15 +348,33 @@ Additionally you need to pass in valid <strong>jid</strong>, <strong>sid</strong
 <strong>bosh_service_url</strong> values.</p>
 </div>
 </div>
+<div class="section" id="example-code-for-server-side-prebinding">
+<h3><a class="toc-backref" href="#id11">Example code for server-side prebinding</a><a class="headerlink" href="#example-code-for-server-side-prebinding" title="Permalink to this headline">¶</a></h3>
+<ul>
+<li><dl class="first docutils">
+<dt>PHP:</dt>
+<dd><p class="first last">See <a class="reference external" href="https://github.com/candy-chat/xmpp-prebind-php">xmpp-prebind-php</a> by
+Michael Weibel and the folks from Candy chat.</p>
+</dd>
+</dl>
+</li>
+<li><dl class="first docutils">
+<dt>Python:</dt>
+<dd><p class="first last">See this <a class="reference external" href="https://github.com/metajack/strophejs/tree/master/examples/attach">example Django application</a> by Jack Moffitt.</p>
+</dd>
+</dl>
+</li>
+</ul>
+</div>
 <div class="section" id="setting-up-a-bosh-server">
-<h3><a class="toc-backref" href="#id11">Setting up a BOSH server</a><a class="headerlink" href="#setting-up-a-bosh-server" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id12">Setting up a BOSH server</a><a class="headerlink" href="#setting-up-a-bosh-server" title="Permalink to this headline">¶</a></h3>
 <p>The <a class="reference external" href="http://movim.eu/">Movim</a> project wiki has a very thorough page on setting up a BOSH server for
 a wide variety of standalone or XMPP servers.</p>
 <p><a class="reference external" href="http://wiki.movim.eu/manual:bosh_servers">http://wiki.movim.eu/manual:bosh_servers</a></p>
 </div>
 </div>
 <div class="section" id="facebook-integration">
-<h2><a class="toc-backref" href="#id12">Facebook integration</a><a class="headerlink" href="#facebook-integration" title="Permalink to this headline">¶</a></h2>
+<h2><a class="toc-backref" href="#id13">Facebook integration</a><a class="headerlink" href="#facebook-integration" title="Permalink to this headline">¶</a></h2>
 <div class="admonition note">
 <p class="first admonition-title">Note</p>
 <p class="last">It should be possible to integrate Converse.js with Facebook chat, and
@@ -388,14 +416,39 @@ connection.facebookConnect(
 Until then, people will have to do this themselves.</p>
 </div>
 </div>
+<div class="section" id="features">
+<h1><a class="toc-backref" href="#id14">Features</a><a class="headerlink" href="#features" title="Permalink to this headline">¶</a></h1>
+<div class="section" id="off-the-record-encryption">
+<h2><a class="toc-backref" href="#id15">Off-the-record encryption</a><a class="headerlink" href="#off-the-record-encryption" title="Permalink to this headline">¶</a></h2>
+<p>Converse.js supports <a class="reference external" href="https://otr.cypherpunks.ca/">Off-the-record (OTR)</a>
+encrypted messaging.</p>
+<p>The OTR protocol not only <strong>encrypts your messages</strong>, it provides ways to
+<strong>verify the identity</strong> of the person you are talking to,
+<strong>plausible deniability</strong> and <strong>perfect forward secrecy</strong> by generating
+new encryption keys for each conversation.</p>
+<p>In its current state, Javascript cryptography is fraught with dangers and
+challenges that make it impossible to reach the same standard of security that
+is available with native &#8220;desktop&#8221; software.</p>
+<p>This is due to its runtime malleability, the way it is &#8220;installed&#8221; (e.g.
+served) and the browser&#8217;s lack of cryptographic primitives needed to implement
+secure crypto.</p>
+<p>For harsh but fairly valid criticism of Javascript cryptography, read:
+<a class="reference external" href="http://www.matasano.com/articles/javascript-cryptography/">Javascript Cryptography Considered Harmful</a>.</p>
+<p>To get an idea on how this applies to OTR support in Converse.js, please read
+<a class="reference external" href="https://opkode.com/media/blog/2013/11/11/conversejs-otr-support">my thoughts on it</a>.</p>
+<p>For now, suffice to say that although its useful to have OTR support in
+Converse.js in order to avoid most eavesdroppers, if you need serious
+communications privacy, then you&#8217;re much better off using native software.</p>
+</div>
+</div>
 <div class="section" id="development">
-<h1><a class="toc-backref" href="#id13">Development</a><a class="headerlink" href="#development" title="Permalink to this headline">¶</a></h1>
+<h1><a class="toc-backref" href="#id16">Development</a><a class="headerlink" href="#development" title="Permalink to this headline">¶</a></h1>
 <p>If you want to work with the non-minified Javascript and CSS files you&#8217;ll soon
 notice that there are references to a missing <em>components</em> folder. Please
 follow the instructions below to create this folder and fetch Converse&#8217;s
 3rd-party dependencies.</p>
 <div class="section" id="install-node-js-and-development-dependencies">
-<h2><a class="toc-backref" href="#id14">Install Node.js and development dependencies</a><a class="headerlink" href="#install-node-js-and-development-dependencies" title="Permalink to this headline">¶</a></h2>
+<h2><a class="toc-backref" href="#id17">Install Node.js and development dependencies</a><a class="headerlink" href="#install-node-js-and-development-dependencies" title="Permalink to this headline">¶</a></h2>
 <p>We use development tools (<a class="reference external" href="http://gruntjs.com">Grunt</a> and <a class="reference external" href="http://bower.io">Bower</a>)
 which depend on Node.js and npm (the Node package manager).</p>
 <p>If you don&#8217;t have Node.js installed, you can download and install the latest
@@ -409,7 +462,7 @@ curious to know what these are, take a look at whats under the <em>devDependenci
 <cite>package.json &lt;https://github.com/jcbrand/converse.js/blob/master/package.json&gt;</cite>.</p>
 </div>
 <div class="section" id="install-3rd-party-dependencies">
-<h2><a class="toc-backref" href="#id15">Install 3rd party dependencies</a><a class="headerlink" href="#install-3rd-party-dependencies" title="Permalink to this headline">¶</a></h2>
+<h2><a class="toc-backref" href="#id18">Install 3rd party dependencies</a><a class="headerlink" href="#install-3rd-party-dependencies" title="Permalink to this headline">¶</a></h2>
 <p>After running <tt class="docutils literal"><span class="pre">npm</span> <span class="pre">install</span></tt>, you will now have Grunt and Bower installed.</p>
 <p>We use Bower to manage Converse&#8217;s front-end dependencies (e.g. Javascript that
 should get loaded in the browser).</p>
@@ -418,16 +471,14 @@ should get loaded in the browser).</p>
 </div>
 <p>If you don&#8217;t have grunt installed globally, you need to specify the relative
 path:</p>
-<dl class="docutils">
-<dt>::</dt>
-<dd>./node_modules/.bin/grunt fetch</dd>
-</dl>
+<div class="highlight-python"><pre>./node_modules/.bin/grunt fetch</pre>
+</div>
 <p>This will call Bower in the background to fetch all the front-end
 dependencies (like backbone.js, strophe.js etc.) and then put them in the
 <em>components</em> folder.</p>
 </div>
 <div class="section" id="with-amd-and-require-js-recommended">
-<h2><a class="toc-backref" href="#id16">With AMD and require.js (recommended)</a><a class="headerlink" href="#with-amd-and-require-js-recommended" title="Permalink to this headline">¶</a></h2>
+<h2><a class="toc-backref" href="#id19">With AMD and require.js (recommended)</a><a class="headerlink" href="#with-amd-and-require-js-recommended" title="Permalink to this headline">¶</a></h2>
 <p>Converse.js uses <a class="reference external" href="http://requirejs.org">require.js</a> to asynchronously load dependencies.</p>
 <p>If you want to develop or customize converse.js, you&#8217;ll want to load the
 non-minified javascript files.</p>
@@ -440,7 +491,7 @@ attribute on the <em>script</em> tag), which will in turn cause converse.js to b
 parsed.</p>
 </div>
 <div class="section" id="without-amd-and-require-js">
-<h2><a class="toc-backref" href="#id17">Without AMD and require.js</a><a class="headerlink" href="#without-amd-and-require-js" title="Permalink to this headline">¶</a></h2>
+<h2><a class="toc-backref" href="#id20">Without AMD and require.js</a><a class="headerlink" href="#without-amd-and-require-js" title="Permalink to this headline">¶</a></h2>
 <p>Converse.js can also be used without require.js. If you for some reason prefer
 to use it this way, please refer to
 <a class="reference external" href="https://github.com/jcbrand/converse.js/blob/master/non_amd.html">non_amd.html</a>
@@ -448,9 +499,9 @@ for an example of how and in what order all the Javascript files that converse.j
 depends on need to be loaded.</p>
 </div>
 <div class="section" id="before-submitting-a-pull-request">
-<h2><a class="toc-backref" href="#id18">Before submitting a pull request</a><a class="headerlink" href="#before-submitting-a-pull-request" title="Permalink to this headline">¶</a></h2>
+<h2><a class="toc-backref" href="#id21">Before submitting a pull request</a><a class="headerlink" href="#before-submitting-a-pull-request" title="Permalink to this headline">¶</a></h2>
 <div class="section" id="add-tests-for-your-bugfix-or-feature">
-<h3><a class="toc-backref" href="#id19">Add tests for your bugfix or feature</a><a class="headerlink" href="#add-tests-for-your-bugfix-or-feature" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id22">Add tests for your bugfix or feature</a><a class="headerlink" href="#add-tests-for-your-bugfix-or-feature" title="Permalink to this headline">¶</a></h3>
 <p>Add a test for any bug fixed or feature added. We use Jasmine
 for testing.</p>
 <p>Take a look at <tt class="docutils literal"><span class="pre">tests.html</span></tt> and <tt class="docutils literal"><span class="pre">spec/MainSpec.js</span></tt> to see how
@@ -459,7 +510,7 @@ the tests are implemented.</p>
 <a class="reference external" href="http://opkode.com/contact">contact me</a> and I&#8217;ll be happy to help.</p>
 </div>
 <div class="section" id="check-that-the-tests-pass">
-<h3><a class="toc-backref" href="#id20">Check that the tests pass</a><a class="headerlink" href="#check-that-the-tests-pass" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id23">Check that the tests pass</a><a class="headerlink" href="#check-that-the-tests-pass" title="Permalink to this headline">¶</a></h3>
 <p>Check that the Jasmine tests complete sucessfully. Open
 <a class="reference external" href="https://github.com/jcbrand/converse.js/blob/master/tests.html">tests.html</a>
 in your browser, and the tests will run automatically.</p>
@@ -468,7 +519,7 @@ in your browser, and the tests will run automatically.</p>
 </div>
 </div>
 <div class="section" id="check-your-code-for-errors-or-bad-habits-by-running-jshint">
-<h3><a class="toc-backref" href="#id21">Check your code for errors or bad habits by running JSHint</a><a class="headerlink" href="#check-your-code-for-errors-or-bad-habits-by-running-jshint" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id24">Check your code for errors or bad habits by running JSHint</a><a class="headerlink" href="#check-your-code-for-errors-or-bad-habits-by-running-jshint" title="Permalink to this headline">¶</a></h3>
 <p><a class="reference external" href="http://jshint.com">JSHint</a> will do a static analysis of your code and hightlight potential errors
 and/or bad habits.</p>
 <div class="highlight-python"><pre>grunt jshint</pre>
@@ -478,20 +529,115 @@ and/or bad habits.</p>
 </div>
 </div>
 </div>
+<div class="section" id="minification">
+<h2><a class="toc-backref" href="#id25">Minification</a><a class="headerlink" href="#minification" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="minifying-javascript-and-css">
+<h3><a class="toc-backref" href="#id26">Minifying Javascript and CSS</a><a class="headerlink" href="#minifying-javascript-and-css" title="Permalink to this headline">¶</a></h3>
+<p>Please make sure to read the section <a class="reference internal" href="#development">Development</a> and that you have installed
+all development dependencies (long story short, you can run <tt class="docutils literal"><span class="pre">npm</span> <span class="pre">install</span></tt>
+and then <tt class="docutils literal"><span class="pre">grunt</span> <span class="pre">fetch</span></tt>).</p>
+<p>We  use <a class="reference external" href="http://requirejs.org">require.js</a> to keep track of <em>Converse.js</em> and its dependencies and to
+to bundle them together in a single minified file fit for deployment to a
+production site.</p>
+<p>To minify the Javascript and CSS, run the following command:</p>
+<div class="highlight-python"><pre>grunt minify</pre>
+</div>
+<p>Javascript will be bundled and minified with <a class="reference external" href="http://requirejs.org">require.js</a>&#8216;s optimization tool,
+using <a class="reference external" href="https://github.com/jrburke/almond">almond</a>.</p>
+<p>You can <a class="reference external" href="http://requirejs.org/docs/optimization.html">read more about require.js&#8217;s optimizer here</a>.</p>
+<p>CSS is minified via <a class="reference external" href="https://github.com/gruntjs/grunt-contrib-cssmin">cssmin</a>.</p>
+</div>
+</div>
+<div class="section" id="translations">
+<h2><a class="toc-backref" href="#id27">Translations</a><a class="headerlink" href="#translations" title="Permalink to this headline">¶</a></h2>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p class="last">Translations take up a lot of space and will bloat your minified file.
+At the time of writing, all the translations add about 50KB of extra data to
+the minified javascript file. Therefore, make sure to only
+include those languages that you intend to support and remove from
+./locale/locales.js those which you don&#8217;t need. Remember to rebuild the
+minified file afterwards.</p>
+</div>
+<p>The gettext POT file located in ./locale/converse.pot is the template
+containing all translations and from which for each language an individual PO
+file is generated.</p>
+<p>The POT file contains all translateable strings extracted from converse.js.</p>
+<p>To make a user facing string translateable, wrap it in the double underscore helper
+function like so:</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="n">__</span><span class="p">(</span><span class="s">&#39;This string will be translated at runtime&#39;</span><span class="p">);</span>
+</pre></div>
+</div>
+<p>After adding the string, you&#8217;ll need to regenerate the POT file, like so:</p>
+<div class="highlight-python"><pre>make pot</pre>
+</div>
+<p>You can then create or update the PO file for a specific language by doing the following:</p>
+<div class="highlight-python"><pre>msgmerge ./locale/de/LC_MESSAGES/converse.po ./locale/converse.pot -U</pre>
+</div>
+<p>To do this for ALL languages, run:</p>
+<div class="highlight-python"><pre>make merge</pre>
+</div>
+<p>The resulting PO file is then what gets translated.</p>
+<p>If you&#8217;ve created a new PO file, please make sure to add the following
+attributes at the top of the file (under <em>Content-Transfer-Encoding</em>). They are
+required as configuration settings for Jed, the Javascript translations library
+that we&#8217;re using.</p>
+<div class="highlight-python"><div class="highlight"><pre><span class="s">&quot;domain: converse</span><span class="se">\n</span><span class="s">&quot;</span>
+<span class="s">&quot;lang: de</span><span class="se">\n</span><span class="s">&quot;</span>
+<span class="s">&quot;plural_forms: nplurals=2; plural=(n != 1);</span><span class="se">\n</span><span class="s">&quot;</span>
+</pre></div>
+</div>
+<p>Unfortunately <a class="reference external" href="http://slexaxton.github.io/Jed">Jed</a> cannot use the PO files directly. We have to generate from it
+a file in JSON format and then put that in a .js file for the specific
+language.</p>
+<p>To generate JSON from a PO file, you&#8217;ll need po2json for node.js. Run the
+following command to install it (npm being the node.js package manager):</p>
+<div class="highlight-python"><pre>npm install po2json</pre>
+</div>
+<p>You can then convert the translations into JSON format:</p>
+<div class="highlight-python"><pre>po2json locale/de/LC_MESSAGES/converse.po locale/de/LC_MESSAGES/converse.json</pre>
+</div>
+<p>Now from converse.json paste the data as a value for the &#8220;locale_data&#8221; key in the
+object in the language&#8217;s .js file.</p>
+<p>So, if you are for example translating into German (language code &#8216;de&#8217;), you&#8217;ll
+create or update the file ./locale/LC_MESSAGES/de.js with the following code:</p>
+<div class="highlight-python"><pre>(function (root, factory) {
+    define("de", ['jed'], function () {
+        return factory(new Jed({
+            "domain": "converse",
+            "locale_data": {
+                // Paste the JSON data from converse.json here
+            }
+        })
+    }
+}(this, function (i18n) {
+    return i18n;
+}));</pre>
+</div>
+<p>making sure to also paste the JSON data as value to the &#8220;locale_data&#8221; key.</p>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p class="last">If you are adding translations for a new language that is not already supported,
+you&#8217;ll have to make one more edit in ./locale/locales.js to make sure the
+language is loaded by require.js.</p>
+</div>
+<p>Congratulations, you&#8217;ve now succesfully added your translations. Sorry for all
+those hoops you had to jump through.</p>
+</div>
 </div>
 <div class="section" id="troubleshooting">
-<h1><a class="toc-backref" href="#id22">Troubleshooting</a><a class="headerlink" href="#troubleshooting" title="Permalink to this headline">¶</a></h1>
+<h1><a class="toc-backref" href="#id28">Troubleshooting</a><a class="headerlink" href="#troubleshooting" title="Permalink to this headline">¶</a></h1>
 <div class="section" id="conflicts-with-other-javascript-libraries">
-<h2><a class="toc-backref" href="#id23">Conflicts with other Javascript libraries</a><a class="headerlink" href="#conflicts-with-other-javascript-libraries" title="Permalink to this headline">¶</a></h2>
+<h2><a class="toc-backref" href="#id29">Conflicts with other Javascript libraries</a><a class="headerlink" href="#conflicts-with-other-javascript-libraries" title="Permalink to this headline">¶</a></h2>
 <div class="section" id="problem">
-<h3><a class="toc-backref" href="#id24">Problem:</a><a class="headerlink" href="#problem" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id30">Problem:</a><a class="headerlink" href="#problem" title="Permalink to this headline">¶</a></h3>
 <p>You are using other Javascript libraries (like JQuery plugins), and
 get errors like these in your browser console:</p>
 <div class="highlight-python"><pre>Uncaught TypeError: Object [object Object] has no method 'xxx' from example.js</pre>
 </div>
 </div>
 <div class="section" id="solution">
-<h3><a class="toc-backref" href="#id25">Solution:</a><a class="headerlink" href="#solution" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id31">Solution:</a><a class="headerlink" href="#solution" title="Permalink to this headline">¶</a></h3>
 <p>First, find out which object is referred to by <tt class="docutils literal"><span class="pre">Object</span> <span class="pre">[object</span> <span class="pre">Object]</span></tt>.</p>
 <p>It will probably be the jQuery object <tt class="docutils literal"><span class="pre">$</span></tt> or perhaps the underscore.js object <tt class="docutils literal"><span class="pre">_</span></tt>.</p>
 <p>For the purpose of demonstration, I&#8217;m going to assume its <tt class="docutils literal"><span class="pre">$</span></tt>, but the same
@@ -533,11 +679,11 @@ jQuery plugins must load after jQuery).</p>
 </div>
 </div>
 <div class="section" id="events">
-<h1><a class="toc-backref" href="#id26">Events</a><a class="headerlink" href="#events" title="Permalink to this headline">¶</a></h1>
+<h1><a class="toc-backref" href="#id32">Events</a><a class="headerlink" href="#events" title="Permalink to this headline">¶</a></h1>
 <p>Converse.js emits events to which you can subscribe from your own Javascript.</p>
 <p>Concerning events, the following methods are available:</p>
 <div class="section" id="event-methods">
-<h2><a class="toc-backref" href="#id27">Event Methods</a><a class="headerlink" href="#event-methods" title="Permalink to this headline">¶</a></h2>
+<h2><a class="toc-backref" href="#id33">Event Methods</a><a class="headerlink" href="#event-methods" title="Permalink to this headline">¶</a></h2>
 <ul>
 <li><p class="first"><strong>on(eventName, callback)</strong>:</p>
 <blockquote>
@@ -581,7 +727,7 @@ exactly once.</p>
 </ul>
 </div>
 <div class="section" id="event-types">
-<h2><a class="toc-backref" href="#id28">Event Types</a><a class="headerlink" href="#event-types" title="Permalink to this headline">¶</a></h2>
+<h2><a class="toc-backref" href="#id34">Event Types</a><a class="headerlink" href="#event-types" title="Permalink to this headline">¶</a></h2>
 <p>Here are the different events that are emitted:</p>
 <ul>
 <li><p class="first"><strong>onInitialized</strong></p>
@@ -667,7 +813,7 @@ got all its ducks in a row.</p>
 </div>
 </div>
 <div class="section" id="configuration">
-<h1><a class="toc-backref" href="#id29">Configuration</a><a class="headerlink" href="#configuration" title="Permalink to this headline">¶</a></h1>
+<h1><a class="toc-backref" href="#id35">Configuration</a><a class="headerlink" href="#configuration" title="Permalink to this headline">¶</a></h1>
 <p>The included minified JS and CSS files can be used for demoing or testing, but
 you&#8217;ll want to configure <em>Converse.js</em> to suit your needs before you deploy it
 on your website.</p>
@@ -681,9 +827,9 @@ all the available configuration settings.</p>
 JS file so that it will include the new settings. Please refer to the
 <a class="reference internal" href="#minification">Minification</a> section for more info on how to do this.</p>
 <div class="section" id="configuration-variables">
-<h2><a class="toc-backref" href="#id30">Configuration variables</a><a class="headerlink" href="#configuration-variables" title="Permalink to this headline">¶</a></h2>
+<h2><a class="toc-backref" href="#id36">Configuration variables</a><a class="headerlink" href="#configuration-variables" title="Permalink to this headline">¶</a></h2>
 <div class="section" id="allow-contact-requests">
-<h3><a class="toc-backref" href="#id31">allow_contact_requests</a><a class="headerlink" href="#allow-contact-requests" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id37">allow_contact_requests</a><a class="headerlink" href="#allow-contact-requests" title="Permalink to this headline">¶</a></h3>
 <p>Default = <tt class="docutils literal"><span class="pre">true</span></tt></p>
 <p>Allow users to add one another as contacts. If this is set to false, the
 <strong>Add a contact</strong> widget, <strong>Contact Requests</strong> and <strong>Pending Contacts</strong> roster
@@ -691,18 +837,18 @@ sections will all not appear. Additionally, all incoming contact requests will b
 ignored.</p>
 </div>
 <div class="section" id="allow-muc">
-<h3><a class="toc-backref" href="#id32">allow_muc</a><a class="headerlink" href="#allow-muc" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id38">allow_muc</a><a class="headerlink" href="#allow-muc" title="Permalink to this headline">¶</a></h3>
 <p>Default = <tt class="docutils literal"><span class="pre">true</span></tt></p>
 <p>Allow multi-user chat (muc) in chatrooms. Setting this to <tt class="docutils literal"><span class="pre">false</span></tt> will remove
 the <tt class="docutils literal"><span class="pre">Chatrooms</span></tt> tab from the control box.</p>
 </div>
 <div class="section" id="animate">
-<h3><a class="toc-backref" href="#id33">animate</a><a class="headerlink" href="#animate" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id39">animate</a><a class="headerlink" href="#animate" title="Permalink to this headline">¶</a></h3>
 <p>Default = <tt class="docutils literal"><span class="pre">true</span></tt></p>
 <p>Show animations, for example when opening and closing chat boxes.</p>
 </div>
 <div class="section" id="auto-list-rooms">
-<h3><a class="toc-backref" href="#id34">auto_list_rooms</a><a class="headerlink" href="#auto-list-rooms" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id40">auto_list_rooms</a><a class="headerlink" href="#auto-list-rooms" title="Permalink to this headline">¶</a></h3>
 <p>Default = <tt class="docutils literal"><span class="pre">false</span></tt></p>
 <p>If true, and the XMPP server on which the current user is logged in supports
 multi-user chat, then a list of rooms on that server will be fetched.</p>
@@ -711,41 +857,74 @@ multi-user chat, then a list of rooms on that server will be fetched.</p>
 features, number of occupants etc.), so on servers with many rooms this
 option will create lots of extra connection traffic.</p>
 </div>
+<div class="section" id="auto-reconnect">
+<h3><a class="toc-backref" href="#id41">auto_reconnect</a><a class="headerlink" href="#auto-reconnect" title="Permalink to this headline">¶</a></h3>
+<p>Default = <tt class="docutils literal"><span class="pre">true</span></tt></p>
+<p>Automatically reconnect to the XMPP server if the connection drops
+unexpectedly.</p>
+</div>
 <div class="section" id="auto-subscribe">
-<h3><a class="toc-backref" href="#id35">auto_subscribe</a><a class="headerlink" href="#auto-subscribe" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id42">auto_subscribe</a><a class="headerlink" href="#auto-subscribe" title="Permalink to this headline">¶</a></h3>
 <p>Default = <tt class="docutils literal"><span class="pre">false</span></tt></p>
 <p>If true, the user will automatically subscribe back to any contact requests.</p>
 </div>
 <div class="section" id="bosh-service-url">
-<h3><a class="toc-backref" href="#id36">bosh_service_url</a><a class="headerlink" href="#bosh-service-url" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id43">bosh_service_url</a><a class="headerlink" href="#bosh-service-url" title="Permalink to this headline">¶</a></h3>
 <p>Connections to an XMPP server depend on a BOSH connection manager which acts as
 a middle man between HTTP and XMPP.</p>
 <p>See <a class="reference external" href="http://metajack.im/2008/09/08/which-bosh-server-do-you-need">here</a> for more information.</p>
 </div>
+<div class="section" id="cache-otr-key">
+<h3><a class="toc-backref" href="#id44">cache_otr_key</a><a class="headerlink" href="#cache-otr-key" title="Permalink to this headline">¶</a></h3>
+<p>Default = <tt class="docutils literal"><span class="pre">false</span></tt></p>
+<p>Let the <a class="reference external" href="https://otr.cypherpunks.ca">OTR (Off-the-record encryption)</a> private
+key be cached in your browser&#8217;s session storage.</p>
+<p>The browser&#8217;s session storage persists across page loads but is deleted once
+the tab or window is closed.</p>
+<p>If this option is set to <tt class="docutils literal"><span class="pre">false</span></tt>, a new OTR private key will be generated
+for each page load. While more inconvenient, this is a much more secure option.</p>
+<p>This setting can only be used together with <tt class="docutils literal"><span class="pre">allow_otr</span> <span class="pre">=</span> <span class="pre">true</span></tt>.</p>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p class="last">A browser window&#8217;s session storage is accessible by all javascript that
+is served from the same domain. So if there is malicious javascript served by
+the same server (or somehow injected via an attacker), then they will be able
+to retrieve your private key and read your all the chat messages in your
+current session. Previous sessions however cannot be decrypted.</p>
+</div>
+</div>
 <div class="section" id="debug">
-<h3><a class="toc-backref" href="#id37">debug</a><a class="headerlink" href="#debug" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id45">debug</a><a class="headerlink" href="#debug" title="Permalink to this headline">¶</a></h3>
 <p>Default = <tt class="docutils literal"><span class="pre">false</span></tt></p>
 <p>If set to true, debugging output will be logged to the browser console.</p>
 </div>
+<div class="section" id="expose-rid-and-sid">
+<h3><a class="toc-backref" href="#id46">expose_rid_and_sid</a><a class="headerlink" href="#expose-rid-and-sid" title="Permalink to this headline">¶</a></h3>
+<p>Allow the prebind tokens, RID (request ID) and SID (session ID), to be exposed
+globally via the API. This allows other scripts served on the same page to use
+these values.</p>
+<p><em>Beware</em>: a malicious script could use these tokens to assume your identity
+and inject fake chat messages.</p>
+</div>
 <div class="section" id="fullname">
-<h3><a class="toc-backref" href="#id38">fullname</a><a class="headerlink" href="#fullname" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id47">fullname</a><a class="headerlink" href="#fullname" title="Permalink to this headline">¶</a></h3>
 <p>If you are using prebinding, can specify the fullname of the currently
 logged in user, otherwise the user&#8217;s vCard will be fetched.</p>
 </div>
 <div class="section" id="hide-muc-server">
-<h3><a class="toc-backref" href="#id39">hide_muc_server</a><a class="headerlink" href="#hide-muc-server" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id48">hide_muc_server</a><a class="headerlink" href="#hide-muc-server" title="Permalink to this headline">¶</a></h3>
 <p>Default = <tt class="docutils literal"><span class="pre">false</span></tt></p>
 <p>Hide the <tt class="docutils literal"><span class="pre">server</span></tt> input field of the form inside the <tt class="docutils literal"><span class="pre">Room</span></tt> panel of the
 controlbox. Useful if you want to restrict users to a specific XMPP server of
 your choosing.</p>
 </div>
 <div class="section" id="i18n">
-<h3><a class="toc-backref" href="#id40">i18n</a><a class="headerlink" href="#i18n" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id49">i18n</a><a class="headerlink" href="#i18n" title="Permalink to this headline">¶</a></h3>
 <p>Specify the locale/language. The language must be in the <tt class="docutils literal"><span class="pre">locales</span></tt> object. Refer to
 <tt class="docutils literal"><span class="pre">./locale/locales.js</span></tt> to see which locales are supported.</p>
 </div>
 <div class="section" id="prebind">
-<h3><a class="toc-backref" href="#id41">prebind</a><a class="headerlink" href="#prebind" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id50">prebind</a><a class="headerlink" href="#prebind" title="Permalink to this headline">¶</a></h3>
 <p>Default = <tt class="docutils literal"><span class="pre">false</span></tt></p>
 <p>Use this option when you want to attach to an existing XMPP connection that was
 already authenticated (usually on the backend before page load).</p>
@@ -758,7 +937,7 @@ values as <tt class="docutils literal"><span class="pre">jid</span></tt>, <tt cl
 <p>Additionally, you have to specify <tt class="docutils literal"><span class="pre">bosh_service_url</span></tt>.</p>
 </div>
 <div class="section" id="show-controlbox-by-default">
-<h3><a class="toc-backref" href="#id42">show_controlbox_by_default</a><a class="headerlink" href="#show-controlbox-by-default" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id51">show_controlbox_by_default</a><a class="headerlink" href="#show-controlbox-by-default" title="Permalink to this headline">¶</a></h3>
 <p>Default = <tt class="docutils literal"><span class="pre">false</span></tt></p>
 <p>The &#8220;controlbox&#8221; refers to the special chatbox containing your contacts roster,
 status widget, chatrooms and other controls.</p>
@@ -767,21 +946,41 @@ the page with class <em>toggle-online-users</em>.</p>
 <p>If this options is set to true, the controlbox will by default be shown upon
 page load.</p>
 </div>
+<div class="section" id="show-call-button">
+<h3><a class="toc-backref" href="#id52">show_call_button</a><a class="headerlink" href="#show-call-button" title="Permalink to this headline">¶</a></h3>
+<p>Default = <tt class="docutils literal"><span class="pre">false</span></tt></p>
+<p>Enable to display a call button on the chatbox toolbar.</p>
+<p>When the call button is pressed, it will emit an event that can be used by a third-party library to initiate a call.</p>
+<div class="highlight-python"><pre>converse.on('onCallButtonClicked', function(event, data) {
+    console.log('Call button was clicked.');
+    console.log('Strophe connection is', data.connection);
+    console.log('Bare buddy JID is', data.model.get('jid'));
+
+    // ... Third-party library code ...
+});</pre>
+</div>
+</div>
 <div class="section" id="show-only-online-users">
-<h3><a class="toc-backref" href="#id43">show_only_online_users</a><a class="headerlink" href="#show-only-online-users" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id53">show_only_online_users</a><a class="headerlink" href="#show-only-online-users" title="Permalink to this headline">¶</a></h3>
 <p>Default = <tt class="docutils literal"><span class="pre">false</span></tt></p>
 <p>If set to <tt class="docutils literal"><span class="pre">true</span></tt>, only online users will be shown in the contacts roster.
 Users with any other status (e.g. away, busy etc.) will not be shown.</p>
 </div>
+<div class="section" id="use-otr-by-default">
+<h3><a class="toc-backref" href="#id54">use_otr_by_default</a><a class="headerlink" href="#use-otr-by-default" title="Permalink to this headline">¶</a></h3>
+<p>Default = <tt class="docutils literal"><span class="pre">false</span></tt></p>
+<p>If set to <tt class="docutils literal"><span class="pre">true</span></tt>, Converse.js will automatically try to initiate an OTR (off-the-record)
+encrypted chat session every time you open a chat box.</p>
+</div>
 <div class="section" id="use-vcards">
-<h3><a class="toc-backref" href="#id44">use_vcards</a><a class="headerlink" href="#use-vcards" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id55">use_vcards</a><a class="headerlink" href="#use-vcards" title="Permalink to this headline">¶</a></h3>
 <p>Default = <tt class="docutils literal"><span class="pre">true</span></tt></p>
 <p>Determines whether the XMPP server will be queried for roster contacts&#8217; VCards
 or not. VCards contain extra personal information such as your fullname and
 avatar image.</p>
 </div>
 <div class="section" id="xhr-custom-status">
-<h3><a class="toc-backref" href="#id45">xhr_custom_status</a><a class="headerlink" href="#xhr-custom-status" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id56">xhr_custom_status</a><a class="headerlink" href="#xhr-custom-status" title="Permalink to this headline">¶</a></h3>
 <p>Default = <tt class="docutils literal"><span class="pre">false</span></tt></p>
 <div class="admonition note">
 <p class="first admonition-title">Note</p>
@@ -791,7 +990,7 @@ avatar image.</p>
 remote server.</p>
 </div>
 <div class="section" id="xhr-custom-status-url">
-<h3><a class="toc-backref" href="#id46">xhr_custom_status_url</a><a class="headerlink" href="#xhr-custom-status-url" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id57">xhr_custom_status_url</a><a class="headerlink" href="#xhr-custom-status-url" title="Permalink to this headline">¶</a></h3>
 <div class="admonition note">
 <p class="first admonition-title">Note</p>
 <p class="last">XHR stands for XMLHTTPRequest, and is meant here in the AJAX sense (Asynchronous Javascript and XML).</p>
@@ -803,7 +1002,7 @@ message will be made.</p>
 <p>The message itself is sent in the request under the key <tt class="docutils literal"><span class="pre">msg</span></tt>.</p>
 </div>
 <div class="section" id="xhr-user-search">
-<h3><a class="toc-backref" href="#id47">xhr_user_search</a><a class="headerlink" href="#xhr-user-search" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id58">xhr_user_search</a><a class="headerlink" href="#xhr-user-search" title="Permalink to this headline">¶</a></h3>
 <p>Default = <tt class="docutils literal"><span class="pre">false</span></tt></p>
 <div class="admonition note">
 <p class="first admonition-title">Note</p>
@@ -820,7 +1019,7 @@ message will be made.</p>
 corresponds to a matched user and needs the keys <tt class="docutils literal"><span class="pre">id</span></tt> and <tt class="docutils literal"><span class="pre">fullname</span></tt>.</p>
 </div>
 <div class="section" id="xhr-user-search-url">
-<h3><a class="toc-backref" href="#id48">xhr_user_search_url</a><a class="headerlink" href="#xhr-user-search-url" title="Permalink to this headline">¶</a></h3>
+<h3><a class="toc-backref" href="#id59">xhr_user_search_url</a><a class="headerlink" href="#xhr-user-search-url" title="Permalink to this headline">¶</a></h3>
 <div class="admonition note">
 <p class="first admonition-title">Note</p>
 <p class="last">XHR stands for XMLHTTPRequest, and is meant here in the AJAX sense (Asynchronous Javascript and XML).</p>
@@ -831,101 +1030,6 @@ corresponds to a matched user and needs the keys <tt class="docutils literal"><s
 The query string will be included in the request with <tt class="docutils literal"><span class="pre">q</span></tt> as its key.</p>
 </div>
 </div>
-</div>
-<div class="section" id="minification">
-<h1><a class="toc-backref" href="#id49">Minification</a><a class="headerlink" href="#minification" title="Permalink to this headline">¶</a></h1>
-<div class="section" id="minifying-javascript-and-css">
-<h2><a class="toc-backref" href="#id50">Minifying Javascript and CSS</a><a class="headerlink" href="#minifying-javascript-and-css" title="Permalink to this headline">¶</a></h2>
-<p>Please make sure to read the section <a class="reference internal" href="#development">Development</a> and that you have installed
-all development dependencies (long story short, you can run <tt class="docutils literal"><span class="pre">npm</span> <span class="pre">install</span></tt>
-and then <tt class="docutils literal"><span class="pre">grunt</span> <span class="pre">fetch</span></tt>).</p>
-<p>We  use <a class="reference external" href="http://requirejs.org">require.js</a> to keep track of <em>Converse.js</em> and its dependencies and to
-to bundle them together in a single minified file fit for deployment to a
-production site.</p>
-<p>To minify the Javascript and CSS, run the following command:</p>
-<div class="highlight-python"><pre>grunt minify</pre>
-</div>
-<p>Javascript will be bundled and minified with <a class="reference external" href="http://requirejs.org">require.js</a>&#8216;s optimization tool,
-using <a class="reference external" href="https://github.com/jrburke/almond">almond</a>.</p>
-<p>You can <a class="reference external" href="http://requirejs.org/docs/optimization.html">read more about require.js&#8217;s optimizer here</a>.</p>
-<p>CSS is minified via <a class="reference external" href="https://github.com/gruntjs/grunt-contrib-cssmin">cssmin</a>.</p>
-</div>
-</div>
-<div class="section" id="translations">
-<h1><a class="toc-backref" href="#id51">Translations</a><a class="headerlink" href="#translations" title="Permalink to this headline">¶</a></h1>
-<div class="admonition note">
-<p class="first admonition-title">Note</p>
-<p class="last">Translations take up a lot of space and will bloat your minified file.
-At the time of writing, all the translations add about 50KB of extra data to
-the minified javascript file. Therefore, make sure to only
-include those languages that you intend to support and remove from
-./locale/locales.js those which you don&#8217;t need. Remember to rebuild the
-minified file afterwards.</p>
-</div>
-<p>The gettext POT file located in ./locale/converse.pot is the template
-containing all translations and from which for each language an individual PO
-file is generated.</p>
-<p>The POT file contains all translateable strings extracted from converse.js.</p>
-<p>To make a user facing string translateable, wrap it in the double underscore helper
-function like so:</p>
-<div class="highlight-python"><div class="highlight"><pre><span class="n">__</span><span class="p">(</span><span class="s">&#39;This string will be translated at runtime&#39;</span><span class="p">);</span>
-</pre></div>
-</div>
-<p>After adding the string, you&#8217;ll need to regenerate the POT file, like so:</p>
-<div class="highlight-python"><pre>make pot</pre>
-</div>
-<p>You can then create or update the PO file for a specific language by doing the following:</p>
-<div class="highlight-python"><pre>msgmerge ./locale/de/LC_MESSAGES/converse.po ./locale/converse.pot -U</pre>
-</div>
-<p>To do this for ALL languages, run:</p>
-<div class="highlight-python"><pre>make merge</pre>
-</div>
-<p>The resulting PO file is then what gets translated.</p>
-<p>If you&#8217;ve created a new PO file, please make sure to add the following
-attributes at the top of the file (under <em>Content-Transfer-Encoding</em>). They are
-required as configuration settings for Jed, the Javascript translations library
-that we&#8217;re using.</p>
-<div class="highlight-python"><div class="highlight"><pre><span class="s">&quot;domain: converse</span><span class="se">\n</span><span class="s">&quot;</span>
-<span class="s">&quot;lang: de</span><span class="se">\n</span><span class="s">&quot;</span>
-<span class="s">&quot;plural_forms: nplurals=2; plural=(n != 1);</span><span class="se">\n</span><span class="s">&quot;</span>
-</pre></div>
-</div>
-<p>Unfortunately <a class="reference external" href="http://slexaxton.github.io/Jed">Jed</a> cannot use the PO files directly. We have to generate from it
-a file in JSON format and then put that in a .js file for the specific
-language.</p>
-<p>To generate JSON from a PO file, you&#8217;ll need po2json for node.js. Run the
-following command to install it (npm being the node.js package manager):</p>
-<div class="highlight-python"><pre>npm install po2json</pre>
-</div>
-<p>You can then convert the translations into JSON format:</p>
-<div class="highlight-python"><pre>po2json locale/de/LC_MESSAGES/converse.po locale/de/LC_MESSAGES/converse.json</pre>
-</div>
-<p>Now from converse.json paste the data as a value for the &#8220;locale_data&#8221; key in the
-object in the language&#8217;s .js file.</p>
-<p>So, if you are for example translating into German (language code &#8216;de&#8217;), you&#8217;ll
-create or update the file ./locale/LC_MESSAGES/de.js with the following code:</p>
-<div class="highlight-python"><pre>(function (root, factory) {
-    define("de", ['jed'], function () {
-        return factory(new Jed({
-            "domain": "converse",
-            "locale_data": {
-                // Paste the JSON data from converse.json here
-            }
-        })
-    }
-}(this, function (i18n) {
-    return i18n;
-}));</pre>
-</div>
-<p>making sure to also paste the JSON data as value to the &#8220;locale_data&#8221; key.</p>
-<div class="admonition note">
-<p class="first admonition-title">Note</p>
-<p class="last">If you are adding translations for a new language that is not already supported,
-you&#8217;ll have to make one more edit in ./locale/locales.js to make sure the
-language is loaded by require.js.</p>
-</div>
-<p>Congratulations, you&#8217;ve now succesfully added your translations. Sorry for all
-those hoops you had to jump through.</p>
 </div>
 
 
@@ -941,7 +1045,7 @@ those hoops you had to jump through.</p>
         <li class="right" style="margin-right: 10px">
           <a href="genindex.html" title="General Index"
              >index</a></li>
-        <li><a href="#">Converse.js 0.7.1 documentation</a> &raquo;</li> 
+        <li><a href="#">Converse.js 0.7.3 documentation</a> &raquo;</li> 
       </ul>
     </div>
 </div>

+ 1 - 1
docs/html/objects.inv

@@ -1,6 +1,6 @@
 # Sphinx inventory version 2
 # Project: Converse.js
-# Version: 0.7.1
+# Version: 0.7.3
 # The remainder of this file is compressed using zlib.
 xÚmÎÁ
 à à{Ÿ"°³ƒ]÷;

+ 5 - 5
docs/html/search.html

@@ -7,7 +7,7 @@
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
     
-    <title>Search &mdash; Converse.js 0.7.1 documentation</title>
+    <title>Search &mdash; Converse.js 0.7.3 documentation</title>
     
     <link rel="stylesheet" href="_static/stylesheet.css" type="text/css" />
     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@@ -15,7 +15,7 @@
     <script type="text/javascript">
       var DOCUMENTATION_OPTIONS = {
         URL_ROOT:    '',
-        VERSION:     '0.7.1',
+        VERSION:     '0.7.3',
         COLLAPSE_INDEX: false,
         FILE_SUFFIX: '.html',
         HAS_SOURCE:  true
@@ -25,7 +25,7 @@
     <script type="text/javascript" src="_static/underscore.js"></script>
     <script type="text/javascript" src="_static/doctools.js"></script>
     <script type="text/javascript" src="_static/searchtools.js"></script>
-    <link rel="top" title="Converse.js 0.7.1 documentation" href="index.html" />
+    <link rel="top" title="Converse.js 0.7.3 documentation" href="index.html" />
   <script type="text/javascript">
     jQuery(function() { Search.loadIndex("searchindex.js"); });
   </script>
@@ -55,7 +55,7 @@
         <li class="right" style="margin-right: 10px">
           <a href="genindex.html" title="General Index"
              accesskey="I">index</a></li>
-        <li><a href="index.html">Converse.js 0.7.1 documentation</a> &raquo;</li> 
+        <li><a href="index.html">Converse.js 0.7.3 documentation</a> &raquo;</li> 
       </ul>
     </div>
 <section id="main_content" class="inner">  
@@ -100,7 +100,7 @@
         <li class="right" style="margin-right: 10px">
           <a href="genindex.html" title="General Index"
              >index</a></li>
-        <li><a href="index.html">Converse.js 0.7.1 documentation</a> &raquo;</li> 
+        <li><a href="index.html">Converse.js 0.7.3 documentation</a> &raquo;</li> 
       </ul>
     </div>
 </div>

Plik diff jest za duży
+ 0 - 0
docs/html/searchindex.js


+ 2 - 2
docs/source/conf.py

@@ -48,9 +48,9 @@ copyright = u'2013, JC Brand'
 # built documents.
 #
 # The short X.Y version.
-version = '0.7.2'
+version = '0.7.3'
 # The full version, including alpha/beta/rc tags.
-release = '0.7.2'
+release = '0.7.3'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.

+ 226 - 135
docs/source/index.rst

@@ -277,6 +277,17 @@ These values are then passed to converse.js's ``initialize`` method.
    **bosh_service_url** values.
 
 
+Example code for server-side prebinding
+---------------------------------------
+
+* PHP: 
+    See `xmpp-prebind-php <https://github.com/candy-chat/xmpp-prebind-php>`_ by
+    Michael Weibel and the folks from Candy chat.
+
+* Python:
+    See this `example Django application`_ by Jack Moffitt.
+
+
 Setting up a BOSH server
 ------------------------
 
@@ -295,7 +306,6 @@ Facebook integration
     this myself. Feedback and patches from people who have succesfully done this
     will be appreciated.
 
-
 Converse.js uses `Strophe.js <http://strophe.im/strophejs>`_ to connect and
 communicate with the XMPP server. One nice thing about Strophe.js is that it
 can be extended via `plugins <http://github.com/strophe/strophejs-plugins>`_.
@@ -339,6 +349,39 @@ The connection is already created inside Converse.js, so the
 If someone submits a sane patch that does the above, I'll be happy to merge it.
 Until then, people will have to do this themselves.
 
+========
+Features
+========
+
+Off-the-record encryption
+=========================
+
+Converse.js supports `Off-the-record (OTR) <https://otr.cypherpunks.ca/>`_
+encrypted messaging.
+
+The OTR protocol not only **encrypts your messages**, it provides ways to
+**verify the identity** of the person you are talking to,
+**plausible deniability** and **perfect forward secrecy** by generating
+new encryption keys for each conversation.
+
+In its current state, Javascript cryptography is fraught with dangers and
+challenges that make it impossible to reach the same standard of security that
+is available with native "desktop" software.
+
+This is due to its runtime malleability, the way it is "installed" (e.g.
+served) and the browser's lack of cryptographic primitives needed to implement
+secure crypto.
+
+For harsh but fairly valid criticism of Javascript cryptography, read:
+`Javascript Cryptography Considered Harmful <http://www.matasano.com/articles/javascript-cryptography/>`_.
+
+To get an idea on how this applies to OTR support in Converse.js, please read
+`my thoughts on it <https://opkode.com/media/blog/2013/11/11/conversejs-otr-support>`_.
+
+For now, suffice to say that although its useful to have OTR support in
+Converse.js in order to avoid most eavesdroppers, if you need serious
+communications privacy, then you're much better off using native software.
+
 ===========
 Development
 ===========
@@ -387,6 +430,7 @@ If you don't have grunt installed globally, you need to specify the relative
 path:
 
 ::
+
     ./node_modules/.bin/grunt fetch
 
 This will call Bower in the background to fetch all the front-end
@@ -467,6 +511,137 @@ You can run both the tests and jshint in one go by calling:
 
     grunt check
 
+Minification
+============
+
+Minifying Javascript and CSS
+----------------------------
+
+Please make sure to read the section `Development`_ and that you have installed
+all development dependencies (long story short, you can run ``npm install``
+and then ``grunt fetch``).
+
+We  use `require.js`_ to keep track of *Converse.js* and its dependencies and to
+to bundle them together in a single minified file fit for deployment to a
+production site.
+
+To minify the Javascript and CSS, run the following command:
+
+::
+
+    grunt minify
+
+Javascript will be bundled and minified with `require.js`_'s optimization tool,
+using `almond <https://github.com/jrburke/almond>`_.
+
+You can `read more about require.js's optimizer here`_.
+
+CSS is minified via `cssmin <https://github.com/gruntjs/grunt-contrib-cssmin>`_.
+
+Translations
+============
+
+.. Note ::
+   Translations take up a lot of space and will bloat your minified file.
+   At the time of writing, all the translations add about 50KB of extra data to
+   the minified javascript file. Therefore, make sure to only
+   include those languages that you intend to support and remove from
+   ./locale/locales.js those which you don't need. Remember to rebuild the
+   minified file afterwards.
+
+The gettext POT file located in ./locale/converse.pot is the template
+containing all translations and from which for each language an individual PO
+file is generated.
+
+The POT file contains all translateable strings extracted from converse.js.
+
+To make a user facing string translateable, wrap it in the double underscore helper
+function like so:
+
+::
+
+    __('This string will be translated at runtime');
+
+After adding the string, you'll need to regenerate the POT file, like so:
+
+::
+
+    make pot
+
+You can then create or update the PO file for a specific language by doing the following:
+
+::
+
+    msgmerge ./locale/de/LC_MESSAGES/converse.po ./locale/converse.pot -U
+
+To do this for ALL languages, run:
+
+::
+
+    make merge
+
+The resulting PO file is then what gets translated.
+
+If you've created a new PO file, please make sure to add the following
+attributes at the top of the file (under *Content-Transfer-Encoding*). They are
+required as configuration settings for Jed, the Javascript translations library
+that we're using.
+
+::
+
+    "domain: converse\n"
+    "lang: de\n"
+    "plural_forms: nplurals=2; plural=(n != 1);\n"
+
+
+Unfortunately `Jed <http://slexaxton.github.io/Jed>`_ cannot use the PO files directly. We have to generate from it
+a file in JSON format and then put that in a .js file for the specific
+language.
+
+To generate JSON from a PO file, you'll need po2json for node.js. Run the
+following command to install it (npm being the node.js package manager):
+
+::
+
+    npm install po2json
+
+You can then convert the translations into JSON format:
+
+::
+
+    po2json locale/de/LC_MESSAGES/converse.po locale/de/LC_MESSAGES/converse.json
+
+Now from converse.json paste the data as a value for the "locale_data" key in the
+object in the language's .js file.
+
+So, if you are for example translating into German (language code 'de'), you'll
+create or update the file ./locale/LC_MESSAGES/de.js with the following code:
+
+::
+
+    (function (root, factory) {
+        define("de", ['jed'], function () {
+            return factory(new Jed({
+                "domain": "converse",
+                "locale_data": {
+                    // Paste the JSON data from converse.json here
+                }
+            })
+        }
+    }(this, function (i18n) {
+        return i18n;
+    }));
+
+making sure to also paste the JSON data as value to the "locale_data" key.
+
+.. Note ::
+    If you are adding translations for a new language that is not already supported,
+    you'll have to make one more edit in ./locale/locales.js to make sure the
+    language is loaded by require.js.
+
+Congratulations, you've now succesfully added your translations. Sorry for all
+those hoops you had to jump through.
+
 
 ===============
 Troubleshooting
@@ -736,6 +911,14 @@ For each room on the server a query is made to fetch further details (e.g.
 features, number of occupants etc.), so on servers with many rooms this
 option will create lots of extra connection traffic.
 
+auto_reconnect
+--------------
+
+Default = ``true``
+
+Automatically reconnect to the XMPP server if the connection drops
+unexpectedly.
+
 auto_subscribe
 --------------
 
@@ -751,6 +934,30 @@ a middle man between HTTP and XMPP.
 
 See `here <http://metajack.im/2008/09/08/which-bosh-server-do-you-need>`_ for more information.
 
+cache_otr_key
+-------------
+
+Default = ``false``
+
+Let the `OTR (Off-the-record encryption) <https://otr.cypherpunks.ca>`_ private
+key be cached in your browser's session storage.
+
+The browser's session storage persists across page loads but is deleted once
+the tab or window is closed.
+
+If this option is set to ``false``, a new OTR private key will be generated
+for each page load. While more inconvenient, this is a much more secure option.
+
+This setting can only be used together with ``allow_otr = true``.
+
+
+.. Note :: 
+    A browser window's session storage is accessible by all javascript that
+    is served from the same domain. So if there is malicious javascript served by
+    the same server (or somehow injected via an attacker), then they will be able
+    to retrieve your private key and read your all the chat messages in your
+    current session. Previous sessions however cannot be decrypted.
+
 debug
 -----
 
@@ -758,6 +965,16 @@ Default = ``false``
 
 If set to true, debugging output will be logged to the browser console.
 
+expose_rid_and_sid
+------------------
+
+Allow the prebind tokens, RID (request ID) and SID (session ID), to be exposed
+globally via the API. This allows other scripts served on the same page to use
+these values. 
+
+*Beware*: a malicious script could use these tokens to assume your identity
+and inject fake chat messages.
+
 fullname
 --------
 
@@ -843,6 +1060,14 @@ Default = ``false``
 If set to ``true``, only online users will be shown in the contacts roster.
 Users with any other status (e.g. away, busy etc.) will not be shown.
 
+use_otr_by_default
+------------------
+
+Default = ``false``
+
+If set to ``true``, Converse.js will automatically try to initiate an OTR (off-the-record)
+encrypted chat session every time you open a chat box.
+
 use_vcards
 ----------
 
@@ -911,140 +1136,6 @@ Used only in conjunction with ``xhr_user_search``.
 This is the URL to which an AJAX GET request will be made to fetch user data from your remote server.
 The query string will be included in the request with ``q`` as its key.
 
-============
-Minification
-============
-
-Minifying Javascript and CSS
-============================
-
-Please make sure to read the section `Development`_ and that you have installed
-all development dependencies (long story short, you can run ``npm install``
-and then ``grunt fetch``).
-
-We  use `require.js`_ to keep track of *Converse.js* and its dependencies and to
-to bundle them together in a single minified file fit for deployment to a
-production site.
-
-To minify the Javascript and CSS, run the following command:
-
-::
-
-    grunt minify
-
-Javascript will be bundled and minified with `require.js`_'s optimization tool,
-using `almond <https://github.com/jrburke/almond>`_.
-
-You can `read more about require.js's optimizer here`_.
-
-CSS is minified via `cssmin <https://github.com/gruntjs/grunt-contrib-cssmin>`_.
-
-
-============
-Translations
-============
-
-.. Note ::
-   Translations take up a lot of space and will bloat your minified file.
-   At the time of writing, all the translations add about 50KB of extra data to
-   the minified javascript file. Therefore, make sure to only
-   include those languages that you intend to support and remove from
-   ./locale/locales.js those which you don't need. Remember to rebuild the
-   minified file afterwards.
-
-The gettext POT file located in ./locale/converse.pot is the template
-containing all translations and from which for each language an individual PO
-file is generated.
-
-The POT file contains all translateable strings extracted from converse.js.
-
-To make a user facing string translateable, wrap it in the double underscore helper
-function like so:
-
-::
-
-    __('This string will be translated at runtime');
-
-After adding the string, you'll need to regenerate the POT file, like so:
-
-::
-
-    make pot
-
-You can then create or update the PO file for a specific language by doing the following:
-
-::
-
-    msgmerge ./locale/de/LC_MESSAGES/converse.po ./locale/converse.pot -U
-
-To do this for ALL languages, run:
-
-::
-
-    make merge
-
-The resulting PO file is then what gets translated.
-
-If you've created a new PO file, please make sure to add the following
-attributes at the top of the file (under *Content-Transfer-Encoding*). They are
-required as configuration settings for Jed, the Javascript translations library
-that we're using.
-
-::
-
-    "domain: converse\n"
-    "lang: de\n"
-    "plural_forms: nplurals=2; plural=(n != 1);\n"
-
-
-Unfortunately `Jed <http://slexaxton.github.io/Jed>`_ cannot use the PO files directly. We have to generate from it
-a file in JSON format and then put that in a .js file for the specific
-language.
-
-To generate JSON from a PO file, you'll need po2json for node.js. Run the
-following command to install it (npm being the node.js package manager):
-
-::
-
-    npm install po2json
-
-You can then convert the translations into JSON format:
-
-::
-
-    po2json locale/de/LC_MESSAGES/converse.po locale/de/LC_MESSAGES/converse.json
-
-Now from converse.json paste the data as a value for the "locale_data" key in the
-object in the language's .js file.
-
-So, if you are for example translating into German (language code 'de'), you'll
-create or update the file ./locale/LC_MESSAGES/de.js with the following code:
-
-::
-
-    (function (root, factory) {
-        define("de", ['jed'], function () {
-            return factory(new Jed({
-                "domain": "converse",
-                "locale_data": {
-                    // Paste the JSON data from converse.json here
-                }
-            })
-        }
-    }(this, function (i18n) {
-        return i18n;
-    }));
-
-making sure to also paste the JSON data as value to the "locale_data" key.
-
-.. Note ::
-    If you are adding translations for a new language that is not already supported,
-    you'll have to make one more edit in ./locale/locales.js to make sure the
-    language is loaded by require.js.
-
-Congratulations, you've now succesfully added your translations. Sorry for all
-those hoops you had to jump through.
-
 .. _`read more about require.js's optimizer here`: http://requirejs.org/docs/optimization.html
 .. _`HTTP`: https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol
 .. _`XMPP`: https://en.wikipedia.org/wiki/Xmpp

+ 14 - 6
index.html

@@ -7,8 +7,8 @@
     <meta name="description" content="Converse.js: Open Source Browser-Based Instant Messaging" />
     <link rel="stylesheet" type="text/css" media="screen" href="stylesheets/stylesheet.css">
     <link rel="stylesheet" type="text/css" media="screen" href="converse.css">
-    <script data-main="main" src="components/requirejs/require.js"></script>
-    <!--<script src="builds/converse.min.js"></script>-->
+    <!--<script data-main="main" src="components/requirejs/require.js"></script>-->
+    <script src="builds/converse.min.js"></script>
     <title>Converse.js</title>
 </head>
 
@@ -54,7 +54,7 @@
         <li>Custom status messages</li>
         <li>Typing notifications</li>
         <li>Third person messages (/me )</li>
-        <li>Translated into multiple languages  (af, de, es, fr, hu, it, nl, pt-BR, ru)</li>
+        <li>Translated into multiple languages  (af, de, en, es, fr, he, hu, id, it, ja, nl, pt_BR, ru)</li>
         <li>Off-the-record encryption (via <a href="http://arlolra.github.io/otr/" target="_blank">OTR.js</a>)</li>
     </ul>
 
@@ -159,9 +159,17 @@
     You can:
     <ul>
         <li>Follow me on <a href="http://twitter.com/jcopkode" target="_blank">Twitter</a></li>
-        <li>Chat via <a href="xmpp:jc@opkode.com" class="xmpp JSnocheck" title="XMPP/Jabber">XMPP/Jabber</a></li>
-        <li>Send me an email via this <a href="http://opkode.com/contact" target="_blank">contact form</a>.</li>
+        <li>Chat with me via XMPP: <a href="xmpp:jc@opkode.com" class="xmpp JSnocheck" title="XMPP/Jabber">jc@opkode.com</a></li>
     <ul>
+    <p>
+        For <strong>support queries</strong>, please write to the mailing list: <a href="mailto:conversejs@librelist.com">conversejs@librelist.com</a>
+    </p>
+    <p>
+        Please <a target="_blank" href="https://github.com/jcbrand/converse.js/issues">file <strong>bugs</strong> on Github</a>.
+    </p>
+    <p>
+        I'm available for special features and consulting work. Please <a href="http://opkode.com/contact" target="_blank">contact me here</a>.
+    </p>
 </section>
 </div>
 
@@ -186,7 +194,7 @@
             allow_otr: true,
             auto_list_rooms: false,
             auto_subscribe: false,
-            bosh_service_url: 'http://devbox:8890/http-bind', // Please use this connection manager only for testing purposes
+            bosh_service_url: 'https://bind.opkode.im', // Please use this connection manager only for testing purposes
             debug: true ,
             hide_muc_server: false,
             i18n: locales['en'], // Refer to ./locale/locales.js to see which locales are supported

+ 171 - 171
locale/converse.pot

@@ -6,9 +6,9 @@
 #, fuzzy
 msgid ""
 msgstr ""
-"Project-Id-Version: Converse.js 0.4\n"
+"Project-Id-Version: Converse.js 0.7.0\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2013-09-15 22:06+0200\n"
+"POT-Creation-Date: 2014-01-28 03:50+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,66 +17,94 @@ msgstr ""
 "Content-Type: text/plain; charset=CHARSET\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: converse.js:125
+#: converse.js:217
 msgid "unencrypted"
 msgstr ""
 
-#: converse.js:126
+#: converse.js:218
 msgid "unverified"
 msgstr ""
 
-#: converse.js:127
+#: converse.js:219
 msgid "verified"
 msgstr ""
 
-#: converse.js:128
+#: converse.js:220
 msgid "finished"
 msgstr ""
 
-#: converse.js:161
+#: converse.js:223
+msgid "This contact is busy"
+msgstr ""
+
+#: converse.js:224
+msgid "This contact is online"
+msgstr ""
+
+#: converse.js:225
+msgid "This contact is offline"
+msgstr ""
+
+#: converse.js:226
+msgid "This contact is unavailable"
+msgstr ""
+
+#: converse.js:227
+msgid "This contact is away for an extended period"
+msgstr ""
+
+#: converse.js:228
+msgid "This contact is away"
+msgstr ""
+
+#: converse.js:321
 msgid "Disconnected"
 msgstr ""
 
-#: converse.js:165
+#: converse.js:331
 msgid "Error"
 msgstr ""
 
-#: converse.js:167
+#: converse.js:333
 msgid "Connecting"
 msgstr ""
 
-#: converse.js:170
+#: converse.js:336
 msgid "Connection Failed"
 msgstr ""
 
-#: converse.js:172
+#: converse.js:338
 msgid "Authenticating"
 msgstr ""
 
-#: converse.js:175
+#: converse.js:341
 msgid "Authentication Failed"
 msgstr ""
 
-#: converse.js:177
+#: converse.js:343
 msgid "Disconnecting"
 msgstr ""
 
-#: converse.js:332
+#: converse.js:479
+msgid "Online Contacts"
+msgstr ""
+
+#: converse.js:540
 msgid "Re-establishing encrypted session"
 msgstr ""
 
-#: converse.js:340
+#: converse.js:548
 msgid ""
 "Your browser needs to generate a private key, which will be used in your "
 "encrypted chat session. This can take up to 30 seconds during which your "
 "browser might freeze and become unresponsive."
 msgstr ""
 
-#: converse.js:349
+#: converse.js:557
 msgid "Private key generated."
 msgstr ""
 
-#: converse.js:380
+#: converse.js:588
 msgid ""
 "Authentication request from %1$s\n"
 "\n"
@@ -86,71 +114,71 @@ msgid ""
 "%2$s"
 msgstr ""
 
-#: converse.js:389
+#: converse.js:597
 msgid "Could not verify this user's identify."
 msgstr ""
 
-#: converse.js:537
+#: converse.js:750
 msgid "Personal message"
 msgstr ""
 
-#: converse.js:559
+#: converse.js:795
 msgid "Start encrypted conversation"
 msgstr ""
 
-#: converse.js:562
+#: converse.js:798
 msgid "Refresh encrypted conversation"
 msgstr ""
 
-#: converse.js:563
+#: converse.js:799
 msgid "End encrypted conversation"
 msgstr ""
 
-#: converse.js:564
+#: converse.js:800
 msgid "Verify with SMP"
 msgstr ""
 
-#: converse.js:567
+#: converse.js:803
 msgid "Verify with fingerprints"
 msgstr ""
 
-#: converse.js:569
+#: converse.js:805
 msgid "What's this?"
 msgstr ""
 
-#: converse.js:641
+#: converse.js:906
 msgid "me"
 msgstr ""
 
-#: converse.js:757 converse.js:1552
+#: converse.js:1022 converse.js:1864
 msgid "Show this menu"
 msgstr ""
 
-#: converse.js:758 converse.js:1553
+#: converse.js:1023 converse.js:1865
 msgid "Write in the third person"
 msgstr ""
 
-#: converse.js:759 converse.js:1557
+#: converse.js:1024 converse.js:1869
 msgid "Remove messages"
 msgstr ""
 
-#: converse.js:830
+#: converse.js:1110
 msgid "Your message could not be sent"
 msgstr ""
 
-#: converse.js:833
+#: converse.js:1113
 msgid "We received an unencrypted message"
 msgstr ""
 
-#: converse.js:836
+#: converse.js:1116
 msgid "We received an unreadable encrypted message"
 msgstr ""
 
-#: converse.js:845
+#: converse.js:1125
 msgid "This user has requested an encrypted session."
 msgstr ""
 
-#: converse.js:863
+#: converse.js:1147
 msgid ""
 "Here are the fingerprints, please confirm them with %1$s, outside of this "
 "chat.\n"
@@ -163,480 +191,452 @@ msgid ""
 "Cancel."
 msgstr ""
 
-#: converse.js:876
+#: converse.js:1160
 msgid ""
 "You will be prompted to provide a security question and then an answer to "
 "that question.\n"
 "\n"
 "Your buddy will then be prompted the same question and if they type the "
-"exact same answer (case sensitive), their identity will have been verified."
+"exact same answer (case sensitive), their identity will be verified."
 msgstr ""
 
-#: converse.js:877
+#: converse.js:1161
 msgid "What is your security question?"
 msgstr ""
 
-#: converse.js:879
+#: converse.js:1163
 msgid "What is the answer to the security question?"
 msgstr ""
 
-#: converse.js:883
+#: converse.js:1167
 msgid "Invalid authentication scheme provided"
 msgstr ""
 
-#: converse.js:953
+#: converse.js:1248
 msgid "Your messages are not encrypted anymore"
 msgstr ""
 
-#: converse.js:955
+#: converse.js:1250
 msgid ""
 "Your messages are now encrypted but your buddy's identity has not been "
 "verified."
 msgstr ""
 
-#: converse.js:957
+#: converse.js:1252
 msgid "Your buddy's identify has been verified."
 msgstr ""
 
-#: converse.js:959
+#: converse.js:1254
 msgid "Your buddy has ended encryption on their end, you should do the same."
 msgstr ""
 
-#: converse.js:968
+#: converse.js:1263
 msgid "Your messages are not encrypted. Click here to enable OTR encryption."
 msgstr ""
 
-#: converse.js:970
+#: converse.js:1265
 msgid "Your messages are encrypted, but your buddy has not been verified."
 msgstr ""
 
-#: converse.js:972
+#: converse.js:1267
 msgid "Your messages are encrypted and your buddy verified."
 msgstr ""
 
-#: converse.js:974
+#: converse.js:1269
 msgid ""
 "Your buddy has closed their end of the private session, you should do the "
 "same"
 msgstr ""
 
-#: converse.js:1049
+#: converse.js:1354
 msgid "Contacts"
 msgstr ""
 
-#: converse.js:1054
+#: converse.js:1359
 msgid "Online"
 msgstr ""
 
-#: converse.js:1055
+#: converse.js:1360
 msgid "Busy"
 msgstr ""
 
-#: converse.js:1056
+#: converse.js:1361
 msgid "Away"
 msgstr ""
 
-#: converse.js:1057
+#: converse.js:1362
 msgid "Offline"
 msgstr ""
 
-#: converse.js:1064
+#: converse.js:1372
 msgid "Click to add new chat contacts"
 msgstr ""
 
-#: converse.js:1065
+#: converse.js:1373
 msgid "Add a contact"
 msgstr ""
 
-#: converse.js:1074
+#: converse.js:1382
 msgid "Contact username"
 msgstr ""
 
-#: converse.js:1075
+#: converse.js:1383
 msgid "Add"
 msgstr ""
 
-#: converse.js:1083
+#: converse.js:1391
 msgid "Contact name"
 msgstr ""
 
-#: converse.js:1084
+#: converse.js:1392
 msgid "Search"
 msgstr ""
 
-#: converse.js:1124
+#: converse.js:1439
 msgid "No users found"
 msgstr ""
 
-#: converse.js:1131
+#: converse.js:1446
 msgid "Click to add as a chat contact"
 msgstr ""
 
-#: converse.js:1191
+#: converse.js:1498
 msgid "Click to open this room"
 msgstr ""
 
-#: converse.js:1193
+#: converse.js:1500
 msgid "Show more information on this room"
 msgstr ""
 
-#: converse.js:1199
+#: converse.js:1506
 msgid "Description:"
 msgstr ""
 
-#: converse.js:1200
+#: converse.js:1507
 msgid "Occupants:"
 msgstr ""
 
-#: converse.js:1201
+#: converse.js:1508
 msgid "Features:"
 msgstr ""
 
-#: converse.js:1203
+#: converse.js:1510
 msgid "Requires authentication"
 msgstr ""
 
-#: converse.js:1206
+#: converse.js:1513
 msgid "Hidden"
 msgstr ""
 
-#: converse.js:1209
+#: converse.js:1516
 msgid "Requires an invitation"
 msgstr ""
 
-#: converse.js:1212
+#: converse.js:1519
 msgid "Moderated"
 msgstr ""
 
-#: converse.js:1215
+#: converse.js:1522
 msgid "Non-anonymous"
 msgstr ""
 
-#: converse.js:1218
+#: converse.js:1525
 msgid "Open room"
 msgstr ""
 
-#: converse.js:1221
+#: converse.js:1528
 msgid "Permanent room"
 msgstr ""
 
-#: converse.js:1224
+#: converse.js:1531
 msgid "Public"
 msgstr ""
 
-#: converse.js:1227
+#: converse.js:1534
 msgid "Semi-anonymous"
 msgstr ""
 
-#: converse.js:1230
+#: converse.js:1537
 msgid "Temporary room"
 msgstr ""
 
-#: converse.js:1233
+#: converse.js:1540
 msgid "Unmoderated"
 msgstr ""
 
-#: converse.js:1239
+#: converse.js:1546
 msgid "Rooms"
 msgstr ""
 
-#: converse.js:1243
+#: converse.js:1550
 msgid "Room name"
 msgstr ""
 
-#: converse.js:1244
+#: converse.js:1551
 msgid "Nickname"
 msgstr ""
 
-#: converse.js:1245
+#: converse.js:1552
 msgid "Server"
 msgstr ""
 
-#: converse.js:1246
+#: converse.js:1553
 msgid "Join"
 msgstr ""
 
-#: converse.js:1247
+#: converse.js:1554
 msgid "Show rooms"
 msgstr ""
 
 #. For translators: %1$s is a variable and will be replaced with the XMPP server name
-#: converse.js:1282
+#: converse.js:1589
 msgid "No rooms on %1$s"
 msgstr ""
 
 #. For translators: %1$s is a variable and will be
 #. replaced with the XMPP server name
-#: converse.js:1297
+#: converse.js:1604
 msgid "Rooms on %1$s"
 msgstr ""
 
-#: converse.js:1554
+#: converse.js:1866
 msgid "Set chatroom topic"
 msgstr ""
 
-#: converse.js:1555
+#: converse.js:1867
 msgid "Kick user from chatroom"
 msgstr ""
 
-#: converse.js:1556
+#: converse.js:1868
 msgid "Ban user from chatroom"
 msgstr ""
 
-#: converse.js:1583
+#: converse.js:1898
 msgid "Message"
 msgstr ""
 
-#: converse.js:1697 converse.js:2783
+#: converse.js:2013 converse.js:3168
 msgid "Save"
 msgstr ""
 
-#: converse.js:1698
+#: converse.js:2014
 msgid "Cancel"
 msgstr ""
 
-#: converse.js:1745
+#: converse.js:2061
 msgid "An error occurred while trying to save the form."
 msgstr ""
 
-#: converse.js:1791
+#: converse.js:2107
 msgid "This chatroom requires a password"
 msgstr ""
 
-#: converse.js:1792
+#: converse.js:2108
 msgid "Password: "
 msgstr ""
 
-#: converse.js:1793
+#: converse.js:2109
 msgid "Submit"
 msgstr ""
 
-#: converse.js:1807
+#: converse.js:2123
 msgid "This room is not anonymous"
 msgstr ""
 
-#: converse.js:1808
+#: converse.js:2124
 msgid "This room now shows unavailable members"
 msgstr ""
 
-#: converse.js:1809
+#: converse.js:2125
 msgid "This room does not show unavailable members"
 msgstr ""
 
-#: converse.js:1810
+#: converse.js:2126
 msgid "Non-privacy-related room configuration has changed"
 msgstr ""
 
-#: converse.js:1811
+#: converse.js:2127
 msgid "Room logging is now enabled"
 msgstr ""
 
-#: converse.js:1812
+#: converse.js:2128
 msgid "Room logging is now disabled"
 msgstr ""
 
-#: converse.js:1813
+#: converse.js:2129
 msgid "This room is now non-anonymous"
 msgstr ""
 
-#: converse.js:1814
+#: converse.js:2130
 msgid "This room is now semi-anonymous"
 msgstr ""
 
-#: converse.js:1815
+#: converse.js:2131
 msgid "This room is now fully-anonymous"
 msgstr ""
 
-#: converse.js:1816
+#: converse.js:2132
 msgid "A new room has been created"
 msgstr ""
 
-#: converse.js:1817
+#: converse.js:2133
 msgid "Your nickname has been changed"
 msgstr ""
 
-#: converse.js:1831
+#: converse.js:2147
 msgid "<strong>%1$s</strong> has been banned"
 msgstr ""
 
-#: converse.js:1832
+#: converse.js:2148
 msgid "<strong>%1$s</strong> has been kicked out"
 msgstr ""
 
-#: converse.js:1833
+#: converse.js:2149
 msgid "<strong>%1$s</strong> has been removed because of an affiliation change"
 msgstr ""
 
-#: converse.js:1834
+#: converse.js:2150
 msgid "<strong>%1$s</strong> has been removed for not being a member"
 msgstr ""
 
-#: converse.js:1838 converse.js:1898
+#: converse.js:2154 converse.js:2214
 msgid "You have been banned from this room"
 msgstr ""
 
-#: converse.js:1839
+#: converse.js:2155
 msgid "You have been kicked from this room"
 msgstr ""
 
-#: converse.js:1840
+#: converse.js:2156
 msgid "You have been removed from this room because of an affiliation change"
 msgstr ""
 
-#: converse.js:1841
+#: converse.js:2157
 msgid ""
 "You have been removed from this room because the room has changed to members-"
 "only and you're not a member"
 msgstr ""
 
-#: converse.js:1842
+#: converse.js:2158
 msgid ""
 "You have been removed from this room because the MUC (Multi-user chat) "
 "service is being shut down."
 msgstr ""
 
-#: converse.js:1896
+#: converse.js:2212
 msgid "You are not on the member list of this room"
 msgstr ""
 
-#: converse.js:1902
+#: converse.js:2218
 msgid "No nickname was specified"
 msgstr ""
 
-#: converse.js:1906
+#: converse.js:2222
 msgid "You are not allowed to create new rooms"
 msgstr ""
 
-#: converse.js:1908
+#: converse.js:2224
 msgid "Your nickname doesn't conform to this room's policies"
 msgstr ""
 
-#: converse.js:1910
+#: converse.js:2226
 msgid "Your nickname is already taken"
 msgstr ""
 
-#: converse.js:1912
+#: converse.js:2228
 msgid "This room does not (yet) exist"
 msgstr ""
 
-#: converse.js:1914
+#: converse.js:2230
 msgid "This room has reached it's maximum number of occupants"
 msgstr ""
 
-#: converse.js:1993
+#: converse.js:2309
 msgid "Topic set by %1$s to: %2$s"
 msgstr ""
 
-#: converse.js:2009
+#: converse.js:2330
 msgid "This user is a moderator"
 msgstr ""
 
-#: converse.js:2012
+#: converse.js:2333
 msgid "This user can send messages in this room"
 msgstr ""
 
-#: converse.js:2015
+#: converse.js:2336
 msgid "This user can NOT send messages in this room"
 msgstr ""
 
-#: converse.js:2225
+#: converse.js:2562
 msgid "Click to chat with this contact"
 msgstr ""
 
-#: converse.js:2228 converse.js:2232
+#: converse.js:2565 converse.js:2569
 msgid "Click to remove this contact"
 msgstr ""
 
-#: converse.js:2263
-msgid "This contact is busy"
-msgstr ""
-
-#: converse.js:2264
-msgid "This contact is online"
-msgstr ""
-
-#: converse.js:2265
-msgid "This contact is offline"
-msgstr ""
-
-#: converse.js:2266
-msgid "This contact is unavailable"
-msgstr ""
-
-#: converse.js:2267
-msgid "This contact is away for an extended period"
-msgstr ""
-
-#: converse.js:2268
-msgid "This contact is away"
-msgstr ""
-
-#: converse.js:2622
+#: converse.js:2919
 msgid "Contact requests"
 msgstr ""
 
-#: converse.js:2623
+#: converse.js:2922
 msgid "My contacts"
 msgstr ""
 
-#: converse.js:2624
+#: converse.js:2925
 msgid "Pending contacts"
 msgstr ""
 
-#: converse.js:2782
+#: converse.js:3167
 msgid "Custom status"
 msgstr ""
 
-#: converse.js:2788
+#: converse.js:3173
 msgid "Click to change your chat status"
 msgstr ""
 
-#: converse.js:2792
+#: converse.js:3177
 msgid "Click here to write a custom status message"
 msgstr ""
 
-#: converse.js:2821 converse.js:2829
+#: converse.js:3206 converse.js:3214
 msgid "online"
 msgstr ""
 
-#: converse.js:2823
+#: converse.js:3208
 msgid "busy"
 msgstr ""
 
-#: converse.js:2825
+#: converse.js:3210
 msgid "away for long"
 msgstr ""
 
-#: converse.js:2827
+#: converse.js:3212
 msgid "away"
 msgstr ""
 
 #. For translators: the %1$s part gets replaced with the status
 #. Example, I am online
-#: converse.js:2841 converse.js:2878
+#: converse.js:3226 converse.js:3263
 msgid "I am %1$s"
 msgstr ""
 
-#: converse.js:2949
+#: converse.js:3334
 msgid "Sign in"
 msgstr ""
 
-#: converse.js:2952
+#: converse.js:3338
 msgid "XMPP/Jabber Username:"
 msgstr ""
 
-#: converse.js:2954
+#: converse.js:3340
 msgid "Password:"
 msgstr ""
 
-#: converse.js:2956
+#: converse.js:3342
 msgid "Log In"
 msgstr ""
 
-#: converse.js:2960
+#: converse.js:3346
 msgid "BOSH Service URL:"
 msgstr ""
-
-#: converse.js:3113
-msgid "Online Contacts"
-msgstr ""

+ 605 - 0
locale/he/LC_MESSAGES/converse.json

@@ -0,0 +1,605 @@
+{
+   "converse": {
+      "": {
+         "Project-Id-Version": "Converse.js 0.7.0",
+         "Report-Msgid-Bugs-To": "",
+         "POT-Creation-Date": "2014-01-28 03:50+0200",
+         "PO-Revision-Date": "2014-02-21 06:07+0200",
+         "Last-Translator": "GreenLunar <GreenLunar@github.com>",
+         "Language-Team": "Rahut <http://sourceforge.net/projects/rahut/>",
+         "Language": "he",
+         "MIME-Version": "1.0",
+         "Content-Type": "text/plain; charset=UTF-8",
+         "Content-Transfer-Encoding": "8bit",
+         "X-Generator": "Poedit 1.5.1"
+      },
+      "unencrypted": [
+         null,
+         "לא מוצפנת"
+      ],
+      "unverified": [
+         null,
+         "לא מאומתת"
+      ],
+      "verified": [
+         null,
+         "מאומתת"
+      ],
+      "finished": [
+         null,
+         "מוגמרת"
+      ],
+      "This contact is busy": [
+         null,
+         "איש קשר זה עסוק"
+      ],
+      "This contact is online": [
+         null,
+         "איש קשר זה מקוון"
+      ],
+      "This contact is offline": [
+         null,
+         "איש קשר זה לא מקוון"
+      ],
+      "This contact is unavailable": [
+         null,
+         "איש קשר זה לא זמין"
+      ],
+      "This contact is away for an extended period": [
+         null,
+         "איש קשר זה נעדר למשך זמן ממושך"
+      ],
+      "This contact is away": [
+         null,
+         "איש קשר זה הינו נעדר"
+      ],
+      "Disconnected": [
+         null,
+         "מנותק"
+      ],
+      "Error": [
+         null,
+         "שגיאה"
+      ],
+      "Connecting": [
+         null,
+         "כעת מתחבר"
+      ],
+      "Connection Failed": [
+         null,
+         "חיבור נכשל"
+      ],
+      "Authenticating": [
+         null,
+         "כעת מאמת"
+      ],
+      "Authentication Failed": [
+         null,
+         "אימות נכשל"
+      ],
+      "Disconnecting": [
+         null,
+         "כעת מתנתק"
+      ],
+      "Online Contacts": [
+         null,
+         "אנשי קשר מקוונים"
+      ],
+      "Re-establishing encrypted session": [
+         null,
+         "בסס מחדש ישיבה מוצפנת"
+      ],
+      "Your browser needs to generate a private key, which will be used in your encrypted chat session. This can take up to 30 seconds during which your browser might freeze and become unresponsive.": [
+         null,
+         "על הדפדפן שלך להפיק מפתח פרטי, אשר ישמש אותך בישיבות שיחה מוצפנות. פעולה זו יכולה לקחת למעלה מן 30 שניות אשר במהלכה הדפדפן שלך עשוי לקפוא ולהפוך לחסר תגובה."
+      ],
+      "Private key generated.": [
+         null,
+         "מפתח פרטי הופק."
+      ],
+      "Authentication request from %1$s\n\nYour buddy is attempting to verify your identity, by asking you the question below.\n\n%2$s": [
+         null,
+         "בקשת אימות מאת %1$s\n\nהאישיות שכנגד מנסה לאמת את הזהות שלך, בעזרת שאילת שאלה להלן.\n\n%2$s"
+      ],
+      "Could not verify this user's identify.": [
+         null,
+         "לא היתה אפשרות לאמת את זהות משתמש זה."
+      ],
+      "Personal message": [
+         null,
+         "הודעה אישית"
+      ],
+      "Start encrypted conversation": [
+         null,
+         "התחל ישיבה מוצפנת"
+      ],
+      "Refresh encrypted conversation": [
+         null,
+         "רענן ישיבה מוצפנת"
+      ],
+      "End encrypted conversation": [
+         null,
+         "סיים ישיבה מוצפנת"
+      ],
+      "Verify with SMP": [
+         null,
+         "אמת בעזרת SMP"
+      ],
+      "Verify with fingerprints": [
+         null,
+         "אמת בעזרת טביעות אצבע"
+      ],
+      "What's this?": [
+         null,
+         "מה זה?"
+      ],
+      "me": [
+         null,
+         "אני"
+      ],
+      "Show this menu": [
+         null,
+         "הצג את תפריט זה"
+      ],
+      "Write in the third person": [
+         null,
+         "כתוב בגוף השלישי"
+      ],
+      "Remove messages": [
+         null,
+         "הסר הודעות"
+      ],
+      "Your message could not be sent": [
+         null,
+         "ההודעה שלך לא היתה יכולה להישלח"
+      ],
+      "We received an unencrypted message": [
+         null,
+         "אנחנו קיבלנו הודעה לא מוצפנת"
+      ],
+      "We received an unreadable encrypted message": [
+         null,
+         "אנחנו קיבלנו הודעה מוצפנת לא קריאה"
+      ],
+      "This user has requested an encrypted session.": [
+         null,
+         "משתמש זה ביקש ישיבה מוצפנת."
+      ],
+      "Here are the fingerprints, please confirm them with %1$s, outside of this chat.\n\nFingerprint for you, %2$s: %3$s\n\nFingerprint for %1$s: %4$s\n\nIf you have confirmed that the fingerprints match, click OK, otherwise click Cancel.": [
+         null,
+         "הרי טביעות האצבע, אנא אמת אותן עם %1$s, מחוץ לשיחה זו.\n\nטביעת אצבע עבורך, %2$s: %3$s\n\nטביעת אצבע עבור %1$s: %4$s\n\nהיה ואימתת כי טביעות האצבע תואמות, לחץ אישור (OK), אחרת לחץ ביטול (Cancel)."
+      ],
+      "You will be prompted to provide a security question and then an answer to that question.\n\nYour buddy will then be prompted the same question and if they type the exact same answer (case sensitive), their identity will be verified.": [
+         null,
+         "אתה תתבקש לספק שאלת אבטחה ולאחריה תשובה לשאלה הזו.\n\nהאישיות שכנגד תתבקש עובר זאת לאותה שאלת אבטחה ואם זו תקלידו את את אותה התשובה במדויק (case sensitive), זהותה תאומת."
+      ],
+      "What is your security question?": [
+         null,
+         "מהי שאלת האבטחה שלך?"
+      ],
+      "What is the answer to the security question?": [
+         null,
+         "מהי התשובה לשאלת האבטחה?"
+      ],
+      "Invalid authentication scheme provided": [
+         null,
+         "סופקה סכימת אימות שגויה"
+      ],
+      "Your messages are not encrypted anymore": [
+         null,
+         "ההודעות שלך אינן מוצפנות עוד"
+      ],
+      "Your messages are now encrypted but your buddy's identity has not been verified.": [
+         null,
+         "ההודעות שלך מוצפנות כעת אך זהות האישיות שכנגד טרם אומתה."
+      ],
+      "Your buddy's identify has been verified.": [
+         null,
+         "זהות האישיות שכנגד אומתה."
+      ],
+      "Your buddy has ended encryption on their end, you should do the same.": [
+         null,
+         "האישיות שכנגד סיימה הצפנה בקצה שלה, עליך לעשות את אותו הדבר."
+      ],
+      "Your messages are not encrypted. Click here to enable OTR encryption.": [
+         null,
+         "ההודעות שלך אינן וצפנות. לחץ כאן כדי לאפשר OTR."
+      ],
+      "Your messages are encrypted, but your buddy has not been verified.": [
+         null,
+         "ההודעות שלך מוצפנות כעת, אך האישיות שכנגד טרם אומתה."
+      ],
+      "Your messages are encrypted and your buddy verified.": [
+         null,
+         "ההודעות שלך מוצפנות כעת והאישיות שכנגד אומתה."
+      ],
+      "Your buddy has closed their end of the private session, you should do the same": [
+         null,
+         "האישיות שכנגד סגרה את קצה הישיבה הפרטית שלה, עליך לעשות את אותו הדבר."
+      ],
+      "Contacts": [
+         null,
+         "אנשי קשר"
+      ],
+      "Online": [
+         null,
+         "מקוון"
+      ],
+      "Busy": [
+         null,
+         "עסוק"
+      ],
+      "Away": [
+         null,
+         "נעדר"
+      ],
+      "Offline": [
+         null,
+         "בלתי מקוון"
+      ],
+      "Click to add new chat contacts": [
+         null,
+         "לחץ כדי להוסיף אנשי קשר שיחה חדשים"
+      ],
+      "Add a contact": [
+         null,
+         "הוסף איש קשר"
+      ],
+      "Contact username": [
+         null,
+         "שם משתמש איש קשר"
+      ],
+      "Add": [
+         null,
+         "הוסף"
+      ],
+      "Contact name": [
+         null,
+         "שם איש קשר"
+      ],
+      "Search": [
+         null,
+         "חיפוש"
+      ],
+      "No users found": [
+         null,
+         "לא נמצאו משתמשים"
+      ],
+      "Click to add as a chat contact": [
+         null,
+         "לחץ כדי להוסיף בתור איש קשר שיחה"
+      ],
+      "Click to open this room": [
+         null,
+         "לחץ כדי לפתוח את חדר זה"
+      ],
+      "Show more information on this room": [
+         null,
+         "הצג עוד מידע אודות חדר זה"
+      ],
+      "Description:": [
+         null,
+         "תיאור:"
+      ],
+      "Occupants:": [
+         null,
+         "נוכחים:"
+      ],
+      "Features:": [
+         null,
+         "תכונות:"
+      ],
+      "Requires authentication": [
+         null,
+         "מצריך אישור"
+      ],
+      "Hidden": [
+         null,
+         "נסתר"
+      ],
+      "Requires an invitation": [
+         null,
+         "מצריך הזמנה"
+      ],
+      "Moderated": [
+         null,
+         "מבוקר"
+      ],
+      "Non-anonymous": [
+         null,
+         "לא אנונימי"
+      ],
+      "Open room": [
+         null,
+         "חדר פתוח"
+      ],
+      "Permanent room": [
+         null,
+         "חדר צמיתה"
+      ],
+      "Public": [
+         null,
+         "פומבי"
+      ],
+      "Semi-anonymous": [
+         null,
+         "אנונימי למחצה"
+      ],
+      "Temporary room": [
+         null,
+         "חדר זמני"
+      ],
+      "Unmoderated": [
+         null,
+         "לא מבוקר"
+      ],
+      "Rooms": [
+         null,
+         "חדרים"
+      ],
+      "Room name": [
+         null,
+         "שם חדר"
+      ],
+      "Nickname": [
+         null,
+         "שם כינוי"
+      ],
+      "Server": [
+         null,
+         "שרת"
+      ],
+      "Join": [
+         null,
+         "הצטרף"
+      ],
+      "Show rooms": [
+         null,
+         "הצג חדרים"
+      ],
+      "No rooms on %1$s": [
+         null,
+         "אין חדרים על %1$s"
+      ],
+      "Rooms on %1$s": [
+         null,
+         "חדרים על %1$s"
+      ],
+      "Set chatroom topic": [
+         null,
+         "קבע נושא חדר שיחה"
+      ],
+      "Kick user from chatroom": [
+         null,
+         "בעט משתמש מתוך חדר שיחה"
+      ],
+      "Ban user from chatroom": [
+         null,
+         "אסור משתמש מתוך חדר שיחה"
+      ],
+      "Message": [
+         null,
+         "הודעה"
+      ],
+      "Save": [
+         null,
+         "שמור"
+      ],
+      "Cancel": [
+         null,
+         "ביטול"
+      ],
+      "An error occurred while trying to save the form.": [
+         null,
+         "אירעה שגיאה במהלך ניסיון שמירת הטופס."
+      ],
+      "This chatroom requires a password": [
+         null,
+         "חדר שיחה זה מצריך סיסמה"
+      ],
+      "Password: ": [
+         null,
+         "סיסמה: "
+      ],
+      "Submit": [
+         null,
+         "שלח"
+      ],
+      "This room is not anonymous": [
+         null,
+         "חדר זה אינו אנונימי"
+      ],
+      "This room now shows unavailable members": [
+         null,
+         "חדר זה כעת מציג חברים לא זמינים"
+      ],
+      "This room does not show unavailable members": [
+         null,
+         "חדר זה לא מציג חברים לא זמינים"
+      ],
+      "Non-privacy-related room configuration has changed": [
+         null,
+         "תצורת חדר אשר לא-קשורה-בפרטיות שונתה"
+      ],
+      "Room logging is now enabled": [
+         null,
+         "יומן חדר הינו מופעל כעת"
+      ],
+      "Room logging is now disabled": [
+         null,
+         "יומן חדר הינו מנוטרל כעת"
+      ],
+      "This room is now non-anonymous": [
+         null,
+         "חדר זה אינו אנונימי כעת"
+      ],
+      "This room is now semi-anonymous": [
+         null,
+         "חדר זה הינו אנונימי למחצה כעת"
+      ],
+      "This room is now fully-anonymous": [
+         null,
+         "חדר זה הינו אנונימי לחלוטין כעת"
+      ],
+      "A new room has been created": [
+         null,
+         "חדר חדש נוצר"
+      ],
+      "Your nickname has been changed": [
+         null,
+         "שם הכינוי שלך שונה"
+      ],
+      "<strong>%1$s</strong> has been banned": [
+         null,
+         "<strong>%1$s</strong> נאסר(ה)"
+      ],
+      "<strong>%1$s</strong> has been kicked out": [
+         null,
+         "<strong>%1$s</strong> נבעט(ה)"
+      ],
+      "<strong>%1$s</strong> has been removed because of an affiliation change": [
+         null,
+         "<strong>%1$s</strong> הוסרה(ה) משום שינוי שיוך"
+      ],
+      "<strong>%1$s</strong> has been removed for not being a member": [
+         null,
+         "<strong>%1$s</strong> הוסר(ה) משום אי הימצאות במסגרת מעמד של חבר"
+      ],
+      "You have been banned from this room": [
+         null,
+         "נאסרת מתוך חדר זה"
+      ],
+      "You have been kicked from this room": [
+         null,
+         "נבעטת מתוך חדר זה"
+      ],
+      "You have been removed from this room because of an affiliation change": [
+         null,
+         "הוסרת מתוך חדר זה משום שינוי שיוך"
+      ],
+      "You have been removed from this room because the room has changed to members-only and you're not a member": [
+         null,
+         "הוסרת מתוך חדר זה משום שהחדר שונה לחברים-בלבד ואינך במעמד של חבר"
+      ],
+      "You have been removed from this room because the MUC (Multi-user chat) service is being shut down.": [
+         null,
+         "הוסרת מתוך חדר זה משום ששירות שמ״מ (שיחה מרובת משתמשים) זה כעת מצוי בהליכי סגירה."
+      ],
+      "You are not on the member list of this room": [
+         null,
+         "אינך ברשימת החברים של חדר זה"
+      ],
+      "No nickname was specified": [
+         null,
+         "לא צוין שום שם כינוי"
+      ],
+      "You are not allowed to create new rooms": [
+         null,
+         "אין לך רשות ליצור חדרים חדשים"
+      ],
+      "Your nickname doesn't conform to this room's policies": [
+         null,
+         "שם הכינוי שלך לא תואם את המדינויות של חדר זה"
+      ],
+      "Your nickname is already taken": [
+         null,
+         "שם הכינוי שלך הינו תפוס"
+      ],
+      "This room does not (yet) exist": [
+         null,
+         "חדר זה (עדיין) לא קיים"
+      ],
+      "This room has reached it's maximum number of occupants": [
+         null,
+         "חדר זה הגיע לסף הנוכחים המרבי שלו"
+      ],
+      "Topic set by %1$s to: %2$s": [
+         null,
+         "נושא חדר זה נקבע על ידי %1$s אל: %2$s"
+      ],
+      "This user is a moderator": [
+         null,
+         "משתמש זה הינו אחראי"
+      ],
+      "This user can send messages in this room": [
+         null,
+         "משתמש זה מסוגל לשלוח הודעות בתוך חדר זה"
+      ],
+      "This user can NOT send messages in this room": [
+         null,
+         "משתמש זה ﬥﬡ מסוגל לשלוח הודעות בתוך חדר זה"
+      ],
+      "Click to chat with this contact": [
+         null,
+         "לחץ כדי לשוחח עם איש קשר זה"
+      ],
+      "Click to remove this contact": [
+         null,
+         "לחץ כדי להסיר את איש קשר זה"
+      ],
+      "Contact requests": [
+         null,
+         "בקשות איש קשר"
+      ],
+      "My contacts": [
+         null,
+         "אנשי הקשר שלי"
+      ],
+      "Pending contacts": [
+         null,
+         "אנשי קשר ממתינים"
+      ],
+      "Custom status": [
+         null,
+         "מצב מותאם"
+      ],
+      "Click to change your chat status": [
+         null,
+         "לחץ כדי לשנות את הודעת השיחה שלך"
+      ],
+      "Click here to write a custom status message": [
+         null,
+         "לחץ כאן כדי לכתוב הודעת מצב מותאמת"
+      ],
+      "online": [
+         null,
+         "מקוון"
+      ],
+      "busy": [
+         null,
+         "עסוק"
+      ],
+      "away for long": [
+         null,
+         "נעדר לזמן מה"
+      ],
+      "away": [
+         null,
+         "נעדר"
+      ],
+      "I am %1$s": [
+         null,
+         "מצבי כעת הינו %1$s"
+      ],
+      "Sign in": [
+         null,
+         "התחברות"
+      ],
+      "XMPP/Jabber Username:": [
+         null,
+         "שם משתמש XMPP/Jabber:"
+      ],
+      "Password:": [
+         null,
+         "סיסמה:"
+      ],
+      "Log In": [
+         null,
+         "כניסה"
+      ],
+      "BOSH Service URL:": [
+         null,
+         "כתובת שירות BOSH:"
+      ]
+   }
+}

+ 672 - 0
locale/he/LC_MESSAGES/converse.po

@@ -0,0 +1,672 @@
+# Language HE translations for Converse.js package.
+# Copyright (C) 2013 Jan-Carel Brand
+# This file is distributed under the same license as the Converse.js package.
+# GreenLunar <GreenLunar@github.com>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Converse.js 0.7.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2014-01-28 03:50+0200\n"
+"PO-Revision-Date: 2014-02-21 06:07+0200\n"
+"Last-Translator: GreenLunar <GreenLunar@github.com>\n"
+"Language-Team: Rahut <http://sourceforge.net/projects/rahut/>\n"
+"Language: he\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.5.1\n"
+
+#: converse.js:217
+msgid "unencrypted"
+msgstr "לא מוצפנת"
+
+#: converse.js:218
+msgid "unverified"
+msgstr "לא מאומתת"
+
+#: converse.js:219
+msgid "verified"
+msgstr "מאומתת"
+
+#: converse.js:220
+msgid "finished"
+msgstr "מוגמרת"
+
+# איש קשר זה הינו
+#: converse.js:223
+msgid "This contact is busy"
+msgstr "איש קשר זה עסוק"
+
+#: converse.js:224
+msgid "This contact is online"
+msgstr "איש קשר זה מקוון"
+
+# איש קשר זה אינו
+#: converse.js:225
+msgid "This contact is offline"
+msgstr "איש קשר זה לא מקוון"
+
+#: converse.js:226
+msgid "This contact is unavailable"
+msgstr "איש קשר זה לא זמין"
+
+#: converse.js:227
+msgid "This contact is away for an extended period"
+msgstr "איש קשר זה נעדר למשך זמן ממושך"
+
+#: converse.js:228
+msgid "This contact is away"
+msgstr "איש קשר זה הינו נעדר"
+
+#: converse.js:321
+msgid "Disconnected"
+msgstr "מנותק"
+
+#: converse.js:331
+msgid "Error"
+msgstr "שגיאה"
+
+#: converse.js:333
+msgid "Connecting"
+msgstr "כעת מתחבר"
+
+#: converse.js:336
+msgid "Connection Failed"
+msgstr "חיבור נכשל"
+
+#: converse.js:338
+msgid "Authenticating"
+msgstr "כעת מאמת"
+
+#: converse.js:341
+msgid "Authentication Failed"
+msgstr "אימות נכשל"
+
+#: converse.js:343
+msgid "Disconnecting"
+msgstr "כעת מתנתק"
+
+#: converse.js:479
+msgid "Online Contacts"
+msgstr "אנשי קשר מקוונים"
+
+#: converse.js:540
+msgid "Re-establishing encrypted session"
+msgstr "בסס מחדש ישיבה מוצפנת"
+
+#: converse.js:548
+msgid ""
+"Your browser needs to generate a private key, which will be used in your "
+"encrypted chat session. This can take up to 30 seconds during which your "
+"browser might freeze and become unresponsive."
+msgstr ""
+"על הדפדפן שלך להפיק מפתח פרטי, אשר ישמש אותך בישיבות שיחה מוצפנות. פעולה זו "
+"יכולה לקחת למעלה מן 30 שניות אשר במהלכה הדפדפן שלך עשוי לקפוא ולהפוך לחסר "
+"תגובה."
+
+#: converse.js:557
+msgid "Private key generated."
+msgstr "מפתח פרטי הופק."
+
+#: converse.js:588
+msgid ""
+"Authentication request from %1$s\n"
+"\n"
+"Your buddy is attempting to verify your identity, by asking you the question "
+"below.\n"
+"\n"
+"%2$s"
+msgstr ""
+"בקשת אימות מאת %1$s\n"
+"\n"
+"האישיות שכנגד מנסה לאמת את הזהות שלך, בעזרת שאילת שאלה להלן.\n"
+"\n"
+"%2$s"
+
+#: converse.js:597
+msgid "Could not verify this user's identify."
+msgstr "לא היתה אפשרות לאמת את זהות משתמש זה."
+
+#: converse.js:750
+msgid "Personal message"
+msgstr "הודעה אישית"
+
+#: converse.js:795
+msgid "Start encrypted conversation"
+msgstr "התחל ישיבה מוצפנת"
+
+#: converse.js:798
+msgid "Refresh encrypted conversation"
+msgstr "רענן ישיבה מוצפנת"
+
+#: converse.js:799
+msgid "End encrypted conversation"
+msgstr "סיים ישיבה מוצפנת"
+
+#: converse.js:800
+msgid "Verify with SMP"
+msgstr "אמת בעזרת SMP"
+
+#: converse.js:803
+msgid "Verify with fingerprints"
+msgstr "אמת בעזרת טביעות אצבע"
+
+#: converse.js:805
+msgid "What's this?"
+msgstr "מה זה?"
+
+#: converse.js:906
+msgid "me"
+msgstr "אני"
+
+#: converse.js:1022 converse.js:1864
+msgid "Show this menu"
+msgstr "הצג את תפריט זה"
+
+#: converse.js:1023 converse.js:1865
+msgid "Write in the third person"
+msgstr "כתוב בגוף השלישי"
+
+#: converse.js:1024 converse.js:1869
+msgid "Remove messages"
+msgstr "הסר הודעות"
+
+#: converse.js:1110
+msgid "Your message could not be sent"
+msgstr "ההודעה שלך לא היתה יכולה להישלח"
+
+#: converse.js:1113
+msgid "We received an unencrypted message"
+msgstr "אנחנו קיבלנו הודעה לא מוצפנת"
+
+#: converse.js:1116
+msgid "We received an unreadable encrypted message"
+msgstr "אנחנו קיבלנו הודעה מוצפנת לא קריאה"
+
+#: converse.js:1125
+msgid "This user has requested an encrypted session."
+msgstr "משתמש זה ביקש ישיבה מוצפנת."
+
+#: converse.js:1147
+msgid ""
+"Here are the fingerprints, please confirm them with %1$s, outside of this "
+"chat.\n"
+"\n"
+"Fingerprint for you, %2$s: %3$s\n"
+"\n"
+"Fingerprint for %1$s: %4$s\n"
+"\n"
+"If you have confirmed that the fingerprints match, click OK, otherwise click "
+"Cancel."
+msgstr ""
+"הרי טביעות האצבע, אנא אמת אותן עם %1$s, מחוץ לשיחה זו.\n"
+"\n"
+"טביעת אצבע עבורך, %2$s: %3$s\n"
+"\n"
+"טביעת אצבע עבור %1$s: %4$s\n"
+"\n"
+"היה ואימתת כי טביעות האצבע תואמות, לחץ אישור (OK), אחרת לחץ ביטול (Cancel)."
+
+# הקצה השני
+#: converse.js:1160
+msgid ""
+"You will be prompted to provide a security question and then an answer to "
+"that question.\n"
+"\n"
+"Your buddy will then be prompted the same question and if they type the "
+"exact same answer (case sensitive), their identity will be verified."
+msgstr ""
+"אתה תתבקש לספק שאלת אבטחה ולאחריה תשובה לשאלה הזו.\n"
+"\n"
+"האישיות שכנגד תתבקש עובר זאת לאותה שאלת אבטחה ואם זו תקלידו את את אותה "
+"התשובה במדויק (case sensitive), זהותה תאומת."
+
+#: converse.js:1161
+msgid "What is your security question?"
+msgstr "מהי שאלת האבטחה שלך?"
+
+#: converse.js:1163
+msgid "What is the answer to the security question?"
+msgstr "מהי התשובה לשאלת האבטחה?"
+
+# תרשים
+#: converse.js:1167
+msgid "Invalid authentication scheme provided"
+msgstr "סופקה סכימת אימות שגויה"
+
+#: converse.js:1248
+msgid "Your messages are not encrypted anymore"
+msgstr "ההודעות שלך אינן מוצפנות עוד"
+
+#: converse.js:1250
+msgid ""
+"Your messages are now encrypted but your buddy's identity has not been "
+"verified."
+msgstr "ההודעות שלך מוצפנות כעת אך זהות האישיות שכנגד טרם אומתה."
+
+#: converse.js:1252
+msgid "Your buddy's identify has been verified."
+msgstr "זהות האישיות שכנגד אומתה."
+
+#: converse.js:1254
+msgid "Your buddy has ended encryption on their end, you should do the same."
+msgstr "האישיות שכנגד סיימה הצפנה בקצה שלה, עליך לעשות את אותו הדבר."
+
+#: converse.js:1263
+msgid "Your messages are not encrypted. Click here to enable OTR encryption."
+msgstr "ההודעות שלך אינן וצפנות. לחץ כאן כדי לאפשר OTR."
+
+#: converse.js:1265
+msgid "Your messages are encrypted, but your buddy has not been verified."
+msgstr "ההודעות שלך מוצפנות כעת, אך האישיות שכנגד טרם אומתה."
+
+#: converse.js:1267
+msgid "Your messages are encrypted and your buddy verified."
+msgstr "ההודעות שלך מוצפנות כעת והאישיות שכנגד אומתה."
+
+#: converse.js:1269
+msgid ""
+"Your buddy has closed their end of the private session, you should do the "
+"same"
+msgstr "האישיות שכנגד סגרה את קצה הישיבה הפרטית שלה, עליך לעשות את אותו הדבר."
+
+#: converse.js:1354
+msgid "Contacts"
+msgstr "אנשי קשר"
+
+#: converse.js:1359
+msgid "Online"
+msgstr "מקוון"
+
+#: converse.js:1360
+msgid "Busy"
+msgstr "עסוק"
+
+#: converse.js:1361
+msgid "Away"
+msgstr "נעדר"
+
+#: converse.js:1362
+msgid "Offline"
+msgstr "בלתי מקוון"
+
+#: converse.js:1372
+msgid "Click to add new chat contacts"
+msgstr "לחץ כדי להוסיף אנשי קשר שיחה חדשים"
+
+#: converse.js:1373
+msgid "Add a contact"
+msgstr "הוסף איש קשר"
+
+#: converse.js:1382
+msgid "Contact username"
+msgstr "שם משתמש איש קשר"
+
+#: converse.js:1383
+msgid "Add"
+msgstr "הוסף"
+
+#: converse.js:1391
+msgid "Contact name"
+msgstr "שם איש קשר"
+
+#: converse.js:1392
+msgid "Search"
+msgstr "חיפוש"
+
+#: converse.js:1439
+msgid "No users found"
+msgstr "לא נמצאו משתמשים"
+
+#: converse.js:1446
+msgid "Click to add as a chat contact"
+msgstr "לחץ כדי להוסיף בתור איש קשר שיחה"
+
+#: converse.js:1498
+msgid "Click to open this room"
+msgstr "לחץ כדי לפתוח את חדר זה"
+
+#: converse.js:1500
+msgid "Show more information on this room"
+msgstr "הצג עוד מידע אודות חדר זה"
+
+#: converse.js:1506
+msgid "Description:"
+msgstr "תיאור:"
+
+#: converse.js:1507
+msgid "Occupants:"
+msgstr "נוכחים:"
+
+#: converse.js:1508
+msgid "Features:"
+msgstr "תכונות:"
+
+#: converse.js:1510
+msgid "Requires authentication"
+msgstr "מצריך אישור"
+
+#: converse.js:1513
+msgid "Hidden"
+msgstr "נסתר"
+
+#: converse.js:1516
+msgid "Requires an invitation"
+msgstr "מצריך הזמנה"
+
+#: converse.js:1519
+msgid "Moderated"
+msgstr "מבוקר"
+
+#: converse.js:1522
+msgid "Non-anonymous"
+msgstr "לא אנונימי"
+
+#: converse.js:1525
+msgid "Open room"
+msgstr "חדר פתוח"
+
+#: converse.js:1528
+msgid "Permanent room"
+msgstr "חדר צמיתה"
+
+#: converse.js:1531
+msgid "Public"
+msgstr "פומבי"
+
+#: converse.js:1534
+msgid "Semi-anonymous"
+msgstr "אנונימי למחצה"
+
+#: converse.js:1537
+msgid "Temporary room"
+msgstr "חדר זמני"
+
+#: converse.js:1540
+msgid "Unmoderated"
+msgstr "לא מבוקר"
+
+#: converse.js:1546
+msgid "Rooms"
+msgstr "חדרים"
+
+#: converse.js:1550
+msgid "Room name"
+msgstr "שם חדר"
+
+#: converse.js:1551
+msgid "Nickname"
+msgstr "שם כינוי"
+
+#: converse.js:1552
+msgid "Server"
+msgstr "שרת"
+
+#: converse.js:1553
+msgid "Join"
+msgstr "הצטרף"
+
+#: converse.js:1554
+msgid "Show rooms"
+msgstr "הצג חדרים"
+
+#. For translators: %1$s is a variable and will be replaced with the XMPP server name
+#: converse.js:1589
+msgid "No rooms on %1$s"
+msgstr "אין חדרים על %1$s"
+
+#. For translators: %1$s is a variable and will be
+#. replaced with the XMPP server name
+#: converse.js:1604
+msgid "Rooms on %1$s"
+msgstr "חדרים על %1$s"
+
+#: converse.js:1866
+msgid "Set chatroom topic"
+msgstr "קבע נושא חדר שיחה"
+
+#: converse.js:1867
+msgid "Kick user from chatroom"
+msgstr "בעט משתמש מתוך חדר שיחה"
+
+#: converse.js:1868
+msgid "Ban user from chatroom"
+msgstr "אסור משתמש מתוך חדר שיחה"
+
+#: converse.js:1898
+msgid "Message"
+msgstr "הודעה"
+
+#: converse.js:2013 converse.js:3168
+msgid "Save"
+msgstr "שמור"
+
+#: converse.js:2014
+msgid "Cancel"
+msgstr "ביטול"
+
+#: converse.js:2061
+msgid "An error occurred while trying to save the form."
+msgstr "אירעה שגיאה במהלך ניסיון שמירת הטופס."
+
+#: converse.js:2107
+msgid "This chatroom requires a password"
+msgstr "חדר שיחה זה מצריך סיסמה"
+
+#: converse.js:2108
+msgid "Password: "
+msgstr "סיסמה: "
+
+#: converse.js:2109
+msgid "Submit"
+msgstr "שלח"
+
+#: converse.js:2123
+msgid "This room is not anonymous"
+msgstr "חדר זה אינו אנונימי"
+
+#: converse.js:2124
+msgid "This room now shows unavailable members"
+msgstr "חדר זה כעת מציג חברים לא זמינים"
+
+#: converse.js:2125
+msgid "This room does not show unavailable members"
+msgstr "חדר זה לא מציג חברים לא זמינים"
+
+#: converse.js:2126
+msgid "Non-privacy-related room configuration has changed"
+msgstr "תצורת חדר אשר לא-קשורה-בפרטיות שונתה"
+
+#: converse.js:2127
+msgid "Room logging is now enabled"
+msgstr "יומן חדר הינו מופעל כעת"
+
+#: converse.js:2128
+msgid "Room logging is now disabled"
+msgstr "יומן חדר הינו מנוטרל כעת"
+
+#: converse.js:2129
+msgid "This room is now non-anonymous"
+msgstr "חדר זה אינו אנונימי כעת"
+
+#: converse.js:2130
+msgid "This room is now semi-anonymous"
+msgstr "חדר זה הינו אנונימי למחצה כעת"
+
+#: converse.js:2131
+msgid "This room is now fully-anonymous"
+msgstr "חדר זה הינו אנונימי לחלוטין כעת"
+
+#: converse.js:2132
+msgid "A new room has been created"
+msgstr "חדר חדש נוצר"
+
+#: converse.js:2133
+msgid "Your nickname has been changed"
+msgstr "שם הכינוי שלך שונה"
+
+#: converse.js:2147
+msgid "<strong>%1$s</strong> has been banned"
+msgstr "<strong>%1$s</strong> נאסר(ה)"
+
+#: converse.js:2148
+msgid "<strong>%1$s</strong> has been kicked out"
+msgstr "<strong>%1$s</strong> נבעט(ה)"
+
+#: converse.js:2149
+msgid "<strong>%1$s</strong> has been removed because of an affiliation change"
+msgstr "<strong>%1$s</strong> הוסרה(ה) משום שינוי שיוך"
+
+# היותו(ה)
+#: converse.js:2150
+msgid "<strong>%1$s</strong> has been removed for not being a member"
+msgstr "<strong>%1$s</strong> הוסר(ה) משום אי הימצאות במסגרת מעמד של חבר"
+
+#: converse.js:2154 converse.js:2214
+msgid "You have been banned from this room"
+msgstr "נאסרת מתוך חדר זה"
+
+#: converse.js:2155
+msgid "You have been kicked from this room"
+msgstr "נבעטת מתוך חדר זה"
+
+#: converse.js:2156
+msgid "You have been removed from this room because of an affiliation change"
+msgstr "הוסרת מתוך חדר זה משום שינוי שיוך"
+
+#: converse.js:2157
+msgid ""
+"You have been removed from this room because the room has changed to members-"
+"only and you're not a member"
+msgstr "הוסרת מתוך חדר זה משום שהחדר שונה לחברים-בלבד ואינך במעמד של חבר"
+
+#: converse.js:2158
+msgid ""
+"You have been removed from this room because the MUC (Multi-user chat) "
+"service is being shut down."
+msgstr ""
+"הוסרת מתוך חדר זה משום ששירות שמ״מ (שיחה מרובת משתמשים) זה כעת מצוי בהליכי "
+"סגירה."
+
+#: converse.js:2212
+msgid "You are not on the member list of this room"
+msgstr "אינך ברשימת החברים של חדר זה"
+
+# אף שם כינוי לא צוין
+#: converse.js:2218
+msgid "No nickname was specified"
+msgstr "לא צוין שום שם כינוי"
+
+# אינך מורשה
+#: converse.js:2222
+msgid "You are not allowed to create new rooms"
+msgstr "אין לך רשות ליצור חדרים חדשים"
+
+#: converse.js:2224
+msgid "Your nickname doesn't conform to this room's policies"
+msgstr "שם הכינוי שלך לא תואם את המדינויות של חדר זה"
+
+# נלקח כבר
+#: converse.js:2226
+msgid "Your nickname is already taken"
+msgstr "שם הכינוי שלך הינו תפוס"
+
+#: converse.js:2228
+msgid "This room does not (yet) exist"
+msgstr "חדר זה (עדיין) לא קיים"
+
+#: converse.js:2230
+msgid "This room has reached it's maximum number of occupants"
+msgstr "חדר זה הגיע לסף הנוכחים המרבי שלו"
+
+#: converse.js:2309
+msgid "Topic set by %1$s to: %2$s"
+msgstr "נושא חדר זה נקבע על ידי %1$s אל: %2$s"
+
+#: converse.js:2330
+msgid "This user is a moderator"
+msgstr "משתמש זה הינו אחראי"
+
+#: converse.js:2333
+msgid "This user can send messages in this room"
+msgstr "משתמש זה מסוגל לשלוח הודעות בתוך חדר זה"
+
+#: converse.js:2336
+msgid "This user can NOT send messages in this room"
+msgstr "משתמש זה ﬥﬡ מסוגל לשלוח הודעות בתוך חדר זה"
+
+#: converse.js:2562
+msgid "Click to chat with this contact"
+msgstr "לחץ כדי לשוחח עם איש קשר זה"
+
+#: converse.js:2565 converse.js:2569
+msgid "Click to remove this contact"
+msgstr "לחץ כדי להסיר את איש קשר זה"
+
+#: converse.js:2919
+msgid "Contact requests"
+msgstr "בקשות איש קשר"
+
+#: converse.js:2922
+msgid "My contacts"
+msgstr "אנשי הקשר שלי"
+
+#: converse.js:2925
+msgid "Pending contacts"
+msgstr "אנשי קשר ממתינים"
+
+#: converse.js:3167
+msgid "Custom status"
+msgstr "מצב מותאם"
+
+#: converse.js:3173
+msgid "Click to change your chat status"
+msgstr "לחץ כדי לשנות את הודעת השיחה שלך"
+
+#: converse.js:3177
+msgid "Click here to write a custom status message"
+msgstr "לחץ כאן כדי לכתוב הודעת מצב מותאמת"
+
+#: converse.js:3206 converse.js:3214
+msgid "online"
+msgstr "מקוון"
+
+#: converse.js:3208
+msgid "busy"
+msgstr "עסוק"
+
+#: converse.js:3210
+msgid "away for long"
+msgstr "נעדר לזמן מה"
+
+#: converse.js:3212
+msgid "away"
+msgstr "נעדר"
+
+# אני במצב
+#. For translators: the %1$s part gets replaced with the status
+#. Example, I am online
+#: converse.js:3226 converse.js:3263
+msgid "I am %1$s"
+msgstr "מצבי כעת הינו %1$s"
+
+#: converse.js:3334
+msgid "Sign in"
+msgstr "התחברות"
+
+#: converse.js:3338
+msgid "XMPP/Jabber Username:"
+msgstr "שם משתמש XMPP/Jabber:"
+
+#: converse.js:3340
+msgid "Password:"
+msgstr "סיסמה:"
+
+#: converse.js:3342
+msgid "Log In"
+msgstr "כניסה"
+
+#: converse.js:3346
+msgid "BOSH Service URL:"
+msgstr "כתובת שירות BOSH:"

+ 622 - 0
locale/he/LC_MESSAGES/he.js

@@ -0,0 +1,622 @@
+(function (root, factory) {
+    var translations = {
+        "domain": "converse",
+        "locale_data": {
+            "converse": {
+                "": {
+                    "Project-Id-Version": "Converse.js 0.7.0",
+                    "Report-Msgid-Bugs-To": "",
+                    "POT-Creation-Date": "2014-01-28 03:50+0200",
+                    "PO-Revision-Date": "2014-02-21 06:07+0200",
+                    "Last-Translator": "GreenLunar <GreenLunar@github.com>",
+                    "Language-Team": "Rahut <http://sourceforge.net/projects/rahut/>",
+                    "Language": "he",
+                    "MIME-Version": "1.0",
+                    "Content-Type": "text/plain; charset=UTF-8",
+                    "Content-Transfer-Encoding": "8bit",
+                    "X-Generator": "Poedit 1.5.1"
+                },
+                "unencrypted": [
+                    null,
+                    "לא מוצפנת"
+                ],
+                "unverified": [
+                    null,
+                    "לא מאומתת"
+                ],
+                "verified": [
+                    null,
+                    "מאומתת"
+                ],
+                "finished": [
+                    null,
+                    "מוגמרת"
+                ],
+                "This contact is busy": [
+                    null,
+                    "איש קשר זה עסוק"
+                ],
+                "This contact is online": [
+                    null,
+                    "איש קשר זה מקוון"
+                ],
+                "This contact is offline": [
+                    null,
+                    "איש קשר זה לא מקוון"
+                ],
+                "This contact is unavailable": [
+                    null,
+                    "איש קשר זה לא זמין"
+                ],
+                "This contact is away for an extended period": [
+                    null,
+                    "איש קשר זה נעדר למשך זמן ממושך"
+                ],
+                "This contact is away": [
+                    null,
+                    "איש קשר זה הינו נעדר"
+                ],
+                "Disconnected": [
+                    null,
+                    "מנותק"
+                ],
+                "Error": [
+                    null,
+                    "שגיאה"
+                ],
+                "Connecting": [
+                    null,
+                    "כעת מתחבר"
+                ],
+                "Connection Failed": [
+                    null,
+                    "חיבור נכשל"
+                ],
+                "Authenticating": [
+                    null,
+                    "כעת מאמת"
+                ],
+                "Authentication Failed": [
+                    null,
+                    "אימות נכשל"
+                ],
+                "Disconnecting": [
+                    null,
+                    "כעת מתנתק"
+                ],
+                "Online Contacts": [
+                    null,
+                    "אנשי קשר מקוונים"
+                ],
+                "Re-establishing encrypted session": [
+                    null,
+                    "בסס מחדש ישיבה מוצפנת"
+                ],
+                "Your browser needs to generate a private key, which will be used in your encrypted chat session. This can take up to 30 seconds during which your browser might freeze and become unresponsive.": [
+                    null,
+                    "על הדפדפן שלך להפיק מפתח פרטי, אשר ישמש אותך בישיבות שיחה מוצפנות. פעולה זו יכולה לקחת למעלה מן 30 שניות אשר במהלכה הדפדפן שלך עשוי לקפוא ולהפוך לחסר תגובה."
+                ],
+                "Private key generated.": [
+                    null,
+                    "מפתח פרטי הופק."
+                ],
+                "Authentication request from %1$s\n\nYour buddy is attempting to verify your identity, by asking you the question below.\n\n%2$s": [
+                    null,
+                    "בקשת אימות מאת %1$s\n\nהאישיות שכנגד מנסה לאמת את הזהות שלך, בעזרת שאילת שאלה להלן.\n\n%2$s"
+                ],
+                "Could not verify this user's identify.": [
+                    null,
+                    "לא היתה אפשרות לאמת את זהות משתמש זה."
+                ],
+                "Personal message": [
+                    null,
+                    "הודעה אישית"
+                ],
+                "Start encrypted conversation": [
+                    null,
+                    "התחל ישיבה מוצפנת"
+                ],
+                "Refresh encrypted conversation": [
+                    null,
+                    "רענן ישיבה מוצפנת"
+                ],
+                "End encrypted conversation": [
+                    null,
+                    "סיים ישיבה מוצפנת"
+                ],
+                "Verify with SMP": [
+                    null,
+                    "אמת בעזרת SMP"
+                ],
+                "Verify with fingerprints": [
+                    null,
+                    "אמת בעזרת טביעות אצבע"
+                ],
+                "What's this?": [
+                    null,
+                    "מה זה?"
+                ],
+                "me": [
+                    null,
+                    "אני"
+                ],
+                "Show this menu": [
+                    null,
+                    "הצג את תפריט זה"
+                ],
+                "Write in the third person": [
+                    null,
+                    "כתוב בגוף השלישי"
+                ],
+                "Remove messages": [
+                    null,
+                    "הסר הודעות"
+                ],
+                "Your message could not be sent": [
+                    null,
+                    "ההודעה שלך לא היתה יכולה להישלח"
+                ],
+                "We received an unencrypted message": [
+                    null,
+                    "אנחנו קיבלנו הודעה לא מוצפנת"
+                ],
+                "We received an unreadable encrypted message": [
+                    null,
+                    "אנחנו קיבלנו הודעה מוצפנת לא קריאה"
+                ],
+                "This user has requested an encrypted session.": [
+                    null,
+                    "משתמש זה ביקש ישיבה מוצפנת."
+                ],
+                "Here are the fingerprints, please confirm them with %1$s, outside of this chat.\n\nFingerprint for you, %2$s: %3$s\n\nFingerprint for %1$s: %4$s\n\nIf you have confirmed that the fingerprints match, click OK, otherwise click Cancel.": [
+                    null,
+                    "הרי טביעות האצבע, אנא אמת אותן עם %1$s, מחוץ לשיחה זו.\n\nטביעת אצבע עבורך, %2$s: %3$s\n\nטביעת אצבע עבור %1$s: %4$s\n\nהיה ואימתת כי טביעות האצבע תואמות, לחץ אישור (OK), אחרת לחץ ביטול (Cancel)."
+                ],
+                "You will be prompted to provide a security question and then an answer to that question.\n\nYour buddy will then be prompted the same question and if they type the exact same answer (case sensitive), their identity will be verified.": [
+                    null,
+                    "אתה תתבקש לספק שאלת אבטחה ולאחריה תשובה לשאלה הזו.\n\nהאישיות שכנגד תתבקש עובר זאת לאותה שאלת אבטחה ואם זו תקלידו את את אותה התשובה במדויק (case sensitive), זהותה תאומת."
+                ],
+                "What is your security question?": [
+                    null,
+                    "מהי שאלת האבטחה שלך?"
+                ],
+                "What is the answer to the security question?": [
+                    null,
+                    "מהי התשובה לשאלת האבטחה?"
+                ],
+                "Invalid authentication scheme provided": [
+                    null,
+                    "סופקה סכימת אימות שגויה"
+                ],
+                "Your messages are not encrypted anymore": [
+                    null,
+                    "ההודעות שלך אינן מוצפנות עוד"
+                ],
+                "Your messages are now encrypted but your buddy's identity has not been verified.": [
+                    null,
+                    "ההודעות שלך מוצפנות כעת אך זהות האישיות שכנגד טרם אומתה."
+                ],
+                "Your buddy's identify has been verified.": [
+                    null,
+                    "זהות האישיות שכנגד אומתה."
+                ],
+                "Your buddy has ended encryption on their end, you should do the same.": [
+                    null,
+                    "האישיות שכנגד סיימה הצפנה בקצה שלה, עליך לעשות את אותו הדבר."
+                ],
+                "Your messages are not encrypted. Click here to enable OTR encryption.": [
+                    null,
+                    "ההודעות שלך אינן וצפנות. לחץ כאן כדי לאפשר OTR."
+                ],
+                "Your messages are encrypted, but your buddy has not been verified.": [
+                    null,
+                    "ההודעות שלך מוצפנות כעת, אך האישיות שכנגד טרם אומתה."
+                ],
+                "Your messages are encrypted and your buddy verified.": [
+                    null,
+                    "ההודעות שלך מוצפנות כעת והאישיות שכנגד אומתה."
+                ],
+                "Your buddy has closed their end of the private session, you should do the same": [
+                    null,
+                    "האישיות שכנגד סגרה את קצה הישיבה הפרטית שלה, עליך לעשות את אותו הדבר."
+                ],
+                "Contacts": [
+                    null,
+                    "אנשי קשר"
+                ],
+                "Online": [
+                    null,
+                    "מקוון"
+                ],
+                "Busy": [
+                    null,
+                    "עסוק"
+                ],
+                "Away": [
+                    null,
+                    "נעדר"
+                ],
+                "Offline": [
+                    null,
+                    "בלתי מקוון"
+                ],
+                "Click to add new chat contacts": [
+                    null,
+                    "לחץ כדי להוסיף אנשי קשר שיחה חדשים"
+                ],
+                "Add a contact": [
+                    null,
+                    "הוסף איש קשר"
+                ],
+                "Contact username": [
+                    null,
+                    "שם משתמש איש קשר"
+                ],
+                "Add": [
+                    null,
+                    "הוסף"
+                ],
+                "Contact name": [
+                    null,
+                    "שם איש קשר"
+                ],
+                "Search": [
+                    null,
+                    "חיפוש"
+                ],
+                "No users found": [
+                    null,
+                    "לא נמצאו משתמשים"
+                ],
+                "Click to add as a chat contact": [
+                    null,
+                    "לחץ כדי להוסיף בתור איש קשר שיחה"
+                ],
+                "Click to open this room": [
+                    null,
+                    "לחץ כדי לפתוח את חדר זה"
+                ],
+                "Show more information on this room": [
+                    null,
+                    "הצג עוד מידע אודות חדר זה"
+                ],
+                "Description:": [
+                    null,
+                    "תיאור:"
+                ],
+                "Occupants:": [
+                    null,
+                    "נוכחים:"
+                ],
+                "Features:": [
+                    null,
+                    "תכונות:"
+                ],
+                "Requires authentication": [
+                    null,
+                    "מצריך אישור"
+                ],
+                "Hidden": [
+                    null,
+                    "נסתר"
+                ],
+                "Requires an invitation": [
+                    null,
+                    "מצריך הזמנה"
+                ],
+                "Moderated": [
+                    null,
+                    "מבוקר"
+                ],
+                "Non-anonymous": [
+                    null,
+                    "לא אנונימי"
+                ],
+                "Open room": [
+                    null,
+                    "חדר פתוח"
+                ],
+                "Permanent room": [
+                    null,
+                    "חדר צמיתה"
+                ],
+                "Public": [
+                    null,
+                    "פומבי"
+                ],
+                "Semi-anonymous": [
+                    null,
+                    "אנונימי למחצה"
+                ],
+                "Temporary room": [
+                    null,
+                    "חדר זמני"
+                ],
+                "Unmoderated": [
+                    null,
+                    "לא מבוקר"
+                ],
+                "Rooms": [
+                    null,
+                    "חדרים"
+                ],
+                "Room name": [
+                    null,
+                    "שם חדר"
+                ],
+                "Nickname": [
+                    null,
+                    "שם כינוי"
+                ],
+                "Server": [
+                    null,
+                    "שרת"
+                ],
+                "Join": [
+                    null,
+                    "הצטרף"
+                ],
+                "Show rooms": [
+                    null,
+                    "הצג חדרים"
+                ],
+                "No rooms on %1$s": [
+                    null,
+                    "אין חדרים על %1$s"
+                ],
+                "Rooms on %1$s": [
+                    null,
+                    "חדרים על %1$s"
+                ],
+                "Set chatroom topic": [
+                    null,
+                    "קבע נושא חדר שיחה"
+                ],
+                "Kick user from chatroom": [
+                    null,
+                    "בעט משתמש מתוך חדר שיחה"
+                ],
+                "Ban user from chatroom": [
+                    null,
+                    "אסור משתמש מתוך חדר שיחה"
+                ],
+                "Message": [
+                    null,
+                    "הודעה"
+                ],
+                "Save": [
+                    null,
+                    "שמור"
+                ],
+                "Cancel": [
+                    null,
+                    "ביטול"
+                ],
+                "An error occurred while trying to save the form.": [
+                    null,
+                    "אירעה שגיאה במהלך ניסיון שמירת הטופס."
+                ],
+                "This chatroom requires a password": [
+                    null,
+                    "חדר שיחה זה מצריך סיסמה"
+                ],
+                "Password: ": [
+                    null,
+                    "סיסמה: "
+                ],
+                "Submit": [
+                    null,
+                    "שלח"
+                ],
+                "This room is not anonymous": [
+                    null,
+                    "חדר זה אינו אנונימי"
+                ],
+                "This room now shows unavailable members": [
+                    null,
+                    "חדר זה כעת מציג חברים לא זמינים"
+                ],
+                "This room does not show unavailable members": [
+                    null,
+                    "חדר זה לא מציג חברים לא זמינים"
+                ],
+                "Non-privacy-related room configuration has changed": [
+                    null,
+                    "תצורת חדר אשר לא-קשורה-בפרטיות שונתה"
+                ],
+                "Room logging is now enabled": [
+                    null,
+                    "יומן חדר הינו מופעל כעת"
+                ],
+                "Room logging is now disabled": [
+                    null,
+                    "יומן חדר הינו מנוטרל כעת"
+                ],
+                "This room is now non-anonymous": [
+                    null,
+                    "חדר זה אינו אנונימי כעת"
+                ],
+                "This room is now semi-anonymous": [
+                    null,
+                    "חדר זה הינו אנונימי למחצה כעת"
+                ],
+                "This room is now fully-anonymous": [
+                    null,
+                    "חדר זה הינו אנונימי לחלוטין כעת"
+                ],
+                "A new room has been created": [
+                    null,
+                    "חדר חדש נוצר"
+                ],
+                "Your nickname has been changed": [
+                    null,
+                    "שם הכינוי שלך שונה"
+                ],
+                "<strong>%1$s</strong> has been banned": [
+                    null,
+                    "<strong>%1$s</strong> נאסר(ה)"
+                ],
+                "<strong>%1$s</strong> has been kicked out": [
+                    null,
+                    "<strong>%1$s</strong> נבעט(ה)"
+                ],
+                "<strong>%1$s</strong> has been removed because of an affiliation change": [
+                    null,
+                    "<strong>%1$s</strong> הוסרה(ה) משום שינוי שיוך"
+                ],
+                "<strong>%1$s</strong> has been removed for not being a member": [
+                    null,
+                    "<strong>%1$s</strong> הוסר(ה) משום אי הימצאות במסגרת מעמד של חבר"
+                ],
+                "You have been banned from this room": [
+                    null,
+                    "נאסרת מתוך חדר זה"
+                ],
+                "You have been kicked from this room": [
+                    null,
+                    "נבעטת מתוך חדר זה"
+                ],
+                "You have been removed from this room because of an affiliation change": [
+                    null,
+                    "הוסרת מתוך חדר זה משום שינוי שיוך"
+                ],
+                "You have been removed from this room because the room has changed to members-only and you're not a member": [
+                    null,
+                    "הוסרת מתוך חדר זה משום שהחדר שונה לחברים-בלבד ואינך במעמד של חבר"
+                ],
+                "You have been removed from this room because the MUC (Multi-user chat) service is being shut down.": [
+                    null,
+                    "הוסרת מתוך חדר זה משום ששירות שמ״מ (שיחה מרובת משתמשים) זה כעת מצוי בהליכי סגירה."
+                ],
+                "You are not on the member list of this room": [
+                    null,
+                    "אינך ברשימת החברים של חדר זה"
+                ],
+                "No nickname was specified": [
+                    null,
+                    "לא צוין שום שם כינוי"
+                ],
+                "You are not allowed to create new rooms": [
+                    null,
+                    "אין לך רשות ליצור חדרים חדשים"
+                ],
+                "Your nickname doesn't conform to this room's policies": [
+                    null,
+                    "שם הכינוי שלך לא תואם את המדינויות של חדר זה"
+                ],
+                "Your nickname is already taken": [
+                    null,
+                    "שם הכינוי שלך הינו תפוס"
+                ],
+                "This room does not (yet) exist": [
+                    null,
+                    "חדר זה (עדיין) לא קיים"
+                ],
+                "This room has reached it's maximum number of occupants": [
+                    null,
+                    "חדר זה הגיע לסף הנוכחים המרבי שלו"
+                ],
+                "Topic set by %1$s to: %2$s": [
+                    null,
+                    "נושא חדר זה נקבע על ידי %1$s אל: %2$s"
+                ],
+                "This user is a moderator": [
+                    null,
+                    "משתמש זה הינו אחראי"
+                ],
+                "This user can send messages in this room": [
+                    null,
+                    "משתמש זה מסוגל לשלוח הודעות בתוך חדר זה"
+                ],
+                "This user can NOT send messages in this room": [
+                    null,
+                    "משתמש זה ﬥﬡ מסוגל לשלוח הודעות בתוך חדר זה"
+                ],
+                "Click to chat with this contact": [
+                    null,
+                    "לחץ כדי לשוחח עם איש קשר זה"
+                ],
+                "Click to remove this contact": [
+                    null,
+                    "לחץ כדי להסיר את איש קשר זה"
+                ],
+                "Contact requests": [
+                    null,
+                    "בקשות איש קשר"
+                ],
+                "My contacts": [
+                    null,
+                    "אנשי הקשר שלי"
+                ],
+                "Pending contacts": [
+                    null,
+                    "אנשי קשר ממתינים"
+                ],
+                "Custom status": [
+                    null,
+                    "מצב מותאם"
+                ],
+                "Click to change your chat status": [
+                    null,
+                    "לחץ כדי לשנות את הודעת השיחה שלך"
+                ],
+                "Click here to write a custom status message": [
+                    null,
+                    "לחץ כאן כדי לכתוב הודעת מצב מותאמת"
+                ],
+                "online": [
+                    null,
+                    "מקוון"
+                ],
+                "busy": [
+                    null,
+                    "עסוק"
+                ],
+                "away for long": [
+                    null,
+                    "נעדר לזמן מה"
+                ],
+                "away": [
+                    null,
+                    "נעדר"
+                ],
+                "I am %1$s": [
+                    null,
+                    "מצבי כעת הינו %1$s"
+                ],
+                "Sign in": [
+                    null,
+                    "התחברות"
+                ],
+                "XMPP/Jabber Username:": [
+                    null,
+                    "שם משתמש XMPP/Jabber:"
+                ],
+                "Password:": [
+                    null,
+                    "סיסמה:"
+                ],
+                "Log In": [
+                    null,
+                    "כניסה"
+                ],
+                "BOSH Service URL:": [
+                    null,
+                    "כתובת שירות BOSH:"
+                ]
+            }
+        }
+    };
+    if (typeof define === 'function' && define.amd) {
+        define("he", ['jed'], function () {
+            return factory(new Jed(translations));
+        });
+    } else {
+        if (!window.locales) {
+            window.locales = {};
+        }
+        window.locales.he = factory(new Jed(translations));
+    }
+}(this, function (he) {
+    return he;
+}));

Plik diff jest za duży
+ 0 - 0
locale/id/LC_MESSAGES/converse.json


+ 677 - 0
locale/id/LC_MESSAGES/converse.po

@@ -0,0 +1,677 @@
+# Bahasa Indonesia translations for Converse.js package.
+# Copyright (C) 2014 Jan-Carel Brand
+# Copyright (C) 2014 Priyadi Iman Nurcahyo
+# This file is distributed under the same license as the Converse.js package.
+# Priyadi Iman Nurcahyo <priyadi@priyadi.net>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Converse.js 0.7.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2014-01-22 17:07+0200\n"
+"PO-Revision-Date: 2014-01-25 21:30+0700\n"
+"Last-Translator: Priyadi Iman Nurcahyo <priyadi@priyadi.net>\n"
+"Language-Team: Bahasa Indonesia\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: id\n"
+
+#: converse.js:217
+msgid "unencrypted"
+msgstr "tak dienkripsi"
+
+#: converse.js:218
+msgid "unverified"
+msgstr "tak diverifikasi"
+
+#: converse.js:219
+msgid "verified"
+msgstr "diverifikasi"
+
+#: converse.js:220
+msgid "finished"
+msgstr "selesai"
+
+#: converse.js:223
+msgid "This contact is busy"
+msgstr "Teman ini sedang sibuk"
+
+#: converse.js:224
+msgid "This contact is online"
+msgstr "Teman ini terhubung"
+
+#: converse.js:225
+msgid "This contact is offline"
+msgstr "Teman ini tidak terhubung"
+
+#: converse.js:226
+msgid "This contact is unavailable"
+msgstr "Teman ini tidak tersedia"
+
+#: converse.js:227
+msgid "This contact is away for an extended period"
+msgstr "Teman ini tidak di tempat untuk waktu yang lama"
+
+#: converse.js:228
+msgid "This contact is away"
+msgstr "Teman ini tidak di tempat"
+
+#: converse.js:321
+msgid "Disconnected"
+msgstr "Terputus"
+
+#: converse.js:331
+msgid "Error"
+msgstr "Kesalahan"
+
+#: converse.js:333
+msgid "Connecting"
+msgstr "Menyambung"
+
+#: converse.js:336
+msgid "Connection Failed"
+msgstr "Gagal Menyambung"
+
+#: converse.js:338
+msgid "Authenticating"
+msgstr "Melakukan otentikasi"
+
+#: converse.js:341
+msgid "Authentication Failed"
+msgstr "Otentikasi gagal"
+
+#: converse.js:343
+msgid "Disconnecting"
+msgstr "Memutuskan hubungan"
+
+#: converse.js:479
+msgid "Online Contacts"
+msgstr "Teman yang Terhubung"
+
+#: converse.js:540
+msgid "Re-establishing encrypted session"
+msgstr "Menyambung kembali sesi terenkripsi"
+
+#: converse.js:548
+msgid ""
+"Your browser needs to generate a private key, which will be used in your "
+"encrypted chat session. This can take up to 30 seconds during which your "
+"browser might freeze and become unresponsive."
+msgstr ""
+"Perambah anda perlu membuat kunci privat, yang akan digunakan pada sesi "
+"perbincangan anda. Ini akan membutuhkan waktu sampai 30 detik, dan selama "
+"itu perambah mungkin akan tidak responsif."
+
+#: converse.js:557
+msgid "Private key generated."
+msgstr "Kunci privat berhasil dibuat."
+
+#: converse.js:588
+msgid ""
+"Authentication request from %1$s\n"
+"\n"
+"Your buddy is attempting to verify your identity, by asking you the question "
+"below.\n"
+"\n"
+"%2$s"
+msgstr ""
+"Permintaan otentikasi dari %1$s\n"
+"\n"
+"Teman anda mencoba untuk melakukan verifikasi identitas anda dengan cara "
+"menanyakan pertanyaan di bawah ini.\n"
+"\n"
+"%2$s"
+
+#: converse.js:597
+msgid "Could not verify this user's identify."
+msgstr "Tak dapat melakukan verifikasi identitas pengguna ini."
+
+#: converse.js:750
+msgid "Personal message"
+msgstr "Pesan pribadi"
+
+#: converse.js:795
+msgid "Start encrypted conversation"
+msgstr "Mulai sesi terenkripsi"
+
+#: converse.js:798
+msgid "Refresh encrypted conversation"
+msgstr "Setel ulang percakapan terenkripsi"
+
+#: converse.js:799
+msgid "End encrypted conversation"
+msgstr "Sudahi percakapan terenkripsi"
+
+#: converse.js:800
+msgid "Verify with SMP"
+msgstr "Verifikasi menggunakan SMP"
+
+#: converse.js:803
+msgid "Verify with fingerprints"
+msgstr "Verifikasi menggunakan sidik jari"
+
+#: converse.js:805
+msgid "What's this?"
+msgstr "Apakah ini?"
+
+#: converse.js:906
+msgid "me"
+msgstr "saya"
+
+#: converse.js:1022 converse.js:1864
+msgid "Show this menu"
+msgstr "Tampilkan menu ini"
+
+#: converse.js:1023 converse.js:1865
+msgid "Write in the third person"
+msgstr "Tulis ini menggunakan bahasa pihak ketiga"
+
+#: converse.js:1024 converse.js:1869
+msgid "Remove messages"
+msgstr "Hapus pesan"
+
+#: converse.js:1110
+msgid "Your message could not be sent"
+msgstr "Pesan anda tak dapat dikirim"
+
+#: converse.js:1113
+msgid "We received an unencrypted message"
+msgstr "Kami menerima pesan terenkripsi"
+
+#: converse.js:1116
+msgid "We received an unreadable encrypted message"
+msgstr "Kami menerima pesan terenkripsi yang gagal dibaca"
+
+#: converse.js:1125
+msgid "This user has requested an encrypted session."
+msgstr "Pengguna ini meminta sesi terenkripsi"
+
+#: converse.js:1147
+msgid ""
+"Here are the fingerprints, please confirm them with %1$s, outside of this "
+"chat.\n"
+"\n"
+"Fingerprint for you, %2$s: %3$s\n"
+"\n"
+"Fingerprint for %1$s: %4$s\n"
+"\n"
+"If you have confirmed that the fingerprints match, click OK, otherwise click "
+"Cancel."
+msgstr ""
+"Ini adalah sidik jari anda, konfirmasikan bersama mereka dengan %1$s, di "
+"luar percakapan ini.\n"
+"\n"
+"Sidik jari untuk anda, %2$s: %3$s\n"
+"\n"
+"Sidik jari untuk %1$s: %4$s\n"
+"\n"
+"Jika anda bisa mengkonfirmasi sidik jadi cocok, klik Lanjutkan, jika tidak "
+"klik Batal."
+
+#: converse.js:1160
+msgid ""
+"You will be prompted to provide a security question and then an answer to "
+"that question.\n"
+"\n"
+"Your buddy will then be prompted the same question and if they type the "
+"exact same answer (case sensitive), their identity will have been verified."
+msgstr ""
+"Anda akan ditanyakan pertanyaan untuk keamanan beserta jawaban untuk "
+"pertanyaan tersebut.\n"
+"\n"
+"Teman anda akan ditanyakan pertanyaan yang sama dan jika dia memberikan "
+"jawaban yang sama (huruf kapital diperhatikan), identitas mereka "
+"diverifikasi."
+
+#: converse.js:1161
+msgid "What is your security question?"
+msgstr "Apakah pertanyaan keamanan anda?"
+
+#: converse.js:1163
+msgid "What is the answer to the security question?"
+msgstr "Apa jawaban dari pertanyaan keamanan tersebut?"
+
+#: converse.js:1167
+msgid "Invalid authentication scheme provided"
+msgstr "Skema otentikasi salah"
+
+#: converse.js:1248
+msgid "Your messages are not encrypted anymore"
+msgstr "Pesan anda tidak lagi terenkripsi"
+
+#: converse.js:1250
+msgid ""
+"Your messages are now encrypted but your buddy's identity has not been "
+"verified."
+msgstr ""
+"Pesan anda sekarang terenkripsi, namun identitas teman anda belum dapat "
+"diverifikasi."
+
+#: converse.js:1252
+msgid "Your buddy's identify has been verified."
+msgstr "Identitas teman anda telah diverifikasi."
+
+#: converse.js:1254
+msgid "Your buddy has ended encryption on their end, you should do the same."
+msgstr ""
+"Teman anda menghentikan percakapan terenkripsi, anda sebaiknya melakukan hal "
+"yang sama."
+
+#: converse.js:1263
+msgid "Your messages are not encrypted. Click here to enable OTR encryption."
+msgstr ""
+"Pesan anda tak terenkripsi. Klik di sini untuk menyalakan enkripsi OTR."
+
+#: converse.js:1265
+msgid "Your messages are encrypted, but your buddy has not been verified."
+msgstr "Pesan anda terenkripsi, tetapi teman anda belum diverifikasi."
+
+#: converse.js:1267
+msgid "Your messages are encrypted and your buddy verified."
+msgstr "Pesan anda terenkripsi dan teman anda telah diverifikasi."
+
+#: converse.js:1269
+msgid ""
+"Your buddy has closed their end of the private session, you should do the "
+"same"
+msgstr ""
+"Teman anda telah mematikan sesi terenkripsi, dan anda juga sebaiknya "
+"melakukan hal yang sama"
+
+#: converse.js:1354
+msgid "Contacts"
+msgstr "Teman"
+
+#: converse.js:1359
+msgid "Online"
+msgstr "Terhubung"
+
+#: converse.js:1360
+msgid "Busy"
+msgstr "Sibuk"
+
+#: converse.js:1361
+msgid "Away"
+msgstr "Pergi"
+
+#: converse.js:1362
+msgid "Offline"
+msgstr "Tak Terhubung"
+
+#: converse.js:1372
+msgid "Click to add new chat contacts"
+msgstr "Klik untuk menambahkan teman baru"
+
+#: converse.js:1373
+msgid "Add a contact"
+msgstr "Tambah teman"
+
+#: converse.js:1382
+msgid "Contact username"
+msgstr "Username teman"
+
+#: converse.js:1383
+msgid "Add"
+msgstr "Tambah"
+
+#: converse.js:1391
+msgid "Contact name"
+msgstr "Nama teman"
+
+#: converse.js:1392
+msgid "Search"
+msgstr "Cari"
+
+#: converse.js:1439
+msgid "No users found"
+msgstr "Pengguna tak ditemukan"
+
+#: converse.js:1446
+msgid "Click to add as a chat contact"
+msgstr "Klik untuk menambahkan sebagai teman"
+
+#: converse.js:1498
+msgid "Click to open this room"
+msgstr "Klik untuk membuka ruangan ini"
+
+#: converse.js:1500
+msgid "Show more information on this room"
+msgstr "Tampilkan informasi ruangan ini"
+
+#: converse.js:1506
+msgid "Description:"
+msgstr "Keterangan:"
+
+#: converse.js:1507
+msgid "Occupants:"
+msgstr "Penghuni:"
+
+#: converse.js:1508
+msgid "Features:"
+msgstr "Fitur:"
+
+#: converse.js:1510
+msgid "Requires authentication"
+msgstr "Membutuhkan otentikasi"
+
+#: converse.js:1513
+msgid "Hidden"
+msgstr "Tersembunyi"
+
+#: converse.js:1516
+msgid "Requires an invitation"
+msgstr "Membutuhkan undangan"
+
+#: converse.js:1519
+msgid "Moderated"
+msgstr "Dimoderasi"
+
+#: converse.js:1522
+msgid "Non-anonymous"
+msgstr "Tidak anonim"
+
+#: converse.js:1525
+msgid "Open room"
+msgstr "Ruangan terbuka"
+
+#: converse.js:1528
+msgid "Permanent room"
+msgstr "Ruangan permanen"
+
+#: converse.js:1531
+msgid "Public"
+msgstr "Umum"
+
+#: converse.js:1534
+msgid "Semi-anonymous"
+msgstr "Semi-anonim"
+
+#: converse.js:1537
+msgid "Temporary room"
+msgstr "Ruangan sementara"
+
+#: converse.js:1540
+msgid "Unmoderated"
+msgstr "Tak dimoderasi"
+
+#: converse.js:1546
+msgid "Rooms"
+msgstr "Ruangan"
+
+#: converse.js:1550
+msgid "Room name"
+msgstr "Nama ruangan"
+
+#: converse.js:1551
+msgid "Nickname"
+msgstr "Nama panggilan"
+
+#: converse.js:1552
+msgid "Server"
+msgstr "Server"
+
+#: converse.js:1553
+msgid "Join"
+msgstr "Ikuti"
+
+#: converse.js:1554
+msgid "Show rooms"
+msgstr "Perlihatkan ruangan"
+
+#. For translators: %1$s is a variable and will be replaced with the XMPP server name
+#: converse.js:1589
+msgid "No rooms on %1$s"
+msgstr "Tak ada ruangan di %1$s"
+
+#. For translators: %1$s is a variable and will be
+#. replaced with the XMPP server name
+#: converse.js:1604
+msgid "Rooms on %1$s"
+msgstr "Ruangan di %1$s"
+
+#: converse.js:1866
+msgid "Set chatroom topic"
+msgstr "Setel topik ruangan"
+
+#: converse.js:1867
+msgid "Kick user from chatroom"
+msgstr "Tendang pengguna dari ruangan"
+
+#: converse.js:1868
+msgid "Ban user from chatroom"
+msgstr "Larang pengguna dari ruangan"
+
+#: converse.js:1898
+msgid "Message"
+msgstr "Pesan"
+
+#: converse.js:2013 converse.js:3168
+msgid "Save"
+msgstr "Simpan"
+
+#: converse.js:2014
+msgid "Cancel"
+msgstr "Batal"
+
+#: converse.js:2061
+msgid "An error occurred while trying to save the form."
+msgstr "Kesalahan terjadi saat menyimpan formulir ini."
+
+#: converse.js:2107
+msgid "This chatroom requires a password"
+msgstr "Ruangan ini membutuhkan kata sandi"
+
+#: converse.js:2108
+msgid "Password: "
+msgstr "Kata sandi: "
+
+#: converse.js:2109
+msgid "Submit"
+msgstr "Kirim"
+
+#: converse.js:2123
+msgid "This room is not anonymous"
+msgstr "Ruangan ini tidak anonim"
+
+#: converse.js:2124
+msgid "This room now shows unavailable members"
+msgstr "Ruangan ini menampilkan anggota yang tak tersedia"
+
+#: converse.js:2125
+msgid "This room does not show unavailable members"
+msgstr "Ruangan ini tidak menampilkan anggota yang tak tersedia"
+
+#: converse.js:2126
+msgid "Non-privacy-related room configuration has changed"
+msgstr "Konfigurasi ruangan yang tak berhubungan dengan privasi telah diubah"
+
+#: converse.js:2127
+msgid "Room logging is now enabled"
+msgstr "Pencatatan di ruangan ini sekarang dinyalakan"
+
+#: converse.js:2128
+msgid "Room logging is now disabled"
+msgstr "Pencatatan di ruangan ini sekarang dimatikan"
+
+#: converse.js:2129
+msgid "This room is now non-anonymous"
+msgstr "Ruangan ini sekarang tak-anonim"
+
+#: converse.js:2130
+msgid "This room is now semi-anonymous"
+msgstr "Ruangan ini sekarang semi-anonim"
+
+#: converse.js:2131
+msgid "This room is now fully-anonymous"
+msgstr "Ruangan ini sekarang anonim"
+
+#: converse.js:2132
+msgid "A new room has been created"
+msgstr "Ruangan baru telah dibuat"
+
+#: converse.js:2133
+msgid "Your nickname has been changed"
+msgstr "Nama panggilan anda telah diubah"
+
+#: converse.js:2147
+msgid "<strong>%1$s</strong> has been banned"
+msgstr "<strong>%1$s</strong> telah dicekal"
+
+#: converse.js:2148
+msgid "<strong>%1$s</strong> has been kicked out"
+msgstr "<strong>%1$s</strong> telah ditendang keluar"
+
+#: converse.js:2149
+msgid "<strong>%1$s</strong> has been removed because of an affiliation change"
+msgstr "<strong>%1$s</strong> telah dihapus karena perubahan afiliasi"
+
+#: converse.js:2150
+msgid "<strong>%1$s</strong> has been removed for not being a member"
+msgstr "<strong>%1$s</strong> telah dihapus karena bukan anggota"
+
+#: converse.js:2154 converse.js:2214
+msgid "You have been banned from this room"
+msgstr "Anda telah dicekal dari ruangan ini"
+
+#: converse.js:2155
+msgid "You have been kicked from this room"
+msgstr "Anda telah ditendang dari ruangan ini"
+
+#: converse.js:2156
+msgid "You have been removed from this room because of an affiliation change"
+msgstr "Anda telah dihapus dari ruangan ini karena perubahan afiliasi"
+
+#: converse.js:2157
+msgid ""
+"You have been removed from this room because the room has changed to members-"
+"only and you're not a member"
+msgstr ""
+"Anda telah dihapus dari ruangan ini karena ruangan ini hanya terbuka untuk "
+"anggota dan anda bukan anggota"
+
+#: converse.js:2158
+msgid ""
+"You have been removed from this room because the MUC (Multi-user chat) "
+"service is being shut down."
+msgstr ""
+"Anda telah dihapus dari ruangan ini karena layanan MUC (Multi-user chat) "
+"telah dimatikan."
+
+#: converse.js:2212
+msgid "You are not on the member list of this room"
+msgstr "Anda bukan anggota dari ruangan ini"
+
+#: converse.js:2218
+msgid "No nickname was specified"
+msgstr "Nama panggilan belum ditentukan"
+
+#: converse.js:2222
+msgid "You are not allowed to create new rooms"
+msgstr "Anda tak diizinkan untuk membuat ruangan baru"
+
+#: converse.js:2224
+msgid "Your nickname doesn't conform to this room's policies"
+msgstr "Nama panggilan anda tidak sesuai aturan ruangan ini"
+
+#: converse.js:2226
+msgid "Your nickname is already taken"
+msgstr "Nama panggilan anda telah digunakan orang lain"
+
+#: converse.js:2228
+msgid "This room does not (yet) exist"
+msgstr "Ruangan ini belum dibuat"
+
+#: converse.js:2230
+msgid "This room has reached it's maximum number of occupants"
+msgstr "Ruangan ini telah mencapai jumlah penghuni maksimum"
+
+#: converse.js:2309
+msgid "Topic set by %1$s to: %2$s"
+msgstr "Topik diganti oleh %1$s menjadi: %2$s"
+
+#: converse.js:2330
+msgid "This user is a moderator"
+msgstr "Pengguna ini adalah moderator"
+
+#: converse.js:2333
+msgid "This user can send messages in this room"
+msgstr "Pengguna ini dapat mengirim pesan di ruangan ini"
+
+#: converse.js:2336
+msgid "This user can NOT send messages in this room"
+msgstr "Pengguna ini tak dapat mengirim pesan di ruangan ini"
+
+#: converse.js:2562
+msgid "Click to chat with this contact"
+msgstr "Klik untuk mulai perbinjangan dengan teman ini"
+
+#: converse.js:2565 converse.js:2569
+msgid "Click to remove this contact"
+msgstr "Klik untuk menghapus teman ini"
+
+#: converse.js:2919
+msgid "Contact requests"
+msgstr "Permintaan pertemanan"
+
+#: converse.js:2922
+msgid "My contacts"
+msgstr "Teman saya"
+
+#: converse.js:2925
+msgid "Pending contacts"
+msgstr "Teman yang menunggu"
+
+#: converse.js:3167
+msgid "Custom status"
+msgstr "Status kustom"
+
+#: converse.js:3173
+msgid "Click to change your chat status"
+msgstr "Klik untuk mengganti status"
+
+#: converse.js:3177
+msgid "Click here to write a custom status message"
+msgstr "Klik untuk menulis status kustom"
+
+#: converse.js:3206 converse.js:3214
+msgid "online"
+msgstr "terhubung"
+
+#: converse.js:3208
+msgid "busy"
+msgstr "sibuk"
+
+#: converse.js:3210
+msgid "away for long"
+msgstr "lama tak di tempat"
+
+#: converse.js:3212
+msgid "away"
+msgstr "tak di tempat"
+
+#. For translators: the %1$s part gets replaced with the status
+#. Example, I am online
+#: converse.js:3226 converse.js:3263
+msgid "I am %1$s"
+msgstr "Saya %1$s"
+
+#: converse.js:3334
+msgid "Sign in"
+msgstr "Masuk"
+
+#: converse.js:3338
+msgid "XMPP/Jabber Username:"
+msgstr "Nama pengguna XMPP/Jabber:"
+
+#: converse.js:3340
+msgid "Password:"
+msgstr "Kata sandi:"
+
+#: converse.js:3342
+msgid "Log In"
+msgstr "Masuk"
+
+#: converse.js:3346
+msgid "BOSH Service URL:"
+msgstr "URL Layanan BOSH:"

+ 180 - 0
locale/id/LC_MESSAGES/id.js

@@ -0,0 +1,180 @@
+(function(root, factory) {
+    var translations = {
+        "domain": "converse",
+        "locale_data": {
+            "converse": {
+                "": {
+                    "project-id-version": "Converse.js 0.7.0",
+                    "report-msgid-bugs-to": "",
+                    "pot-creation-date": "2014-01-22 17:07+0200",
+                    "po-revision-date": "2014-01-25 21:30+0700",
+                    "last-translator": "Priyadi Iman Nurcahyo <priyadi@priyadi.net>",
+                    "language-team": "Bahasa Indonesia",
+                    "mime-version": "1.0",
+                    "content-type": "text/plain; charset=UTF-8",
+                    "content-transfer-encoding": "8bit",
+                    "language": "id"
+                },
+                "unencrypted": [null, "tak dienkripsi"],
+                "unverified": [null, "tak diverifikasi"],
+                "verified": [null, "diverifikasi"],
+                "finished": [null, "selesai"],
+                "This contact is busy": [null, "Teman ini sedang sibuk"],
+                "This contact is online": [null, "Teman ini terhubung"],
+                "This contact is offline": [null, "Teman ini tidak terhubung"],
+                "This contact is unavailable": [null, "Teman ini tidak tersedia"],
+                "This contact is away for an extended period": [null, "Teman ini tidak di tempat untuk waktu yang lama"],
+                "This contact is away": [null, "Teman ini tidak di tempat"],
+                "Disconnected": [null, "Terputus"],
+                "Error": [null, "Kesalahan"],
+                "Connecting": [null, "Menyambung"],
+                "Connection Failed": [null, "Gagal Menyambung"],
+                "Authenticating": [null, "Melakukan otentikasi"],
+                "Authentication Failed": [null, "Otentikasi gagal"],
+                "Disconnecting": [null, "Memutuskan hubungan"],
+                "Online Contacts": [null, "Teman yang Terhubung"],
+                "Re-establishing encrypted session": [null, "Menyambung kembali sesi terenkripsi"],
+                "Your browser needs to generate a private key, which will be used in your encrypted chat session. This can take up to 30 seconds during which your browser might freeze and become unresponsive.": [null, "Perambah anda perlu membuat kunci privat, yang akan digunakan pada sesi perbincangan anda. Ini akan membutuhkan waktu sampai 30 detik, dan selama itu perambah mungkin akan tidak responsif."],
+                "Private key generated.": [null, "Kunci privat berhasil dibuat."],
+                "Authentication request from %1$s\n\nYour buddy is attempting to verify your identity, by asking you the question below.\n\n%2$s": [null, "Permintaan otentikasi dari %1$s\n\nTeman anda mencoba untuk melakukan verifikasi identitas anda dengan cara menanyakan pertanyaan di bawah ini.\n\n%2$s"],
+                "Could not verify this user's identify.": [null, "Tak dapat melakukan verifikasi identitas pengguna ini."],
+                "Personal message": [null, "Pesan pribadi"],
+                "Start encrypted conversation": [null, "Mulai sesi terenkripsi"],
+                "Refresh encrypted conversation": [null, "Setel ulang percakapan terenkripsi"],
+                "End encrypted conversation": [null, "Sudahi percakapan terenkripsi"],
+                "Verify with SMP": [null, "Verifikasi menggunakan SMP"],
+                "Verify with fingerprints": [null, "Verifikasi menggunakan sidik jari"],
+                "What's this?": [null, "Apakah ini?"],
+                "me": [null, "saya"],
+                "Show this menu": [null, "Tampilkan menu ini"],
+                "Write in the third person": [null, "Tulis ini menggunakan bahasa pihak ketiga"],
+                "Remove messages": [null, "Hapus pesan"],
+                "Your message could not be sent": [null, "Pesan anda tak dapat dikirim"],
+                "We received an unencrypted message": [null, "Kami menerima pesan terenkripsi"],
+                "We received an unreadable encrypted message": [null, "Kami menerima pesan terenkripsi yang gagal dibaca"],
+                "This user has requested an encrypted session.": [null, "Pengguna ini meminta sesi terenkripsi"],
+                "Here are the fingerprints, please confirm them with %1$s, outside of this chat.\n\nFingerprint for you, %2$s: %3$s\n\nFingerprint for %1$s: %4$s\n\nIf you have confirmed that the fingerprints match, click OK, otherwise click Cancel.": [null, "Ini adalah sidik jari anda, konfirmasikan bersama mereka dengan %1$s, di luar percakapan ini.\n\nSidik jari untuk anda, %2$s: %3$s\n\nSidik jari untuk %1$s: %4$s\n\nJika anda bisa mengkonfirmasi sidik jadi cocok, klik Lanjutkan, jika tidak klik Batal."],
+                "You will be prompted to provide a security question and then an answer to that question.\n\nYour buddy will then be prompted the same question and if they type the exact same answer (case sensitive), their identity will have been verified.": [null, "Anda akan ditanyakan pertanyaan untuk keamanan beserta jawaban untuk pertanyaan tersebut.\n\nTeman anda akan ditanyakan pertanyaan yang sama dan jika dia memberikan jawaban yang sama (huruf kapital diperhatikan), identitas mereka diverifikasi."],
+                "What is your security question?": [null, "Apakah pertanyaan keamanan anda?"],
+                "What is the answer to the security question?": [null, "Apa jawaban dari pertanyaan keamanan tersebut?"],
+                "Invalid authentication scheme provided": [null, "Skema otentikasi salah"],
+                "Your messages are not encrypted anymore": [null, "Pesan anda tidak lagi terenkripsi"],
+                "Your messages are now encrypted but your buddy's identity has not been verified.": [null, "Pesan anda sekarang terenkripsi, namun identitas teman anda belum dapat diverifikasi."],
+                "Your buddy's identify has been verified.": [null, "Identitas teman anda telah diverifikasi."],
+                "Your buddy has ended encryption on their end, you should do the same.": [null, "Teman anda menghentikan percakapan terenkripsi, anda sebaiknya melakukan hal yang sama."],
+                "Your messages are not encrypted. Click here to enable OTR encryption.": [null, "Pesan anda tak terenkripsi. Klik di sini untuk menyalakan enkripsi OTR."],
+                "Your messages are encrypted, but your buddy has not been verified.": [null, "Pesan anda terenkripsi, tetapi teman anda belum diverifikasi."],
+                "Your messages are encrypted and your buddy verified.": [null, "Pesan anda terenkripsi dan teman anda telah diverifikasi."],
+                "Your buddy has closed their end of the private session, you should do the same": [null, "Teman anda telah mematikan sesi terenkripsi, dan anda juga sebaiknya melakukan hal yang sama"],
+                "Contacts": [null, "Teman"],
+                "Online": [null, "Terhubung"],
+                "Busy": [null, "Sibuk"],
+                "Away": [null, "Pergi"],
+                "Offline": [null, "Tak Terhubung"],
+                "Click to add new chat contacts": [null, "Klik untuk menambahkan teman baru"],
+                "Add a contact": [null, "Tambah teman"],
+                "Contact username": [null, "Username teman"],
+                "Add": [null, "Tambah"],
+                "Contact name": [null, "Nama teman"],
+                "Search": [null, "Cari"],
+                "No users found": [null, "Pengguna tak ditemukan"],
+                "Click to add as a chat contact": [null, "Klik untuk menambahkan sebagai teman"],
+                "Click to open this room": [null, "Klik untuk membuka ruangan ini"],
+                "Show more information on this room": [null, "Tampilkan informasi ruangan ini"],
+                "Description:": [null, "Keterangan:"],
+                "Occupants:": [null, "Penghuni:"],
+                "Features:": [null, "Fitur:"],
+                "Requires authentication": [null, "Membutuhkan otentikasi"],
+                "Hidden": [null, "Tersembunyi"],
+                "Requires an invitation": [null, "Membutuhkan undangan"],
+                "Moderated": [null, "Dimoderasi"],
+                "Non-anonymous": [null, "Tidak anonim"],
+                "Open room": [null, "Ruangan terbuka"],
+                "Permanent room": [null, "Ruangan permanen"],
+                "Public": [null, "Umum"],
+                "Semi-anonymous": [null, "Semi-anonim"],
+                "Temporary room": [null, "Ruangan sementara"],
+                "Unmoderated": [null, "Tak dimoderasi"],
+                "Rooms": [null, "Ruangan"],
+                "Room name": [null, "Nama ruangan"],
+                "Nickname": [null, "Nama panggilan"],
+                "Server": [null, "Server"],
+                "Join": [null, "Ikuti"],
+                "Show rooms": [null, "Perlihatkan ruangan"],
+                "No rooms on %1$s": [null, "Tak ada ruangan di %1$s"],
+                "Rooms on %1$s": [null, "Ruangan di %1$s"],
+                "Set chatroom topic": [null, "Setel topik ruangan"],
+                "Kick user from chatroom": [null, "Tendang pengguna dari ruangan"],
+                "Ban user from chatroom": [null, "Larang pengguna dari ruangan"],
+                "Message": [null, "Pesan"],
+                "Save": [null, "Simpan"],
+                "Cancel": [null, "Batal"],
+                "An error occurred while trying to save the form.": [null, "Kesalahan terjadi saat menyimpan formulir ini."],
+                "This chatroom requires a password": [null, "Ruangan ini membutuhkan kata sandi"],
+                "Password: ": [null, "Kata sandi: "],
+                "Submit": [null, "Kirim"],
+                "This room is not anonymous": [null, "Ruangan ini tidak anonim"],
+                "This room now shows unavailable members": [null, "Ruangan ini menampilkan anggota yang tak tersedia"],
+                "This room does not show unavailable members": [null, "Ruangan ini tidak menampilkan anggota yang tak tersedia"],
+                "Non-privacy-related room configuration has changed": [null, "Konfigurasi ruangan yang tak berhubungan dengan privasi telah diubah"],
+                "Room logging is now enabled": [null, "Pencatatan di ruangan ini sekarang dinyalakan"],
+                "Room logging is now disabled": [null, "Pencatatan di ruangan ini sekarang dimatikan"],
+                "This room is now non-anonymous": [null, "Ruangan ini sekarang tak-anonim"],
+                "This room is now semi-anonymous": [null, "Ruangan ini sekarang semi-anonim"],
+                "This room is now fully-anonymous": [null, "Ruangan ini sekarang anonim"],
+                "A new room has been created": [null, "Ruangan baru telah dibuat"],
+                "Your nickname has been changed": [null, "Nama panggilan anda telah diubah"],
+                "<strong>%1$s</strong> has been banned": [null, "<strong>%1$s</strong> telah dicekal"],
+                "<strong>%1$s</strong> has been kicked out": [null, "<strong>%1$s</strong> telah ditendang keluar"],
+                "<strong>%1$s</strong> has been removed because of an affiliation change": [null, "<strong>%1$s</strong> telah dihapus karena perubahan afiliasi"],
+                "<strong>%1$s</strong> has been removed for not being a member": [null, "<strong>%1$s</strong> telah dihapus karena bukan anggota"],
+                "You have been banned from this room": [null, "Anda telah dicekal dari ruangan ini"],
+                "You have been kicked from this room": [null, "Anda telah ditendang dari ruangan ini"],
+                "You have been removed from this room because of an affiliation change": [null, "Anda telah dihapus dari ruangan ini karena perubahan afiliasi"],
+                "You have been removed from this room because the room has changed to members-only and you're not a member": [null, "Anda telah dihapus dari ruangan ini karena ruangan ini hanya terbuka untuk anggota dan anda bukan anggota"],
+                "You have been removed from this room because the MUC (Multi-user chat) service is being shut down.": [null, "Anda telah dihapus dari ruangan ini karena layanan MUC (Multi-user chat) telah dimatikan."],
+                "You are not on the member list of this room": [null, "Anda bukan anggota dari ruangan ini"],
+                "No nickname was specified": [null, "Nama panggilan belum ditentukan"],
+                "You are not allowed to create new rooms": [null, "Anda tak diizinkan untuk membuat ruangan baru"],
+                "Your nickname doesn't conform to this room's policies": [null, "Nama panggilan anda tidak sesuai aturan ruangan ini"],
+                "Your nickname is already taken": [null, "Nama panggilan anda telah digunakan orang lain"],
+                "This room does not (yet) exist": [null, "Ruangan ini belum dibuat"],
+                "This room has reached it's maximum number of occupants": [null, "Ruangan ini telah mencapai jumlah penghuni maksimum"],
+                "Topic set by %1$s to: %2$s": [null, "Topik diganti oleh %1$s menjadi: %2$s"],
+                "This user is a moderator": [null, "Pengguna ini adalah moderator"],
+                "This user can send messages in this room": [null, "Pengguna ini dapat mengirim pesan di ruangan ini"],
+                "This user can NOT send messages in this room": [null, "Pengguna ini tak dapat mengirim pesan di ruangan ini"],
+                "Click to chat with this contact": [null, "Klik untuk mulai perbinjangan dengan teman ini"],
+                "Click to remove this contact": [null, "Klik untuk menghapus teman ini"],
+                "Contact requests": [null, "Permintaan pertemanan"],
+                "My contacts": [null, "Teman saya"],
+                "Pending contacts": [null, "Teman yang menunggu"],
+                "Custom status": [null, "Status kustom"],
+                "Click to change your chat status": [null, "Klik untuk mengganti status"],
+                "Click here to write a custom status message": [null, "Klik untuk menulis status kustom"],
+                "online": [null, "terhubung"],
+                "busy": [null, "sibuk"],
+                "away for long": [null, "lama tak di tempat"],
+                "away": [null, "tak di tempat"],
+                "I am %1$s": [null, "Saya %1$s"],
+                "Sign in": [null, "Masuk"],
+                "XMPP/Jabber Username:": [null, "Nama pengguna XMPP/Jabber:"],
+                "Password:": [null, "Kata sandi:"],
+                "Log In": [null, "Masuk"],
+                "BOSH Service URL:": [null, "URL Layanan BOSH:"]
+            }
+        }
+    };
+    if (typeof define === 'function' && define.amd) {
+        define("id", ['jed'], function () {
+            return factory(new Jed(translations));
+        });
+    } else {
+        if (!window.locales) {
+            window.locales = {};
+        }
+        window.locales.id = factory(new Jed(translations));
+    }
+}(this, function (id) { 
+    return id; 
+}));

+ 7 - 1
locale/locales.js

@@ -14,7 +14,9 @@
             "en": "locale/en/LC_MESSAGES/en",
             "es": "locale/es/LC_MESSAGES/es",
             "fr": "locale/fr/LC_MESSAGES/fr",
+            "he": "locale/he/LC_MESSAGES/he",
             "hu": "locale/hu/LC_MESSAGES/hu",
+            "id": "locale/id/LC_MESSAGES/id",
             "it": "locale/it/LC_MESSAGES/it",
             "ja": "locale/ja/LC_MESSAGES/ja",
             "nl": "locale/nl/LC_MESSAGES/nl",
@@ -30,20 +32,24 @@
         'en',
         'es',
         'fr',
+        'he',
         'hu',
+        'id',
         'it',
         'ja',
         'nl',
         'pt_BR',
         'ru'
-        ], function (jed, af, de, en, es, fr, hu, it, ja, nl, pt_BR, ru) {
+        ], function (jed, af, de, en, es, fr, he, hu, id, it, ja, nl, pt_BR, ru) {
             root.locales = {
                 'af': af,
                 'de': de,
                 'en': en,
                 'es': es,
                 'fr': fr,
+                'he': he,
                 'hu': hu,
+                'id': id,
                 'it': it,
                 'ja': ja,
                 'nl': nl,

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "converse.js",
-  "version": "0.7.2",
+  "version": "0.7.3",
   "description": "Browser based XMPP instant messaging client",
   "main": "main.js",
   "directories": {

+ 34 - 54
spec/converse.js

@@ -8,60 +8,40 @@
     );
 } (this, function (mock, utils) {
     return describe("Converse", $.proxy(function(mock, utils) {
-        window.localStorage.clear();
 
-        it("allows you to subscribe to emitted events", function () {
-            this.callback = function () {};
-            spyOn(this, 'callback');
-            converse.on('onInitialized', this.callback);
-            converse.emit('onInitialized');
-            expect(this.callback).toHaveBeenCalled();
-            converse.emit('onInitialized');
-            expect(this.callback.callCount, 2);
-            converse.emit('onInitialized');
-            expect(this.callback.callCount, 3);
-        });
-
-        it("allows you to listen once for an emitted event", function () {
-            this.callback = function () {};
-            spyOn(this, 'callback');
-            converse.once('onInitialized', this.callback);
-            converse.emit('onInitialized');
-            expect(this.callback).toHaveBeenCalled();
-            converse.emit('onInitialized');
-            expect(this.callback.callCount, 1);
-            converse.emit('onInitialized');
-            expect(this.callback.callCount, 1);
-        });
-
-        it("allows you to stop listening or subscribing to an event", function () {
-            this.callback = function () {};
-            this.anotherCallback = function () {};
-            this.neverCalled = function () {};
-
-            spyOn(this, 'callback');
-            spyOn(this, 'anotherCallback');
-            spyOn(this, 'neverCalled');
-            converse.on('onInitialized', this.callback);
-            converse.on('onInitialized', this.anotherCallback);
-
-            converse.emit('onInitialized');
-            expect(this.callback).toHaveBeenCalled();
-            expect(this.anotherCallback).toHaveBeenCalled();
-
-            converse.off('onInitialized', this.callback);
-
-            converse.emit('onInitialized');
-            expect(this.callback.callCount, 1);
-            expect(this.anotherCallback.callCount, 2);
-
-            converse.once('onInitialized', this.neverCalled);
-            converse.off('onInitialized', this.neverCalled);
-
-            converse.emit('onInitialized');
-            expect(this.callback.callCount, 1);
-            expect(this.anotherCallback.callCount, 3);
-            expect(this.neverCalled).not.toHaveBeenCalled();
-        });
+        beforeEach($.proxy(function () {
+            window.localStorage.clear();
+            window.sessionStorage.clear();
+        }, converse));
+
+        it("has an API method for retrieving the next RID", $.proxy(function () {
+            var old_connection = converse.connection;
+            converse.connection.rid = '1234';
+            converse.expose_rid_and_sid = false;
+            expect(converse_api.getRID()).toBe(null);
+
+            converse.expose_rid_and_sid = true;
+            expect(converse_api.getRID()).toBe('1234');
+
+            converse.connection = undefined;
+            expect(converse_api.getRID()).toBe(null);
+            // Restore the connection
+            converse.connection = old_connection;
+        }, converse));
+
+        it("has an API method for retrieving the SID", $.proxy(function () {
+            var old_connection = converse.connection;
+            converse.connection.sid = '1234';
+            converse.expose_rid_and_sid = false;
+            expect(converse_api.getSID()).toBe(null);
+
+            converse.expose_rid_and_sid = true;
+            expect(converse_api.getSID()).toBe('1234');
+
+            converse.connection = undefined;
+            expect(converse_api.getSID()).toBe(null);
+            // Restore the connection
+            converse.connection = old_connection;
+        }, converse));
     }, converse, mock, utils));
 }));

+ 67 - 0
spec/eventemitter.js

@@ -0,0 +1,67 @@
+(function (root, factory) {
+    define([
+        "mock",
+        "utils"
+        ], function (mock, utils) {
+            return factory(mock, utils);
+        }
+    );
+} (this, function (mock, utils) {
+    return describe("The Converse Event Emitter", $.proxy(function(mock, utils) {
+        window.localStorage.clear();
+
+        it("allows you to subscribe to emitted events", function () {
+            this.callback = function () {};
+            spyOn(this, 'callback');
+            converse.on('onInitialized', this.callback);
+            converse.emit('onInitialized');
+            expect(this.callback).toHaveBeenCalled();
+            converse.emit('onInitialized');
+            expect(this.callback.callCount, 2);
+            converse.emit('onInitialized');
+            expect(this.callback.callCount, 3);
+        });
+
+        it("allows you to listen once for an emitted event", function () {
+            this.callback = function () {};
+            spyOn(this, 'callback');
+            converse.once('onInitialized', this.callback);
+            converse.emit('onInitialized');
+            expect(this.callback).toHaveBeenCalled();
+            converse.emit('onInitialized');
+            expect(this.callback.callCount, 1);
+            converse.emit('onInitialized');
+            expect(this.callback.callCount, 1);
+        });
+
+        it("allows you to stop listening or subscribing to an event", function () {
+            this.callback = function () {};
+            this.anotherCallback = function () {};
+            this.neverCalled = function () {};
+
+            spyOn(this, 'callback');
+            spyOn(this, 'anotherCallback');
+            spyOn(this, 'neverCalled');
+            converse.on('onInitialized', this.callback);
+            converse.on('onInitialized', this.anotherCallback);
+
+            converse.emit('onInitialized');
+            expect(this.callback).toHaveBeenCalled();
+            expect(this.anotherCallback).toHaveBeenCalled();
+
+            converse.off('onInitialized', this.callback);
+
+            converse.emit('onInitialized');
+            expect(this.callback.callCount, 1);
+            expect(this.anotherCallback.callCount, 2);
+
+            converse.once('onInitialized', this.neverCalled);
+            converse.off('onInitialized', this.neverCalled);
+
+            converse.emit('onInitialized');
+            expect(this.callback.callCount, 1);
+            expect(this.anotherCallback.callCount, 3);
+            expect(this.neverCalled).not.toHaveBeenCalled();
+        });
+    }, converse, mock, utils));
+}));

+ 40 - 0
spec/otr.js

@@ -0,0 +1,40 @@
+(function (root, factory) {
+    define([
+        "mock",
+        "utils"
+        ], function (mock, utils) {
+            return factory(mock, utils);
+        }
+    );
+} (this, function (mock, utils) {
+    return describe("The OTR module", $.proxy(function(mock, utils) {
+
+        beforeEach($.proxy(function () {
+            window.localStorage.clear();
+            window.sessionStorage.clear();
+        }, converse));
+
+        it("can store a session passphrase in session storage", $.proxy(function () {
+            var pp;
+            // With no prebind, the user's XMPP password is used and nothing is
+            // stored in session storage.
+            this.prebind = false;
+            this.connection.pass = 's3cr3t!';
+            expect(this.otr.getSessionPassphrase()).toBe(this.connection.pass);
+            expect(window.sessionStorage.length).toBe(0); 
+            expect(window.localStorage.length).toBe(0); 
+
+            // With prebind, a random passphrase is generated and stored in
+            // session storage.
+            this.prebind = true;
+            pp = this.otr.getSessionPassphrase();
+            expect(pp).not.toBe(this.connection.pass);
+            expect(window.sessionStorage.length).toBe(1);
+            expect(window.localStorage.length).toBe(0); 
+            expect(pp).toBe(window.sessionStorage[hex_sha1(converse.connection.jid)]);
+
+            // Clean up
+            this.prebind = false;
+        }, converse));
+    }, converse, mock, utils));
+}));

+ 0 - 2
src/build-no-locales-no-otr.js

@@ -7,8 +7,6 @@
         "jquery": "components/jquery/jquery",
         "jed": "components/jed/jed",
         "locales": "locale/nolocales",
-        "pt_BR": "locale/pt_BR/LC_MESSAGES/pt_BR", 
-        "ru": "locale/ru/LC_MESSAGES/ru",
         "jquery.tinysort": "components/tinysort/src/jquery.tinysort",
         "underscore": "components/underscore/underscore",
         "backbone": "components/backbone/backbone",

+ 3 - 0
src/build-no-otr.js

@@ -12,8 +12,11 @@
         "en": "locale/en/LC_MESSAGES/en",
         "es": "locale/es/LC_MESSAGES/es",
         "fr": "locale/fr/LC_MESSAGES/fr",
+        "he": "locale/he/LC_MESSAGES/he",
         "hu": "locale/hu/LC_MESSAGES/hu",
         "it": "locale/it/LC_MESSAGES/it",
+        "id": "locale/id/LC_MESSAGES/id",
+        "ja": "locale/ja/LC_MESSAGES/ja",
         "nl": "locale/nl/LC_MESSAGES/nl",
         "pt_BR": "locale/pt_BR/LC_MESSAGES/pt_BR", 
         "ru": "locale/ru/LC_MESSAGES/ru",

+ 3 - 0
src/build.js

@@ -12,8 +12,11 @@
         "en": "locale/en/LC_MESSAGES/en",
         "es": "locale/es/LC_MESSAGES/es",
         "fr": "locale/fr/LC_MESSAGES/fr",
+        "he": "locale/he/LC_MESSAGES/he",
         "hu": "locale/hu/LC_MESSAGES/hu",
+        "id": "locale/id/LC_MESSAGES/id",
         "it": "locale/it/LC_MESSAGES/it",
+        "ja": "locale/ja/LC_MESSAGES/ja",
         "nl": "locale/nl/LC_MESSAGES/nl",
         "pt_BR": "locale/pt_BR/LC_MESSAGES/pt_BR", 
         "ru": "locale/ru/LC_MESSAGES/ru",

+ 11 - 0
tests_main.js

@@ -47,6 +47,7 @@ require([
     "jasmine-html"
     ], function($, converse, mock, jasmine) {
         // Set up converse.js
+        window.converse_api = converse;
         window.localStorage.clear();
         converse.initialize({
             prebind: false,
@@ -58,10 +59,20 @@ require([
             testing: true
         }, function (converse) {
             window.converse = converse;
+            window.crypto = {
+                getRandomValues: function (buf) {
+                    var i;
+                    for (i=0, len=buf.length; i<len; i++) {
+                        buf[i] = Math.floor(Math.random()*256);
+                    } 
+                }
+            };
             require([
                 "jasmine-console-reporter",
                 "jasmine-junit-reporter",
                 "spec/converse",
+                "spec/otr",
+                "spec/eventemitter",
                 "spec/controlbox",
                 "spec/chatbox",
                 "spec/chatroom"

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików