2
0
Эх сурвалжийг харах

Add jed.js for i18n support and wrap all strings

JC Brand 12 жил өмнө
parent
commit
debb773ea5
2 өөрчлөгдсөн 802 нэмэгдсэн , 131 устгасан
  1. 632 0
      Libraries/jed.js
  2. 170 131
      converse.js

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 632 - 0
Libraries/jed.js


+ 170 - 131
converse.js

@@ -14,6 +14,7 @@
     if (typeof define === 'function' && define.amd) {
         require.config({
             paths: {
+                "jed": "Libraries/jed",
                 "sjcl": "Libraries/sjcl",
                 "tinysort": "Libraries/jquery.tinysort",
                 "underscore": "Libraries/underscore",
@@ -48,6 +49,7 @@
         });
 
         define("converse", [
+            "jed",
             "localstorage",
             "tinysort",
             "sjcl",
@@ -61,7 +63,7 @@
                     evaluate : /\{\[([\s\S]+?)\]\}/g,
                     interpolate : /\{\{([\s\S]+?)\}\}/g
                 };
-                return factory(jQuery, _, console);
+                return factory(jQuery, _, Jed, console);
             }
         );
     } else {
@@ -72,16 +74,37 @@
         };
         root.converse = factory(jQuery, _, console || {log: function(){}});
     }
-}(this, function ($, _, console) {
+}(this, function ($, _, Jed, console) {
     var converse = {};
-    converse.msg_counter = 0;
-
-    var strinclude = function(str, needle){
-      if (needle === '') { return true; }
-      if (str === null) { return false; }
-      return String(str).indexOf(needle) !== -1;
+    var i18n = new Jed({
+        domain: "messages",
+        // This is the translation data, which is often generated by
+        // a po2json converter. You would ideally have one per locale
+        // and only pull in the locale_data that you need.
+        "locale_data" : {
+            // This is the domain key
+            "messages" : {
+                // The empty string key is used as the configuration
+                // block for each domain
+                "" : {
+                    "domain" : "messages",
+                    "lang" : "en",
+                    "plural_forms" : "nplurals=2; plural=(n != 1);"
+                }
+            }
+        }
+    });
+    var __ = function (str) {
+        var t = i18n.translate(str);
+        if (arguments.length>1) {
+            return t.fetch.apply(t, [].slice.call(arguments,1));
+        } else {
+            return t.fetch();
+        }
     };
 
+    converse.msg_counter = 0;
+
     converse.autoLink = function (text) {
         // Convert URLs into hyperlinks
         var re = /((http|https|ftp):\/\/[\w?=&.\/\-;#~%\-]+(?![\w\s?&.\/;#~%"=\-]*>))/g;
@@ -390,9 +413,9 @@
                 }
                 else if (match[1] === "help") {
                     msgs = [
-                        '<strong>/help</strong>: Show this menu',
-                        '<strong>/me</strong>: Write in the third person',
-                        '<strong>/clear</strong>: Remove messages'
+                        '<strong>/help</strong>:'+__('Show this menu')+'',
+                        '<strong>/me</strong>:'+__('Write in the third person')+'',
+                        '<strong>/clear</strong>:'+__('Remove messages')+''
                         ];
                     this.addHelpMessages(msgs);
                     return;
@@ -532,7 +555,7 @@
             '<textarea ' +
                 'type="text" ' +
                 'class="chat-textarea" ' +
-                'placeholder="Personal message"/>'+
+                'placeholder="'+__('Personal message')+'"/>'+
             '</form>'),
 
         renderAvatar: function () {
@@ -606,21 +629,22 @@
             'click a.subscribe-to-user': 'addContactFromList'
         },
 
-        tab_template: _.template('<li><a class="s current" href="#users">Contacts</a></li>'),
+        tab_template: _.template('<li><a class="s current" href="#users">'+__('Contacts')+'</a></li>'),
         template: _.template(
             '<form class="set-xmpp-status" action="" method="post">'+
                 '<span id="xmpp-status-holder">'+
                     '<select id="select-xmpp-status" style="display:none">'+
-                        '<option value="online">Online</option>'+
-                        '<option value="dnd">Busy</option>'+
-                        '<option value="away">Away</option>'+
-                        '<option value="offline">Offline</option>'+
+                        '<option value="online">'+__('Online')+'</option>'+
+                        '<option value="dnd">'+__('Busy')+'</option>'+
+                        '<option value="away">'+__('Away')+'</option>'+
+                        '<option value="offline">'+__('Offline')+'</option>'+
                     '</select>'+
                 '</span>'+
             '</form>'+
             '<dl class="add-converse-contact dropdown">' +
                 '<dt id="xmpp-contact-search" class="fancy-dropdown">' +
-                    '<a class="toggle-xmpp-contact-form" href="#" title="Click to add new chat contacts">Add a contact</a>' +
+                    '<a class="toggle-xmpp-contact-form" href="#"'+
+                        'title="'+__('Click to add new chat contacts')+'">'+__('Add a contact')+'</a>' +
                 '</dt>' +
                 '<dd class="search-xmpp" style="display:none"><ul></ul></dd>' +
             '</dl>'
@@ -629,8 +653,8 @@
         add_contact_template: _.template(
             '<li>'+
                 '<form class="add-xmpp-contact">' +
-                    '<input type="text" name="identifier" class="username" placeholder="Contact username"/>' +
-                    '<button type="submit">Add</button>' +
+                    '<input type="text" name="identifier" class="username" placeholder="'+__('Contact username')+'"/>' +
+                    '<button type="submit">'+__('Add')+'</button>' +
                 '</form>'+
             '<li>'
         ),
@@ -638,8 +662,8 @@
         search_contact_template: _.template(
             '<li>'+
                 '<form class="search-xmpp-contact">' +
-                    '<input type="text" name="identifier" class="username" placeholder="Contact name"/>' +
-                    '<button type="submit">Search</button>' +
+                    '<input type="text" name="identifier" class="username" placeholder="'+__('Contact name')+'"/>' +
+                    '<button type="submit">'+__('Search')+'</button>' +
                 '</form>'+
             '<li>'
         ),
@@ -674,14 +698,14 @@
                 $ul.find('li.found-user').remove();
                 $ul.find('li.chat-info').remove();
                 if (!data.length) {
-                    $ul.append('<li class="chat-info">No users found</li>');
+                    $ul.append('<li class="chat-info">'+__('No users found')+'</li>');
                 }
 
                 $(data).each(function (idx, obj) {
                     $ul.append(
                         $('<li class="found-user"></li>')
                         .append(
-                            $('<a class="subscribe-to-user" href="#" title="Click to add as a chat contact"></a>')
+                            $('<a class="subscribe-to-user" href="#" title="'+__('Click to add as a chat contact')+'"></a>')
                             .attr('data-recipient', Strophe.escapeNode(obj.id)+'@'+converse.domain)
                             .text(obj.fullname)
                         )
@@ -744,61 +768,63 @@
         },
         room_template: _.template(
             '<dd class="available-chatroom">'+
-            '<a class="open-room" data-room-jid="{{jid}}" title="Click to open this room" href="#">{{name}}</a>'+
-            '<a class="room-info" data-room-jid="{{jid}}" title="Show more information on this room" href="#">&nbsp;</a>'+
+            '<a class="open-room" data-room-jid="{{jid}}"'+
+               'title="'+__('Click to open this room')+'" href="#">{{name}}</a>'+
+            '<a class="room-info" data-room-jid="{{jid}}"'+
+               'title="'+__('Show more information on this room')+'" href="#">&nbsp;</a>'+
             '</dd>'),
 
         room_description_template: _.template(
             '<div class="room-info">'+
-            '<p class="room-info"><strong>Description:</strong> {{desc}}</p>' +
-            '<p class="room-info"><strong>Occupants:</strong> {{occ}}</p>' +
-            '<p class="room-info"><strong>Features:</strong> <ul>'+
+            '<p class="room-info"><strong>'+__('Description:')+'</strong> {{desc}}</p>' +
+            '<p class="room-info"><strong>'+__('Occupants:')+'</strong> {{occ}}</p>' +
+            '<p class="room-info"><strong>'+__('Features:')+'</strong> <ul>'+
             '{[ if (passwordprotected) { ]}' +
-                '<li class="room-info locked">Requires authentication</li>' +
+                '<li class="room-info locked">'+__('Requires authentication')+'</li>' +
             '{[ } ]}' +
             '{[ if (hidden) { ]}' +
-                '<li class="room-info">Hidden</li>' +
+                '<li class="room-info">'+__('Hidden')+'</li>' +
             '{[ } ]}' +
             '{[ if (membersonly) { ]}' +
-                '<li class="room-info">Requires an invitation</li>' +
+                '<li class="room-info">'+__('Requires an invitation')+'</li>' +
             '{[ } ]}' +
             '{[ if (moderated) { ]}' +
-                '<li class="room-info">Moderated</li>' +
+                '<li class="room-info">'+__('Moderated')+'</li>' +
             '{[ } ]}' +
             '{[ if (nonanonymous) { ]}' +
-                '<li class="room-info">Non-anonymous</li>' +
+                '<li class="room-info">'+__('Non-anonymous')+'</li>' +
             '{[ } ]}' +
             '{[ if (open) { ]}' +
-                '<li class="room-info">Open room</li>' +
+                '<li class="room-info">'+__('Open room')+'</li>' +
             '{[ } ]}' +
             '{[ if (persistent) { ]}' +
-                '<li class="room-info">Permanent room</li>' +
+                '<li class="room-info">'+__('Permanent room')+'</li>' +
             '{[ } ]}' +
             '{[ if (publicroom) { ]}' +
-                '<li class="room-info">Public</li>' +
+                '<li class="room-info">'+__('Public')+'</li>' +
             '{[ } ]}' +
             '{[ if (semianonymous) { ]}' +
-                '<li class="room-info">Semi-anonymous</li>' +
+                '<li class="room-info">'+__('Semi-anonymous')+'</li>' +
             '{[ } ]}' +
             '{[ if (temporary) { ]}' +
-                '<li class="room-info">Temporary room</li>' +
+                '<li class="room-info">'+__('Temporary room')+'</li>' +
             '{[ } ]}' +
             '{[ if (unmoderated) { ]}' +
-                '<li class="room-info">Unmoderated</li>' +
+                '<li class="room-info">'+__('Unmoderated')+'</li>' +
             '{[ } ]}' +
             '</p>' +
             '</div>'
         ),
 
-        tab_template: _.template('<li><a class="s" href="#chatrooms">Rooms</a></li>'),
+        tab_template: _.template('<li><a class="s" href="#chatrooms">'+__('Rooms')+'</a></li>'),
 
         template: _.template(
             '<form class="add-chatroom" action="" method="post">'+
-                '<input type="text" name="chatroom" class="new-chatroom-name" placeholder="Room name"/>'+
-                '<input type="text" name="nick" class="new-chatroom-nick" placeholder="Nickname"/>'+
-                '<input type="{{ server_input_type }}" name="server" class="new-chatroom-server" placeholder="Server"/>'+
-                '<input type="submit" name="join" value="Join"/>'+
-                '<input type="button" name="show" id="show-rooms" value="Show rooms"/>'+
+                '<input type="text" name="chatroom" class="new-chatroom-name" placeholder="'+__('Room name')+'"/>'+
+                '<input type="text" name="nick" class="new-chatroom-nick" placeholder="'+__('Nickname')+'"/>'+
+                '<input type="{{ server_input_type }}" name="server" class="new-chatroom-server" placeholder="'+__('Server')+'"/>'+
+                '<input type="submit" name="join" value="'+__('Join')+'"/>'+
+                '<input type="button" name="show" id="show-rooms" value="'+__('Show rooms')+'"/>'+
             '</form>'+
             '<dl id="available-chatrooms"></dl>'),
 
@@ -1063,7 +1089,7 @@
                         }
                     }
                 });
-                converse.xmppstatusview = new converse.XMPPStatusView({'model': converse.xmppstatus})
+                converse.xmppstatusview = new converse.XMPPStatusView({'model': converse.xmppstatus});
                 converse.xmppstatusview.render();
                 this.roomspanel = new converse.RoomsPanel();
                 this.roomspanel.$parent = this.$el;
@@ -1112,12 +1138,12 @@
                 case 'help':
                     $chat_content = this.$el.find('.chat-content');
                     msgs = [
-                        '<strong>/help</strong>: Show this menu',
-                        '<strong>/me</strong>: Write in the third person',
-                        '<strong>/topic</strong>: Set chatroom topic',
-                        '<strong>/kick</strong>: Kick user from chatroom',
-                        '<strong>/ban</strong>: Ban user from chatroom',
-                        '<strong>/clear</strong>: Remove messages'
+                        '<strong>/help</strong>:'+__('Show this menu')+'',
+                        '<strong>/me</strong>:'+__('Write in the third person')+'',
+                        '<strong>/topic</strong>:'+__('Set chatroom topic')+'',
+                        '<strong>/kick</strong>:'+__('Kick user from chatroom')+'',
+                        '<strong>/ban</strong>:'+__('Ban user from chatroom')+'',
+                        '<strong>/clear</strong>:'+__('Remove messages')+''
                         ];
                     this.addHelpMessages(msgs);
                     break;
@@ -1143,7 +1169,7 @@
                 '<div class="chat-content"></div>' +
                 '<form class="sendXMPPMessage" action="" method="post">' +
                     '<textarea type="text" class="chat-textarea" ' +
-                        'placeholder="Message"/>' +
+                        'placeholder="'+__('Message')+'"/>' +
                 '</form>' +
             '</div>' +
             '<div class="participants">' +
@@ -1257,8 +1283,8 @@
                     }));
                 }
             }
-            $form.append('<input type="submit" value="Save"/>');
-            $form.append('<input type="button" value="Cancel"/>');
+            $form.append('<input type="submit" value="'+__('Save')+'"/>');
+            $form.append('<input type="button" value="'+__('Cancel')+'"/>');
             $form.on('submit', $.proxy(this.saveConfiguration, this));
             $form.find('input[type=button]').on('click', $.proxy(this.cancelConfiguration, this));
         },
@@ -1305,7 +1331,7 @@
         },
 
         onErrorConfigSaved: function (stanza) {
-            this.insertStatusNotification("An error occurred while trying to save the form.");
+            this.insertStatusNotification(__("An error occurred while trying to save the form."));
         },
 
         cancelConfiguration: function (ev) {
@@ -1351,9 +1377,9 @@
             this.$el.find('.chat-body').append(
                 $('<div class="chatroom-form-container">'+
                     '<form class="chatroom-form">'+
-                        '<legend>This chat room requires a password</legend>' +
-                        '<label>Password: <input type="password" name="password"/></label>' +
-                        '<input type="submit"/>' +
+                        '<legend>'+__('This chatroom requires a password')+'</legend>' +
+                        '<label>'+__('Password: ')+'<input type="password" name="password"/></label>' +
+                        '<input type="submit" value="'+__('Submit')+'/>' +
                     '</form>'+
                   '</div>'));
             this.$el.find('.chatroom-form').on('submit', $.proxy(this.submitPassword, this));
@@ -1367,34 +1393,44 @@
         },
 
         infoMessages: {
-            100: 'This room is not anonymous',
-            102: 'This room now shows unavailable members',
-            103: 'This room does not show unavailable members',
-            104: 'Non-privacy-related room configuration has changed',
-            170: 'Room logging is now enabled',
-            171: 'Room logging is now disabled',
-            172: 'This room is now non-anonymous',
-            173: 'This room is now semi-anonymous',
-            174: 'This room is now fully-anonymous',
-            201: 'A new room has been created',
-            210: 'Your nickname has been changed'
+            100: __('This room is not anonymous'),
+            102: __('This room now shows unavailable members'),
+            103: __('This room does not show unavailable members'),
+            104: __('Non-privacy-related room configuration has changed'),
+            170: __('Room logging is now enabled'),
+            171: __('Room logging is now disabled'),
+            172: __('This room is now non-anonymous'),
+            173: __('This room is now semi-anonymous'),
+            174: __('This room is now fully-anonymous'),
+            201: __('A new room has been created'),
+            210: __('Your nickname has been changed')
         },
 
         actionInfoMessages: {
-            301: ' has been banned',
-            307: ' has been kicked out',
-            321: " has been removed because of an affiliation change",
-            322: " has been removed for not being a member"
+            // # For translations: %1$s will be replaced with the user's nickname
+            // # Don't translate "strong"
+            // # Example: <strong>jcbrand</strong> has been banned
+            301: i18n.translate('<strong>%1$s</strong> has been banned'),
+            // # For translations: %1$s will be replaced with the user's nickname
+            // # Don't translate "strong"
+            // # Example: <strong>jcbrand</strong> has been kicked out
+            307: i18n.translate('<strong>%1$s</strong> has been kicked out'),
+            // # For translations: %1$s will be replaced with the user's nickname
+            // # Don't translate "strong"
+            // # Example: <strong>jcbrand</strong> has been removed because of an affiliasion change
+            321: i18n.translate("<strong>%1$s</strong> has been removed because of an affiliation change"),
+            // # For translations: %1$s will be replaced with the user's nickname
+            // # Don't translate "strong"
+            // # Example: <strong>jcbrand</strong> has been removed for not being a member 
+            322: i18n.translate("<strong>%1$s</strong> has been removed for not being a member")
         },
 
         disconnectMessages: {
-            301: 'You have been banned from this room',
-            307: 'You have been kicked from this room',
-            321: "You have been removed from this room because of an affiliation change",
-            322: "You have been removed from this room because the room" +
-                "has changed to members-only and you're not a member",
-            332: "You have been removed from this room because the MUC " +
-                "(Multi-user chat) service is being shut down."
+            301: __('You have been banned from this room'),
+            307: __('You have been kicked from this room'),
+            321: __("You have been removed from this room because of an affiliation change"),
+            322: __("You have been removed from this room because the room has changed to members-only and you're not a member"),
+            332: __("You have been removed from this room because the MUC (Multi-user chat) service is being shut down.")
         },
 
         showStatusMessages: function ($el, is_self) {
@@ -1418,10 +1454,9 @@
                         info_msgs.push(this.infoMessages[stat]);
                     } else if (_.contains(_.keys(this.actionInfoMessages), stat)) {
                         action_msgs.push(
-                            '<strong>'+
-                                Strophe.unescapeNode(Strophe.getResourceFromJid($el.attr('from')))+
-                            '</strong>'+
-                             this.actionInfoMessages[stat]);
+                             this.actionInfoMessages[stat].fetch(
+                                Strophe.unescapeNode(Strophe.getResourceFromJid($el.attr('from')))
+                        ));
                     }
                 }
             }
@@ -1429,7 +1464,7 @@
                 for (i=0; i<disconnect_msgs.length; i++) {
                     this.showDisconnectMessage(disconnect_msgs[i]);
                 }
-                this.model.set('connected', false)
+                this.model.set('connected', false);
                 return;
             }
             this.renderChatArea();
@@ -1451,25 +1486,25 @@
                 if ($error.find('not-authorized').length) {
                     this.renderPasswordForm();
                 } else if ($error.find('registration-required').length) {
-                    this.showDisconnectMessage('You are not on the member list of this room');
+                    this.showDisconnectMessage(__('You are not on the member list of this room'));
                 } else if ($error.find('forbidden').length) {
-                    this.showDisconnectMessage('You have been banned from this room');
+                    this.showDisconnectMessage(__('You have been banned from this room'));
                 }
             } else if ($error.attr('type') == 'modify') {
                 if ($error.find('jid-malformed').length) {
-                    this.showDisconnectMessage('No nickname was specified');
+                    this.showDisconnectMessage(__('No nickname was specified'));
                 }
             } else if ($error.attr('type') == 'cancel') {
                 if ($error.find('not-allowed').length) {
-                    this.showDisconnectMessage('You are not allowed to create new rooms');
+                    this.showDisconnectMessage(__('You are not allowed to create new rooms'));
                 } else if ($error.find('not-acceptable').length) {
-                    this.showDisconnectMessage("Your nickname doesn't conform to this room's policies");
+                    this.showDisconnectMessage(__("Your nickname doesn't conform to this room's policies"));
                 } else if ($error.find('conflict').length) {
-                    this.showDisconnectMessage("Your nickname is already taken");
+                    this.showDisconnectMessage(__("Your nickname is already taken"));
                 } else if ($error.find('item-not-found').length) {
-                    this.showDisconnectMessage("This room does not (yet) exist");
+                    this.showDisconnectMessage(__("This room does not (yet) exist"));
                 } else if ($error.find('service-unavailable').length) {
-                    this.showDisconnectMessage("This room has reached it's maximum number of occupants");
+                    this.showDisconnectMessage(__("This room has reached it's maximum number of occupants"));
                 }
             }
         },
@@ -1482,7 +1517,7 @@
                 $item;
 
             if ($presence.attr('type') === 'error') {
-                this.model.set('connected', false)
+                this.model.set('connected', false);
                 this.showErrorMessage($presence.find('error'), room);
             } else {
                 this.model.set('connected', true);
@@ -1544,7 +1579,9 @@
             this.showStatusMessages($message);
             if (subject) {
                 this.$el.find('.chatroom-topic').text(subject).attr('title', subject);
-                $chat_content.append(this.info_template({'message': 'Topic set by '+sender+' to: '+subject }));
+                // # For translators: the %1$s and %2$s parts will get replaced by the user and topic text respectively
+                // # Example: Topic set by JC Brand to: Hello World! 
+                $chat_content.append(this.info_template({'message': __('Topic set by %1$s to: %2$s', sender, subject)}));
             }
             if (!body) { return true; }
             this.appendMessage($chat_content,
@@ -1560,13 +1597,13 @@
         occupant_template: _.template(
             '<li class="{{role}}" '+
                 '{[ if (role === "moderator") { ]}' +
-                    'title="This user is a moderator"' +
+                    'title="'+__('This user is a moderator')+'"' +
                 '{[ } ]}'+
                 '{[ if (role === "participant") { ]}' +
-                    'title="This user can send messages in this room"' +
+                    'title="'+__('This user can send messages in this room')+'"' +
                 '{[ } ]}'+
                 '{[ if (role === "visitor") { ]}' +
-                    'title="This user can NOT send messages in this room"' +
+                    'title="'+__('This user can NOT send messages in this room')+'"' +
                 '{[ } ]}'+
             '>{{nick}}</li>'
         ),
@@ -1770,12 +1807,12 @@
         },
 
         template: _.template(
-                    '<a class="open-chat" title="Click to chat with this contact" href="#">{{ fullname }}</a>' +
-                    '<a class="remove-xmpp-contact" title="Click to remove this contact" href="#"></a>'),
+                    '<a class="open-chat" title="'+__('Click to chat with this contact')+'" href="#">{{ fullname }}</a>' +
+                    '<a class="remove-xmpp-contact" title="'+__('Click to remove this contact')+'" href="#"></a>'),
 
         pending_template: _.template(
                     '<span>{{ fullname }}</span>' +
-                    '<a class="remove-xmpp-contact" title="Click to remove this contact" href="#"></a>'),
+                    '<a class="remove-xmpp-contact" title="'+__('Click to remove this contact')+'" href="#"></a>'),
 
         request_template: _.template('<div>{{ fullname }}</div>' +
                     '<button type="button" class="accept-xmpp-request">' +
@@ -2137,9 +2174,9 @@
             chatbox.save(changes);
         },
 
-        template: _.template('<dt id="xmpp-contact-requests">Contact requests</dt>' +
-                            '<dt id="xmpp-contacts">My contacts</dt>' +
-                            '<dt id="pending-xmpp-contacts">Pending contacts</dt>'),
+        template: _.template('<dt id="xmpp-contact-requests">'+__('Contact requests')+'</dt>' +
+                            '<dt id="xmpp-contacts">'+__('My contacts')+'</dt>' +
+                            '<dt id="pending-xmpp-contacts">'+__('Pending contacts')+'</dt>'),
 
         render: function (item) {
             var $my_contacts = this.$el.find('#xmpp-contacts'),
@@ -2290,16 +2327,17 @@
 
         change_status_message_template: _.template(
             '<form id="set-custom-xmpp-status">' +
-                '<input type="text" class="custom-xmpp-status" {{ status_message }}" placeholder="Custom status"/>' +
-                '<button type="submit">Save</button>' +
+                '<input type="text" class="custom-xmpp-status" {{ status_message }}"'+
+                       'placeholder="'+__('Custom status')+'"/>' +
+                '<button type="submit">'+__('Save')+'</button>' +
             '</form>'),
 
         status_template: _.template(
             '<div class="xmpp-status">' +
-                '<a class="choose-xmpp-status {{ chat_status }}" data-value="{{status_message}}" href="#" title="Click to change your chat status">' +
+                '<a class="choose-xmpp-status {{ chat_status }}" data-value="{{status_message}}" href="#" title="'+__('Click to change your chat status')+'">' +
                     '{{ status_message }}' +
                 '</a>' +
-                '<a class="change-xmpp-status-message" href="#" Title="Click here to write a custom status message"></a>' +
+                '<a class="change-xmpp-status-message" href="#" title="'+__('Click here to write a custom status message')+'"></a>' +
             '</div>'),
 
         renderStatusChangeForm: function (ev) {
@@ -2343,8 +2381,10 @@
             if (!(_.has(model.changed, 'status')) && !(_.has(model.changed, 'status_message'))) {
                 return;
             }
-            var stat = model.get('status'),
-                status_message = model.get('status_message') || "I am " + this.getPrettyStatus(stat);
+            var stat = model.get('status');
+            // # For translators: the %1$s part gets replaced with the status
+            // # Example, I am online
+            var status_message = model.get('status_message') || __("I am %1$s", this.getPrettyStatus(stat));
             this.$el.find('#fancy-xmpp-status-select').html(
                 this.status_template({
                     'chat_status': stat,
@@ -2378,9 +2418,9 @@
             this.$el.html(this.choose_template());
             this.$el.find('#fancy-xmpp-status-select')
                     .html(this.status_template({
-                            'status_message': "I am " + this.getPrettyStatus(chat_status),
-                            'chat_status': chat_status
-                            }));
+                        'status_message': __("I am %1$s", this.getPrettyStatus(chat_status)),
+                        'chat_status': chat_status
+                        }));
             // iterate through all the <option> elements and add option values
             options.each(function(){
                 options_list.push(that.option_template({'value': $(this).val(),
@@ -2449,18 +2489,18 @@
             'submit form#converse-login': 'authenticate'
         },
         tab_template: _.template(
-            '<li><a class="current" href="#login">Sign in</a></li>'),
+            '<li><a class="current" href="#login">'+__('Sign in')+'</a></li>'),
         template: _.template(
             '<form id="converse-login">' +
-            '<label>XMPP/Jabber Username:</label>' +
+            '<label>'+__('XMPP/Jabber Username:')+'</label>' +
             '<input type="text" id="jid">' +
-            '<label>Password:</label>' +
+            '<label>'+__('Password:')+'</label>' +
             '<input type="password" id="password">' +
-            '<input class="login-submit" type="submit" value="Log In">' +
+            '<input class="login-submit" type="submit" value="'+__('Log In')+'">' +
             '</form">'),
 
         bosh_url_input: _.template(
-            '<label>BOSH Service URL:</label>' +
+            '<label>'+__('BOSH Service URL:')+'</label>' +
             '<input type="text" id="bosh_service_url">'),
 
         connect: function ($form, jid, password) {
@@ -2472,29 +2512,29 @@
             }
             connection.connect(jid, password, $.proxy(function (status, message) {
                 if (status === Strophe.Status.CONNECTED) {
-                    console.log('Connected');
+                    console.log(__('Connected'));
                     converse.onConnected(connection);
                 } else if (status === Strophe.Status.DISCONNECTED) {
                     if ($button) { $button.show().siblings('img').remove(); }
-                    converse.giveFeedback('Disconnected', 'error');
+                    converse.giveFeedback(__('Disconnected'), 'error');
                     this.connect(null, connection.jid, connection.pass);
                 } else if (status === Strophe.Status.Error) {
                     if ($button) { $button.show().siblings('img').remove(); }
-                    converse.giveFeedback('Error', 'error');
+                    converse.giveFeedback(__('Error'), 'error');
                 } else if (status === Strophe.Status.CONNECTING) {
-                    converse.giveFeedback('Connecting');
+                    converse.giveFeedback(__('Connecting'));
                 } else if (status === Strophe.Status.CONNFAIL) {
                     if ($button) { $button.show().siblings('img').remove(); }
-                    converse.giveFeedback('Connection Failed', 'error');
+                    converse.giveFeedback(__('Connection Failed'), 'error');
                 } else if (status === Strophe.Status.AUTHENTICATING) {
-                    converse.giveFeedback('Authenticating');
+                    converse.giveFeedback(__('Authenticating'));
                 } else if (status === Strophe.Status.AUTHFAIL) {
                     if ($button) { $button.show().siblings('img').remove(); }
-                    converse.giveFeedback('Authentication Failed', 'error');
+                    converse.giveFeedback(__('Authentication Failed'), 'error');
                 } else if (status === Strophe.Status.DISCONNECTING) {
-                    converse.giveFeedback('Disconnecting', 'error');
+                    converse.giveFeedback(__('Disconnecting'), 'error');
                 } else if (status === Strophe.Status.ATTACHED) {
-                    console.log('Attached');
+                    console.log(__('Attached'));
                 }
             }, this));
         },
@@ -2591,7 +2631,6 @@
         this.domain = Strophe.getDomainFromJid(this.connection.jid);
         this.features = new this.Features();
 
-
         // Set up the roster
         this.roster = new this.RosterItems();
         this.roster.localStorage = new Backbone.LocalStorage(
@@ -2626,7 +2665,7 @@
             }
             this.windowState = e.type;
         },this));
-        this.giveFeedback('Online Contacts');
+        this.giveFeedback(__('Online Contacts'));
     };
 
     converse.initialize = function (settings) {

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно