aboutsummaryrefslogtreecommitdiffstats
path: root/library/ajaxchat/chat/js
diff options
context:
space:
mode:
authorfriendica <info@friendica.com>2014-01-18 23:49:39 -0800
committerfriendica <info@friendica.com>2014-01-18 23:49:39 -0800
commit724ad4505628d493b43b4f585512d67dc0b4ee76 (patch)
tree4fb920a79e3dff961a6301ec56ec9f40e91f6af3 /library/ajaxchat/chat/js
parent3f7032e542e3c451507fc9266ab3536155c8190f (diff)
downloadvolse-hubzilla-724ad4505628d493b43b4f585512d67dc0b4ee76.tar.gz
volse-hubzilla-724ad4505628d493b43b4f585512d67dc0b4ee76.tar.bz2
volse-hubzilla-724ad4505628d493b43b4f585512d67dc0b4ee76.zip
add ajaxchat library - needs a lot of integration work to handle decentralisation (e.g. chatroom@website) and zotid w/permissions (e.g. ACL controlled chatrooms); we can also rip out a lot of stuff we don't need.
Diffstat (limited to 'library/ajaxchat/chat/js')
-rw-r--r--library/ajaxchat/chat/js/FABridge.js591
-rw-r--r--library/ajaxchat/chat/js/chat.js2940
-rw-r--r--library/ajaxchat/chat/js/config.js261
-rw-r--r--library/ajaxchat/chat/js/custom.js16
-rw-r--r--library/ajaxchat/chat/js/index.html0
-rw-r--r--library/ajaxchat/chat/js/lang/ar.js92
-rw-r--r--library/ajaxchat/chat/js/lang/bg.js92
-rw-r--r--library/ajaxchat/chat/js/lang/ca.js91
-rw-r--r--library/ajaxchat/chat/js/lang/cy.js93
-rw-r--r--library/ajaxchat/chat/js/lang/cz.js91
-rw-r--r--library/ajaxchat/chat/js/lang/da.js91
-rw-r--r--library/ajaxchat/chat/js/lang/de.js91
-rw-r--r--library/ajaxchat/chat/js/lang/el.js92
-rw-r--r--library/ajaxchat/chat/js/lang/en.js91
-rw-r--r--library/ajaxchat/chat/js/lang/es.js92
-rw-r--r--library/ajaxchat/chat/js/lang/et.js91
-rw-r--r--library/ajaxchat/chat/js/lang/fi.js93
-rw-r--r--library/ajaxchat/chat/js/lang/fr.js92
-rw-r--r--library/ajaxchat/chat/js/lang/gl.js92
-rw-r--r--library/ajaxchat/chat/js/lang/he.js92
-rw-r--r--library/ajaxchat/chat/js/lang/hr.js91
-rw-r--r--library/ajaxchat/chat/js/lang/hu.js91
-rw-r--r--library/ajaxchat/chat/js/lang/in.js91
-rw-r--r--library/ajaxchat/chat/js/lang/index.html0
-rw-r--r--library/ajaxchat/chat/js/lang/it.js93
-rw-r--r--library/ajaxchat/chat/js/lang/ja.js91
-rw-r--r--library/ajaxchat/chat/js/lang/ka.js91
-rw-r--r--library/ajaxchat/chat/js/lang/kr.js91
-rw-r--r--library/ajaxchat/chat/js/lang/mk.js9
-rw-r--r--library/ajaxchat/chat/js/lang/nl-be.js92
-rw-r--r--library/ajaxchat/chat/js/lang/nl.js92
-rw-r--r--library/ajaxchat/chat/js/lang/no.js92
-rw-r--r--library/ajaxchat/chat/js/lang/pl.js92
-rw-r--r--library/ajaxchat/chat/js/lang/pt-br.js92
-rw-r--r--library/ajaxchat/chat/js/lang/pt-pt.js92
-rw-r--r--library/ajaxchat/chat/js/lang/ro.js92
-rw-r--r--library/ajaxchat/chat/js/lang/ru.js93
-rw-r--r--library/ajaxchat/chat/js/lang/sk.js92
-rw-r--r--library/ajaxchat/chat/js/lang/sl.js92
-rw-r--r--library/ajaxchat/chat/js/lang/sr.js92
-rw-r--r--library/ajaxchat/chat/js/lang/sv.js92
-rw-r--r--library/ajaxchat/chat/js/lang/th.js92
-rw-r--r--library/ajaxchat/chat/js/lang/tr.js92
-rw-r--r--library/ajaxchat/chat/js/lang/uk.js92
-rw-r--r--library/ajaxchat/chat/js/lang/zh-tw.js91
-rw-r--r--library/ajaxchat/chat/js/lang/zh.js92
-rw-r--r--library/ajaxchat/chat/js/logs.js128
-rw-r--r--library/ajaxchat/chat/js/shoutbox.js12
48 files changed, 7536 insertions, 0 deletions
diff --git a/library/ajaxchat/chat/js/FABridge.js b/library/ajaxchat/chat/js/FABridge.js
new file mode 100644
index 000000000..59424573b
--- /dev/null
+++ b/library/ajaxchat/chat/js/FABridge.js
@@ -0,0 +1,591 @@
+/*
+/*
+Copyright 2006 Adobe Systems Incorporated
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+
+
+/*
+ * The Bridge class, responsible for navigating AS instances
+ */
+function FABridge(target,bridgeName)
+{
+ this.target = target;
+ this.remoteTypeCache = {};
+ this.remoteInstanceCache = {};
+ this.remoteFunctionCache = {};
+ this.localFunctionCache = {};
+ this.bridgeID = FABridge.nextBridgeID++;
+ this.name = bridgeName;
+ this.nextLocalFuncID = 0;
+ FABridge.instances[this.name] = this;
+ FABridge.idMap[this.bridgeID] = this;
+
+ return this;
+}
+
+// type codes for packed values
+FABridge.TYPE_ASINSTANCE = 1;
+FABridge.TYPE_ASFUNCTION = 2;
+
+FABridge.TYPE_JSFUNCTION = 3;
+FABridge.TYPE_ANONYMOUS = 4;
+
+FABridge.initCallbacks = {}
+
+FABridge.argsToArray = function(args)
+{
+ var result = [];
+ for (var i = 0; i < args.length; i++)
+ {
+ result[i] = args[i];
+ }
+ return result;
+}
+
+function instanceFactory(objID)
+{
+ this.fb_instance_id = objID;
+ return this;
+}
+
+function FABridge__invokeJSFunction(args)
+{
+ var funcID = args[0];
+ var throughArgs = args.concat();//FABridge.argsToArray(arguments);
+ throughArgs.shift();
+
+ var bridge = FABridge.extractBridgeFromID(funcID);
+ return bridge.invokeLocalFunction(funcID, throughArgs);
+}
+
+FABridge.addInitializationCallback = function(bridgeName, callback)
+{
+ var inst = FABridge.instances[bridgeName];
+ if (inst != undefined)
+ {
+ callback.call(inst);
+ return;
+ }
+
+ var callbackList = FABridge.initCallbacks[bridgeName];
+ if(callbackList == null)
+ {
+ FABridge.initCallbacks[bridgeName] = callbackList = [];
+ }
+
+ callbackList.push(callback);
+}
+
+function FABridge__bridgeInitialized(bridgeName) {
+ var objects = document.getElementsByTagName("object");
+ var ol = objects.length;
+ var activeObjects = [];
+ if (ol > 0) {
+ for (var i = 0; i < ol; i++) {
+ if (typeof objects[i].SetVariable != "undefined") {
+ activeObjects[activeObjects.length] = objects[i];
+ }
+ }
+ }
+ var embeds = document.getElementsByTagName("embed");
+ var el = embeds.length;
+ var activeEmbeds = [];
+ if (el > 0) {
+ for (var j = 0; j < el; j++) {
+ if (typeof embeds[j].SetVariable != "undefined") {
+ activeEmbeds[activeEmbeds.length] = embeds[j];
+ }
+ }
+ }
+ var aol = activeObjects.length;
+ var ael = activeEmbeds.length;
+ var searchStr = "bridgeName="+ bridgeName;
+ if ((aol == 1 && !ael) || (aol == 1 && ael == 1)) {
+ FABridge.attachBridge(activeObjects[0], bridgeName);
+ }
+ else if (ael == 1 && !aol) {
+ FABridge.attachBridge(activeEmbeds[0], bridgeName);
+ }
+ else {
+ var flash_found = false;
+ if (aol > 1) {
+ for (var k = 0; k < aol; k++) {
+ var params = activeObjects[k].childNodes;
+ for (var l = 0; l < params.length; l++) {
+ var param = params[l];
+ if (param.nodeType == 1 && param.tagName.toLowerCase() == "param" && param["name"].toLowerCase() == "flashvars" && param["value"].indexOf(searchStr) >= 0) {
+ FABridge.attachBridge(activeObjects[k], bridgeName);
+ flash_found = true;
+ break;
+ }
+ }
+ if (flash_found) {
+ break;
+ }
+ }
+ }
+ if (!flash_found && ael > 1) {
+ for (var m = 0; m < ael; m++) {
+ var flashVars = activeEmbeds[m].attributes.getNamedItem("flashVars").nodeValue;
+ if (flashVars.indexOf(searchStr) >= 0) {
+ FABridge.attachBridge(activeEmbeds[m], bridgeName);
+ break;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+// used to track multiple bridge instances, since callbacks from AS are global across the page.
+
+FABridge.nextBridgeID = 0;
+FABridge.instances = {};
+FABridge.idMap = {};
+FABridge.refCount = 0;
+
+FABridge.extractBridgeFromID = function(id)
+{
+ var bridgeID = (id >> 16);
+ return FABridge.idMap[bridgeID];
+}
+
+FABridge.attachBridge = function(instance, bridgeName)
+{
+ var newBridgeInstance = new FABridge(instance, bridgeName);
+
+ FABridge[bridgeName] = newBridgeInstance;
+
+/* FABridge[bridgeName] = function() {
+ return newBridgeInstance.root();
+ }
+*/
+ var callbacks = FABridge.initCallbacks[bridgeName];
+ if (callbacks == null)
+ {
+ return;
+ }
+ for (var i = 0; i < callbacks.length; i++)
+ {
+ callbacks[i].call(newBridgeInstance);
+ }
+ delete FABridge.initCallbacks[bridgeName]
+}
+
+// some methods can't be proxied. You can use the explicit get,set, and call methods if necessary.
+
+FABridge.blockedMethods =
+{
+ toString: true,
+ get: true,
+ set: true,
+ call: true
+};
+
+FABridge.prototype =
+{
+
+
+// bootstrapping
+
+ root: function()
+ {
+ return this.deserialize(this.target.getRoot());
+ },
+//clears all of the AS objects in the cache maps
+ releaseASObjects: function()
+ {
+ return this.target.releaseASObjects();
+ },
+//clears a specific object in AS from the type maps
+ releaseNamedASObject: function(value)
+ {
+ if(typeof(value) != "object")
+ {
+ return false;
+ }
+ else
+ {
+ var ret = this.target.releaseNamedASObject(value.fb_instance_id);
+ return ret;
+ }
+ },
+//create a new AS Object
+ create: function(className)
+ {
+ return this.deserialize(this.target.create(className));
+ },
+
+
+ // utilities
+
+ makeID: function(token)
+ {
+ return (this.bridgeID << 16) + token;
+ },
+
+
+ // low level access to the flash object
+
+//get a named property from an AS object
+ getPropertyFromAS: function(objRef, propName)
+ {
+ if (FABridge.refCount > 0)
+ {
+ throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround.");
+ }
+ else
+ {
+ FABridge.refCount++;
+ retVal = this.target.getPropFromAS(objRef, propName);
+ retVal = this.handleError(retVal);
+ FABridge.refCount--;
+ return retVal;
+ }
+ },
+//set a named property on an AS object
+ setPropertyInAS: function(objRef,propName, value)
+ {
+ if (FABridge.refCount > 0)
+ {
+ throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround.");
+ }
+ else
+ {
+ FABridge.refCount++;
+ retVal = this.target.setPropInAS(objRef,propName, this.serialize(value));
+ retVal = this.handleError(retVal);
+ FABridge.refCount--;
+ return retVal;
+ }
+ },
+
+//call an AS function
+ callASFunction: function(funcID, args)
+ {
+ if (FABridge.refCount > 0)
+ {
+ throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround.");
+ }
+ else
+ {
+ FABridge.refCount++;
+ retVal = this.target.invokeASFunction(funcID, this.serialize(args));
+ retVal = this.handleError(retVal);
+ FABridge.refCount--;
+ return retVal;
+ }
+ },
+//call a method on an AS object
+ callASMethod: function(objID, funcName, args)
+ {
+ if (FABridge.refCount > 0)
+ {
+ throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround.");
+ }
+ else
+ {
+ FABridge.refCount++;
+ args = this.serialize(args);
+ retVal = this.target.invokeASMethod(objID, funcName, args);
+ retVal = this.handleError(retVal);
+ FABridge.refCount--;
+ return retVal;
+ }
+ },
+
+ // responders to remote calls from flash
+
+ //callback from flash that executes a local JS function
+ //used mostly when setting js functions as callbacks on events
+ invokeLocalFunction: function(funcID, args)
+ {
+ var result;
+ var func = this.localFunctionCache[funcID];
+
+ if(func != undefined)
+ {
+ result = this.serialize(func.apply(null, this.deserialize(args)));
+ }
+
+ return result;
+ },
+
+ // Object Types and Proxies
+
+ // accepts an object reference, returns a type object matching the obj reference.
+ getTypeFromName: function(objTypeName)
+ {
+ return this.remoteTypeCache[objTypeName];
+ },
+ //create an AS proxy for the given object ID and type
+ createProxy: function(objID, typeName)
+ {
+ var objType = this.getTypeFromName(typeName);
+ instanceFactory.prototype = objType;
+ var instance = new instanceFactory(objID);
+ this.remoteInstanceCache[objID] = instance;
+ return instance;
+ },
+ //return the proxy associated with the given object ID
+ getProxy: function(objID)
+ {
+ return this.remoteInstanceCache[objID];
+ },
+
+ // accepts a type structure, returns a constructed type
+ addTypeDataToCache: function(typeData)
+ {
+ newType = new ASProxy(this, typeData.name);
+ var accessors = typeData.accessors;
+ for (var i = 0; i < accessors.length; i++)
+ {
+ this.addPropertyToType(newType, accessors[i]);
+ }
+
+ var methods = typeData.methods;
+ for (var i = 0; i < methods.length; i++)
+ {
+ if (FABridge.blockedMethods[methods[i]] == undefined)
+ {
+ this.addMethodToType(newType, methods[i]);
+ }
+ }
+
+
+ this.remoteTypeCache[newType.typeName] = newType;
+ return newType;
+ },
+
+ //add a property to a typename; used to define the properties that can be called on an AS proxied object
+ addPropertyToType: function(ty, propName)
+ {
+ var c = propName.charAt(0);
+ var setterName;
+ var getterName;
+ if(c >= "a" && c <= "z")
+ {
+ getterName = "get" + c.toUpperCase() + propName.substr(1);
+ setterName = "set" + c.toUpperCase() + propName.substr(1);
+ }
+ else
+ {
+ getterName = "get" + propName;
+ setterName = "set" + propName;
+ }
+ ty[setterName] = function(val)
+ {
+ this.bridge.setPropertyInAS(this.fb_instance_id, propName, val);
+ }
+ ty[getterName] = function()
+ {
+ return this.bridge.deserialize(this.bridge.getPropertyFromAS(this.fb_instance_id, propName));
+ }
+ },
+
+ //add a method to a typename; used to define the methods that can be callefd on an AS proxied object
+ addMethodToType: function(ty, methodName)
+ {
+ ty[methodName] = function()
+ {
+ return this.bridge.deserialize(this.bridge.callASMethod(this.fb_instance_id, methodName, FABridge.argsToArray(arguments)));
+ }
+ },
+
+ // Function Proxies
+
+ //returns the AS proxy for the specified function ID
+ getFunctionProxy: function(funcID)
+ {
+ var bridge = this;
+ if (this.remoteFunctionCache[funcID] == null)
+ {
+ this.remoteFunctionCache[funcID] = function()
+ {
+ bridge.callASFunction(funcID, FABridge.argsToArray(arguments));
+ }
+ }
+ return this.remoteFunctionCache[funcID];
+ },
+
+ //reutrns the ID of the given function; if it doesnt exist it is created and added to the local cache
+ getFunctionID: function(func)
+ {
+ if (func.__bridge_id__ == undefined)
+ {
+ func.__bridge_id__ = this.makeID(this.nextLocalFuncID++);
+ this.localFunctionCache[func.__bridge_id__] = func;
+ }
+ return func.__bridge_id__;
+ },
+
+ // serialization / deserialization
+
+ serialize: function(value)
+ {
+ var result = {};
+
+ var t = typeof(value);
+ //primitives are kept as such
+ if (t == "number" || t == "string" || t == "boolean" || t == null || t == undefined)
+ {
+ result = value;
+ }
+ else if (value instanceof Array)
+ {
+ //arrays are serializesd recursively
+ result = [];
+ for (var i = 0; i < value.length; i++)
+ {
+ result[i] = this.serialize(value[i]);
+ }
+ }
+ else if (t == "function")
+ {
+ //js functions are assigned an ID and stored in the local cache
+ result.type = FABridge.TYPE_JSFUNCTION;
+ result.value = this.getFunctionID(value);
+ }
+ else if (value instanceof ASProxy)
+ {
+ result.type = FABridge.TYPE_ASINSTANCE;
+ result.value = value.fb_instance_id;
+ }
+ else
+ {
+ result.type = FABridge.TYPE_ANONYMOUS;
+ result.value = value;
+ }
+
+ return result;
+ },
+
+ //on deserialization we always check the return for the specific error code that is used to marshall NPE's into JS errors
+ // the unpacking is done by returning the value on each pachet for objects/arrays
+ deserialize: function(packedValue)
+ {
+
+ var result;
+
+ var t = typeof(packedValue);
+ if (t == "number" || t == "string" || t == "boolean" || packedValue == null || packedValue == undefined)
+ {
+ result = this.handleError(packedValue);
+ }
+ else if (packedValue instanceof Array)
+ {
+ result = [];
+ for (var i = 0; i < packedValue.length; i++)
+ {
+ result[i] = this.deserialize(packedValue[i]);
+ }
+ }
+ else if (t == "object")
+ {
+ for(var i = 0; i < packedValue.newTypes.length; i++)
+ {
+ this.addTypeDataToCache(packedValue.newTypes[i]);
+ }
+ for (var aRefID in packedValue.newRefs)
+ {
+ this.createProxy(aRefID, packedValue.newRefs[aRefID]);
+ }
+ if (packedValue.type == FABridge.TYPE_PRIMITIVE)
+ {
+ result = packedValue.value;
+ }
+ else if (packedValue.type == FABridge.TYPE_ASFUNCTION)
+ {
+ result = this.getFunctionProxy(packedValue.value);
+ }
+ else if (packedValue.type == FABridge.TYPE_ASINSTANCE)
+ {
+ result = this.getProxy(packedValue.value);
+ }
+ else if (packedValue.type == FABridge.TYPE_ANONYMOUS)
+ {
+ result = packedValue.value;
+ }
+ }
+ return result;
+ },
+ //increases the reference count for the given object
+ addRef: function(obj)
+ {
+ this.target.incRef(obj.fb_instance_id);
+ },
+ //decrease the reference count for the given object and release it if needed
+ release:function(obj)
+ {
+ this.target.releaseRef(obj.fb_instance_id);
+ },
+
+ // check the given value for the components of the hard-coded error code : __FLASHERROR
+ // used to marshall NPE's into flash
+
+ handleError: function(value)
+ {
+ if (typeof(value)=="string" && value.indexOf("__FLASHERROR")==0)
+ {
+ var myErrorMessage = value.split("||");
+ if(FABridge.refCount > 0 )
+ {
+ FABridge.refCount--;
+ }
+ throw new Error(myErrorMessage[1]);
+ return value;
+ }
+ else
+ {
+ return value;
+ }
+ }
+};
+
+// The root ASProxy class that facades a flash object
+
+ASProxy = function(bridge, typeName)
+{
+ this.bridge = bridge;
+ this.typeName = typeName;
+ return this;
+};
+//methods available on each ASProxy object
+ASProxy.prototype =
+{
+ get: function(propName)
+ {
+ return this.bridge.deserialize(this.bridge.getPropertyFromAS(this.fb_instance_id, propName));
+ },
+
+ set: function(propName, value)
+ {
+ this.bridge.setPropertyInAS(this.fb_instance_id, propName, value);
+ },
+
+ call: function(funcName, args)
+ {
+ this.bridge.callASMethod(this.fb_instance_id, funcName, args);
+ },
+
+ addRef: function() {
+ this.bridge.addRef(this);
+ },
+
+ release: function() {
+ this.bridge.release(this);
+ }
+};
diff --git a/library/ajaxchat/chat/js/chat.js b/library/ajaxchat/chat/js/chat.js
new file mode 100644
index 000000000..9a93f5e45
--- /dev/null
+++ b/library/ajaxchat/chat/js/chat.js
@@ -0,0 +1,2940 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ *
+ * The SELFHTML documentation has been used throughout this project:
+ * http://selfhtml.org
+ *
+ * Stylesheet and cookie methods have been inspired by Paul Sowden (A List Apart):
+ * http://www.alistapart.com/stories/alternate/
+ */
+
+// AJAX Chat client side logic:
+var ajaxChat = {
+
+ settingsInitiated: null,
+ styleInitiated: null,
+ initializeFunction: null,
+ finalizeFunction: null,
+ loginChannelID: null,
+ loginChannelName: null,
+ timerRate: null,
+ timer: null,
+ ajaxURL: null,
+ baseURL: null,
+ regExpMediaUrl: null,
+ dirs: null,
+ startChatOnLoad: null,
+ chatStarted: null,
+ domIDs: null,
+ dom: null,
+ settings: null,
+ nonPersistentSettings: null,
+ unusedSettings: null,
+ bbCodeTags: null,
+ colorCodes: null,
+ emoticonCodes: null,
+ emoticonFiles: null,
+ soundFiles: null,
+ sounds: null,
+ soundTransform: null,
+ sessionName: null,
+ cookieExpiration: null,
+ cookiePath: null,
+ cookieDomain: null,
+ cookieSecure: null,
+ chatBotName: null,
+ chatBotID: null,
+ allowUserMessageDelete: null,
+ inactiveTimeout: null,
+ privateChannelDiff: null,
+ privateMessageDiff: null,
+ showChannelMessages: null,
+ messageTextMaxLength: null,
+ socketServerEnabled: null,
+ socketServerHost: null,
+ socketServerPort: null,
+ socketServerChatID: null,
+ socket: null,
+ socketIsConnected: null,
+ socketTimerRate: null,
+ socketReconnectTimer: null,
+ socketRegistrationID: null,
+ userID: null,
+ userName: null,
+ userRole: null,
+ channelID: null,
+ channelName: null,
+ channelSwitch: null,
+ usersList: null,
+ userNamesList: null,
+ userMenuCounter: null,
+ encodedUserName: null,
+ userNodeString: null,
+ ignoredUserNames: null,
+ lastID: null,
+ localID: null,
+ lang: null,
+ langCode: null,
+ baseDirection: null,
+ originalDocumentTitle: null,
+ blinkInterval: null,
+ httpRequest: null,
+ retryTimer: null,
+ retryTimerDelay: null,
+ requestStatus: 'ok',
+ DOMbuffering: null,
+ DOMbuffer: null,
+ DOMbufferRowClass: 'rowOdd',
+
+ init: function(config, lang, initSettings, initStyle, initialize, initializeFunction, finalizeFunction) {
+ this.httpRequest = {};
+ this.usersList = [];
+ this.userNamesList = [];
+ this.userMenuCounter = 0;
+ this.lastID = 0;
+ this.localID = 0;
+ this.lang = lang;
+ this.initConfig(config);
+ this.initDirectories();
+ if(initSettings) {
+ this.initSettings();
+ }
+ if(initStyle) {
+ this.initStyle();
+ }
+ this.initializeFunction = initializeFunction;
+ this.finalizeFunction = finalizeFunction;
+ if(initialize) {
+ this.setLoadHandler();
+ }
+ },
+
+ initConfig: function(config) {
+ this.loginChannelID = config['loginChannelID'];
+ this.loginChannelName = config['loginChannelName'];
+ this.timerRate = config['timerRate'];
+ this.ajaxURL = config['ajaxURL'];
+ this.baseURL = config['baseURL'];
+ this.regExpMediaUrl = config['regExpMediaUrl'];
+ this.startChatOnLoad = config['startChatOnLoad'];
+ this.domIDs = config['domIDs'];
+ this.settings = config['settings'];
+ this.nonPersistentSettings = config['nonPersistentSettings'];
+ this.bbCodeTags = config['bbCodeTags'];
+ this.colorCodes = config['colorCodes'];
+ this.emoticonCodes = config['emoticonCodes'];
+ this.emoticonFiles = config['emoticonFiles'];
+ this.soundFiles = config['soundFiles'];
+ this.sessionName = config['sessionName'];
+ this.cookieExpiration = config['cookieExpiration'];
+ this.cookiePath = config['cookiePath'];
+ this.cookieDomain = config['cookieDomain'];
+ this.cookieSecure = config['cookieSecure'];
+ this.chatBotName = config['chatBotName'];
+ this.chatBotID = config['chatBotID'];
+ this.allowUserMessageDelete = config['allowUserMessageDelete'];
+ this.inactiveTimeout = config['inactiveTimeout'];
+ this.privateChannelDiff = config['privateChannelDiff'];
+ this.privateMessageDiff = config['privateMessageDiff'];
+ this.showChannelMessages = config['showChannelMessages'];
+ this.messageTextMaxLength = config['messageTextMaxLength'];
+ this.socketServerEnabled = config['socketServerEnabled'];
+ this.socketServerHost = config['socketServerHost'];
+ this.socketServerPort = config['socketServerPort'];
+ this.socketServerChatID = config['socketServerChatID'];
+ this.DOMbuffering = false;
+ this.DOMbuffer = "";
+ this.retryTimerDelay = (this.inactiveTimeout*6000 - this.timerRate)/4 + this.timerRate;
+ },
+
+ initDirectories: function() {
+ this.dirs = {};
+ this.dirs['emoticons'] = this.baseURL+'img/emoticons/';
+ this.dirs['sounds'] = this.baseURL+'sounds/';
+ this.dirs['flash'] = this.baseURL+'flash/';
+ },
+
+ initSettings: function() {
+ var cookie = this.readCookie(this.sessionName + '_settings'),
+ i, settingsArray, setting, key, value, number;
+ this.settingsInitiated = true;
+ this.unusedSettings = {};
+ if(cookie) {
+ settingsArray = cookie.split('&');
+ for(i=0; i<settingsArray.length; i++) {
+ setting = settingsArray[i].split('=');
+ if(setting.length === 2) {
+ key = setting[0];
+ value = this.decodeText(setting[1]);
+ switch(value) {
+ case 'true':
+ value = true;
+ break;
+ case 'false':
+ value = false;
+ break;
+ case 'null':
+ value = null;
+ break;
+ default:
+ number = parseFloat(value);
+ if(!isNaN(number)) {
+ if(parseInt(number) === number) {
+ value = parseInt(number);
+ } else {
+ value = number;
+ }
+ }
+ }
+ if(this.inArray(this.nonPersistentSettings, key)) {
+ // The setting is not used, store it for the persistSettings method:
+ this.unusedSettings[key] = value;
+ } else {
+ this.settings[key] = value;
+ }
+ }
+ }
+ }
+ },
+
+ persistSettings: function() {
+ var settingsArray;
+ if(this.settingsInitiated) {
+ settingsArray = [];
+ for(var property in this.settings) {
+ if(this.inArray(this.nonPersistentSettings, property)) {
+ if(this.unusedSettings && this.unusedSettings[property]) {
+ // Store the unusedSetting previously stored:
+ this.settings[property] = this.unusedSettings[property];
+ } else {
+ continue;
+ }
+ }
+ settingsArray.push(property + '=' + this.encodeText(this.settings[property]));
+ }
+ this.createCookie(this.sessionName + '_settings', settingsArray.join('&'), this.cookieExpiration);
+ }
+ },
+
+ getSettings: function() {
+ return this.settings;
+ },
+
+ getSetting: function(key) {
+ // Only return null if setting is null or undefined, not if it is false:
+ for(var property in this.settings) {
+ if(property === key) {
+ return this.settings[key];
+ }
+ }
+ return null;
+ },
+
+ setSetting: function(key, value) {
+ this.settings[key] = value;
+ },
+
+ initializeSettings: function() {
+ if(this.settings['persistFontColor'] && this.settings['fontColor']) {
+ // Set the inputField font color to the font color:
+ if(this.dom['inputField']) {
+ this.dom['inputField'].style.color = this.settings['fontColor'];
+ }
+ }
+ },
+
+ initialize: function() {
+ this.setUnloadHandler();
+ this.initializeDocumentNodes();
+ this.loadPageAttributes();
+ this.initEmoticons();
+ this.initColorCodes();
+ this.initializeSettings();
+ this.setSelectedStyle();
+ this.customInitialize();
+ //preload the Alert icon (it can't display if there's no connection unless it's cached!)
+ this.setStatus('retrying');
+ if(typeof this.initializeFunction === 'function') {
+ this.initializeFunction();
+ }
+ if(!this.isCookieEnabled()) {
+ this.addChatBotMessageToChatList('/error CookiesRequired');
+ } else {
+ if(this.startChatOnLoad) {
+ this.startChat();
+ } else {
+ this.setStartChatHandler();
+ this.requestTeaserContent();
+ }
+ }
+ },
+
+ requestTeaserContent: function() {
+ var params = '&view=teaser';
+ params += '&getInfos=' + this.encodeText('userID,userName,userRole');
+ if(!isNaN(parseInt(this.loginChannelID))) {
+ params += '&channelID='+this.loginChannelID;
+ } else if(this.loginChannelName !== null) {
+ params += '&channelName='+this.encodeText(this.loginChannelName);
+ }
+ this.updateChat(params);
+ },
+
+ setStartChatHandler: function() {
+ if(this.dom['inputField']) {
+ this.dom['inputField'].onfocus = function() {
+ ajaxChat.startChat();
+ // Reset the onfocus event on first call:
+ ajaxChat.dom['inputField'].onfocus = '';
+ };
+ }
+ },
+
+ startChat: function() {
+ this.chatStarted = true;
+ if(this.dom['inputField'] && this.settings['autoFocus']) {
+ this.dom['inputField'].focus();
+ }
+ this.loadFlashInterface();
+ this.startChatUpdate();
+ },
+
+ loadPageAttributes: function() {
+ var htmlTag = document.getElementsByTagName('html')[0];
+ this.langCode = htmlTag.getAttribute('lang') ? htmlTag.getAttribute('lang') : 'en';
+ this.baseDirection = htmlTag.getAttribute('dir') ? htmlTag.getAttribute('dir') : 'ltr';
+ },
+
+ setLoadHandler: function() {
+ // Make sure initialize() is called on page load:
+ var onload = window.onload;
+ if(typeof onload !== 'function') {
+ window.onload = function() {
+ ajaxChat.initialize();
+ };
+ } else {
+ window.onload = function() {
+ onload();
+ ajaxChat.initialize();
+ };
+ }
+ },
+
+ setUnloadHandler: function() {
+ // Make sure finalize() is called on page unload:
+ var onunload = window.onunload;
+ if(typeof onunload !== 'function') {
+ window.onunload = function() {
+ ajaxChat.finalize();
+ };
+ } else {
+ window.onunload = function() {
+ ajaxChat.finalize();
+ onunload();
+ };
+ }
+ },
+
+ updateDOM: function(id, str, prepend, overwrite) {
+ var domNode = this.dom[id] ? this.dom[id] : document.getElementById(id);
+ if(!domNode) {
+ return;
+ }
+ try {
+ // Test for validity before adding the string to the DOM:
+ domNode.cloneNode(false).innerHTML = str;
+ if(overwrite) {
+ domNode.innerHTML = str;
+ } else if(prepend) {
+ domNode.innerHTML = str + domNode.innerHTML;
+ } else {
+ domNode.innerHTML += str;
+ }
+ } catch(e) {
+ this.addChatBotMessageToChatList('/error DOMSyntax '+id);
+ this.updateChatlistView();
+ }
+ },
+
+ initializeDocumentNodes: function() {
+ this.dom = {};
+ for(var key in this.domIDs) {
+ this.dom[key] = document.getElementById(this.domIDs[key]);
+ }
+ },
+
+ initEmoticons: function() {
+ this.DOMbuffer = "";
+ for(var i=0; i<this.emoticonCodes.length; i++) {
+ // Replace specials characters in emoticon codes:
+ this.emoticonCodes[i] = this.encodeSpecialChars(this.emoticonCodes[i]);
+ this.DOMbuffer = this.DOMbuffer
+ + '<a href="javascript:ajaxChat.insertText(\''
+ + this.scriptLinkEncode(this.emoticonCodes[i])
+ + '\');"><img src="'
+ + this.dirs['emoticons']
+ + this.emoticonFiles[i]
+ + '" alt="'
+ + this.emoticonCodes[i]
+ + '" title="'
+ + this.emoticonCodes[i]
+ + '"/></a>';
+ }
+ if(this.dom['emoticonsContainer']) {
+ this.updateDOM('emoticonsContainer', this.DOMbuffer);
+ }
+ this.DOMbuffer = "";
+ },
+
+ initColorCodes: function() {
+ if(this.dom['colorCodesContainer']) {
+ this.DOMbuffer = "";
+ for(var i=0; i<this.colorCodes.length; i++) {
+ this.DOMbuffer = this.DOMbuffer
+ + '<a href="javascript:ajaxChat.setFontColor(\''
+ + this.colorCodes[i]
+ + '\');" style="background-color:'
+ + this.colorCodes[i]
+ + ';" title="'
+ + this.colorCodes[i]
+ + '"></a>'
+ + "\n";
+ }
+ this.updateDOM('colorCodesContainer', this.DOMbuffer);
+ this.DOMbuffer = "";
+ }
+ },
+
+
+ startChatUpdate: function() {
+ // Start the chat update and retrieve current user and channel info and set the login channel:
+ var infos = 'userID,userName,userRole,channelID,channelName';
+ if(this.socketServerEnabled) {
+ infos += ',socketRegistrationID';
+ }
+ var params = '&getInfos=' + this.encodeText(infos);
+ if(!isNaN(parseInt(this.loginChannelID))) {
+ params += '&channelID='+this.loginChannelID;
+ } else if(this.loginChannelName !== null) {
+ params += '&channelName='+this.encodeText(this.loginChannelName);
+ }
+ this.updateChat(params);
+ },
+
+ updateChat: function(paramString) {
+ var requestUrl = this.ajaxURL
+ + '&lastID='
+ + this.lastID;
+ if(paramString) {
+ requestUrl += paramString;
+ }
+ this.makeRequest(requestUrl,'GET',null);
+ },
+
+ loadFlashInterface: function() {
+ if(this.dom['flashInterfaceContainer']) {
+ this.updateDOM(
+ 'flashInterfaceContainer',
+ '<object id="ajaxChatFlashInterface" style="position:absolute; left:-100px;" '
+ +'classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" '
+ +'codebase="'
+ + window.location.protocol
+ +'//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" '
+ +'height="1" width="1">'
+ +'<param name="flashvars" value="bridgeName=ajaxChat"/>'
+ +'<param name="src" value="'+this.dirs['flash']+'FABridge.swf"/>'
+ +'<embed name="ajaxChatFlashInterface" type="application/x-shockwave-flash" pluginspage="'
+ + window.location.protocol
+ +'//www.macromedia.com/go/getflashplayer" '
+ +'src="'+this.dirs['flash']+'FABridge.swf" height="1" width="1" flashvars="bridgeName=ajaxChat"/>'
+ +'</object>'
+ );
+ FABridge.addInitializationCallback('ajaxChat', this.flashInterfaceLoadCompleteHandler);
+ }
+ },
+
+ flashInterfaceLoadCompleteHandler: function() {
+ ajaxChat.initializeFlashInterface();
+ },
+
+ initializeFlashInterface: function() {
+ if(this.socketServerEnabled) {
+ this.socketTimerRate = (this.inactiveTimeout-1)*60*1000;
+ this.socketConnect();
+ }
+ this.loadSounds();
+ this.initializeCustomFlashInterface();
+ },
+
+ socketConnect: function() {
+ if(!this.socketIsConnected) {
+ try {
+ if(!this.socket && FABridge.ajaxChat) {
+ this.socket = FABridge.ajaxChat.create('flash.net.XMLSocket');
+ this.socket.addEventListener('connect', this.socketConnectHandler);
+ this.socket.addEventListener('close', this.socketCloseHandler);
+ this.socket.addEventListener('data', this.socketDataHandler);
+ this.socket.addEventListener('ioError', this.socketIOErrorHandler);
+ this.socket.addEventListener('securityError', this.socketSecurityErrorHandler);
+ }
+ this.socket.connect(this.socketServerHost, this.socketServerPort);
+ } catch(e) {
+ //alert(e);
+ }
+ }
+ clearTimeout(this.socketReconnectTimer);
+ this.socketReconnectTimer = null;
+ },
+
+ socketConnectHandler: function(event) {
+ ajaxChat.socketIsConnected = true;
+ // setTimeout is needed to avoid calling the flash interface recursively:
+ setTimeout(ajaxChat.socketRegister, 0);
+ },
+
+ socketCloseHandler: function(event) {
+ ajaxChat.socketIsConnected = false;
+ if(ajaxChat.socket) {
+ clearTimeout(ajaxChat.timer);
+ ajaxChat.updateChat(null);
+ }
+ },
+
+ socketDataHandler: function(event) {
+ ajaxChat.socketUpdate(event.getData());
+ },
+
+ socketIOErrorHandler: function(event) {
+ // setTimeout is needed to avoid calling the flash interface recursively (e.g. sound on new messages):
+ setTimeout(function() { ajaxChat.addChatBotMessageToChatList('/error SocketIO'); }, 0);
+ setTimeout(ajaxChat.updateChatlistView, 1);
+ },
+
+ socketSecurityErrorHandler: function(event) {
+ // setTimeout is needed to avoid calling the flash interface recursively (e.g. sound on new messages):
+ setTimeout(function() { ajaxChat.addChatBotMessageToChatList('/error SocketSecurity'); }, 0);
+ setTimeout(ajaxChat.updateChatlistView, 1);
+ },
+
+ socketRegister: function() {
+ if(this.socket && this.socketIsConnected) {
+ try {
+ this.socket.send(
+ '<register chatID="'
+ +this.socketServerChatID
+ +'" userID="'
+ +this.userID
+ +'" regID="'
+ +this.socketRegistrationID
+ +'"/>'
+ );
+ } catch(e) {
+ //alert(e);
+ }
+ }
+ },
+
+ loadXML: function(str) {
+ if(!arguments.callee.parser) {
+ try {
+ // DOMParser native implementation (Mozilla, Opera):
+ arguments.callee.parser = new DOMParser();
+ } catch(e) {
+ var customDOMParser = function() {};
+ if(navigator.appName === 'Microsoft Internet Explorer') {
+ // IE implementation:
+ customDOMParser.prototype.parseFromString = function(str, contentType) {
+ if(!arguments.callee.XMLDOM) {
+ arguments.callee.XMLDOM = new ActiveXObject('Microsoft.XMLDOM');
+ }
+ arguments.callee.XMLDOM.loadXML(str);
+ return arguments.callee.XMLDOM;
+ };
+ } else {
+ // Safari, Konqueror:
+ customDOMParser.prototype.parseFromString = function(str, contentType) {
+ if(!arguments.callee.httpRequest) {
+ arguments.callee.httpRequest = new XMLHttpRequest();
+ }
+ arguments.callee.httpRequest.open(
+ 'GET',
+ 'data:text/xml;charset=utf-8,'+encodeURIComponent(str),
+ false
+ );
+ arguments.callee.httpRequest.send(null);
+ return arguments.callee.httpRequest.responseXML;
+ };
+ }
+ arguments.callee.parser = new customDOMParser();
+ }
+ }
+ return arguments.callee.parser.parseFromString(str, 'text/xml');
+ },
+
+ socketUpdate: function(data) {
+ var xmlDoc = this.loadXML(data);
+ if(xmlDoc) {
+ this.handleOnlineUsers(xmlDoc.getElementsByTagName('user'));
+ // If the root node has the attribute "mode" set to "1" it is a channel message:
+ if((this.showChannelMessages || xmlDoc.firstChild.getAttribute('mode') !== '1') && !this.channelSwitch) {
+ var channelID = xmlDoc.firstChild.getAttribute('channelID');
+ if(channelID === this.channelID ||
+ parseInt(channelID) === parseInt(this.userID)+this.privateMessageDiff
+ ) {
+ this.handleChatMessages(xmlDoc.getElementsByTagName('message'));
+ }
+ }
+ }
+ },
+
+ setAudioVolume: function(volume) {
+ volume = parseFloat(volume);
+ if(!isNaN(volume)) {
+ if(volume < 0) {
+ volume = 0.0;
+ } else if(volume > 1) {
+ volume = 1.0;
+ }
+ this.settings['audioVolume'] = volume;
+ try {
+ if(!this.soundTransform) {
+ this.soundTransform = FABridge.ajaxChat.create('flash.media.SoundTransform');
+ }
+ this.soundTransform.setVolume(volume);
+ } catch(e) {
+ //alert(e);
+ }
+ }
+ },
+
+ loadSounds: function() {
+ try {
+ this.setAudioVolume(this.settings['audioVolume']);
+ this.sounds = {};
+ var sound,urlRequest;
+ for(var key in this.soundFiles) {
+ sound = FABridge.ajaxChat.create('flash.media.Sound');
+ sound.addEventListener('complete', this.soundLoadCompleteHandler);
+ sound.addEventListener('ioError', this.soundIOErrorHandler);
+ urlRequest = FABridge.ajaxChat.create('flash.net.URLRequest');
+ urlRequest.setUrl(this.dirs['sounds']+this.soundFiles[key]);
+ sound.load(urlRequest);
+ }
+ } catch(e) {
+ alert(e);
+ }
+ },
+
+ soundLoadCompleteHandler: function(event) {
+ var sound = event.getTarget();
+ for(var key in ajaxChat.soundFiles) {
+ // Get the sound key by matching the sound URL with the sound filename:
+ if((new RegExp(ajaxChat.soundFiles[key])).test(sound.getUrl())) {
+ // Add the loaded sound to the sounds list:
+ ajaxChat.sounds[key] = sound;
+ }
+ }
+ },
+
+ soundIOErrorHandler: function(event) {
+ // setTimeout is needed to avoid calling the flash interface recursively (e.g. sound on new messages):
+ setTimeout(function() { ajaxChat.addChatBotMessageToChatList('/error SoundIO'); }, 0);
+ setTimeout(ajaxChat.updateChatlistView, 1);
+ },
+
+ soundPlayCompleteHandler: function(event) {
+ // soundChannel event 'soundComplete'
+ },
+
+ playSound: function(soundID) {
+ if(this.sounds && this.sounds[soundID]) {
+ try {
+ // play() parameters are
+ // startTime:Number (default = 0),
+ // loops:int (default = 0) and
+ // sndTransform:SoundTransform (default = null)
+ return this.sounds[soundID].play(0, 0, this.soundTransform);
+ } catch(e) {
+ //alert(e);
+ }
+ }
+ return null;
+ },
+
+ playSoundOnNewMessage: function(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip) {
+ if(this.settings['audio'] && this.sounds && this.lastID && !this.channelSwitch) {
+ switch(userID) {
+ case this.chatBotID:
+ var messageParts = messageText.split(' ', 1);
+ switch(messageParts[0]) {
+ case '/login':
+ case '/channelEnter':
+ this.playSound(this.settings['soundEnter']);
+ break;
+ case '/logout':
+ case '/channelLeave':
+ case '/kick':
+ this.playSound(this.settings['soundLeave']);
+ break;
+ case '/error':
+ this.playSound(this.settings['soundError']);
+ break;
+ default:
+ this.playSound(this.settings['soundChatBot']);
+ }
+ break;
+ case this.userID:
+ this.playSound(this.settings['soundSend']);
+ break;
+ default:
+ this.playSound(this.settings['soundReceive']);
+ break;
+ }
+ }
+ },
+
+ fillSoundSelection: function(selectionID, selectedSound) {
+ var selection = document.getElementById(selectionID);
+ // Skip the first, empty selection:
+ var i = 1;
+ for(var key in this.soundFiles) {
+ selection.options[i] = new Option(key, key);
+ if(key === selectedSound){
+ selection.options[i].selected = true;
+ }
+ i++;
+ }
+ },
+
+ setStatus: function(newStatus) {
+ // status options are: ok, retrying, waiting
+ if (this.requestStatus !== 'retrying' || newStatus === 'ok') {
+ this.requestStatus = newStatus;
+ }
+
+ var statusIcon = document.getElementById('statusIconContainer');
+
+ if (statusIcon) {
+ switch (this.requestStatus) {
+ case 'ok':
+ this.setClass(statusIcon, 'statusContainerOff');
+ break;
+ case 'waiting':
+ this.setClass(statusIcon, 'statusContainerOn');
+ break;
+ case 'retrying':
+ this.setClass(statusIcon, 'statusContainerAlert');
+ break;
+ }
+ }
+ },
+
+ forceNewRequest: function() {
+ ajaxChat.updateChat(null);
+ ajaxChat.setStatus('retrying');
+ },
+
+ getHttpRequest: function(identifier) {
+ if(!this.httpRequest[identifier]) {
+ if (window.XMLHttpRequest) {
+ this.httpRequest[identifier] = new XMLHttpRequest();
+ if (this.httpRequest[identifier].overrideMimeType) {
+ this.httpRequest[identifier].overrideMimeType('text/xml');
+ }
+ } else if (window.ActiveXObject) {
+ try {
+ this.httpRequest[identifier] = new ActiveXObject("Msxml2.XMLHTTP");
+ } catch (e) {
+ try {
+ this.httpRequest[identifier] = new ActiveXObject("Microsoft.XMLHTTP");
+ } catch (e) {
+ }
+ }
+ }
+ }
+ return this.httpRequest[identifier];
+ },
+
+ makeRequest: function(url, method, data) {
+ var identifier;
+ this.setStatus('waiting');
+
+ try {
+ if(data) {
+ // Create up to 50 HTTPRequest objects:
+ if(!arguments.callee.identifier || arguments.callee.identifier > 50) {
+ arguments.callee.identifier = 1;
+ } else {
+ arguments.callee.identifier++;
+ }
+ identifier = arguments.callee.identifier;
+ } else {
+ identifier = 0;
+ }
+ //if the response takes longer than retryTimerDelay to give an OK status, abort the connection and start again.
+ this.retryTimer = setTimeout(ajaxChat.forceNewRequest, ajaxChat.retryTimerDelay);
+
+ this.getHttpRequest(identifier).open(method, url, true);
+ this.getHttpRequest(identifier).onreadystatechange = function() {
+ try {
+ ajaxChat.handleResponse(identifier);
+ } catch(e) {
+ try {
+ clearTimeout(ajaxChat.timer);
+ } catch(e) {
+ //alert(e);
+ }
+ try {
+ if(data) {
+ ajaxChat.addChatBotMessageToChatList('/error ConnectionTimeout');
+ ajaxChat.setStatus('retrying');
+ ajaxChat.updateChatlistView();
+ }
+ } catch(e) {
+ //alert(e);
+ }
+ try {
+ ajaxChat.timer = setTimeout(function() { ajaxChat.updateChat(null); }, ajaxChat.timerRate);
+ } catch(e) {
+ //alert(e);
+ }
+ }
+ };
+ if(method === 'POST') {
+ this.getHttpRequest(identifier).setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
+ }
+ this.getHttpRequest(identifier).send(data);
+ } catch(e) {
+ clearTimeout(this.timer);
+ if(data) {
+ this.addChatBotMessageToChatList('/error ConnectionTimeout');
+ ajaxChat.setStatus('retrying');
+ this.updateChatlistView();
+ }
+ this.timer = setTimeout(function() { ajaxChat.updateChat(null); }, this.timerRate);
+ }
+ },
+
+ handleResponse: function(identifier) {
+ var xmlDoc;
+ if (this.getHttpRequest(identifier).readyState === 4) {
+ if (this.getHttpRequest(identifier).status === 200) {
+ clearTimeout(ajaxChat.retryTimer);
+ xmlDoc = this.getHttpRequest(identifier).responseXML;
+ ajaxChat.setStatus('ok');
+ } else {
+ // Connection status 0 can be ignored.
+ if (this.getHttpRequest(identifier).status === 0) {
+ this.setStatus('waiting');
+ this.updateChatlistView();
+ return false;
+ } else {
+ this.addChatBotMessageToChatList('/error ConnectionStatus '+this.getHttpRequest(identifier).status);
+ this.setStatus('retrying');
+ this.updateChatlistView();
+ return false;
+ }
+ }
+ }
+ if(!xmlDoc) {
+ return false;
+ }
+ this.handleXML(xmlDoc);
+ return true;
+ },
+
+ handleXML: function(xmlDoc) {
+ this.handleInfoMessages(xmlDoc.getElementsByTagName('info'));
+ this.handleOnlineUsers(xmlDoc.getElementsByTagName('user'));
+ this.handleChatMessages(xmlDoc.getElementsByTagName('message'));
+ this.channelSwitch = null;
+ this.setChatUpdateTimer();
+ },
+
+ setChatUpdateTimer: function() {
+ clearTimeout(this.timer);
+ if(this.chatStarted) {
+ var timeout;
+ if(this.socketIsConnected) {
+ timeout = this.socketTimerRate;
+ } else {
+ timeout = this.timerRate;
+ if(this.socketServerEnabled && !this.socketReconnectTimer) {
+ // If the socket connection fails try to reconnect once in a minute:
+ this.socketReconnectTimer = setTimeout(ajaxChat.socketConnect, 60000);
+ }
+ }
+ this.timer = setTimeout(function() {ajaxChat.updateChat(null);}, timeout);
+ }
+ },
+
+ handleInfoMessages: function(infoNodes) {
+ var infoType, infoData;
+ for(var i=0; i<infoNodes.length; i++) {
+ infoType = infoNodes[i].getAttribute('type');
+ infoData = infoNodes[i].firstChild ? infoNodes[i].firstChild.nodeValue : '';
+ this.handleInfoMessage(infoType, infoData);
+ }
+ },
+
+ handleInfoMessage: function(infoType, infoData) {
+ switch(infoType) {
+ case 'channelSwitch':
+ this.clearChatList();
+ this.clearOnlineUsersList();
+ this.setSelectedChannel(infoData);
+ this.channelName = infoData;
+ this.channelSwitch = true;
+ break;
+ case 'channelName':
+ this.setSelectedChannel(infoData);
+ this.channelName = infoData;
+ break;
+ case 'channelID':
+ this.channelID = infoData;
+ break;
+ case 'userID':
+ this.userID = infoData;
+ break;
+ case 'userName':
+ this.userName = infoData;
+ this.encodedUserName = this.scriptLinkEncode(this.userName);
+ this.userNodeString = null;
+ break;
+ case 'userRole':
+ this.userRole = infoData;
+ break;
+ case 'logout':
+ this.handleLogout(infoData);
+ return;
+ case 'socketRegistrationID':
+ this.socketRegistrationID = infoData;
+ this.socketRegister();
+ default:
+ this.handleCustomInfoMessage(infoType, infoData);
+ }
+ },
+
+ handleOnlineUsers: function(userNodes) {
+ if(userNodes.length) {
+ var index,userID,userName,userRole,i,
+ onlineUsers = [];
+ for(i=0; i<userNodes.length; i++) {
+ userID = userNodes[i].getAttribute('userID');
+ userName = userNodes[i].firstChild ? userNodes[i].firstChild.nodeValue : '';
+ userRole = userNodes[i].getAttribute('userRole');
+ onlineUsers.push(userID);
+ index = this.arraySearch(userID, this.usersList);
+ if(index === false) {
+ this.addUserToOnlineList(
+ userID,
+ userName,
+ userRole
+ );
+ } else if(this.userNamesList[index] !== userName) {
+ this.removeUserFromOnlineList(userID, index);
+ this.addUserToOnlineList(
+ userID,
+ userName,
+ userRole
+ );
+ }
+ }
+ // Clear the offline users from the online users list:
+ for(i=0; i<this.usersList.length; i++) {
+ if(!this.inArray(onlineUsers, this.usersList[i])) {
+ this.removeUserFromOnlineList(this.usersList[i], i);
+ }
+ }
+ this.setOnlineListRowClasses();
+ }
+ },
+
+ handleChatMessages: function(messageNodes) {
+ var userNode,userName,textNode,messageText,i;
+ if(messageNodes.length) {
+ for(i=0; i<messageNodes.length; i++) {
+ this.DOMbuffering = true;
+ userNode = messageNodes[i].getElementsByTagName('username')[0];
+ userName = userNode.firstChild ? userNode.firstChild.nodeValue : '';
+ textNode = messageNodes[i].getElementsByTagName('text')[0];
+ messageText = textNode.firstChild ? textNode.firstChild.nodeValue : '';
+ if (i === (messageNodes.length - 1)) {this.DOMbuffering = false;}
+ this.addMessageToChatList(
+ new Date(messageNodes[i].getAttribute('dateTime')),
+ messageNodes[i].getAttribute('userID'),
+ userName,
+ messageNodes[i].getAttribute('userRole'),
+ messageNodes[i].getAttribute('id'),
+ messageText,
+ messageNodes[i].getAttribute('channelID'),
+ messageNodes[i].getAttribute('ip')
+ );
+ }
+ this.DOMbuffering = false;
+ this.updateChatlistView();
+ this.lastID = messageNodes[messageNodes.length-1].getAttribute('id');
+ }
+ },
+
+ setSelectedChannel: function(channel) {
+ var channelSelected = false,
+ i,option,text;
+ if(this.dom['channelSelection']) {
+ // Replace the entities in the channel name with their character equivalent:
+ channel = this.decodeSpecialChars(channel);
+ for(i=0; i<this.dom['channelSelection'].options.length; i++) {
+ if(this.dom['channelSelection'].options[i].value === channel) {
+ this.dom['channelSelection'].options[i].selected = true;
+ channelSelected = true;
+ break;
+ }
+ }
+ // The given channel is not in the list, add it:
+ if(!channelSelected) {
+ option = document.createElement('option');
+ text = document.createTextNode(channel);
+ option.appendChild(text);
+ option.setAttribute('value', channel);
+ option.setAttribute('selected', 'selected');
+ this.dom['channelSelection'].appendChild(option);
+ }
+ }
+ },
+
+ removeUserFromOnlineList: function(userID, index) {
+ this.usersList.splice(index, 1);
+ this.userNamesList.splice(index, 1);
+ if(this.dom['onlineList']) {
+ this.dom['onlineList'].removeChild(this.getUserNode(userID));
+ }
+ },
+
+ addUserToOnlineList: function(userID, userName, userRole) {
+ this.usersList.push(userID);
+ this.userNamesList.push(userName);
+ if(this.dom['onlineList']) {
+ this.updateDOM(
+ 'onlineList',
+ this.getUserNodeString(userID, userName, userRole),
+ (this.userID === userID)
+ );
+ }
+ },
+
+ getUserNodeString: function(userID, userName, userRole) {
+ var encodedUserName, str;
+ if(this.userNodeString && userID === this.userID) {
+ return this.userNodeString;
+ } else {
+ encodedUserName = this.scriptLinkEncode(userName);
+ str = '<div id="'
+ + this.getUserDocumentID(userID)
+ + '"><a href="javascript:ajaxChat.toggleUserMenu(\''
+ + this.getUserMenuDocumentID(userID)
+ + '\', \''
+ + encodedUserName
+ + '\', '
+ + userID
+ + ');" class="'
+ + this.getRoleClass(userRole)
+ + '" title="'
+ + this.lang['toggleUserMenu'].replace(/%s/, userName)
+ + '">'
+ + userName
+ + '</a>'
+ + '<ul class="userMenu" id="'
+ + this.getUserMenuDocumentID(userID)
+ + '"'
+ + ((userID === this.userID) ?
+ '>'+this.getUserNodeStringItems(encodedUserName, userID, false) :
+ ' style="display:none;">')
+ + '</ul>'
+ +'</div>';
+ if(userID === this.userID) {
+ this.userNodeString = str;
+ }
+ return str;
+ }
+ },
+
+ toggleUserMenu: function(menuID, userName, userID) {
+ // If the menu is empty, fill it with user node menu items before toggling it.
+ var isInline = false;
+ if (menuID.indexOf('ium') >= 0 ) {
+ isInline = true;
+ }
+ if(!document.getElementById(menuID).firstChild) {
+ this.updateDOM(
+ menuID,
+ this.getUserNodeStringItems(
+ this.encodeText(this.addSlashes(this.getScriptLinkValue(userName))),
+ userID,
+ isInline
+ ),
+ false,
+ true
+ )
+ }
+ this.showHide(menuID);
+ this.dom['chatList'].scrollTop = this.dom['chatList'].scrollHeight;
+ },
+
+ getUserNodeStringItems: function(encodedUserName, userID, isInline) {
+ var menu;
+ if(encodedUserName !== this.encodedUserName) {
+ menu = '<li><a href="javascript:ajaxChat.insertMessageWrapper(\'/msg '
+ + encodedUserName
+ + ' \');">'
+ + this.lang['userMenuSendPrivateMessage']
+ + '</a></li>'
+ + '<li><a href="javascript:ajaxChat.insertMessageWrapper(\'/describe '
+ + encodedUserName
+ + ' \');">'
+ + this.lang['userMenuDescribe']
+ + '</a></li>'
+ + '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/query '
+ + encodedUserName
+ + '\');">'
+ + this.lang['userMenuOpenPrivateChannel']
+ + '</a></li>'
+ + '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/query\');">'
+ + this.lang['userMenuClosePrivateChannel']
+ + '</a></li>'
+ + '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/ignore '
+ + encodedUserName
+ + '\');">'
+ + this.lang['userMenuIgnore']
+ + '</a></li>';
+ if (isInline) {
+ menu += '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/invite '
+ + encodedUserName
+ + '\');">'
+ + this.lang['userMenuInvite']
+ + '</a></li>'
+ + '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/uninvite '
+ + encodedUserName
+ + '\');">'
+ + this.lang['userMenuUninvite']
+ + '</a></li>'
+ + '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/whereis '
+ + encodedUserName
+ + '\');">'
+ + this.lang['userMenuWhereis']
+ + '</a></li>';
+ }
+ if(this.userRole === '2' || this.userRole === '3') {
+ menu += '<li><a href="javascript:ajaxChat.insertMessageWrapper(\'/kick '
+ + encodedUserName
+ + ' \');">'
+ + this.lang['userMenuKick']
+ + '</a></li>'
+ + '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/whois '
+ + encodedUserName
+ + '\');">'
+ + this.lang['userMenuWhois']
+ + '</a></li>';
+ }
+ } else {
+ menu = '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/quit\');">'
+ + this.lang['userMenuLogout']
+ + '</a></li>'
+ + '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/who\');">'
+ + this.lang['userMenuWho']
+ + '</a></li>'
+ + '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/ignore\');">'
+ + this.lang['userMenuIgnoreList']
+ + '</a></li>'
+ + '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/list\');">'
+ + this.lang['userMenuList']
+ + '</a></li>'
+ + '<li><a href="javascript:ajaxChat.insertMessageWrapper(\'/action \');">'
+ + this.lang['userMenuAction']
+ + '</a></li>'
+ + '<li><a href="javascript:ajaxChat.insertMessageWrapper(\'/roll \');">'
+ + this.lang['userMenuRoll']
+ + '</a></li>'
+ + '<li><a href="javascript:ajaxChat.insertMessageWrapper(\'/nick \');">'
+ + this.lang['userMenuNick']
+ + '</a></li>';
+ if(this.userRole === '1' || this.userRole === '2' || this.userRole === '3') {
+ menu += '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/join\');">'
+ + this.lang['userMenuEnterPrivateRoom']
+ + '</a></li>';
+ if(this.userRole === '2' || this.userRole === '3') {
+ menu += '<li><a href="javascript:ajaxChat.sendMessageWrapper(\'/bans\');">'
+ + this.lang['userMenuBans']
+ + '</a></li>';
+ }
+ }
+ }
+ menu += this.getCustomUserMenuItems(encodedUserName, userID);
+ return menu;
+ },
+
+ setOnlineListRowClasses: function() {
+ if(this.dom['onlineList']) {
+ var node = this.dom['onlineList'].firstChild;
+ var rowEven = false;
+ while(node) {
+ this.setClass(node, (rowEven ? 'rowEven' : 'rowOdd'));
+ node = node.nextSibling;
+ rowEven = !rowEven;
+ }
+ }
+ },
+
+ clearChatList: function() {
+ while(this.dom['chatList'].hasChildNodes()) {
+ this.dom['chatList'].removeChild(this.dom['chatList'].firstChild);
+ }
+ },
+
+ clearOnlineUsersList: function() {
+ this.usersList = [];
+ this.userNamesList = [];
+ if(this.dom['onlineList']) {
+ while(this.dom['onlineList'].hasChildNodes()) {
+ this.dom['onlineList'].removeChild(this.dom['onlineList'].firstChild);
+ }
+ }
+ },
+
+ getEncodedChatBotName: function() {
+ if(typeof arguments.callee.encodedChatBotName === 'undefined') {
+ arguments.callee.encodedChatBotName = this.encodeSpecialChars(this.chatBotName);
+ }
+ return arguments.callee.encodedChatBotName;
+ },
+
+ addChatBotMessageToChatList: function(messageText) {
+ this.addMessageToChatList(
+ new Date(),
+ this.chatBotID,
+ this.getEncodedChatBotName(),
+ 4,
+ null,
+ messageText,
+ null
+ );
+ },
+
+ addMessageToChatList: function(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip) {
+ // Prevent adding the same message twice:
+ if(this.getMessageNode(messageID)) {
+ return;
+ }
+ if(!this.onNewMessage(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip)) {
+ return;
+ }
+ this.DOMbufferRowClass = this.DOMbufferRowClass === 'rowEven' ? 'rowOdd' : 'rowEven';
+ this.DOMbuffer = this.DOMbuffer +
+ this.getChatListMessageString(
+ dateObject, userID, userName, userRole, messageID, messageText, channelID, ip
+ );
+ if(!this.DOMbuffering){
+ this.updateDOM('chatList', this.DOMbuffer);
+ this.DOMbuffer = "";
+ }
+ },
+
+ getChatListMessageString: function(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip) {
+ var rowClass = this.DOMbufferRowClass;
+ var userClass = this.getRoleClass(userRole);
+ var colon;
+ if(messageText.indexOf('/action') === 0 || messageText.indexOf('/me') === 0 || messageText.indexOf('/privaction') === 0) {
+ userClass += ' action';
+ colon = ' ';
+ } else {
+ colon = ': ';
+ }
+ var dateTime = this.settings['dateFormat'] ? '<span class="dateTime">'
+ + this.formatDate(this.settings['dateFormat'], dateObject) + '</span> ' : '';
+ return '<div id="'
+ + this.getMessageDocumentID(messageID)
+ + '" class="'
+ + rowClass
+ + '">'
+ + this.getDeletionLink(messageID, userID, userRole, channelID)
+ + dateTime
+ + '<span class="'
+ + userClass
+ + '"'
+ + this.getChatListUserNameTitle(userID, userName, userRole, ip)
+ + ' dir="'
+ + this.baseDirection
+ + '" onclick="ajaxChat.insertText(this.firstChild.nodeValue);">'
+ + userName
+ + '</span>'
+ + colon
+ + this.replaceText(messageText)
+ + '</div>';
+ },
+
+ getChatListUserNameTitle: function(userID, userName, userRole, ip) {
+ return (ip !== null) ? ' title="IP: ' + ip + '"' : '';
+ },
+
+ getMessageDocumentID: function(messageID) {
+ return ((messageID === null) ? 'ajaxChat_lm_'+(this.localID++) : 'ajaxChat_m_'+messageID);
+ },
+
+ getMessageNode: function(messageID) {
+ return ((messageID === null) ? null : document.getElementById(this.getMessageDocumentID(messageID)));
+ },
+
+ getUserDocumentID: function(userID) {
+ return 'ajaxChat_u_'+userID;
+ },
+
+ getUserNode: function(userID) {
+ return document.getElementById(this.getUserDocumentID(userID));
+ },
+
+ getUserMenuDocumentID: function(userID) {
+ return 'ajaxChat_um_'+userID;
+ },
+
+ getInlineUserMenuDocumentID: function(menuID, index) {
+ return 'ajaxChat_ium_'+menuID+'_'+index;
+ },
+
+ getDeletionLink: function(messageID, userID, userRole, channelID) {
+ if(messageID !== null && this.isAllowedToDeleteMessage(messageID, userID, userRole, channelID)) {
+ if(!arguments.callee.deleteMessage) {
+ arguments.callee.deleteMessage = this.encodeSpecialChars(this.lang['deleteMessage']);
+ }
+ return '<a class="delete" title="'
+ + arguments.callee.deleteMessage
+ + '" href="javascript:ajaxChat.deleteMessage('
+ + messageID
+ + ');"> </a>'; // Adding a space - without any content Opera messes up the chatlist display
+ }
+ return '';
+ },
+
+ isAllowedToDeleteMessage: function(messageID, userID, userRole, channelID) {
+ if((((this.userRole === '1' && this.allowUserMessageDelete && (userID === this.userID ||
+ parseInt(channelID) === parseInt(this.userID)+this.privateMessageDiff ||
+ parseInt(channelID) === parseInt(this.userID)+this.privateChannelDiff)) ||
+ this.userRole === '2') && userRole !== '3' && userRole !== '4') || this.userRole === '3') {
+ return true;
+ }
+ return false;
+ },
+
+ onNewMessage: function(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip) {
+ if(!this.customOnNewMessage(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip)) {
+ return false;
+ }
+ if(this.ignoreMessage(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip)) {
+ return false;
+ }
+ if(this.parseDeleteMessageCommand(messageText)) {
+ return false;
+ }
+ this.blinkOnNewMessage(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip);
+ this.playSoundOnNewMessage(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip);
+ return true;
+ },
+
+ parseDeleteMessageCommand: function(messageText) {
+ if(messageText.indexOf('/delete') === 0) {
+ var messageID = messageText.substr(8);
+ var messageNode = this.getMessageNode(messageID);
+ if(messageNode) {
+ var nextSibling = messageNode.nextSibling;
+ try {
+ this.dom['chatList'].removeChild(messageNode);
+ if(nextSibling) {
+ this.updateChatListRowClasses(nextSibling);
+ }
+ } catch(e) {
+ }
+ }
+ return true;
+ }
+ return false;
+ },
+
+ blinkOnNewMessage: function(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip) {
+ if(this.settings['blink'] && this.lastID && !this.channelSwitch && userID !== this.userID) {
+ clearInterval(this.blinkInterval);
+ this.blinkInterval = setInterval(
+ 'ajaxChat.blinkUpdate(\''+this.addSlashes(this.decodeSpecialChars(userName))+'\')',
+ this.settings['blinkInterval']
+ );
+ }
+ },
+
+ blinkUpdate: function(blinkStr) {
+ if(!this.originalDocumentTitle) {
+ this.originalDocumentTitle = document.title;
+ }
+ if(!arguments.callee.blink) {
+ document.title = '[@ ] '+blinkStr+' - '+this.originalDocumentTitle;
+ arguments.callee.blink = 1;
+ } else if(arguments.callee.blink > this.settings['blinkIntervalNumber']) {
+ clearInterval(this.blinkInterval);
+ document.title = this.originalDocumentTitle;
+ arguments.callee.blink = 0;
+ } else {
+ if(arguments.callee.blink % 2 !== 0) {
+ document.title = '[@ ] '+blinkStr+' - '+this.originalDocumentTitle;
+ } else {
+ document.title = '[ @] '+blinkStr+' - '+this.originalDocumentTitle;
+ }
+ arguments.callee.blink++;
+ }
+ },
+
+ updateChatlistView: function() {
+ if(this.dom['chatList'].childNodes && this.settings['maxMessages']) {
+ while(this.dom['chatList'].childNodes.length > this.settings['maxMessages']) {
+ this.dom['chatList'].removeChild(this.dom['chatList'].firstChild);
+ }
+ }
+
+ if(this.settings['autoScroll']) {
+ this.dom['chatList'].scrollTop = this.dom['chatList'].scrollHeight;
+ }
+ },
+
+ encodeText: function(text) {
+ return encodeURIComponent(text);
+ },
+
+ decodeText: function(text) {
+ return decodeURIComponent(text);
+ },
+
+ utf8Encode: function(plainText) {
+ var utf8Text = '';
+ for(var i=0; i<plainText.length; i++) {
+ var c=plainText.charCodeAt(i);
+ if(c<128) {
+ utf8Text += String.fromCharCode(c);
+ } else if((c>127) && (c<2048)) {
+ utf8Text += String.fromCharCode((c>>6)|192);
+ utf8Text += String.fromCharCode((c&63)|128);
+ } else {
+ utf8Text += String.fromCharCode((c>>12)|224);
+ utf8Text += String.fromCharCode(((c>>6)&63)|128);
+ utf8Text += String.fromCharCode((c&63)|128);
+ }
+ }
+ return utf8Text;
+ },
+
+ utf8Decode: function(utf8Text) {
+ var plainText = '';
+ var c,c2,c3;
+ var i=0;
+ while(i<utf8Text.length) {
+ c = utf8Text.charCodeAt(i);
+ if(c<128) {
+ plainText += String.fromCharCode(c);
+ i++;
+ } else if((c>191) && (c<224)) {
+ c2 = utf8Text.charCodeAt(i+1);
+ plainText += String.fromCharCode(((c&31)<<6) | (c2&63));
+ i+=2;
+ } else {
+ c2 = utf8Text.charCodeAt(i+1);
+ c3 = utf8Text.charCodeAt(i+2);
+ plainText += String.fromCharCode(((c&15)<<12) | ((c2&63)<<6) | (c3&63));
+ i+=3;
+ }
+ }
+ return plainText;
+ },
+
+ encodeSpecialChars: function(text) {
+ return text.replace(
+ /[&<>'"]/g,
+ this.encodeSpecialCharsCallback
+ );
+ },
+
+ encodeSpecialCharsCallback: function(str) {
+ switch(str) {
+ case '&':
+ return '&amp;';
+ case '<':
+ return '&lt;';
+ case '>':
+ return '&gt;';
+ case '\'':
+ // As &apos; is not supported by IE, we use &#39; as replacement for ('):
+ return '&#39;';
+ case '"':
+ return '&quot;';
+ default:
+ return str;
+ }
+ },
+
+ decodeSpecialChars: function(text) {
+ var regExp = new RegExp('(&amp;)|(&lt;)|(&gt;)|(&#39;)|(&quot;)', 'g');
+
+ return text.replace(
+ regExp,
+ this.decodeSpecialCharsCallback
+ );
+ },
+
+ decodeSpecialCharsCallback: function(str) {
+ switch(str) {
+ case '&amp;':
+ return '&';
+ case '&lt;':
+ return '<';
+ case '&gt;':
+ return '>';
+ case '&#39;':
+ return '\'';
+ case '&quot;':
+ return '"';
+ default:
+ return str;
+ }
+ },
+
+ inArray: function(haystack, needle) {
+ var i = haystack.length;
+ while(i--) {
+ if(haystack[i] === needle) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ arraySearch: function(needle, haystack) {
+ var i = haystack.length;
+ while(i--) {
+ if(haystack[i] === needle) {
+ return i;
+ }
+ }
+ return false;
+ },
+
+ stripTags: function(str) {
+ if (!arguments.callee.regExp) {
+ arguments.callee.regExp = new RegExp('<\\/?[^>]+?>', 'g');
+ }
+
+ return str.replace(arguments.callee.regExp, '');
+ },
+
+ stripBBCodeTags: function(str) {
+ if (!arguments.callee.regExp) {
+ arguments.callee.regExp = new RegExp('\\[\\/?[^\\]]+?\\]', 'g');
+ }
+
+ return str.replace(arguments.callee.regExp, '');
+ },
+
+ escapeRegExp: function(text) {
+ if (!arguments.callee.regExp) {
+ var specials = new Array(
+ '^', '$', '*', '+', '?', '.', '|', '/',
+ '(', ')', '[', ']', '{', '}', '\\'
+ );
+ arguments.callee.regExp = new RegExp(
+ '(\\' + specials.join('|\\') + ')', 'g'
+ );
+ }
+ return text.replace(arguments.callee.regExp, '\\$1');
+ },
+
+ addSlashes: function(text) {
+ // Adding slashes in front of apostrophs and backslashes to ensure a valid JavaScript expression:
+ return text.replace(/\\/g, '\\\\').replace(/\'/g, '\\\'');
+ },
+
+ removeSlashes: function(text) {
+ // Removing slashes added by calling addSlashes(text) previously:
+ return text.replace(/\\\\/g, '\\').replace(/\\\'/g, '\'');
+ },
+
+ formatDate: function(format, date) {
+ date = (date == null) ? new date() : date;
+
+ return format
+ .replace(/%Y/g, date.getFullYear())
+ .replace(/%m/g, this.addLeadingZero(date.getMonth()+1))
+ .replace(/%d/g, this.addLeadingZero(date.getDate()))
+ .replace(/%H/g, this.addLeadingZero(date.getHours()))
+ .replace(/%i/g, this.addLeadingZero(date.getMinutes()))
+ .replace(/%s/g, this.addLeadingZero(date.getSeconds()));
+ },
+
+ addLeadingZero: function(number) {
+ number = number.toString();
+ if(number.length < 2) {
+ number = '0'+number;
+ }
+ return number;
+ },
+
+ getUserIDFromUserName: function(userName) {
+ var index = this.arraySearch(userName, this.userNamesList);
+ if(index !== false) {
+ return this.usersList[index];
+ }
+ return null;
+ },
+
+ getUserNameFromUserID: function(userID) {
+ var index = this.arraySearch(userID, this.usersList);
+ if(index !== false) {
+ return this.userNamesList[index];
+ }
+ return null;
+ },
+
+ getRoleClass: function(roleID) {
+ switch(parseInt(roleID)) {
+ case 0:
+ return 'guest';
+ case 1:
+ return 'user';
+ case 2:
+ return 'moderator';
+ case 3:
+ return 'admin';
+ case 4:
+ return 'chatBot';
+ default:
+ return 'default';
+ }
+ },
+
+ handleInputFieldKeyPress: function(event) {
+ if(event.keyCode === 13 && !event.shiftKey) {
+ this.sendMessage();
+ try {
+ event.preventDefault();
+ } catch(e) {
+ event.returnValue = false; // IE
+ }
+ return false;
+ }
+ return true;
+ },
+
+ handleInputFieldKeyUp: function(event) {
+ this.updateMessageLengthCounter();
+ },
+
+ updateMessageLengthCounter: function() {
+ if(this.dom['messageLengthCounter']) {
+ this.updateDOM(
+ 'messageLengthCounter',
+ this.dom['inputField'].value.length + '/' + this.messageTextMaxLength,
+ false,
+ true
+ );
+ }
+ },
+
+ sendMessage: function(text) {
+ text = text ? text : this.dom['inputField'].value;
+ if(!text) {
+ return;
+ }
+ text = this.parseInputMessage(text);
+ if(text) {
+ clearTimeout(this.timer);
+ var message = 'lastID='
+ + this.lastID
+ + '&text='
+ + this.encodeText(text);
+ this.makeRequest(this.ajaxURL,'POST',message);
+ }
+ this.dom['inputField'].value = '';
+ this.dom['inputField'].focus();
+ this.updateMessageLengthCounter();
+ },
+
+ parseInputMessage: function(text) {
+ var textParts;
+ if(text.charAt(0) === '/') {
+ textParts = text.split(' ');
+ switch(textParts[0]) {
+ case '/ignore':
+ text = this.parseIgnoreInputCommand(text, textParts);
+ break;
+ case '/clear':
+ this.clearChatList();
+ return false;
+ break;
+ default:
+ text = this.parseCustomInputCommand(text, textParts);
+ }
+ if(text && this.settings['persistFontColor'] && this.settings['fontColor']) {
+ text = this.assignFontColorToCommandMessage(text, textParts);
+ }
+ } else {
+ text = this.parseCustomInputMessage(text);
+ if(text && this.settings['persistFontColor'] && this.settings['fontColor']) {
+ text = this.assignFontColorToMessage(text);
+ }
+ }
+ return text;
+ },
+
+ assignFontColorToMessage: function(text) {
+ return '[color='+this.settings['fontColor']+']'+text+'[/color]';
+ },
+
+ assignFontColorToCommandMessage: function(text, textParts) {
+ switch(textParts[0]) {
+ case '/msg':
+ case '/describe':
+ if(textParts.length > 2) {
+ return textParts[0]+' '+textParts[1]+' '
+ + '[color='+this.settings['fontColor']+']'
+ + textParts.slice(2).join(' ')
+ + '[/color]';
+ }
+ break;
+ case '/me':
+ case '/action':
+ if(textParts.length > 1) {
+ return textParts[0]+' '
+ + '[color='+this.settings['fontColor']+']'
+ + textParts.slice(1).join(' ')
+ + '[/color]';
+ }
+ break;
+ }
+ return text;
+ },
+
+ parseIgnoreInputCommand: function(text, textParts) {
+ var userName, ignoredUserNames = this.getIgnoredUserNames(), i;
+ if(textParts.length > 1) {
+ userName = this.encodeSpecialChars(textParts[1]);
+ // Prevent adding the chatBot or current user to the list:
+ if(userName === this.userName || userName === this.getEncodedChatBotName()) {
+ // Display the list of ignored users instead:
+ return this.parseIgnoreInputCommand(null, new Array('/ignore'));
+ }
+ if(ignoredUserNames.length > 0) {
+ i = ignoredUserNames.length;
+ while(i--) {
+ if(ignoredUserNames[i] === userName) {
+ ignoredUserNames.splice(i,1);
+ this.addChatBotMessageToChatList('/ignoreRemoved '+userName);
+ this.setIgnoredUserNames(ignoredUserNames);
+ this.updateChatlistView();
+ return null;
+ }
+ }
+ }
+ ignoredUserNames.push(userName);
+ this.addChatBotMessageToChatList('/ignoreAdded '+userName);
+ this.setIgnoredUserNames(ignoredUserNames);
+ } else {
+ if(ignoredUserNames.length === 0) {
+ this.addChatBotMessageToChatList('/ignoreListEmpty -');
+ } else {
+ this.addChatBotMessageToChatList('/ignoreList '+ignoredUserNames.join(' '));
+ }
+ }
+ this.updateChatlistView();
+ return null;
+ },
+
+ getIgnoredUserNames: function() {
+ var ignoredUserNamesString;
+ if(!this.ignoredUserNames) {
+ ignoredUserNamesString = this.getSetting('ignoredUserNames');
+ if(ignoredUserNamesString) {
+ this.ignoredUserNames = ignoredUserNamesString.split(' ');
+ } else {
+ this.ignoredUserNames = [];
+ }
+ }
+ return this.ignoredUserNames;
+ },
+
+ setIgnoredUserNames: function(ignoredUserNames) {
+ this.ignoredUserNames = ignoredUserNames;
+ this.setSetting('ignoredUserNames', ignoredUserNames.join(' '));
+ },
+
+ ignoreMessage: function(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip) {
+ var textParts;
+ if(userID === this.chatBotID && messageText.charAt(0) === '/') {
+ textParts = messageText.split(' ');
+ if(textParts.length > 1) {
+ switch(textParts[0]) {
+ case '/invite':
+ case '/uninvite':
+ case '/roll':
+ userName = textParts[1];
+ break;
+ }
+ }
+ }
+ if(this.inArray(this.getIgnoredUserNames(), userName)) {
+ return true;
+ }
+ return false;
+ },
+
+ deleteMessage: function(messageID) {
+ var messageNode = this.getMessageNode(messageID), originalClass, nextSibling;
+ if(messageNode) {
+ originalClass = this.getClass(messageNode);
+ this.setClass(messageNode, originalClass+' deleteSelected');
+ if(confirm(this.lang['deleteMessageConfirm'])) {
+ nextSibling = messageNode.nextSibling;
+ try {
+ this.dom['chatList'].removeChild(messageNode);
+ if(nextSibling) {
+ this.updateChatListRowClasses(nextSibling);
+ }
+ this.updateChat('&delete='+messageID);
+ } catch(e) {
+ this.setClass(messageNode, originalClass);
+ }
+ } else {
+ this.setClass(messageNode, originalClass);
+ }
+ }
+ },
+
+ updateChatListRowClasses: function(node) {
+ var previousNode, rowEven;
+ if(!node) {
+ node = this.dom['chatList'].firstChild;
+ }
+ if(node) {
+ previousNode = node.previousSibling;
+ rowEven = (previousNode && this.getClass(previousNode) === 'rowOdd') ? true : false;
+ while(node) {
+ this.setClass(node, (rowEven ? 'rowEven' : 'rowOdd'));
+ node = node.nextSibling;
+ rowEven = !rowEven;
+ }
+ }
+ },
+
+ getClass: function(node) {
+ if(typeof node.className !== 'undefined') {
+ return node.className; // IE
+ } else {
+ return node.getAttribute('class');
+ }
+ },
+
+ setClass: function(node, className) {
+ if(typeof node.className !== 'undefined') {
+ node.className = className; // IE
+ } else {
+ node.setAttribute('class', className);
+ }
+ },
+
+ scriptLinkEncode: function(text) {
+ return this.encodeText(this.addSlashes(this.decodeSpecialChars(text)));
+ },
+
+ scriptLinkDecode: function(text) {
+ return this.encodeSpecialChars(this.removeSlashes(this.decodeText(text)));
+ },
+
+ getScriptLinkValue: function(value) {
+ // This method returns plainText encoded values from javascript links
+ // The value has to be utf8Decoded for MSIE and Opera:
+ if(typeof arguments.callee.utf8Decode === 'undefined') {
+ switch(navigator.appName) {
+ case 'Microsoft Internet Explorer':
+ case 'Opera':
+ arguments.callee.utf8Decode = true;
+ return this.utf8Decode(value);
+ default:
+ arguments.callee.utf8Decode = false;
+ return value;
+ }
+ } else if(arguments.callee.utf8Decode) {
+ return this.utf8Decode(value);
+ } else {
+ return value;
+ }
+ },
+
+ sendMessageWrapper: function(text) {
+ this.sendMessage(this.getScriptLinkValue(text));
+ },
+
+ insertMessageWrapper: function(text) {
+ this.insertText(this.getScriptLinkValue(text), true);
+ },
+
+ switchChannel: function(channel) {
+ if(!this.chatStarted) {
+ this.clearChatList();
+ this.channelSwitch = true;
+ this.loginChannelID = null;
+ this.loginChannelName = channel;
+ this.requestTeaserContent();
+ return;
+ }
+ clearTimeout(this.timer);
+ var message = 'lastID='
+ + this.lastID
+ + '&channelName='
+ + this.encodeText(channel);
+ this.makeRequest(this.ajaxURL,'POST',message);
+ if(this.dom['inputField'] && this.settings['autoFocus']) {
+ this.dom['inputField'].focus();
+ }
+ },
+
+ logout: function() {
+ clearTimeout(this.timer);
+ var message = 'logout=true';
+ this.makeRequest(this.ajaxURL,'POST',message);
+ },
+
+ handleLogout: function(url) {
+ window.location.href = url;
+ },
+
+ toggleSetting: function(setting, buttonID) {
+ this.setSetting(setting, !this.getSetting(setting));
+ if(buttonID) {
+ this.updateButton(setting, buttonID);
+ }
+ },
+
+ updateButton: function(setting, buttonID) {
+ var node = document.getElementById(buttonID);
+ if(node) {
+ this.setClass(node, (this.getSetting(setting) ? 'button' : 'button off'));
+ }
+ },
+
+ showHide: function(id, styleDisplay, displayInline) {
+ var node = document.getElementById(id);
+ if(node) {
+ if(styleDisplay) {
+ node.style.display = styleDisplay;
+ } else {
+ if(node.style.display === 'none') {
+ node.style.display = (displayInline ? 'inline' : 'block');
+ } else {
+ node.style.display = 'none';
+ }
+ }
+ }
+ },
+
+ setPersistFontColor: function(bool) {
+ this.settings['persistFontColor'] = bool;
+ if(!this.settings['persistFontColor']) {
+ this.settings['fontColor'] = null;
+ if(this.dom['inputField']) {
+ this.dom['inputField'].style.color = '';
+ }
+ }
+ },
+
+ setFontColor: function(color) {
+ if(this.settings['persistFontColor']) {
+ this.settings['fontColor'] = color;
+ if(this.dom['inputField']) {
+ this.dom['inputField'].style.color = color;
+ }
+ if(this.dom['colorCodesContainer']) {
+ this.dom['colorCodesContainer'].style.display = 'none';
+ if(this.dom['inputField']) {
+ this.dom['inputField'].focus();
+ }
+ }
+ } else {
+ this.insert('[color=' + color + ']', '[/color]');
+ }
+ },
+
+ insertText: function(text, clearInputField) {
+ if(clearInputField) {
+ this.dom['inputField'].value = '';
+ }
+ this.insert(text, '');
+ },
+
+ insertBBCode: function(bbCode) {
+ switch(bbCode) {
+ case 'url':
+ var url = prompt(this.lang['urlDialog'], 'http://');
+ if(url)
+ this.insert('[url=' + url + ']', '[/url]');
+ else
+ this.dom['inputField'].focus();
+ break;
+ default:
+ this.insert('[' + bbCode + ']', '[/' + bbCode + ']');
+ }
+ },
+
+ insert: function(startTag, endTag) {
+ this.dom['inputField'].focus();
+ // Internet Explorer:
+ if(typeof document.selection !== 'undefined') {
+ // Insert the tags:
+ var range = document.selection.createRange();
+ var insText = range.text;
+ range.text = startTag + insText + endTag;
+ // Adjust the cursor position:
+ range = document.selection.createRange();
+ if (insText.length === 0) {
+ range.move('character', -endTag.length);
+ } else {
+ range.moveStart('character', startTag.length + insText.length + endTag.length);
+ }
+ range.select();
+ }
+ // Firefox, etc. (Gecko based browsers):
+ else if(typeof this.dom['inputField'].selectionStart !== 'undefined') {
+ // Insert the tags:
+ var start = this.dom['inputField'].selectionStart;
+ var end = this.dom['inputField'].selectionEnd;
+ var insText = this.dom['inputField'].value.substring(start, end);
+ this.dom['inputField'].value = this.dom['inputField'].value.substr(0, start)
+ + startTag
+ + insText
+ + endTag
+ + this.dom['inputField'].value.substr(end);
+ // Adjust the cursor position:
+ var pos;
+ if (insText.length === 0) {
+ pos = start + startTag.length;
+ } else {
+ pos = start + startTag.length + insText.length + endTag.length;
+ }
+ this.dom['inputField'].selectionStart = pos;
+ this.dom['inputField'].selectionEnd = pos;
+ }
+ // Other browsers:
+ else {
+ var pos = this.dom['inputField'].value.length;
+ this.dom['inputField'].value = this.dom['inputField'].value.substr(0, pos)
+ + startTag
+ + endTag
+ + this.dom['inputField'].value.substr(pos);
+ }
+ },
+
+ replaceText: function(text) {
+ try{
+ text = this.replaceLineBreaks(text);
+ if(text.charAt(0) === '/') {
+ text = this.replaceCommands(text);
+ } else {
+ text = this.replaceBBCode(text);
+ text = this.replaceHyperLinks(text);
+ text = this.replaceEmoticons(text);
+ }
+ text = this.breakLongWords(text);
+ text = this.replaceCustomText(text);
+ } catch(e){
+ //alert(e);
+ }
+ return text;
+ },
+
+ replaceCommands: function(text) {
+ try {
+ if(text.charAt(0) !== '/') {
+ return text;
+ }
+ var textParts = text.split(' ');
+ switch(textParts[0]) {
+ case '/login':
+ return this.replaceCommandLogin(textParts);
+ case '/logout':
+ return this.replaceCommandLogout(textParts);
+ case '/channelEnter':
+ return this.replaceCommandChannelEnter(textParts);
+ case '/channelLeave':
+ return this.replaceCommandChannelLeave(textParts);
+ case '/privmsg':
+ return this.replaceCommandPrivMsg(textParts);
+ case '/privmsgto':
+ return this.replaceCommandPrivMsgTo(textParts);
+ case '/privaction':
+ return this.replaceCommandPrivAction(textParts);
+ case '/privactionto':
+ return this.replaceCommandPrivActionTo(textParts);
+ case '/me':
+ case '/action':
+ return this.replaceCommandAction(textParts);
+ case '/invite':
+ return this.replaceCommandInvite(textParts);
+ case '/inviteto':
+ return this.replaceCommandInviteTo(textParts);
+ case '/uninvite':
+ return this.replaceCommandUninvite(textParts);
+ case '/uninviteto':
+ return this.replaceCommandUninviteTo(textParts);
+ case '/queryOpen':
+ return this.replaceCommandQueryOpen(textParts);
+ case '/queryClose':
+ return this.replaceCommandQueryClose(textParts);
+ case '/ignoreAdded':
+ return this.replaceCommandIgnoreAdded(textParts);
+ case '/ignoreRemoved':
+ return this.replaceCommandIgnoreRemoved(textParts);
+ case '/ignoreList':
+ return this.replaceCommandIgnoreList(textParts);
+ case '/ignoreListEmpty':
+ return this.replaceCommandIgnoreListEmpty(textParts);
+ case '/kick':
+ return this.replaceCommandKick(textParts);
+ case '/who':
+ return this.replaceCommandWho(textParts);
+ case '/whoChannel':
+ return this.replaceCommandWhoChannel(textParts);
+ case '/whoEmpty':
+ return this.replaceCommandWhoEmpty(textParts);
+ case '/list':
+ return this.replaceCommandList(textParts);
+ case '/bans':
+ return this.replaceCommandBans(textParts);
+ case '/bansEmpty':
+ return this.replaceCommandBansEmpty(textParts);
+ case '/unban':
+ return this.replaceCommandUnban(textParts);
+ case '/whois':
+ return this.replaceCommandWhois(textParts);
+ case '/whereis':
+ return this.replaceCommandWhereis(textParts);
+ case '/roll':
+ return this.replaceCommandRoll(textParts);
+ case '/nick':
+ return this.replaceCommandNick(textParts);
+ case '/error':
+ return this.replaceCommandError(textParts);
+ default:
+ return this.replaceCustomCommands(text, textParts);
+ }
+ } catch(e) {
+ //alert(e);
+ }
+ return text;
+ },
+
+ replaceCommandLogin: function(textParts) {
+ return '<span class="chatBotMessage">'
+ + this.lang['login'].replace(/%s/, textParts[1])
+ + '</span>';
+ },
+
+ replaceCommandLogout: function(textParts) {
+ var type = '';
+ if(textParts.length === 3)
+ type = textParts[2];
+ return '<span class="chatBotMessage">'
+ + this.lang['logout' + type].replace(/%s/, textParts[1])
+ + '</span>';
+ },
+
+ replaceCommandChannelEnter: function(textParts) {
+ return '<span class="chatBotMessage">'
+ + this.lang['channelEnter'].replace(/%s/, textParts[1])
+ + '</span>';
+ },
+
+ replaceCommandChannelLeave: function(textParts) {
+ return '<span class="chatBotMessage">'
+ + this.lang['channelLeave'].replace(/%s/, textParts[1])
+ + '</span>';
+ },
+
+ replaceCommandPrivMsg: function(textParts) {
+ var privMsgText = textParts.slice(1).join(' ');
+ privMsgText = this.replaceBBCode(privMsgText);
+ privMsgText = this.replaceHyperLinks(privMsgText);
+ privMsgText = this.replaceEmoticons(privMsgText);
+ return '<span class="privmsg">'
+ + this.lang['privmsg']
+ + '</span> '
+ + privMsgText;
+ },
+
+ replaceCommandPrivMsgTo: function(textParts) {
+ var privMsgText = textParts.slice(2).join(' ');
+ privMsgText = this.replaceBBCode(privMsgText);
+ privMsgText = this.replaceHyperLinks(privMsgText);
+ privMsgText = this.replaceEmoticons(privMsgText);
+ return '<span class="privmsg">'
+ + this.lang['privmsgto'].replace(/%s/, textParts[1])
+ + '</span> '
+ + privMsgText;
+ },
+
+ replaceCommandPrivAction: function(textParts) {
+ var privActionText = textParts.slice(1).join(' ');
+ privActionText = this.replaceBBCode(privActionText);
+ privActionText = this.replaceHyperLinks(privActionText);
+ privActionText = this.replaceEmoticons(privActionText);
+ return '<span class="action">'
+ + privActionText
+ + '</span> <span class="privmsg">'
+ + this.lang['privmsg']
+ + '</span> ';
+ },
+
+ replaceCommandPrivActionTo: function(textParts) {
+ var privActionText = textParts.slice(2).join(' ');
+ privActionText = this.replaceBBCode(privActionText);
+ privActionText = this.replaceHyperLinks(privActionText);
+ privActionText = this.replaceEmoticons(privActionText);
+ return '<span class="action">'
+ + privActionText
+ + '</span> <span class="privmsg">'
+ + this.lang['privmsgto'].replace(/%s/, textParts[1])
+ + '</span> ';
+ },
+
+ replaceCommandAction: function(textParts) {
+ var actionText = textParts.slice(1).join(' ');
+ actionText = this.replaceBBCode(actionText);
+ actionText = this.replaceHyperLinks(actionText);
+ actionText = this.replaceEmoticons(actionText);
+ return '<span class="action">'
+ + actionText
+ + '</span>';
+ },
+
+ replaceCommandInvite: function(textParts) {
+ var inviteText = this.lang['invite']
+ .replace(/%s/, textParts[1])
+ .replace(
+ /%s/,
+ '<a href="javascript:ajaxChat.sendMessageWrapper(\'/join '
+ + this.scriptLinkEncode(textParts[2])
+ + '\');" title="'
+ + this.lang['joinChannel'].replace(/%s/, textParts[2])
+ + '">'
+ + textParts[2]
+ + '</a>'
+ );
+ return '<span class="chatBotMessage">'
+ + inviteText
+ + '</span>';
+ },
+
+ replaceCommandInviteTo: function(textParts) {
+ var inviteText = this.lang['inviteto']
+ .replace(/%s/, textParts[1])
+ .replace(/%s/, textParts[2]);
+ return '<span class="chatBotMessage">'
+ + inviteText
+ + '</span>';
+ },
+
+ replaceCommandUninvite: function(textParts) {
+ var uninviteText = this.lang['uninvite']
+ .replace(/%s/, textParts[1])
+ .replace(/%s/, textParts[2]);
+ return '<span class="chatBotMessage">'
+ + uninviteText
+ + '</span>';
+ },
+
+ replaceCommandUninviteTo: function(textParts) {
+ var uninviteText = this.lang['uninviteto']
+ .replace(/%s/, textParts[1])
+ .replace(/%s/, textParts[2]);
+ return '<span class="chatBotMessage">'
+ + uninviteText
+ + '</span>';
+ },
+
+ replaceCommandQueryOpen: function(textParts) {
+ return '<span class="chatBotMessage">'
+ + this.lang['queryOpen'].replace(/%s/, textParts[1])
+ + '</span>';
+ },
+
+ replaceCommandQueryClose: function(textParts) {
+ return '<span class="chatBotMessage">'
+ + this.lang['queryClose'].replace(/%s/, textParts[1])
+ + '</span>';
+ },
+
+ replaceCommandIgnoreAdded: function(textParts) {
+ return '<span class="chatBotMessage">'
+ + this.lang['ignoreAdded'].replace(/%s/, textParts[1])
+ + '</span>';
+ },
+
+ replaceCommandIgnoreRemoved: function(textParts) {
+ return '<span class="chatBotMessage">'
+ + this.lang['ignoreRemoved'].replace(/%s/, textParts[1])
+ + '</span>';
+ },
+
+ replaceCommandIgnoreList: function(textParts) {
+ return '<span class="chatBotMessage">'
+ + this.lang['ignoreList'] + ' '
+ + this.getInlineUserMenu(textParts.slice(1))
+ + '</span>';
+ },
+
+ replaceCommandIgnoreListEmpty: function(textParts) {
+ return '<span class="chatBotMessage">'
+ + this.lang['ignoreListEmpty']
+ + '</span>';
+ },
+
+ replaceCommandKick: function(textParts) {
+ return '<span class="chatBotMessage">'
+ + this.lang['logoutKicked'].replace(/%s/, textParts[1])
+ + '</span>';
+ },
+
+ replaceCommandWho: function(textParts) {
+ return '<span class="chatBotMessage">'
+ + this.lang['who'] + ' '
+ + this.getInlineUserMenu(textParts.slice(1))
+ + '</span>';
+ },
+
+ replaceCommandWhoChannel: function(textParts) {
+ return '<span class="chatBotMessage">'
+ + this.lang['whoChannel'].replace(/%s/, textParts[1]) + ' '
+ + this.getInlineUserMenu(textParts.slice(2))
+ + '</span>';
+ },
+
+ replaceCommandWhoEmpty: function(textParts) {
+ return '<span class="chatBotMessage">'
+ + this.lang['whoEmpty']
+ + '</span>';
+ },
+
+ replaceCommandList: function(textParts) {
+ var channels = textParts.slice(1);
+ var listChannels = [];
+ var channelName;
+ for(var i=0; i<channels.length; i++) {
+ channelName = (channels[i] === this.channelName) ? '<b>'+channels[i]+'</b>' : channels[i];
+ listChannels.push(
+ '<a href="javascript:ajaxChat.sendMessageWrapper(\'/join '
+ + this.scriptLinkEncode(channels[i])
+ + '\');" title="'
+ + this.lang['joinChannel'].replace(/%s/, channels[i])
+ + '">'
+ + channelName
+ + '</a>'
+ );
+ }
+ return '<span class="chatBotMessage">'
+ + this.lang['list'] + ' '
+ + listChannels.join(', ')
+ + '</span>';
+ },
+
+ replaceCommandBans: function(textParts) {
+ var users = textParts.slice(1);
+ var listUsers = [];
+ for(var i=0; i<users.length; i++) {
+ listUsers.push(
+ '<a href="javascript:ajaxChat.sendMessageWrapper(\'/unban '
+ + this.scriptLinkEncode(users[i])
+ + '\');" title="'
+ + this.lang['unbanUser'].replace(/%s/, users[i])
+ + '">'
+ + users[i]
+ + '</a>'
+ );
+ }
+ return '<span class="chatBotMessage">'
+ + this.lang['bans'] + ' '
+ + listUsers.join(', ')
+ + '</span>';
+ },
+
+ replaceCommandBansEmpty: function(textParts) {
+ return '<span class="chatBotMessage">'
+ + this.lang['bansEmpty']
+ + '</span>';
+ },
+
+ replaceCommandUnban: function(textParts) {
+ return '<span class="chatBotMessage">'
+ + this.lang['unban'].replace(/%s/, textParts[1])
+ + '</span>';
+ },
+
+ replaceCommandWhois: function(textParts) {
+ return '<span class="chatBotMessage">'
+ + this.lang['whois'].replace(/%s/, textParts[1]) + ' '
+ + textParts[2]
+ + '</span>';
+ },
+
+ replaceCommandWhereis: function(textParts) {
+ return '<span class="chatBotMessage">'
+ + this.lang['whereis'].replace(/%s/, textParts[1]).replace(
+ /%s/,
+ '<a href="javascript:ajaxChat.sendMessageWrapper(\'/join '
+ + this.scriptLinkEncode(textParts[2])
+ + '\');" title="'
+ + this.lang['joinChannel'].replace(/%s/, textParts[2])
+ + '">'
+ + textParts[2]
+ + '</a>'
+ )
+ + '</span>';
+ },
+
+ replaceCommandRoll: function(textParts) {
+ var rollText = this.lang['roll'].replace(/%s/, textParts[1]);
+ rollText = rollText.replace(/%s/, textParts[2]);
+ rollText = rollText.replace(/%s/, textParts[3]);
+ return '<span class="chatBotMessage">'
+ + rollText
+ + '</span>';
+ },
+
+ replaceCommandNick: function(textParts) {
+ return '<span class="chatBotMessage">'
+ + this.lang['nick'].replace(/%s/, textParts[1]).replace(/%s/, textParts[2])
+ + '</span>';
+ },
+
+ replaceCommandError: function(textParts) {
+ var errorMessage = this.lang['error'+textParts[1]];
+ if(!errorMessage) {
+ errorMessage = 'Error: Unknown.';
+ } else if(textParts.length > 2) {
+ errorMessage = errorMessage.replace(/%s/, textParts.slice(2).join(' '));
+ }
+ return '<span class="chatBotErrorMessage">'
+ + errorMessage
+ + '</span>';
+ },
+
+ getInlineUserMenu: function(users) {
+ var menu = '';
+ for(var i=0; i<users.length; i++) {
+ if(i>0) {
+ menu += ', ';
+ }
+ menu += '<a href="javascript:ajaxChat.toggleUserMenu(\''
+ + this.getInlineUserMenuDocumentID(this.userMenuCounter, i)
+ + '\', \''
+ + this.scriptLinkEncode(users[i])
+ + '\', null);" title="'
+ + this.lang['toggleUserMenu'].replace(/%s/, users[i])
+ + '" dir="'
+ + this.baseDirection
+ + '">'
+ + ((users[i] === this.userName) ? '<b>'+users[i]+'</b>' : users[i])
+ + '</a>'
+ + '<ul class="inlineUserMenu" id="'
+ + this.getInlineUserMenuDocumentID(this.userMenuCounter, i)
+ + '" style="display:none;">'
+ + '</ul>';
+ }
+ this.userMenuCounter++;
+ return menu;
+ },
+
+ containsUnclosedTags: function(str) {
+ var openTags, closeTags,
+ regExpOpenTags = /<[^>\/]+?>/gm,
+ regExpCloseTags = /<\/[^>]+?>/gm;
+
+ openTags = str.match(regExpOpenTags);
+ closeTags = str.match(regExpCloseTags);
+ // Return true if the number of tags doesn't match:
+ if((!openTags && closeTags) ||
+ (openTags && !closeTags) ||
+ (openTags && closeTags && (openTags.length !== closeTags.length))) {
+ return true;
+ }
+ return false;
+ },
+
+ breakLongWords: function(text) {
+ var newText, charCounter, currentChar, withinTag, withinEntity, i;
+
+ if(!this.settings['wordWrap'])
+ return text;
+
+ newText = '';
+ charCounter = 0;
+
+ for(i=0; i<text.length; i++) {
+ currentChar = text.charAt(i);
+
+ // Check if we are within a tag or entity:
+ if(currentChar === '<') {
+ withinTag = true;
+ // Reset the charCounter after newline tags (<br/>):
+ if(i>5 && text.substr(i-5,4) === '<br/')
+ charCounter = 0;
+ } else if(withinTag && i>0 && text.charAt(i-1) === '>') {
+ withinTag = false;
+ // Reset the charCounter after newline tags (<br/>):
+ if(i>4 && text.substr(i-5,4) === '<br/')
+ charCounter = 0;
+ }
+
+ if(!withinTag && currentChar === '&') {
+ withinEntity = true;
+ } else if(withinEntity && i>0 && text.charAt(i-1) === ';') {
+ withinEntity = false;
+ // We only increase the charCounter once for the whole entiy:
+ charCounter++;
+ }
+
+ if(!withinTag && !withinEntity) {
+ // Reset the charCounter if we encounter a word boundary:
+ if(currentChar === ' ' || currentChar === '\n' || currentChar === '\t') {
+ charCounter = 0;
+ } else {
+ // We are not within a tag or entity, increase the charCounter:
+ charCounter++;
+ }
+ if(charCounter > this.settings['maxWordLength']) {
+ // maxWordLength has been reached, break here and reset the charCounter:
+ newText += '&#8203;';
+ charCounter = 0;
+ }
+ }
+ // Add the current char to the text:
+ newText += currentChar;
+ }
+
+ return newText;
+ },
+
+ replaceBBCode: function(text) {
+ if(!this.settings['bbCode']) {
+ // If BBCode is disabled, just strip the text from BBCode tags:
+ return text.replace(/\[(?:\/)?(\w+)(?:=([^<>]*?))?\]/, '');
+ }
+ // Remove the BBCode tags:
+ return text.replace(
+ /\[(\w+)(?:=([^<>]*?))?\](.+?)\[\/\1\]/gm,
+ this.replaceBBCodeCallback
+ );
+ },
+
+ replaceBBCodeCallback: function(str, p1, p2, p3) {
+ // Only replace predefined BBCode tags:
+ if(!ajaxChat.inArray(ajaxChat.bbCodeTags, p1)) {
+ return str;
+ }
+ // Avoid invalid XHTML (unclosed tags):
+ if(ajaxChat.containsUnclosedTags(p3)) {
+ return str;
+ }
+ switch(p1) {
+ case 'color':
+ return ajaxChat.replaceBBCodeColor(p3, p2);
+ case 'url':
+ return ajaxChat.replaceBBCodeUrl(p3, p2);
+ case 'img':
+ return ajaxChat.replaceBBCodeImage(p3);
+ case 'quote':
+ return ajaxChat.replaceBBCodeQuote(p3, p2);
+ case 'code':
+ return ajaxChat.replaceBBCodeCode(p3);
+ case 'u':
+ return ajaxChat.replaceBBCodeUnderline(p3);
+ default:
+ return ajaxChat.replaceCustomBBCode(p1, p2, p3);
+ }
+ },
+
+ replaceBBCodeColor: function(content, attribute) {
+ if(this.settings['bbCodeColors']) {
+ // Only allow predefined color codes:
+ if(!attribute || !this.inArray(ajaxChat.colorCodes, attribute))
+ return content;
+ return '<span style="color:'
+ + attribute + ';">'
+ + this.replaceBBCode(content)
+ + '</span>';
+ }
+ return content;
+ },
+
+ replaceBBCodeUrl: function(content, attribute) {
+ var url, regExpUrl;
+ if(attribute)
+ url = attribute.replace(/\s/gm, this.encodeText(' '));
+ else
+ url = this.stripBBCodeTags(content.replace(/\s/gm, this.encodeText(' ')));
+ regExpUrl = new RegExp(
+ '^(?:(?:http)|(?:https)|(?:ftp)|(?:irc)):\\/\\/',
+ ''
+ );
+ if(!url || !url.match(regExpUrl))
+ return content;
+ return '<a href="'
+ + url
+ + '" onclick="window.open(this.href); return false;">'
+ + this.replaceBBCode(content)
+ + '</a>';
+ },
+
+ replaceBBCodeImage: function(url) {
+ var regExpUrl, maxWidth, maxHeight;
+ if(this.settings['bbCodeImages']) {
+ regExpUrl = new RegExp(
+ this.regExpMediaUrl,
+ ''
+ );
+ if(!url || !url.match(regExpUrl))
+ return url;
+ url = url.replace(/\s/gm, this.encodeText(' '));
+ maxWidth = this.dom['chatList'].offsetWidth-50;
+ maxHeight = this.dom['chatList'].offsetHeight-50;
+ return '<a href="'
+ +url
+ +'" onclick="window.open(this.href); return false;">'
+ +'<img class="bbCodeImage" style="max-width:'
+ +maxWidth
+ +'px; max-height:'
+ +maxHeight
+ +'px;" src="'
+ +url
+ +'" alt="" onload="ajaxChat.updateChatlistView();"/></a>';
+ }
+ return url;
+ },
+
+ replaceBBCodeQuote: function(content, attribute) {
+ if(attribute)
+ return '<span class="quote"><cite>'
+ + this.lang['cite'].replace(/%s/, attribute)
+ + '</cite><q>'
+ + this.replaceBBCode(content)
+ + '</q></span>';
+ return '<span class="quote"><q>'
+ + this.replaceBBCode(content)
+ + '</q></span>';
+ },
+
+ replaceBBCodeCode: function(content) {
+ // Replace vertical tabs and multiple spaces with two non-breaking space characters:
+ return '<code>'
+ + this.replaceBBCode(content.replace(/\t|(?: )/gm, '&#160;&#160;'))
+ + '</code>';
+ },
+
+ replaceBBCodeUnderline: function(content) {
+ return '<span style="text-decoration:underline;">'
+ + this.replaceBBCode(content)
+ + '</span>';
+ },
+
+ replaceHyperLinks: function(text) {
+ var regExp;
+ if(!this.settings['hyperLinks']) {
+ return text;
+ }
+ regExp = new RegExp(
+ '(^|\\s|>)((?:(?:http)|(?:https)|(?:ftp)|(?:irc)):\\/\\/[^\\s<>]+)(<\\/a>)?',
+ 'gm'
+ );
+ return text.replace(
+ regExp,
+ // Specifying an anonymous function as second parameter:
+ function(str, p1, p2, p3) {
+ // Do not replace URL's inside URL's:
+ if(p3) {
+ return str;
+ }
+ return p1
+ + '<a href="'
+ + p2
+ + '" onclick="window.open(this.href); return false;">'
+ + p2
+ + '</a>';
+ }
+ );
+ },
+
+ replaceLineBreaks: function(text) {
+ var regExp = new RegExp('\\n', 'g');
+
+ if(!this.settings['lineBreaks']) {
+ return text.replace(regExp, ' ');
+ } else {
+ return text.replace(regExp, '<br/>');
+ }
+ },
+
+ replaceEmoticons: function(text) {
+ if(!this.settings['emoticons']) {
+ return text;
+ }
+ if(!arguments.callee.regExp) {
+ var regExpStr = '^(.*)(';
+ for(var i=0; i<this.emoticonCodes.length; i++) {
+ if(i!==0)
+ regExpStr += '|';
+ regExpStr += '(?:' + this.escapeRegExp(this.emoticonCodes[i]) + ')';
+ }
+ regExpStr += ')(.*)$';
+ arguments.callee.regExp = new RegExp(regExpStr, 'gm');
+ }
+ return text.replace(
+ arguments.callee.regExp,
+ this.replaceEmoticonsCallback
+ );
+ },
+
+ replaceEmoticonsCallback: function(str, p1, p2, p3) {
+ if (!arguments.callee.regExp) {
+ arguments.callee.regExp = new RegExp('(="[^"]*$)|(&[^;]*$)', '');
+ }
+ // Avoid replacing emoticons in tag attributes or XHTML entities:
+ if(p1.match(arguments.callee.regExp)) {
+ return str;
+ }
+ if(p2) {
+ var index = ajaxChat.arraySearch(p2, ajaxChat.emoticonCodes);
+ return ajaxChat.replaceEmoticons(p1)
+ + '<img src="'
+ + ajaxChat.dirs['emoticons']
+ + ajaxChat.emoticonFiles[index]
+ + '" alt="'
+ + p2
+ + '" />'
+ + ajaxChat.replaceEmoticons(p3);
+ }
+ return str;
+ },
+
+ getActiveStyle: function() {
+ var cookie = this.readCookie(this.sessionName + '_style');
+ var style = cookie ? cookie : this.getPreferredStyleSheet();
+ return style;
+ },
+
+ initStyle: function() {
+ this.styleInitiated = true;
+ this.setActiveStyleSheet(this.getActiveStyle());
+ },
+
+ persistStyle: function() {
+ if(this.styleInitiated) {
+ this.createCookie(this.sessionName + '_style', this.getActiveStyleSheet(), this.cookieExpiration);
+ }
+ },
+
+ setSelectedStyle: function() {
+ if(this.dom['styleSelection']) {
+ var style = this.getActiveStyle();
+ var styleOptions = this.dom['styleSelection'].getElementsByTagName('option');
+ for(var i=0; i<styleOptions.length; i++) {
+ if(styleOptions[i].value == style) {
+ styleOptions[i].selected = true;
+ break;
+ }
+ }
+ }
+ },
+
+ getSelectedStyle: function() {
+ var styleOptions = this.dom['styleSelection'].getElementsByTagName('option');
+ if(this.dom['styleSelection'].selectedIndex === -1) {
+ return styleOptions[0].value;
+ } else {
+ return styleOptions[this.dom['styleSelection'].selectedIndex].value;
+ }
+ },
+
+ setActiveStyleSheet: function(title) {
+ var i, a, main, titleFound = false;
+ for(i=0; (a = document.getElementsByTagName('link')[i]); i++) {
+ if(a.getAttribute('rel').indexOf('style') !== -1 && a.getAttribute('title')) {
+ a.disabled = true;
+ if(a.getAttribute('title') === title) {
+ a.disabled = false;
+ titleFound = true;
+ }
+ }
+ }
+ if(!titleFound && title !== null) {
+ this.setActiveStyleSheet(this.getPreferredStyleSheet());
+ }
+ },
+
+ getActiveStyleSheet: function() {
+ var i, a;
+ for(i=0; (a = document.getElementsByTagName('link')[i]); i++) {
+ if(a.getAttribute('rel').indexOf('style') != -1 && a.getAttribute('title') && !a.disabled) {
+ return a.getAttribute('title');
+ }
+ }
+ return null;
+ },
+
+ getPreferredStyleSheet: function() {
+ var i,a;
+ for(i=0; (a = document.getElementsByTagName('link')[i]); i++) {
+ if(a.getAttribute('rel').indexOf('style') !== -1
+ && a.getAttribute('rel').indexOf('alt') === -1
+ && a.getAttribute('title')
+ ) {
+ return a.getAttribute('title');
+ }
+ }
+ return null;
+ },
+
+ switchLanguage: function(langCode) {
+ window.location.search = '?lang='+langCode;
+ },
+
+ createCookie: function(name,value,days) {
+ var expires = '';
+ if(days) {
+ var date = new Date();
+ date.setTime(date.getTime()+(days*24*60*60*1000));
+ expires = '; expires='+date.toGMTString();
+ }
+ var path = '; path='+this.cookiePath;
+ var domain = this.cookieDomain ? '; domain='+this.cookieDomain : '';
+ var secure = this.cookieSecure ? '; secure' : '';
+ document.cookie = name+'='+encodeURIComponent(value)+expires+path+domain+secure;
+ },
+
+ readCookie: function(name) {
+ if(!document.cookie)
+ return null;
+ var nameEQ = name + '=';
+ var ca = document.cookie.split(';');
+ for(var i=0; i<ca.length; i++) {
+ var c = ca[i];
+ while(c.charAt(0) === ' ') {
+ c = c.substring(1, c.length);
+ }
+ if(c.indexOf(nameEQ) === 0) {
+ return decodeURIComponent(c.substring(nameEQ.length, c.length));
+ }
+ }
+ return null;
+ },
+
+ isCookieEnabled: function() {
+ this.createCookie(this.sessionName + '_cookie_test', true, 1);
+ var cookie = this.readCookie(this.sessionName + '_cookie_test');
+ if(cookie) {
+ // Unset the test cookie:
+ this.createCookie(this.sessionName + '_cookie_test', true, -1);
+ // Cookie test successfull, return true:
+ return true;
+ }
+ return false;
+ },
+
+ finalize: function() {
+ if(typeof this.finalizeFunction === 'function') {
+ this.finalizeFunction();
+ }
+ // Ensure the socket connection is closed on unload:
+ if(this.socket) {
+ try {
+ this.socket.close();
+ this.socket = null;
+ } catch(e) {
+ //alert(e);
+ }
+ }
+ this.persistSettings();
+ this.persistStyle();
+ this.customFinalize();
+ },
+
+ // Override to perform custom actions on flash initialization:
+ initializeCustomFlashInterface: function() {
+ },
+
+ // Override to handle custom info messages
+ handleCustomInfoMessage: function(infoType, infoData) {
+ },
+
+ // Override to add custom initialization code
+ // This method is called on page load
+ customInitialize: function() {
+ },
+
+ // Override to add custom finalization code
+ // This method is called on page unload
+ customFinalize: function() {
+ },
+
+ // Override to add custom user menu items:
+ // Return a string with list items ( <li>menuItem</li> )
+ // encodedUserName contains the userName ready to be used for javascript links
+ // userID is only available for the online users menu - not for the inline user menu
+ // use (encodedUserName == this.encodedUserName) to check for the current user
+ getCustomUserMenuItems: function(encodedUserName, userID) {
+ return '';
+ },
+
+ // Override to parse custom input messages:
+ // Return replaced text
+ // text contains the whole message
+ parseCustomInputMessage: function(text) {
+ return text;
+ },
+
+ // Override to parse custom input commands:
+ // Return parsed text
+ // text contains the whole message, textParts the message split up as words array
+ parseCustomInputCommand: function(text, textParts) {
+ return text;
+ },
+
+ // Override to replace custom text:
+ // Return replaced text
+ // text contains the whole message
+ replaceCustomText: function(text) {
+ return text;
+ },
+
+ // Override to replace custom commands:
+ // Return replaced text for custom commands
+ // text contains the whole message, textParts the message split up as words array
+ replaceCustomCommands: function(text, textParts) {
+ return text;
+ },
+
+ // Override to replace custom BBCodes:
+ // Return replaced text and call replaceBBCode recursively for the content text
+ // tag contains the BBCode tag, attribute the BBCode attribute and content the content text
+ // This method is only called for BBCode tags which are in the bbCodeTags list
+ replaceCustomBBCode: function(tag, attribute, content) {
+ return '<' + tag + '>' + this.replaceBBCode(content) + '</' + tag + '>';
+ },
+
+ // Override to perform custom actions on new messages:
+ // Return true if message is to be added to the chatList, else false
+ customOnNewMessage: function(dateObject, userID, userName, userRole, messageID, messageText, channelID, ip) {
+ return true;
+ }
+
+}; \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/config.js b/library/ajaxchat/chat/js/config.js
new file mode 100644
index 000000000..a4d3c3f75
--- /dev/null
+++ b/library/ajaxchat/chat/js/config.js
@@ -0,0 +1,261 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat config parameters:
+var ajaxChatConfig = {
+
+ // The channelID of the channel to enter on login (the loginChannelName is used if set to null):
+ loginChannelID: null,
+ // The channelName of the channel to enter on login (the default channel is used if set to null):
+ loginChannelName: null,
+
+ // The time in ms between update calls to retrieve new chat messages:
+ timerRate: 2000,
+
+ // The URL to retrieve the XML chat messages (must at least contain one parameter):
+ ajaxURL: './?ajax=true',
+ // The base URL of the chat directory, used to retrieve media files (images, sound files, etc.):
+ baseURL: './',
+
+ // A regular expression for allowed source URL's for media content (e.g. images displayed inline);
+ regExpMediaUrl: '^((http)|(https)):\\/\\/',
+
+ // If set to false the chat update is delayed until the event defined in ajaxChat.setStartChatHandler():
+ startChatOnLoad: true,
+
+ // Defines the IDs of DOM nodes accessed by the chat:
+ domIDs: {
+ // The ID of the chat messages list:
+ chatList: 'chatList',
+ // The ID of the online users list:
+ onlineList: 'onlineList',
+ // The ID of the message text input field:
+ inputField: 'inputField',
+ // The ID of the message text length counter:
+ messageLengthCounter: 'messageLengthCounter',
+ // The ID of the channel selection:
+ channelSelection: 'channelSelection',
+ // The ID of the style selection:
+ styleSelection: 'styleSelection',
+ // The ID of the emoticons container:
+ emoticonsContainer: 'emoticonsContainer',
+ // The ID of the color codes container:
+ colorCodesContainer: 'colorCodesContainer',
+ // The ID of the flash interface container:
+ flashInterfaceContainer: 'flashInterfaceContainer'
+ },
+
+ // Defines the settings which can be modified by users:
+ settings: {
+ // Defines if BBCode tags are replaced with the associated HTML code tags:
+ bbCode: true,
+ // Defines if image BBCode is replaced with the associated image HTML code:
+ bbCodeImages: true,
+ // Defines if color BBCode is replaced with the associated color HTML code:
+ bbCodeColors: true,
+ // Defines if hyperlinks are made clickable:
+ hyperLinks: true,
+ // Defines if line breaks are enabled:
+ lineBreaks: true,
+ // Defines if emoticon codes are replaced with their associated images:
+ emoticons: true,
+
+ // Defines if the focus is automatically set to the input field on chat load or channel switch:
+ autoFocus: true,
+ // Defines if the chat list scrolls automatically to display the latest messages:
+ autoScroll: true,
+ // The maximum count of messages displayed in the chat list (will be ignored if set to 0):
+ maxMessages: 0,
+
+ // Defines if long words are wrapped to avoid vertical scrolling:
+ wordWrap: true,
+ // Defines the maximum length before a word gets wrapped:
+ maxWordLength: 32,
+
+ // Defines the format of the date and time displayed for each chat message:
+ dateFormat: '(%H:%i:%s)',
+
+ // Defines if font colors persist without the need to assign them to each message:
+ persistFontColor: false,
+ // The default font color, uses the page default font color if set to null:
+ fontColor: null,
+
+ // Defines if sounds are played:
+ audio: true,
+ // Defines the sound volume (0.0 = mute, 1.0 = max):
+ audioVolume: 1.0,
+
+ // Defines the sound that is played when normal messages are reveived:
+ soundReceive: 'sound_1',
+ // Defines the sound that is played on sending normal messages:
+ soundSend: 'sound_2',
+ // Defines the sound that is played on channel enter or login:
+ soundEnter: 'sound_3',
+ // Defines the sound that is played on channel leave or logout:
+ soundLeave: 'sound_4',
+ // Defines the sound that is played on chatBot messages:
+ soundChatBot: 'sound_5',
+ // Defines the sound that is played on error messages:
+ soundError: 'sound_6',
+
+ // Defines if the document title blinks on new messages:
+ blink: true,
+ // Defines the blink interval in ms:
+ blinkInterval: 500,
+ // Defines the number of blink intervals:
+ blinkIntervalNumber: 10
+ },
+
+ // Defines a list of settings which are not to be stored in a session cookie:
+ nonPersistentSettings: [],
+
+ // Defines the list of allowed BBCodes:
+ bbCodeTags:[
+ 'b',
+ 'i',
+ 'u',
+ 'quote',
+ 'code',
+ 'color',
+ 'url',
+ 'img'
+ ],
+
+ // Defines the list of allowed color codes:
+ colorCodes: [
+ 'gray',
+ 'silver',
+ 'white',
+ 'yellow',
+ 'orange',
+ 'red',
+ 'fuchsia',
+ 'purple',
+ 'navy',
+ 'blue',
+ 'aqua',
+ 'teal',
+ 'green',
+ 'lime',
+ 'olive',
+ 'maroon',
+ 'black'
+ ],
+
+ // Defines the list of allowed emoticon codes:
+ emoticonCodes: [
+ ':)',
+ ':(',
+ ';)',
+ ':P',
+ ':D',
+ ':|',
+ ':O',
+ ':?',
+ '8)',
+ '8o',
+ 'B)',
+ ':-)',
+ ':-(',
+ ':-*',
+ 'O:-D',
+ '>:-D',
+ ':o)',
+ ':idea:',
+ ':important:',
+ ':help:',
+ ':error:',
+ ':warning:',
+ ':favorite:'
+ ],
+
+ // Defines the list of emoticon files associated with the emoticon codes:
+ emoticonFiles: [
+ 'smile.png',
+ 'sad.png',
+ 'wink.png',
+ 'razz.png',
+ 'grin.png',
+ 'plain.png',
+ 'surprise.png',
+ 'confused.png',
+ 'glasses.png',
+ 'eek.png',
+ 'cool.png',
+ 'smile-big.png',
+ 'crying.png',
+ 'kiss.png',
+ 'angel.png',
+ 'devilish.png',
+ 'monkey.png',
+ 'idea.png',
+ 'important.png',
+ 'help.png',
+ 'error.png',
+ 'warning.png',
+ 'favorite.png'
+ ],
+
+ // Defines the available sounds loaded on chat start:
+ soundFiles: {
+ sound_1: 'sound_1.mp3',
+ sound_2: 'sound_2.mp3',
+ sound_3: 'sound_3.mp3',
+ sound_4: 'sound_4.mp3',
+ sound_5: 'sound_5.mp3',
+ sound_6: 'sound_6.mp3'
+ },
+
+
+ // Once users have been logged in, the following values are overridden by those in config.php.
+ // You should set these to be the same as the ones in config.php to avoid confusion.
+
+ // Session identification, used for style and setting cookies:
+ sessionName: 'ajax_chat',
+
+ // The time in days until the style and setting cookies expire:
+ cookieExpiration: 365,
+ // The path of the cookies, '/' allows to read the cookies from all directories:
+ cookiePath: '/',
+ // The domain of the cookies, defaults to the hostname of the server if set to null:
+ cookieDomain: null,
+ // If enabled, cookies must be sent over secure (SSL/TLS encrypted) connections:
+ cookieSecure: null,
+
+ // The name of the chat bot:
+ chatBotName: 'ChatBot',
+ // The userID of the chat bot:
+ chatBotID: 2147483647,
+
+ // Allow/Disallow registered users to delete their own messages:
+ allowUserMessageDelete: true,
+
+ // Minutes until a user is declared inactive (last status update) - the minimum is 2 minutes:
+ inactiveTimeout: 2,
+
+ // UserID plus this value are private channels (this is also the max userID and max channelID):
+ privateChannelDiff: 500000000,
+ // UserID plus this value are used for private messages:
+ privateMessageDiff: 1000000000,
+
+ // Defines if login/logout and channel enter/leave are displayed:
+ showChannelMessages: true,
+
+ // Max messageText length:
+ messageTextMaxLength: 1040,
+
+ // Defines if the socket server is enabled:
+ socketServerEnabled: false,
+ // Defines the hostname of the socket server used to connect from client side:
+ socketServerHost: 'localhost',
+ // Defines the port of the socket server:
+ socketServerPort: 1935,
+ // This ID can be used to distinguish between different chat installations using the same socket server:
+ socketServerChatID: 0
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/custom.js b/library/ajaxchat/chat/js/custom.js
new file mode 100644
index 000000000..6d801534e
--- /dev/null
+++ b/library/ajaxchat/chat/js/custom.js
@@ -0,0 +1,16 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Overriding client side functionality:
+
+/*
+// Example - Overriding the replaceCustomCommands method:
+ajaxChat.replaceCustomCommands = function(text, textParts) {
+ return text;
+}
+ */ \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/index.html b/library/ajaxchat/chat/js/index.html
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/library/ajaxchat/chat/js/index.html
diff --git a/library/ajaxchat/chat/js/lang/ar.js b/library/ajaxchat/chat/js/lang/ar.js
new file mode 100644
index 000000000..7fd18db10
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/ar.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author pepotiger (www.dd4bb.com)
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s دخول.',
+ logout: '%s خروج.',
+ logoutTimeout: '%s تم تسجيل الخروج (Timeout).',
+ logoutIP: '%s تم تسجيل الخروج (Invalid IP address).',
+ logoutKicked: '%s تم تسجيل الخروج (Kicked).',
+ channelEnter: '%s دخول المحطة.',
+ channelLeave: '%s خروج.',
+ privmsg: '(رسالة خاصة)',
+ privmsgto: '(رسالة خاصة الى %s)',
+ invite: '%s يدعوك الى %s.',
+ inviteto: 'دعوتك لـ %s للإنضمام الى %s تم ارسالها.',
+ uninvite: '%s الغاء دعوتك من %s.',
+ uninviteto: 'الغاء الدعوة من %s للـ %s تم ارسالها.',
+ queryOpen: 'تم فتح نافذة خاصة مع %s.',
+ queryClose: 'النافذة الخاصة مع %s تم غلقها.',
+ ignoreAdded: 'اضيف %s الى قائمة التجاهل.',
+ ignoreRemoved: 'حذف %s من قائمة التجاهل.',
+ ignoreList: 'اعضاء متجاهلين:',
+ ignoreListEmpty: 'لا يوجد اعضاء تم تجاهلهم.',
+ who: 'المستخدمين المتواجدين:',
+ whoChannel: 'Online Users in channel %s:',
+ whoEmpty: 'لا يوجد اعضاء بهذه المحطة.',
+ list: 'المحطات المتوفرة:',
+ bans: 'اعضاء محجوبين:',
+ bansEmpty: 'لا يوجد اعضاء محجوبين.',
+ unban: 'حظر العضو %s تم الغائه.',
+ whois: 'الأى بى للعضو %s:',
+ whereis: 'User %s is in channel %s.',
+ roll: '%s rolls %s and gets %s.',
+ nick: '%s is now known as %s.',
+ toggleUserMenu: 'Toggle user menu for %s',
+ userMenuLogout: 'Logout',
+ userMenuWho: 'List online users',
+ userMenuList: 'List available channels',
+ userMenuAction: 'Describe action',
+ userMenuRoll: 'Roll dice',
+ userMenuNick: 'Change username',
+ userMenuEnterPrivateRoom: 'Enter private room',
+ userMenuSendPrivateMessage: 'Send private message',
+ userMenuDescribe: 'Send private action',
+ userMenuOpenPrivateChannel: 'Open private channel',
+ userMenuClosePrivateChannel: 'Close private channel',
+ userMenuInvite: 'Invite',
+ userMenuUninvite: 'Uninvite',
+ userMenuIgnore: 'Ignore/Accept',
+ userMenuIgnoreList: 'List ignored users',
+ userMenuWhereis: 'Display channel',
+ userMenuKick: 'Kick/Ban',
+ userMenuBans: 'List banned users',
+ userMenuWhois: 'Display IP',
+ unbanUser: 'Revoke ban of user %s',
+ joinChannel: 'الإنضمام للمحطة %s',
+ cite: '%s كتب:',
+ urlDialog: 'من فضلك ادخل الرابط (URL) لعنوان الأنترنت:',
+ deleteMessage: 'Delete this chat message',
+ deleteMessageConfirm: 'Really delete the selected chat message?',
+ errorCookiesRequired: 'الكوكييز مطلوبة لهذا الشات.',
+ errorUserNameNotFound: 'خطأ: العضو %s لم يتم العثور عليه.',
+ errorMissingText: 'خطأ: نص الرسالة مفقود.',
+ errorMissingUserName: 'خطأ: اسم المستخدم مفقود.',
+ errorInvalidUserName: 'Error: Invalid username.',
+ errorUserNameInUse: 'Error: Username already in use.',
+ errorMissingChannelName: 'خطأ: اسم المحطة مفقود.',
+ errorInvalidChannelName: 'خطأ: اسم المحطة غير صحيح: %s',
+ errorPrivateMessageNotAllowed: 'خطأ: غير مسموح بالرسائل الخاصة.',
+ errorInviteNotAllowed: 'خطأ: غير مسموح بدعوة الأخرين.',
+ errorUninviteNotAllowed: 'خطأ: غير مسموح بإلغاء دعوات الأخرين.',
+ errorNoOpenQuery: 'خطأ: لم يتم فتح اى نوافذ خاصة.',
+ errorKickNotAllowed: 'خطأ: غير مسموح لك بطرد احد %s.',
+ errorCommandNotAllowed: 'خطأ: غير مسموح بالأمر: %s',
+ errorUnknownCommand: 'خطأ: امر غير معروف: %s',
+ errorMaxMessageRate: 'Error: You exceeded the maximum number of messages per minute.',
+ errorConnectionTimeout: 'خطأ: وقت الأتصال استنفذ. من فضلك حاول مرة اخرى.',
+ errorConnectionStatus: 'خطأ: حالة الأتصال: %s',
+ errorSoundIO: 'Error: Failed to load sound file (Flash IO Error).',
+ errorSocketIO: 'Error: Connection to socket server failed (Flash IO Error).',
+ errorSocketSecurity: 'Error: Connection to socket server failed (Flash Security Error).',
+ errorDOMSyntax: 'Error: Invalid DOM Syntax (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/bg.js b/library/ajaxchat/chat/js/lang/bg.js
new file mode 100644
index 000000000..c1e1886ad
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/bg.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author Borislav Manolov
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s влезе в чата.',
+ logout: '%s излезе от чата.',
+ logoutTimeout: '%s излезе автоматично от чата (Изтичане на времето).',
+ logoutIP: '%s излезе автоматично от чата (Грешен айпи адрес).',
+ logoutKicked: '%s излезе автоматично от чата (Изритване).',
+ channelEnter: '%s влезе в канала.',
+ channelLeave: '%s напусна канала.',
+ privmsg: '(прошепва)',
+ privmsgto: '(прошепва на %s)',
+ invite: '%s ви кани да се присъедините към %s.',
+ inviteto: 'Поканата ви към %s да се присъедини към канала %s беше изпратена.',
+ uninvite: '%s отмени поканата ви за канала %s.',
+ uninviteto: 'Отмяната на поканата ви към %s за канала %s беше изпратена.',
+ queryOpen: 'Отворен е личен канал за %s.',
+ queryClose: 'Затворен е личен канал за %s.',
+ ignoreAdded: '%s беше добавен към списъка с пренебрегнатите.',
+ ignoreRemoved: '%s беше изваден от списъка с пренебрегнатите.',
+ ignoreList: 'Пренебрегнати потребители:',
+ ignoreListEmpty: 'Няма пренебрегнати потребители.',
+ who: 'Потребители на линия:',
+ whoChannel: 'Потребители на линия в канала %s:',
+ whoEmpty: 'В дадения канал няма потребители на линия.',
+ list: 'Налични канали:',
+ bans: 'Изгонени потребители:',
+ bansEmpty: 'Няма изгонени потребители.',
+ unban: 'Изгонването на потребителя %s е отменено.',
+ whois: 'Потребител %s — айпи адрес:',
+ whereis: 'Потребителят %s е в канала %s.',
+ roll: '%s хвърли %s и получи %s.',
+ nick: '%s вече се казва %s.',
+ toggleUserMenu: 'Показване/скриване на потребителското меню за %s',
+ userMenuLogout: 'Изход',
+ userMenuWho: 'Потребители на линия',
+ userMenuList: 'Налични канали',
+ userMenuAction: 'Описване на действие',
+ userMenuRoll: 'Хвърляне на зар',
+ userMenuNick: 'Смяна на името',
+ userMenuEnterPrivateRoom: 'Влизане в личната стая',
+ userMenuSendPrivateMessage: 'Изпращане на лично съобщение',
+ userMenuDescribe: 'Изпращане на лично действие',
+ userMenuOpenPrivateChannel: 'Отваряне на личен канал',
+ userMenuClosePrivateChannel: 'Затваряне на личен канал',
+ userMenuInvite: 'Покана',
+ userMenuUninvite: 'Отмяна на покана',
+ userMenuIgnore: 'Пренебрегване/Приемане',
+ userMenuIgnoreList: 'Пренебрегнати потребители',
+ userMenuWhereis: 'Преглед на канал',
+ userMenuKick: 'Изритване/Изгонване',
+ userMenuBans: 'Изгонени потребители',
+ userMenuWhois: 'Преглед на айпи адреса',
+ unbanUser: 'Отмяна на изгонването на %s',
+ joinChannel: 'Присъединяване към канала %s',
+ cite: '%s каза:',
+ urlDialog: 'Моля, въведете адреса (URL) на страницата:',
+ deleteMessage: 'Изтриване на съобщението',
+ deleteMessageConfirm: 'Наистина ли желаете да изтриете съобщението?',
+ errorCookiesRequired: 'За чата се изискват бисквитки (cookies).',
+ errorUserNameNotFound: 'Грешка: Не е намерен потребител %s.',
+ errorMissingText: 'Грешка: Липсва текст на съобщението.',
+ errorMissingUserName: 'Грешка: Липсва потребителско име.',
+ errorInvalidUserName: 'Грешка: Невалидно потребителско име.',
+ errorUserNameInUse: 'Грешка: Това потребителско име вече се използва.',
+ errorMissingChannelName: 'Грешка: Липсва име на канал.',
+ errorInvalidChannelName: 'Грешка: Невалидно име на канал: %s',
+ errorPrivateMessageNotAllowed: 'Грешка: Личните съобщения не са позволени.',
+ errorInviteNotAllowed: 'Грешка: Не ви е позволено да каните потребители в този канал.',
+ errorUninviteNotAllowed: 'Грешка: Не ви е позволено да отменяте покани в този канал.',
+ errorNoOpenQuery: 'Грешка: Не е отворен личен канал.',
+ errorKickNotAllowed: 'Грешка: Не ви е позволено да изритвате %s.',
+ errorCommandNotAllowed: 'Грешка: Командата не е позволена: %s',
+ errorUnknownCommand: 'Грешка: Непозната команда: %s',
+ errorMaxMessageRate: 'Грешка: Превишихте допустимия брой съобщения в минута.',
+ errorConnectionTimeout: 'Грешка: Изтичане на времето за връзка. Моля, опитайте отново!',
+ errorConnectionStatus: 'Грешка: Състояние на връзката: %s',
+ errorSoundIO: 'Грешка: Неуспешно зареждане на звуковия файл (Входно-изходна грешка при Флаш).',
+ errorSocketIO: 'Грешка: Неуспешна връзка към сокетния сървър (Входно-изходна грешка при Флаш).',
+ errorSocketSecurity: 'Грешка: Неуспешна връзка към сокетния сървър (Грешка в сигурността при Флаш).',
+ errorDOMSyntax: 'Грешка: Неправилен синтаксис при DOM (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/ca.js b/library/ajaxchat/chat/js/lang/ca.js
new file mode 100644
index 000000000..83eab4df5
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/ca.js
@@ -0,0 +1,91 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author Manu Quintans
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+ login: '%s ha entrat al xat.',
+ logout: '%s ha sortit del xat.',
+ logoutTimeout: '%s s\'ha desconnectat (Temps d\'espera esgotat).',
+ logoutIP: '%s s\'ha desconnectat (Adreça IP no vàlida).',
+ logoutKicked: '%s s\'ha desconnectat (Patejat).',
+ channelEnter: '%s entra al canal.',
+ channelLeave: '%s se\'n va del canal.',
+ privmsg: '(xiuxiueigs)',
+ privmsgto: '(xiuxiueigs a %s)',
+ invite: '%s et convida a unir-te a %s.',
+ inviteto: 'El teu convit a %s per a unir-se a %s ha estat enviat.',
+ uninvite: '%s no et convida a %s.',
+ uninviteto: 'El teu no convit a %s per al canal %s ha estat enviat',
+ queryOpen: 'Canal privat obert %s.',
+ queryClose: 'Canal privat tancat %s tancat',
+ ignoreAdded: 'Agregat %s a la llista de usuaris ignorats.',
+ ignoreRemoved: 'Eliminant %s de la llista de usuaris ignorats.',
+ ignoreList: 'Usuaris ignorats',
+ ignoreListEmpty: 'Llista d\'usuaris no ignorats.',
+ who: 'Usuaris connectats:',
+ whoChannel: 'Usuaris en línia al canal %s:',
+ whoEmpty: 'No hi ha usuaris connectats ara.',
+ list: 'Canals disponibles:',
+ bans: 'Usuaris Bannejats:',
+ bansEmpty: 'No s\'han registrat usuaris bannejats.',
+ unban: 'Ban de l\'usuari %s revocat.',
+ whois: 'Usuari %s - Adreça IP:',
+ whereis: 'L\'usuari %s és al canal %s.',
+ roll: '%s tirà els daus %s i aconsegueix %s.',
+ nick: '%s es fa dir ara %s.',
+ toggleUserMenu: 'Tanca menu de l\'usuari per a %s',
+ userMenuLogout: 'Tancar sessió',
+ userMenuWho: 'Llista d\'usuaris en línia',
+ userMenuList: 'Llista de canals disponibles',
+ userMenuAction: 'Descriure una acció',
+ userMenuRoll: 'Tirar daus',
+ userMenuNick: 'Canviar el nom de l\'usuari',
+ userMenuEnterPrivateRoom: 'Entrar en un lloc privat',
+ userMenuSendPrivateMessage: 'Enviar un missatge privat',
+ userMenuDescribe: 'Enviar una acció privada',
+ userMenuOpenPrivateChannel: 'Obrir un canal privat',
+ userMenuClosePrivateChannel: 'Tancar un canal privat',
+ userMenuInvite: 'Convidar',
+ userMenuUninvite: 'Desconvidar',
+ userMenuIgnore: 'Ignorar/Acceptar',
+ userMenuIgnoreList: 'Llista d\'usuaris ignorats',
+ userMenuWhereis: 'Visualitzar el canal',
+ userMenuKick: 'Pateig/Banneig',
+ userMenuBans: 'Llista d\'usuaris banejats',
+ userMenuWhois: 'Mostrar IP',
+ unbanUser: 'Cancel·lar banejament de usuari %s',
+ joinChannel: 'Unir-se al canal %s',
+ cite: '%s va dir:',
+ urlDialog: 'Si us plau, introdueix la adreça (URL) de la pàgina web:',
+ deleteMessage: 'Esborra aquest missatge',
+ deleteMessageConfirm: 'Realment vols esborrar el missatge seleccionat?',
+ errorCookiesRequired: 'Les galetes són necessaries per aquest xat .',
+ errorUserNameNotFound: 'Error: usuari %s no s\'ha trobat.',
+ errorMissingText: 'Error: Missatge perdut.',
+ errorMissingUserName: 'Error: Usuari no trobat.',
+ errorInvalidUserName: 'Error: Nom d\'usuari no vàlid.',
+ errorUserNameInUse: 'Error: El nom d\'usuari ja està en ús.',
+ errorMissingChannelName: 'Error: No es troba el canal.',
+ errorInvalidChannelName: 'Error: nombre del canal invàlid: %s',
+ errorPrivateMessageNotAllowed: 'Error: Els missatges privats no t\'estan permesos.',
+ errorInviteNotAllowed: 'Error: No t\'està permés convidar a ningú a aquest canal.',
+ errorUninviteNotAllowed: 'Error: No t\'està permés desconvidar ningú d\'aquest canal.',
+ errorNoOpenQuery: 'Error: Cap canal privat obert.',
+ errorKickNotAllowed: 'Error: No t\'està permés expulsar a ningú %s.',
+ errorCommandNotAllowed: 'Error: Ordre desconeguda: %s',
+ errorUnknownCommand: 'Error: Ordre desconeguda: %s',
+ errorMaxMessageRate: 'Error: has excedit el màxim nombre de missatges per minut.',
+ errorConnectionTimeout: 'Error: Temps d\'espera de la connexió expirat. Reintenta-ho de nou.',
+ errorConnectionStatus: 'Error: Estat de la connexió: %s',
+ errorSoundIO: 'Error: No ha estat possible carregar el so (Flash IO Error).',
+ errorSocketIO: 'Error: La connexió al servidor ha fallat (Flash IO Error).',
+ errorSocketSecurity: 'Error: La connexió al servidor ha fallat (Flash Security Error).',
+ errorDOMSyntax: 'Error: Sintaxi DOM invàlida (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/cy.js b/library/ajaxchat/chat/js/lang/cy.js
new file mode 100644
index 000000000..fd63aea95
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/cy.js
@@ -0,0 +1,93 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ * @translation Alan Davies, ardavies@tiscali.co.uk
+ * @language: Welsh (Cymraeg)
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: 'Mae %s wedi mewngofnodi.',
+ logout: 'Allgofnododd %s.',
+ logoutTimeout: 'Allgofnodwyd %s (Terfyn amser).',
+ logoutIP: 'Allgofnodwyd %s (Cyfeiriad IP annilys).',
+ logoutKicked: 'Allgofnodwyd %s (Cic).',
+ channelEnter: 'Mae %s wedi ymuno \'r sianel.',
+ channelLeave: 'Mae %s wedi gadael y sianel.',
+ privmsg: '(sibrwd)',
+ privmsgto: '(sibrwd i %s)',
+ invite: 'Mae %s yn eich gwahodd i ymuno %s.',
+ inviteto: 'Mae eich gwahoddiad i %s i ymuno sianel %s wedi\'i anfon.',
+ uninvite: 'Mae %s yn tynnu\'r gwahoddiad i sianel %s yn l.',
+ uninviteto: 'Mae\'r neges yn tynnu\'r gwahoddiad i sianel %s yn l wedi\'i hanfon.',
+ queryOpen: 'Agorwyd sianel breifat i %s.',
+ queryClose: 'Ceuwyd sianel breifat i %s.',
+ ignoreAdded: 'Ychwanegwyd %s i\'r anwybyddion.',
+ ignoreRemoved: 'Tynnwyd %s bant o\'r anwybyddion.',
+ ignoreList: 'Anwybyddion:',
+ ignoreListEmpty: 'Dim anwybyddion wedi\'u rhestru.',
+ who: 'Defnyddwyr Ar-lein:',
+ whoChannel: 'Defnyddwyr Ar-lein ar sianel %s:',
+ whoEmpty: 'Dim defnyddwyr ar-lein ar y sianel hon.',
+ list: 'Sianeli ar gael:',
+ bans: 'Gwaharddogion:',
+ bansEmpty: 'Dim gwaharddogion wedi\'u rhestru.',
+ unban: 'Diddymwyd gwaharddiad %s.',
+ whois: 'Defnyddiwr %s - cyfeiriad IP:',
+ whereis: 'Mae defnyddiwr %s yn y sianel %s.',
+ roll: 'Mae %s yn rholio %s a chael %s.',
+ nick: 'Enw %s nawr yw %s.',
+ toggleUserMenu: 'Togl dewislen defnyddiwr ar gyfer %s',
+ userMenuLogout: 'Allgofnodi',
+ userMenuWho: 'Rhestr ddefnyddwyr ar-lein',
+ userMenuList: 'Rhestr sianeli ar gael',
+ userMenuAction: 'Disgrifio gweithred',
+ userMenuRoll: 'Rholio dis',
+ userMenuNick: 'Newid enw',
+ userMenuEnterPrivateRoom: 'Myned i mewn i ystafell breifat',
+ userMenuSendPrivateMessage: 'Anfon neges breifat',
+ userMenuDescribe: 'Anfon gweithred breifat',
+ userMenuOpenPrivateChannel: 'Agor sianel breifat',
+ userMenuClosePrivateChannel: 'Cau sianel breifat',
+ userMenuInvite: 'Gwahodd',
+ userMenuUninvite: 'Tynnu gwahoddiad',
+ userMenuIgnore: 'Anwybyddu/Derbyn',
+ userMenuIgnoreList: 'Rhestr anwybyddion',
+ userMenuWhereis: 'Dangos sianel',
+ userMenuKick: 'Cic/Gwahardd',
+ userMenuBans: 'Rhestr waharddogion',
+ userMenuWhois: 'Dangos IP',
+ unbanUser: 'Diddynu gwaharddiad %s',
+ joinChannel: 'Ymuno sianel %s',
+ cite: 'Dywedodd %s:',
+ urlDialog: 'Rhowch gyfeiriad (URL) y wefan:',
+ deleteMessage: 'Dilwch y neges hon',
+ deleteMessageConfirm: 'Ydych wir am ddileu\'r neges hon?',
+ errorCookiesRequired: 'Mae nagen cwcis ar gyfer y sgwrs hon.',
+ errorUserNameNotFound: 'Gwall: Heb ffeindio %s.',
+ errorMissingText: 'Gwall: testun neges ar goll.',
+ errorMissingUserName: 'Gwall: Enw ar goll.',
+ errorInvalidUserName: 'Gwall: Enw annilys.',
+ errorUserNameInUse: 'Gwall: Enw\'n bodoli eisoes.',
+ errorMissingChannelName: 'Gwall: Enw sianel ar goll.',
+ errorInvalidChannelName: 'Gwall: Enw sianel annilys: %s',
+ errorPrivateMessageNotAllowed: 'Gwall: Ni chaniateir negesuon preifat.',
+ errorInviteNotAllowed: 'Gwall: Nid oes hawl gwahodd rhywun i\'r sianel hon.',
+ errorUninviteNotAllowed: 'Gwall: Nid oes hawl tynnu gwahaoddiad yn l o\'r sianel hon.',
+ errorNoOpenQuery: 'Gwall: Dim sianel breifat ar agor.',
+ errorKickNotAllowed: 'Gwall: Nid oes hawl cicio %s.',
+ errorCommandNotAllowed: 'Gwall: Nid oes hawl defnyddio\'r gorchymyn: %s',
+ errorUnknownCommand: 'Gwall: Gorchymyn anhysbys: %s',
+ errorMaxMessageRate: 'Gwall: Rydych wedi myn dros y nifer o negeseuon sydd hawl gennych anfon pob munud.',
+ errorConnectionTimeout: 'Gwall: Terfyn amser cysylltiad. Ceisiwch eto.',
+ errorConnectionStatus: 'Gwall: Statws cysylltiad: %s',
+ errorSoundIO: 'Gwall: Methu llwytho ffeil sain (Gwall Flash IO).',
+ errorSocketIO: 'Gwall: Cysylltiad i\'r gweinyddwr soced wedi methu (Gwall Flash IO).',
+ errorSocketSecurity: 'Gwall: Cysylltiad i\'r gweinyddwr soced wedi methu (Gwall Diogelwch Flash).',
+ errorDOMSyntax: 'Gwall: Cystrawen DOM Annilys (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/cz.js b/library/ajaxchat/chat/js/lang/cz.js
new file mode 100644
index 000000000..4a0a7b8b2
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/cz.js
@@ -0,0 +1,91 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s se přihlásil.',
+ logout: '%s se odhlásil.',
+ logoutTimeout: '%s byl odhlášen (překročen timeout).',
+ logoutIP: '%s byl odhlášen (neplatná IP adresa).',
+ logoutKicked: '%s byl vyhozen.',
+ channelEnter: '%s vstoupil do místnosti.',
+ channelLeave: '%s odešel z místnosti.',
+ privmsg: '(šeptá)',
+ privmsgto: '(šeptá %s)',
+ invite: '%s tě zve do místnosti %s.',
+ inviteto: 'Tvoje pozvání %s do místnosti %s bylo odesláno.',
+ uninvite: '%s odmítl pozvání do pokoje %s.',
+ uninviteto: 'Tvoje pozvání %s do pokoje %s bylo odmítnuto.',
+ queryOpen: 'Soukromý rozhovor s %s byl započat.',
+ queryClose: 'Soukromý rozhovor s %s byl ukončen.',
+ ignoreAdded: '%s byl přidán do seznamu ignorovaných.',
+ ignoreRemoved: '%s byl odebrán ze seznamu ignorovaných.',
+ ignoreList: 'Seznam ignorovaných:',
+ ignoreListEmpty: 'Seznam je prázdný...',
+ who: 'Přihlášení uživatelé:',
+ whoChannel: 'Uživatelé, přihlášení v místnosti %s:',
+ whoEmpty: 'Tady nikdo není...',
+ list: 'Dostupné místnosti:',
+ bans: 'Vyhození uživatelé:',
+ bansEmpty: 'Seznam je prázdný...',
+ unban: 'Uživatel %s byl omilostněn.',
+ whois: 'Uživatel %s - IP adresa:',
+ whereis: 'Uživatel %s je v místnosti %s.',
+ roll: '%s hodil %s a vyhrává %s.',
+ nick: '%s se nyní jmenuje %s.',
+ toggleUserMenu: 'Vyvolej/zhasni uživatelskou nabídku pro %s',
+ userMenuLogout: 'Odhlásit',
+ userMenuWho: 'Seznam přihlášených uživatelů',
+ userMenuList: 'Seznam místností',
+ userMenuAction: 'Co právě dělám',
+ userMenuRoll: 'Hodit kostkou',
+ userMenuNick: 'Změnit jméno uživatele',
+ userMenuEnterPrivateRoom: 'Vstoupit do soukromé místnosti',
+ userMenuSendPrivateMessage: 'Poslat soukromou zprávu',
+ userMenuDescribe: 'Co právě dělám (soukromě)',
+ userMenuOpenPrivateChannel: 'Zahájit soukromý rozhovor',
+ userMenuClosePrivateChannel: 'Ukončit soukromý rozhovor',
+ userMenuInvite: 'Pozvat',
+ userMenuUninvite: 'Odmítnout pozvání',
+ userMenuIgnore: 'Ignorovat/Přijmout',
+ userMenuIgnoreList: 'Seznam ignorovaných uživatelů',
+ userMenuWhereis: 'Zobrazit místnost',
+ userMenuKick: 'Vyhodit/Zablokovat',
+ userMenuBans: 'Seznam vyhozených uživatelů',
+ userMenuWhois: 'Zobrazit IP adresu',
+ unbanUser: 'Omilostnit uživatele %s',
+ joinChannel: 'Vstoupit do místnosti %s',
+ cite: '%s prohlásil:',
+ urlDialog: 'Zadej, prosím adresu (URL) stránky:',
+ deleteMessage: 'Vymazat zprávu',
+ deleteMessageConfirm: 'Opravdu vymazat tuto zprávu ?',
+ errorCookiesRequired: 'Pro tento chat je nutno povolit Cookies.',
+ errorUserNameNotFound: 'Chyba: Uživatel %s nebyl nalezen.',
+ errorMissingText: 'Chyba: Schází text zprávy.',
+ errorMissingUserName: 'Chyba: Schází jméno uživatele.',
+ errorInvalidUserName: 'Chyba: Neplatné jméno uživatele.',
+ errorUserNameInUse: 'Chyba: Jméno uživatele už je používáno.',
+ errorMissingChannelName: 'Chyba: Schází název místnosti.',
+ errorInvalidChannelName: 'Chyba: Neplatný název místnosti: %s',
+ errorPrivateMessageNotAllowed: 'Chyba: Soukromé zprávy nejsou povoleny.',
+ errorInviteNotAllowed: 'Chyba: Nejsi oprávněn zvát do této místnosti.',
+ errorUninviteNotAllowed: 'Chyba: Nejsi oprávněn odmítat pozvání z této místnosti.',
+ errorNoOpenQuery: 'Chyba: Nebyl zahájen žádný soukromý rozhovor.',
+ errorKickNotAllowed: 'Chyba: Nemáš právo vyhodit %s.',
+ errorCommandNotAllowed: 'Chyba: Tento příkaz není povolen: %s',
+ errorUnknownCommand: 'Chyba: Neznámý příkaz: %s',
+ errorMaxMessageRate: 'Chyba: Překročil jsi maximální počet zpráv za minutu.',
+ errorConnectionTimeout: 'Chyba: Čas připojení vypršel. Připoj se znovu.',
+ errorConnectionStatus: 'Chyba: Stav připojení: %s',
+ errorSoundIO: 'Chyba: Nepodařilo se přehrát zvukový soubor (Flash IO Error).',
+ errorSocketIO: 'Chyba: Nepodařilo se připojení k serveru (Flash IO Error).',
+ errorSocketSecurity: 'Chyba: Připojení k serveru selhalo (Flash Security Error).',
+ errorDOMSyntax: 'Chyba: Neplatná syntaxe DOM (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/da.js b/library/ajaxchat/chat/js/lang/da.js
new file mode 100644
index 000000000..c6e537aad
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/da.js
@@ -0,0 +1,91 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s Logger dig ind.',
+ logout: '%s Logger dig ud.',
+ logoutTimeout: '%s Er logget ud (Timeout).',
+ logoutIP: '%s er logget ud (ugyldig IP addresse).',
+ logoutKicked: '%s er logget ud (Kicked).',
+ channelEnter: '%s kom ind i kanalen.',
+ channelLeave: '%s forlod kanalen.',
+ privmsg: '(hvisker)',
+ privmsgto: '(hvisker til %s)',
+ invite: '%s inviterede dig til at joine %s.',
+ inviteto: 'Din invitation %s til at joine kanal %s er blevet sendt.',
+ uninvite: '%s Du er nu ikke længere inviteret til %s.',
+ uninviteto: 'Anullere invitation for %s på kanal %s.',
+ queryOpen: 'Privat kanal åben for %s.',
+ queryClose: 'Privat kanal for %s lukket.',
+ ignoreAdded: 'Tilføjede %s til ignorerings listen.',
+ ignoreRemoved: 'fjernede %s fra ignorerings listen.',
+ ignoreList: 'Ignorerede brugere:',
+ ignoreListEmpty: 'Ingen ignorerede brugere.',
+ who: 'Online brugere:',
+ whoChannel: 'Online brugere på kanal %s:',
+ whoEmpty: 'ingen online brugere på den angivne kanal.',
+ list: 'Tilgængelige kanaler:',
+ bans: 'Banlyste brugere:',
+ bansEmpty: 'Ingen banlyste brugere på listen.',
+ unban: 'Banlysning af %s ophævet.',
+ whois: 'bruger %s - IP addresse:',
+ whereis: 'brugeren %s er på kanal %s.',
+ roll: '%s Kastede terninger %s og fik %s.',
+ nick: '%s Er nu kendt som %s.',
+ toggleUserMenu: 'skift bruger menu for %s',
+ userMenuLogout: 'Log ud',
+ userMenuWho: 'Vis online brugere',
+ userMenuList: 'Vis tilgængelige kanaler',
+ userMenuAction: 'Beskrivende handling',
+ userMenuRoll: 'Kast terninger',
+ userMenuNick: 'Skift brugernavn',
+ userMenuEnterPrivateRoom: 'Gå ind i privat rum.',
+ userMenuSendPrivateMessage: 'Send privat besked',
+ userMenuDescribe: 'Send privat handling',
+ userMenuOpenPrivateChannel: 'Åben privat kanal',
+ userMenuClosePrivateChannel: 'Luk privat kanal',
+ userMenuInvite: 'Inviter',
+ userMenuUninvite: 'Anuller invitation',
+ userMenuIgnore: 'Ignorer/Accepter',
+ userMenuIgnoreList: 'Vis ignorerede brugere',
+ userMenuWhereis: 'vis kanal',
+ userMenuKick: 'Spark ud/Banlys',
+ userMenuBans: 'Vis banlyste brugere',
+ userMenuWhois: 'Vis IP adresse',
+ unbanUser: 'Fjernede banlysning af brugere %s',
+ joinChannel: 'Deltag i en kanal %s',
+ cite: '%s sagde:',
+ urlDialog: 'Venligst indsæt adressen (URL) for den pågældende hjemmeside:',
+ deleteMessage: 'Fjern denne chat besked',
+ deleteMessageConfirm: 'Vil du virkelig fjerne denne besked?',
+ errorCookiesRequired: 'Cookies er nødvændige for denne chat',
+ errorUserNameNotFound: 'FEJL: bruger %s ikke fundet.',
+ errorMissingText: 'FEJL: Manglende besked.',
+ errorMissingUserName: 'FEJL: Manglende brugernavn.',
+ errorInvalidUserName: 'FEJL: Ugyldigt brugernavn.',
+ errorUserNameInUse: 'FEJL: Brugernavnet er allerede i brug.',
+ errorMissingChannelName: 'FEJL: Manglende kanal navn.',
+ errorInvalidChannelName: 'FEJL: Ugyldigt kanal navn: %s',
+ errorPrivateMessageNotAllowed: 'FEJL: Privat beskeder er ikke tilladt.',
+ errorInviteNotAllowed: 'FEJL: Du har ikke tilstrækkelige rettigheder til at invitere til denne kanal.',
+ errorUninviteNotAllowed: 'FEJL: Du har ikke tilstrækkelige rettigheder til at anullere invitationer for denne kanal.',
+ errorNoOpenQuery: 'FEJL: Ingen privat kanal åben.',
+ errorKickNotAllowed: 'FEJL: Du har ikke tilstrækkelige rettigheder til at sparke. %s.',
+ errorCommandNotAllowed: 'FEJL: Kommando ikke tillad: %s',
+ errorUnknownCommand: 'FEJL: Ukendt kommando: %s',
+ errorMaxMessageRate: 'FEJL: Du har overskredet max antal beskeder per minut.',
+ errorConnectionTimeout: 'FEJL: Forbindelses timeout. Prøv venligst igen.',
+ errorConnectionStatus: 'FEJL: Status for forbindelse. %s',
+ errorSoundIO: 'FEJL: Kunne ikke indlæse lydfil (Flash IO Fejl).',
+ errorSocketIO: 'FEJL: Connection to socket server failed (Flash IO fejl).',
+ errorSocketSecurity: 'FEJL: forbindelse til til socket server fejlede (Flash sikkerheds fejl).',
+ errorDOMSyntax: 'FEJL: Ugyldig DOM Syntaks(DOM ID: %s).'
+
+}
diff --git a/library/ajaxchat/chat/js/lang/de.js b/library/ajaxchat/chat/js/lang/de.js
new file mode 100644
index 000000000..b46b3f323
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/de.js
@@ -0,0 +1,91 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s betritt den Chat.',
+ logout: '%s verlässt den Chat.',
+ logoutTimeout: '%s wurde ausgeloggt (Timeout).',
+ logoutIP: '%s wurde ausgeloggt (Ungültige IP-Adresse).',
+ logoutKicked: '%s wurde ausgeloggt (Ausschluss).',
+ channelEnter: '%s betritt den Raum.',
+ channelLeave: '%s verlässt den Raum.',
+ privmsg: '(flüstert)',
+ privmsgto: '(flüstert zu %s)',
+ invite: '%s lädt dich ein den Raum %s zu betreten.',
+ inviteto: 'Deine Einladung an %s den Raum %s zu betreten wurde versendet.',
+ uninvite: '%s hat dich wieder ausgeladen den Raum %s zu betreten.',
+ uninviteto: 'Deine Ausladung an %s den Raum %s zu betreten wurde versendet.',
+ queryOpen: 'Privater Kanal zu %s geöffnet.',
+ queryClose: 'Privater Kanal zu %s geschlossen.',
+ ignoreAdded: '%s wurde auf die Ignorier-Liste gesetzt.',
+ ignoreRemoved: '%s wurde von der Ignorier-Liste entfernt.',
+ ignoreList: 'Ignorierte Benutzer:',
+ ignoreListEmpty: 'Keine Benutzer werden ignoriert.',
+ who: 'Benutzer online:',
+ whoChannel: 'Benutzer online im Raum %s:',
+ whoEmpty: 'Keine Benutzer online im angegebenen Kanal.',
+ list: 'Verfügbare Räume:',
+ bans: 'Ausgeschlossene Nutzer:',
+ bansEmpty: 'Keine ausgeschlossenen Nutzer vorhanden.',
+ unban: 'Ausschluss des Benutzers %s aufgehoben.',
+ whois: 'Benutzer %s - IP-Adresse:',
+ whereis: 'Benutzer %s ist im Raum %s.',
+ roll: '%s würfelt %s und erhält %s.',
+ nick: '%s heißt jetzt %s.',
+ toggleUserMenu: 'Benutzer-Menü für %s anzeigen/ausblenden',
+ userMenuLogout: 'Logout',
+ userMenuWho: 'Online Benutzer auflisten',
+ userMenuList: 'Verfügbare Räume auflisten',
+ userMenuAction: 'Aktion beschreiben',
+ userMenuRoll: 'Würfeln',
+ userMenuNick: 'Benutzernamen ändern',
+ userMenuEnterPrivateRoom: 'Privaten Raum betreten',
+ userMenuSendPrivateMessage: 'Private Nachricht schicken',
+ userMenuDescribe: 'Private Aktion schicken',
+ userMenuOpenPrivateChannel: 'Privaten Kanal öffnen',
+ userMenuClosePrivateChannel: 'Privaten Kanal schließen',
+ userMenuInvite: 'Einladen',
+ userMenuUninvite: 'Ausladen',
+ userMenuIgnore: 'Ignorieren / Akzeptieren',
+ userMenuIgnoreList: 'Ignorierte Benutzer auflisten',
+ userMenuWhereis: 'Raum anzeigen',
+ userMenuKick: 'Ausschließen / Verbannen',
+ userMenuBans: 'Ausgeschlossene Benutzer auflisten',
+ userMenuWhois: 'IP anzeigen',
+ unbanUser: 'Ausschluss von %s aufheben',
+ joinChannel: 'Raum %s betreten',
+ cite: '%s sagte:',
+ urlDialog: 'Bitte die Adresse (URL) der Webseite eingeben:',
+ deleteMessage: 'Diese Chat-Nachricht löschen',
+ deleteMessageConfirm: 'Die ausgewählte Chat-Nachricht wirklich löschen?',
+ errorCookiesRequired: 'Cookies werden für diesen Chat benötigt.',
+ errorUserNameNotFound: 'Fehler: Benutzer %s wurde nicht gefunden.',
+ errorMissingText: 'Fehler: Nachrichtentext fehlt.',
+ errorMissingUserName: 'Fehler: Benutzername fehlt.',
+ errorInvalidUserName: 'Fehler: Ungültiger Benutzername.',
+ errorUserNameInUse: 'Fehler: Benutzername schon vergeben.',
+ errorMissingChannelName: 'Fehler: Raumname fehlt.',
+ errorInvalidChannelName: 'Fehler: Ungültiger Raumname: %s',
+ errorPrivateMessageNotAllowed: 'Fehler: Private Nachrichten sind nicht erlaubt.',
+ errorInviteNotAllowed: 'Fehler: Du kannst niemanden zu diesem Raum Einladen.',
+ errorUninviteNotAllowed: 'Fehler: Du kannst niemanden von diesem Raum Ausladen.',
+ errorNoOpenQuery: 'Fehler: Kein privater Kanal offen.',
+ errorKickNotAllowed: 'Fehler: Du kannst %s nicht ausschließen.',
+ errorCommandNotAllowed: 'Fehler: Befehl nicht erlaubt: %s',
+ errorUnknownCommand: 'Fehler: Unbekannter Befehl: %s',
+ errorMaxMessageRate: 'Fehler: Du hast die maximale Anzahl an Nachrichten pro Minute überschritten.',
+ errorConnectionTimeout: 'Fehler: Verbindungsabbruch. Bitte erneut versuchen.',
+ errorConnectionStatus: 'Fehler: Verbindungsstatus: %s',
+ errorSoundIO: 'Fehler: Laden einer Sound-Datei fehlgeschlagen (Flash IO Error).',
+ errorSocketIO: 'Fehler: Verbindung zum Socket Server fehlgeschlagen (Flash IO Error).',
+ errorSocketSecurity: 'Fehler: Verbindung zum Socket Server fehlgeschlagen (Flash Security Error).',
+ errorDOMSyntax: 'Error: Invalid DOM Syntax (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/el.js b/library/ajaxchat/chat/js/lang/el.js
new file mode 100644
index 000000000..2864c3a76
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/el.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author panas
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s μπήκε στο Chat.',
+ logout: '%s βγήκε από το Chat.',
+ logoutTimeout: '%s βγήκε από το Chat (Ανενεργό).',
+ logoutIP: '%s βγήκε από το Chat (Λανθασμένη IP).',
+ logoutKicked: '%s βγήκε από το Chat (Kicked).',
+ channelEnter: '%s μπήκε στο κανάλι.',
+ channelLeave: '%s βγήκε από το κανάλι.',
+ privmsg: '(ψιθυρίζει)',
+ privmsgto: '( ψιθυρίζει σε %s)',
+ invite: '%s σας καλεί να συμμετάσχετε στο %s.',
+ inviteto: 'Η πρόσκληση σας σε %s να συμμετάσχει στο κανάλι %s έχει σταλεί.',
+ uninvite: '%s τερματίζει την πρόσκληση σας για το κανάλι %s.',
+ uninviteto: 'Η πρόσκληση σας σε %s για το κανάλι %s έχει σταλεί.',
+ queryOpen: 'Άνοιξε πρίβε κανάλι σε %s.',
+ queryClose: ' Το πρίβε κανάλι %s έκλεισε.',
+ ignoreAdded: '%s προστέθηκε στη λίστα αγνόησης.',
+ ignoreRemoved: ' %s αφαιρέθηκε από τη λίστα αγνόησης .',
+ ignoreList: 'Αγνοήμενοι χρήστες:',
+ ignoreListEmpty: 'Δεν υπάρχουν αγνοημένοι χρήστες.',
+ who: 'Χρήστες παρόν:',
+ whoChannel: 'Χρήστες συνδεδεμένοι στο κανάλι %s:',
+ whoEmpty: 'Δεν υπάρχουν χρήστες στο συγκεκριμένο κανάλι.',
+ list: 'Διαθέσιμα κανάλια:',
+ bans: 'Αποκλεισμένοι χρήστες:',
+ bansEmpty: 'Δεν υπάρχουν αποκλεισμένοι χρήστες.',
+ unban: 'Ο αποκλεισμός %s αφαιρέθηκε.',
+ whois: ' %s - IP διεύθυνση:',
+ whereis: 'Χρήστης %s είναι στο κανάλι %s.',
+ roll: '%s ρίχνει %s και φέρνει %s.',
+ nick: '%s άλλαξε το όνομα σε %s.',
+ toggleUserMenu: 'Αλλαγή μενού χρήστη για %s',
+ userMenuLogout: 'Αποσύνδεση',
+ userMenuWho: 'Εμφάνιση λίστας συνδεδεμένων',
+ userMenuList: 'Εμφάνιση λίστας διαθέσιμων καναλιών',
+ userMenuAction: 'Περιγραφή ενέργειας',
+ userMenuRoll: 'Ρίξιμο ζαριών',
+ userMenuNick: 'Αλλαγή ονόματος',
+ userMenuEnterPrivateRoom: 'Εισαγωγή σε πριβέ δωμάτιο',
+ userMenuSendPrivateMessage: 'Αποστολή προσωπικού μηνύματος',
+ userMenuDescribe: 'Αποστολή προσωπικής ενέργειας',
+ userMenuOpenPrivateChannel: 'Άνοιγμα πριβέ καναλιού',
+ userMenuClosePrivateChannel: 'Κλείσιμο πριβέ καναλιού',
+ userMenuInvite: 'Πρόσκληση',
+ userMenuUninvite: 'Ακύρωση πρόσκλησης',
+ userMenuIgnore: 'Αγνόηση/Αποδοχή',
+ userMenuIgnoreList: 'Εμφάνιση λίστας αγνοημένων',
+ userMenuWhereis: 'Εμφάνιση καναλιού',
+ userMenuKick: 'Kick/Ban',
+ userMenuBans: 'Εμφάνιση λίστας αποκλεισμένων',
+ userMenuWhois: 'Εμφάνιση IP',
+ unbanUser: 'Επαναφορά αποκλεισμού για %s',
+ joinChannel: 'Μπαίνει στο κανάλι %s',
+ cite: '%s είπε:',
+ urlDialog: 'παρακαλούμε εισάγετε την διεύθυνση (URL) της ιστοσελίδας:',
+ deleteMessage: 'Διαγραφή αυτού του μηνύματος',
+ deleteMessageConfirm: 'Θέλετε να διαγράψετε το επιλεγμένο μήνυμα?',
+ errorCookiesRequired: 'Τα cookies είναι απαραίτητα για το chat.',
+ errorUserNameNotFound: 'Σφάλμα: Ο χρήστης %s δεν βρέθηκε.',
+ errorMissingText: 'Σφάλμα: Λείπει το μήνυμα.',
+ errorMissingUserName: ': Λείπει ο χρήστης.',
+ errorInvalidUserName: 'Error: Invalid username.',
+ errorUserNameInUse: 'Error: Username already in use.',
+ errorMissingChannelName: 'Σφάλμα: Λείπει το όνομα του καναλιού.',
+ errorInvalidChannelName: 'Σφάλμα: Ακατάλληλο όνομα καναλιού: %s',
+ errorPrivateMessageNotAllowed: 'Σφάλμα: Τα προσωπικά μηνύματα δεν επιτρέπονται.',
+ errorInviteNotAllowed: 'Σφάλμα: Δεν σας επιτρέπετε να καλέσετε άλλούς στο κανάλι.',
+ errorUninviteNotAllowed: 'Σφάλμα: Δεν σας επιτρέπετε να τερματίσετε την πρόσκληση άλλων από το κανάλι.',
+ errorNoOpenQuery: ': Δεν ανοίχθηκε πρίβε κανάλι.',
+ errorKickNotAllowed: 'Δεν σας επιτρέπετε να πετάξετε %s.',
+ errorCommandNotAllowed: 'Σφάλμα: Δεν επιτρέπετε η εντολή: %s',
+ errorUnknownCommand: 'Σφάλμα: Άγνωστη εντολή: %s',
+ errorMaxMessageRate: 'Σφάλμα: Υπερβήκατε τον μέγιστο αριθμό μηνυμάτων ανά λεπτό.',
+ errorConnectionTimeout: 'Σφάλμα: Έληξε ο χρόνος σύνδεσης. Προσπαθήστε ξανά.',
+ errorConnectionStatus: 'Σφάλμα: Κατάσταση σύνδεσης: %s',
+ errorSoundIO: 'Σφάλμα: Απέτυχε η φόρτωση του αρχείου ήχου (Flash IO Σφάλμα).',
+ errorSocketIO: 'Σφάλμα: Η σύνδεση στο socket του διακομιστή απέτυχε (Flash IO Σφάλμα).',
+ errorSocketSecurity: 'Σφάλμα:Η σύνδεση στο socket του διακομιστή απέτυχε (Σφάλμα ασφαλείας του Flash ).',
+ errorDOMSyntax: 'Σφάλμα: Άκυρη DOM σύνταξη (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/en.js b/library/ajaxchat/chat/js/lang/en.js
new file mode 100644
index 000000000..16b4ab472
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/en.js
@@ -0,0 +1,91 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s logs into the Chat.',
+ logout: '%s logs out of the Chat.',
+ logoutTimeout: '%s has been logged out (Timeout).',
+ logoutIP: '%s has been logged out (Invalid IP address).',
+ logoutKicked: '%s has been logged out (Kicked).',
+ channelEnter: '%s enters the channel.',
+ channelLeave: '%s leaves the channel.',
+ privmsg: '(whispers)',
+ privmsgto: '(whispers to %s)',
+ invite: '%s invites you to join %s.',
+ inviteto: 'Your invitation to %s to join channel %s has been sent.',
+ uninvite: '%s uninvites you from channel %s.',
+ uninviteto: 'Your uninvitation to %s for channel %s has been sent.',
+ queryOpen: 'Private channel opened to %s.',
+ queryClose: 'Private channel to %s closed.',
+ ignoreAdded: 'Added %s to the ignore list.',
+ ignoreRemoved: 'Removed %s from the ignore list.',
+ ignoreList: 'Ignored Users:',
+ ignoreListEmpty: 'No ignored Users listed.',
+ who: 'Online Users:',
+ whoChannel: 'Online Users in channel %s:',
+ whoEmpty: 'No online users in the given channel.',
+ list: 'Available channels:',
+ bans: 'Banned Users:',
+ bansEmpty: 'No banned Users listed.',
+ unban: 'Ban of user %s revoked.',
+ whois: 'User %s - IP address:',
+ whereis: 'User %s is in channel %s.',
+ roll: '%s rolls %s and gets %s.',
+ nick: '%s is now known as %s.',
+ toggleUserMenu: 'Toggle user menu for %s',
+ userMenuLogout: 'Logout',
+ userMenuWho: 'List online users',
+ userMenuList: 'List available channels',
+ userMenuAction: 'Describe action',
+ userMenuRoll: 'Roll dice',
+ userMenuNick: 'Change username',
+ userMenuEnterPrivateRoom: 'Enter private room',
+ userMenuSendPrivateMessage: 'Send private message',
+ userMenuDescribe: 'Send private action',
+ userMenuOpenPrivateChannel: 'Open private channel',
+ userMenuClosePrivateChannel: 'Close private channel',
+ userMenuInvite: 'Invite',
+ userMenuUninvite: 'Uninvite',
+ userMenuIgnore: 'Ignore/Accept',
+ userMenuIgnoreList: 'List ignored users',
+ userMenuWhereis: 'Display channel',
+ userMenuKick: 'Kick/Ban',
+ userMenuBans: 'List banned users',
+ userMenuWhois: 'Display IP',
+ unbanUser: 'Revoke ban of user %s',
+ joinChannel: 'Join channel %s',
+ cite: '%s said:',
+ urlDialog: 'Please enter the address (URL) of the webpage:',
+ deleteMessage: 'Delete this chat message',
+ deleteMessageConfirm: 'Really delete the selected chat message?',
+ errorCookiesRequired: 'Cookies are required for this chat.',
+ errorUserNameNotFound: 'Error: User %s not found.',
+ errorMissingText: 'Error: Missing message text.',
+ errorMissingUserName: 'Error: Missing username.',
+ errorInvalidUserName: 'Error: Invalid username.',
+ errorUserNameInUse: 'Error: Username already in use.',
+ errorMissingChannelName: 'Error: Missing channel name.',
+ errorInvalidChannelName: 'Error: Invalid channel name: %s',
+ errorPrivateMessageNotAllowed: 'Error: Private messages are not allowed.',
+ errorInviteNotAllowed: 'Error: You are not allowed to invite someone to this channel.',
+ errorUninviteNotAllowed: 'Error: You are not allowed to uninvite someone from this channel.',
+ errorNoOpenQuery: 'Error: No private channel open.',
+ errorKickNotAllowed: 'Error: You are not allowed to kick %s.',
+ errorCommandNotAllowed: 'Error: Command not allowed: %s',
+ errorUnknownCommand: 'Error: Unknown command: %s',
+ errorMaxMessageRate: 'Error: You exceeded the maximum number of messages per minute.',
+ errorConnectionTimeout: 'Error: Connection timeout. Please try again.',
+ errorConnectionStatus: 'Error: Connection status: %s',
+ errorSoundIO: 'Error: Failed to load sound file (Flash IO Error).',
+ errorSocketIO: 'Error: Connection to socket server failed (Flash IO Error).',
+ errorSocketSecurity: 'Error: Connection to socket server failed (Flash Security Error).',
+ errorDOMSyntax: 'Error: Invalid DOM Syntax (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/es.js b/library/ajaxchat/chat/js/lang/es.js
new file mode 100644
index 000000000..393467a8c
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/es.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author Manu Quintans / KeScI [www.e-nologia.com]
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s entra al Chat.',
+ logout: '%s sale del Chat.',
+ logoutTimeout: '%s se ha desconectado (Tiempo de espera agotado).',
+ logoutIP: '%s se ha desconectado (Direccion IP no valida).',
+ logoutKicked: '%s se ha desconectado (Pateado).',
+ channelEnter: '%s entra en el canal.',
+ channelLeave: '%s se va del canal.',
+ privmsg: '(susurra)',
+ privmsgto: '(susurra a %s)',
+ invite: '%s te invita a unirte a %s.',
+ inviteto: 'Su invitación a %s para unirse al canal %s se ha enviado.',
+ uninvite: '%s le retira la invitación del canal %s.',
+ uninviteto: 'Su retirada de invitación a %s para el canal %s se ha enviado.',
+ queryOpen: 'Privado abierto a %s.',
+ queryClose: 'Privado cerrado a %s.',
+ ignoreAdded: 'Agregado %s a la lista de usuarios ignorados.',
+ ignoreRemoved: 'Eliminado %s de la lista de usuarios ignorados.',
+ ignoreList: 'Usuarios ignorados',
+ ignoreListEmpty: 'Lista de usuarios no ignorados.',
+ who: 'Usuarios conectados:',
+ whoChannel: 'Usuarios conectados en el canal %s:',
+ whoEmpty: 'No hay usuarios conectados en este momento.',
+ list: 'Canales disponibles:',
+ bans: 'Usuarios Baneados:',
+ bansEmpty: 'No se han listado usuarios baneados.',
+ unban: 'Ban del usuario %s retirado.',
+ whois: 'Usuario %s - Direccion IP:',
+ whereis: 'Usuario %s está en el canal %s.',
+ roll: '%s lanza %s y obtiene un %s.',
+ nick: '%s es ahora %s.',
+ toggleUserMenu: 'Abrir/Cerrar menú del usuario %s',
+ userMenuLogout: 'Desconectar',
+ userMenuWho: 'Mostrar usuarios conectados',
+ userMenuList: 'Mostrar canales disponibles',
+ userMenuAction: 'Describir acción',
+ userMenuRoll: 'Tirar dado',
+ userMenuNick: 'Cambiar Nombre de Usuario',
+ userMenuEnterPrivateRoom: 'Entrar en canal privado',
+ userMenuSendPrivateMessage: 'Enviar mensaje privado',
+ userMenuDescribe: 'Enviar acción privada',
+ userMenuOpenPrivateChannel: 'Abrir canal privado',
+ userMenuClosePrivateChannel: 'Cerrar canal privado',
+ userMenuInvite: 'Invitar',
+ userMenuUninvite: 'Quitar invitación',
+ userMenuIgnore: 'Ignorar/Aceptar',
+ userMenuIgnoreList: 'Mostrar usuarios ignorados',
+ userMenuWhereis: 'Mostrar canal',
+ userMenuKick: 'Patada/Ban',
+ userMenuBans: 'Mostrar usuarios baneados',
+ userMenuWhois: 'Mostrar la IP',
+ unbanUser: 'Quitar el ban al usuario %s',
+ joinChannel: 'Entrar al canal %s',
+ cite: '%s dijo:',
+ urlDialog: 'Por favor intruduzca la dirección (URL) de la página web:',
+ deleteMessage: 'Borrar este mensaje del chat',
+ deleteMessageConfirm: 'Really delete the selected chat message?',
+ errorCookiesRequired: 'Se necesitan las Cookies para este chat.',
+ errorUserNameNotFound: 'Error: usuario %s no se ha encontrado.',
+ errorMissingText: 'Error: Mensaje perdido.',
+ errorMissingUserName: 'Error: Usuario no encontrado.',
+ errorInvalidUserName: 'Error: Nombre de usuario no válido.',
+ errorUserNameInUse: 'Error: Nombre de usuario está en uso.',
+ errorMissingChannelName: 'Error: No se encuentra el canal.',
+ errorInvalidChannelName: 'Error: Nombre invalido del canal: %s',
+ errorPrivateMessageNotAllowed: 'Error: No se permiten mensajes privados.',
+ errorInviteNotAllowed: 'Error: No está autorizado a invitar a alguien a este canal.',
+ errorUninviteNotAllowed: 'Error: No está autorizado a quitar la invitación a alguien de este canal.',
+ errorNoOpenQuery: 'Error: Ningún privado abierto.',
+ errorKickNotAllowed: 'Error: No está autorizado a patear a %s.',
+ errorCommandNotAllowed: 'Error: Comando no permitido: %s',
+ errorUnknownCommand: 'Error: Comando desconocido: %s',
+ errorMaxMessageRate: 'Error: Ha sobrepasado el número máximo de mensajes por minuto.',
+ errorConnectionTimeout: 'Error: Connection timeout. Please try again.',
+ errorConnectionStatus: 'Error: Estado de la conexión: %s',
+ errorSoundIO: 'Error: No se ha podido cargar el fichero de sonido (Error IO Flash).',
+ errorSocketIO: 'Error: No se ha podido conectar al servidor socket (Error IO Flash).',
+ errorSocketSecurity: 'Error: No se ha podido conectar al servidor socket (Error Seguridad Flash).',
+ errorDOMSyntax: 'Error: Sintaxis DOM No Válida (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/et.js b/library/ajaxchat/chat/js/lang/et.js
new file mode 100644
index 000000000..e83c986b9
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/et.js
@@ -0,0 +1,91 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s logis jutukasse.',
+ logout: '%s logis jutukast välja.',
+ logoutTimeout: '%s logiti jutukast välja (Aeg otsas).',
+ logoutIP: '%s logiti jutukast välja (Vigane IP aadress).',
+ logoutKicked: '%s logiti jutukast välja (Välja heidetud).',
+ channelEnter: '%s sisenes kanalisse.',
+ channelLeave: '%s lahkus kanalist.',
+ privmsg: '(sosinad)',
+ privmsgto: '(sosinad %s -le)',
+ invite: '%s kutsub sind %s.',
+ inviteto: 'Sinu kutse %s -le ühineda kanaliga %s saadeti ära.',
+ uninvite: '%s palub sul lahkuda kanalist %s.',
+ uninviteto: 'Sinu palve %s -le lahkuda kanalist %s saadeti ära.',
+ queryOpen: 'Privaat kanal avati %s -le.',
+ queryClose: 'Privaat kanal %s -le suleti.',
+ ignoreAdded: ' %s -t ignoreeritakse.',
+ ignoreRemoved: ' %s ignoreerimine tühistati.',
+ ignoreList: 'Ignoreeritud kasutajad:',
+ ignoreListEmpty: 'Ignoreeritud kasutajad puuduvad.',
+ who: 'Sisse loginud kasutajad:',
+ whoChannel: 'Sisse loginud kasutajad kanalis %s:',
+ whoEmpty: 'Antud kanalis sisse loginud kasutajaid ei ole.',
+ list: 'Vabad kanalid:',
+ bans: 'Kasutajate must nimekiri:',
+ bansEmpty: 'Mustas nimekirjas kasutajaid ei ole.',
+ unban: 'Kasutaja %s eemaldati mustast nimekirjast.',
+ whois: 'Kasutaja %s - IP aadress:',
+ whereis: 'Kasutaja %s on kanalis %s.',
+ roll: '%s veeretas %s ja sai %s.',
+ nick: '%s nimetas end ümber: %s.',
+ toggleUserMenu: 'Näita/ära näita kasutaja menüüd',
+ userMenuLogout: 'Lahku',
+ userMenuWho: 'Näita sisse loginud kasutajaid',
+ userMenuList: 'Näita vabad kanalid',
+ userMenuAction: 'Kirjelda tegevust',
+ userMenuRoll: 'Veereta täringut',
+ userMenuNick: 'Muuda kasutajanimi',
+ userMenuEnterPrivateRoom: 'Sisene privaat-ruumi',
+ userMenuSendPrivateMessage: 'Saada privaat-sõnum',
+ userMenuDescribe: 'Saada privaat-tegevus',
+ userMenuOpenPrivateChannel: 'Ava privaat-kanal',
+ userMenuClosePrivateChannel: 'Sulge privaat-kanal',
+ userMenuInvite: 'Kutsu',
+ userMenuUninvite: 'Palu lahkuda',
+ userMenuIgnore: 'Ignoreeri/Tunnusta',
+ userMenuIgnoreList: 'Ignoreeritud kasutajad',
+ userMenuWhereis: 'Asukoha kanal',
+ userMenuKick: 'Viska välja/Lisa musta nimekirja',
+ userMenuBans: 'Musta nimekirja kasutajad',
+ userMenuWhois: 'Näita IP-d',
+ unbanUser: 'Eemalda %s mustast nimekirjast',
+ joinChannel: 'Liitu kanaliga %s',
+ cite: '%s ütles:',
+ urlDialog: 'Palun sisesta oma veebilehe (URL):',
+ deleteMessage: 'Kustuta see jutuka teade',
+ deleteMessageConfirm: 'Kas tahad tõesti kustutada seda sõnumit??',
+ errorCookiesRequired: 'Luba "küpsised", et kasutada seda jutukat.',
+ errorUserNameNotFound: 'Viga: Kasutajat nimega %s ei leitud.',
+ errorMissingText: 'Viga: Sõnumi tekst kadunud.',
+ errorMissingUserName: 'Viga: Kasutajanimi puuduv.',
+ errorInvalidUserName: 'Viga: Vigane kasutajanimi.',
+ errorUserNameInUse: 'Viga: Kasutajanimi on juba võetud.',
+ errorMissingChannelName: 'Viga: Kanali nimi on kadunud.',
+ errorInvalidChannelName: 'Viga: Vigane kanali nimi: %s',
+ errorPrivateMessageNotAllowed: 'Viga: Privaat-sõnumid ei ole lubatud.',
+ errorInviteNotAllowed: 'Viga: Sul ei ole lubatud kutsuda kedagi siia kanalisse.',
+ errorUninviteNotAllowed: 'Viga: Sul ei ole lubatud kedagi sellest kanalist lahkuma paluda.',
+ errorNoOpenQuery: 'Viga: htegi privaat-kanalit pole avatud.',
+ errorKickNotAllowed: 'Viga: Sul ei ole lubatud välja visata %s.',
+ errorCommandNotAllowed: 'Viga: Korraldus pole lubatud: %s',
+ errorUnknownCommand: 'Viga: Tundmatu korraldus: %s',
+ errorMaxMessageRate: 'Viga: Sinu maksimum sõnumite hulk, minuti vältel, on ületatud.',
+ errorConnectionTimeout: 'Viga: hendus aegus. Please proovi uuesti.',
+ errorConnectionStatus: 'Viga: henduse olek: %s',
+ errorSoundIO: 'Viga: Helifaili ei õnnestunud laadida (Flash IO Viga).',
+ errorSocketIO: 'Viga: hendus socket serveriga ebaõnnestus (Flash IO Viga).',
+ errorSocketSecurity: 'Viga: hendus socket serveriga ebaõnnestus (Flash Turvalisuse Viga).',
+ errorDOMSyntax: 'Viga: Vigane DOM Süntaks (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/fi.js b/library/ajaxchat/chat/js/lang/fi.js
new file mode 100644
index 000000000..68a536c73
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/fi.js
@@ -0,0 +1,93 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author Asmo Soinio
+ * @author Saku Laukkanen
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s kirjautui sisään.',
+ logout: '%s kirjautui ulos.',
+ logoutTimeout: '%s kirjautui ulos (Aikakatkaisu).',
+ logoutIP: '%s kirjautui ulos (virheellinen IP-osoite).',
+ logoutKicked: '%s kirjautui ulos (Potkut).',
+ channelEnter: '%s liittyi kanavalle.',
+ channelLeave: '%s poistui kanavalta.',
+ privmsg: '(kuiskaa)',
+ privmsgto: '(kuiskaa käyttäjälle %s)',
+ invite: '%s kutsuu sinut liittymään kanavalle %s.',
+ inviteto: 'Sinun kutsusi käyttäjälle %s, liittymisestä kanavalle %s, on lähetetty.',
+ uninvite: '%s peruu kutsun kanavalle %s.',
+ uninviteto: 'Kutsusi peruminen käyttäjälle %s kanavaa %s varten, on lähetetty.',
+ queryOpen: 'Yksityinen kanava käyttäjälle %s on avattu.',
+ queryClose: 'Yksityinen kanava käyttäjälle %s on suljettu.',
+ ignoreAdded: 'Käyttäjä %s on lisätty huomiotta jätettäviin.',
+ ignoreRemoved: 'Käyttäjä %s on poistettu huomiotta jätettävistä.',
+ ignoreList: 'Huomiotta jätettävät käyttäjät:',
+ ignoreListEmpty: 'Ei huomiotta jätettäviä käyttäjiä.',
+ who: 'Paikallaolijat:',
+ whoChannel: 'Paikallaolijat kanavalla %s:',
+ whoEmpty: 'Ei käyttäjiä annetulla kanavalla.',
+ list: 'Käytettävät kanavat:',
+ bans: 'Potkitut käyttäjät:',
+ bansEmpty: 'Ei potkittuja käyttäjiä.',
+ unban: 'Käyttäjän %s potkut on poistettu.',
+ whois: 'Käyttäjän %s IP osoite:',
+ whereis: 'Käyttäjä %s on kanavalla %s.',
+ roll: '%s heittää %s ja saa %s.',
+ nick: '%s on nyt %s.',
+ toggleUserMenu: 'Näytä/piilota valikko käyttäjälle %s',
+ userMenuLogout: 'Poistu',
+ userMenuWho: 'Listaa paikallaolijat',
+ userMenuList: 'Listaa käytettävissä olevat kanavat',
+ userMenuAction: 'Määrittele toiminta',
+ userMenuRoll: 'Heitä noppaa',
+ userMenuNick: 'Vaihda käyttäjätunnusta',
+ userMenuEnterPrivateRoom: 'Mene yksityiseen kanavaasi',
+ userMenuSendPrivateMessage: 'Lähetä yksityinen viesti',
+ userMenuDescribe: 'Lähetä yksityinen toiminto',
+ userMenuOpenPrivateChannel: 'Avaa yksityinen kanava',
+ userMenuClosePrivateChannel: 'Sulje yksityinen kanava',
+ userMenuInvite: 'Kutsu',
+ userMenuUninvite: 'Peru kutsu',
+ userMenuIgnore: 'Ohita/Hyväksy',
+ userMenuIgnoreList: 'Listaa huomiota jätettävät käyttäjät',
+ userMenuWhereis: 'Näytä kanavat',
+ userMenuKick: 'Poista/Porttikielto',
+ userMenuBans: 'Listaa käyttäjät, joilla porttikielto',
+ userMenuWhois: 'Näytä IP-osoite',
+ unbanUser: 'Poista käyttäjän %s porttikielto',
+ joinChannel: 'Liity kanavalle %s',
+ cite: '%s sanoi:',
+ urlDialog: 'Lisää nettisivujen osoite (URL):',
+ deleteMessage: 'Poista tämä viesti',
+ deleteMessageConfirm: 'Poistetaanko viesti?',
+ errorCookiesRequired: 'Evästeiden pitää olla sallituja käyttääksesi tätä keskustelua.',
+ errorUserNameNotFound: 'Virhe: Käyttäjää %s ei löydetty.',
+ errorMissingText: 'Virhe: Puuttuva viestin teksti.',
+ errorMissingUserName: 'Virhe: Puuttuva käyttäjänimi.',
+ errorInvalidUserName: 'Virhe: Virheellinen käyttäjätunnus.',
+ errorUserNameInUse: 'Virhe: Käyttäjätunnus on jo käytössä.',
+ errorMissingChannelName: 'Virhe: Puuttuva kanavan nimi.',
+ errorInvalidChannelName: 'Virhe: Virheellinen kanavan nimi: %s',
+ errorPrivateMessageNotAllowed: 'Virhe: Yksityisviestit eivät ole sallittuja.',
+ errorInviteNotAllowed: 'Virhe: Sinulla ei ole oikeutta kutsua ketään kanavalle.',
+ errorUninviteNotAllowed: 'Virhe: Sinulla ei ole oikeutta perua kutsua tälle kanavalle.',
+ errorNoOpenQuery: 'Virhe: Ei yksityistä kanavaa auki.',
+ errorKickNotAllowed: 'Virhe: Sinulla ei ole oikeutta potkia käyttäjää %s.',
+ errorCommandNotAllowed: 'Virhe: Komento ei ole sallittu: %s',
+ errorUnknownCommand: 'Virhe: Tuntematon komento: %s',
+ errorMaxMessageRate: 'Virhe: Liikaa viestejä minuutissa.',
+ errorConnectionTimeout: 'Virhe: Yhteyden aikakatkaisu, olkaa hyvä ja yrittäkää uudelleen.',
+ errorConnectionStatus: 'Virhe: Yhteyden tila: %s',
+ errorSoundIO: 'Virhe: Äänitiedoston lataus epäonnistui (Flash IO-virhe).',
+ errorSocketIO: 'Virhe: Yhteys socket palvelimeen epäonnistui (Flash IO-virhe).',
+ errorSocketSecurity: 'Virhe: Yhteys socket palvelimeen epäonnistui (Flash-turvallisuus virhe).',
+ errorDOMSyntax: 'Virhe: Virheellinen DOM-syntaksi (DOM-tunniste: %s).'
+
+}
diff --git a/library/ajaxchat/chat/js/lang/fr.js b/library/ajaxchat/chat/js/lang/fr.js
new file mode 100644
index 000000000..35846f95e
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/fr.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @contributors Ettelcar, Massimiliano Tiraboschi, Xytovl
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s se connecte au Chat.',
+ logout: '%s se déconnecte du Chat.',
+ logoutTimeout: '%s a été déconnecté (Temps écoulé).',
+ logoutIP: '%s a été déconnecté (Adresse IP invalide).',
+ logoutKicked: '%s a été déconnecté (Éjecté).',
+ channelEnter: '%s entre dans le salon.',
+ channelLeave: '%s sort du salon.',
+ privmsg: '(murmure)',
+ privmsgto: '(murmure à l’oreille de %s)',
+ invite: '%s vous invite à rejoindre %s.',
+ inviteto: 'Votre invation pour %s à rejoindre le salon %s a bien été envoyée.',
+ uninvite: '%s annule son invitation pour le salon %s.',
+ uninviteto: 'Votre annulaton d’invitation pour %s au salon %s a bien été envoyée.',
+ queryOpen: 'Salon privé ouvert sous le titre %s.',
+ queryClose: 'Le salon privé %s a été fermé.',
+ ignoreAdded: '%s a été ajouté à la liste des personnes ignorées.',
+ ignoreRemoved: '%s a été enlevé de la liste des personnes ignorées.',
+ ignoreList: 'Utilisateurs ignorés:',
+ ignoreListEmpty: 'Aucun utilisateur ignoré référencé.',
+ who: 'Utilisateurs en ligne:',
+ whoChannel: 'Utilisateurs en ligne dans le salon %s :',
+ whoEmpty: 'Aucun utilisateur en ligne dans le salon concerné.',
+ list: 'Salons disponibles :',
+ bans: 'Utilisateurs bannis :',
+ bansEmpty: 'Aucun utilisateur banni référencé.',
+ unban: 'Le ban de l’utilisateur %s a été levé.',
+ whois: 'Utilisateur %s - Adresse IP:',
+ whereis: 'L’utilisateur %s est dans le salon %s.',
+ roll: '%s jette %s et obtient %s.',
+ nick: '%s est maintenant %s.',
+ toggleUserMenu: 'Montrer/cacher menu pour %s',
+ userMenuLogout: 'Déconnexion',
+ userMenuWho: 'Liste membres en ligne',
+ userMenuList: 'Liste salons disponibles',
+ userMenuAction: 'Décrire une action',
+ userMenuRoll: 'Jeter un dé',
+ userMenuNick: 'Changer nom',
+ userMenuEnterPrivateRoom: 'Rejoindre un salon privé',
+ userMenuSendPrivateMessage: 'Envoyer un message privé',
+ userMenuDescribe: 'Envoyer une action privé',
+ userMenuOpenPrivateChannel: 'Ouvrir un salon privé',
+ userMenuClosePrivateChannel: 'Fermer un salon privé',
+ userMenuInvite: 'Inviter',
+ userMenuUninvite: 'Uninvite',
+ userMenuIgnore: 'Ignorer/Accepter',
+ userMenuIgnoreList: 'Liste utilisateurs ignorés',
+ userMenuWhereis: 'Montrer les salons',
+ userMenuKick: 'Éjecter/bannir',
+ userMenuBans: 'Liste utilisateurs bannis',
+ userMenuWhois: 'Display IP',
+ unbanUser: 'Revoke ban of user %s',
+ joinChannel: 'Rejoindre le salon %s',
+ cite: '%s a dit:',
+ urlDialog: 'Veuillez entrer l’addresse (URL) de la page web:',
+ deleteMessage: 'Effacer ce message',
+ deleteMessageConfirm: 'Effacer le message selectionné ?',
+ errorCookiesRequired: 'Ce Chat requiert l’acceptation des cookies.',
+ errorUserNameNotFound: 'Erreur : Utilisateur %s introuvable.',
+ errorMissingText: 'Erreur : Texte du message manquant.',
+ errorMissingUserName: 'Erreur : Nom d’utilisateur manquant.',
+ errorMissingChannelName: 'Erreur : Nom de salon manquant.',
+ errorInvalidChannelName: 'Erreur : Mauvais nom de salon: %s',
+ errorPrivateMessageNotAllowed: 'Erreur : Les messages privés sont interdits.',
+ errorInviteNotAllowed: 'Erreur : Vous n’êtes pas autorisé à inviter quelqu’un à ce salon.',
+ errorUninviteNotAllowed: 'Erreur : Vous n’êtes pas autorisé à annuler une invitation à ce salon.',
+ errorNoOpenQuery: 'Erreur : Aucun salon privé ouvert.',
+ errorKickNotAllowed: 'Erreur : Vous n’êtes pas autorisé à éjecter %s.',
+ errorCommandNotAllowed: 'Erreur : Commande interdite: %s',
+ errorUnknownCommand: 'Erreur : Commande inconnue: %s',
+ errorMaxMessageRate: 'Error : You exceeded the maximum number of messages per minute.',
+ errorConnectionTimeout: 'Erreur : Temps de connexion écoulé. Veuillez réessayer.',
+ errorConnectionStatus: 'Erreur : Statut de connexion: %s',
+ errorSoundIO: 'Erreur : Impossible de charger le fichier son (Erreur E/S Flash).',
+ errorSocketIO: 'Erreur : Connexion au serveur échouée (Erreur E/S Flash).',
+ errorSocketSecurity: 'Erreur : Connexion au serveur échouée (Erreur de sécurité Flash).',
+ errorDOMSyntax: 'Erreur : Syntaxe DOM invalide (ID DOM : %s).'
+
+}
+
+
diff --git a/library/ajaxchat/chat/js/lang/gl.js b/library/ajaxchat/chat/js/lang/gl.js
new file mode 100644
index 000000000..314e226f8
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/gl.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author Manu Quintans
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s logs dentro de Chat.',
+ logout: '%s logs fora del Chat.',
+ logoutTimeout: '%s desconectouse(Tempo de espera esgotado).',
+ logoutIP: '%s desconectouse (Dirección IP non válida ).',
+ logoutKicked: '%s desconectouse (Pateado).',
+ channelEnter: '%s Entra no chat.',
+ channelLeave: '%s Vaise do chat.',
+ privmsg: '(whispers)',
+ privmsgto: '(whispers to %s)',
+ invite: '%s invítache a unirte a %s.',
+ inviteto: 'A túa invitación a %s para unirse a %s foi enviada.',
+ uninvite: '%s rechazado en %s.',
+ uninviteto: 'O teu rechazo a %s para %s foi enviado.',
+ queryOpen: 'Chat privado aberto %s.',
+ queryClose: 'Chat privado pechado %s pechado.',
+ ignoreAdded: 'Engadido %s a lista de usuarios ignorados.',
+ ignoreRemoved: 'Eliminado %s da lista de usuarios ignorados.',
+ ignoreList: 'Usuarios ignorados',
+ ignoreListEmpty: 'Lista de usuarios non ignorados.',
+ who: 'Usuarios conectados:',
+ whoChannel: 'Usuarios en liña na canle %s:',
+ whoEmpty: 'Non hai usuarios conectados neste momento.',
+ list: 'Chats disponibles:',
+ bans: 'Usuarios Baneados:',
+ bansEmpty: 'Non hai usuarios baneados.',
+ unban: 'Baneo do usuario %s revocado.',
+ whois: 'Usuario %s - Direccion IP:',
+ whereis: 'Usuario %s en chat %s.',
+ roll: '%s rolls %s e toma %s.',
+ nick: '%s agora como %s.',
+ toggleUserMenu: 'Cambiar menu de usuario para %s',
+ userMenuLogout: 'Sair',
+ userMenuWho: 'Listar usuarios en liña',
+ userMenuList: 'Canles disponibles',
+ userMenuAction: 'Describe acción',
+ userMenuRoll: 'Roll di',
+ userMenuNick: 'Cambiar nome de usuario',
+ userMenuEnterPrivateRoom: 'Entrar nun privado',
+ userMenuSendPrivateMessage: 'Enviar mensaxe privada',
+ userMenuDescribe: 'Enviar accion en privado',
+ userMenuOpenPrivateChannel: 'Abrir privado',
+ userMenuClosePrivateChannel: 'Pechar privado',
+ userMenuInvite: 'Invitar',
+ userMenuUninvite: 'Rechazar invitado',
+ userMenuIgnore: 'Ignorar/Aceptar',
+ userMenuIgnoreList: 'Lista usuarios ignorados',
+ userMenuWhereis: 'Amosar canle',
+ userMenuKick: 'Banear',
+ userMenuBans: 'Lista usuarios baneados',
+ userMenuWhois: 'Amosar IP',
+ unbanUser: 'Eliminar baneo de %s',
+ joinChannel: 'Unirte a %s',
+ cite: '%s dixo:',
+ urlDialog: 'Por favor, introduce a URL da paxina web:',
+ deleteMessage: 'Eliminar mensaxe',
+ deleteMessageConfirm: 'Queres borra-la mensaxe?',
+ errorCookiesRequired: 'As Cookies son necesarias para o chat.',
+ errorUserNameNotFound: 'Error: usuario %s non encontrado.',
+ errorMissingText: 'Error: mensaxe perdida.',
+ errorMissingUserName: 'Error: Usuario non encontrado.',
+ errorInvalidUserName: 'Error: Nome de usuario non valido.',
+ errorUserNameInUse: 'Error: Usuario en uso.',
+ errorMissingChannelName: 'Error: No se atopa a canle.',
+ errorInvalidChannelName: 'Error: Nome inválido de canle: %s',
+ errorPrivateMessageNotAllowed: 'Error: mensaxes privadas non permitidas.',
+ errorInviteNotAllowed: 'Error: Non se che permite invitar nesta canle.',
+ errorUninviteNotAllowed: 'Error: Non se che permite rechazar invitados nesta canle.',
+ errorNoOpenQuery: 'Error: Ningunha canle privado aberto.',
+ errorKickNotAllowed: 'Error: Non podes banear %s.',
+ errorCommandNotAllowed: 'Error: Comando non permitido: %s',
+ errorUnknownCommand: 'Error: Comando descoñecido: %s',
+ errorMaxMessageRate: 'Error: Excedes o numero maximo de mensaxes por minuto.',
+ errorConnectionTimeout: 'Error: Tempo superado. Téntao de novo.',
+ errorConnectionStatus: 'Error: Estado de conexión: %s',
+ errorSoundIO: 'Error: Error o reproducir son(Flash IO Error).',
+ errorSocketIO: 'Error: Conexión co servidor fallida (Flash IO Error).',
+ errorSocketSecurity: 'Error: Conexión co servidor fallida(Flash Security Error).',
+ errorDOMSyntax: 'Error: Sintaxis DOM Inválida(DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/he.js b/library/ajaxchat/chat/js/lang/he.js
new file mode 100644
index 000000000..94bbdc5e1
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/he.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author Smiley Barry
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s נכנס לתוך הצאט.',
+ logout: '%s יוצא מהצאט.',
+ logoutTimeout: '%s הוצא מהצאט (היה לא זמין).',
+ logoutIP: '%s הוצא מהצאט (כתובת מחשב בלתי חוקית).',
+ logoutKicked: '%s הוצא מהצאט (הועף/נבעט).',
+ channelEnter: '%s נכנס לתוך הערוץ.',
+ channelLeave: '%s יוצא מהערוץ.',
+ privmsg: '(לוחש)',
+ privmsgto: '(לוחש ל%s)',
+ invite: '%s מזמין אותך להצטרף לערוץ %s.',
+ inviteto: 'ההזמנה שלך עבור %s להצטרף לערוץ %s נשלחה.',
+ uninvite: '%s ביטל את הזמנתו לערוץ %s.',
+ uninviteto: 'ביטול ההזמנה שלך עבור %s להצטרף לערוץ %s נשלח.',
+ queryOpen: 'ערוץ פרטי עבור %s נפתח.',
+ queryClose: 'ערוץ פרטי עבור %s נסגר.',
+ ignoreAdded: 'המשתמש %s נוסף לרשימת ההתעלמות.',
+ ignoreRemoved: 'המשתמש %s נמחק מרשימת ההתעלמות.',
+ ignoreList: 'משתמשים אשר אתה מתעלם מהם:',
+ ignoreListEmpty: 'אין משתמשים ברשימה.',
+ who: 'משתמשים מחוברים:',
+ whoChannel: 'Online Users in channel %s:',
+ whoEmpty: 'אין משתמשים מחוברים בערוץ.',
+ list: 'ערוצים פתוחים:',
+ bans: 'משתמשים חסומים:',
+ bansEmpty: 'אין משתמשים חסומים.',
+ unban: 'בוטלה החסימה נגד המשתמש %s.',
+ whois: 'כתובת המחשב של המשתמש %s:',
+ whereis: 'User %s is in channel %s.',
+ roll: '%s מגלגל %s ומקבל %s.',
+ nick: '%s is now known as %s.',
+ toggleUserMenu: 'Toggle user menu for %s',
+ userMenuLogout: 'Logout',
+ userMenuWho: 'List online users',
+ userMenuList: 'List available channels',
+ userMenuAction: 'Describe action',
+ userMenuRoll: 'Roll dice',
+ userMenuNick: 'Change username',
+ userMenuEnterPrivateRoom: 'Enter private room',
+ userMenuSendPrivateMessage: 'Send private message',
+ userMenuDescribe: 'Send private action',
+ userMenuOpenPrivateChannel: 'Open private channel',
+ userMenuClosePrivateChannel: 'Close private channel',
+ userMenuInvite: 'Invite',
+ userMenuUninvite: 'Uninvite',
+ userMenuIgnore: 'Ignore/Accept',
+ userMenuIgnoreList: 'List ignored users',
+ userMenuWhereis: 'Display channel',
+ userMenuKick: 'Kick/Ban',
+ userMenuBans: 'List banned users',
+ userMenuWhois: 'Display IP',
+ unbanUser: 'Revoke ban of user %s',
+ joinChannel: 'הצטרף לערוץ %s',
+ cite: '%s אמר:',
+ urlDialog: 'אנא הכנס את כתובת האינטרנט (URL) של הדף:',
+ deleteMessage: 'Delete this chat message',
+ deleteMessageConfirm: 'Really delete the selected chat message?',
+ errorCookiesRequired: 'הצאט מבקש עוגיות כדי לפעול. אנא רד לחנות לקנות.',
+ errorUserNameNotFound: 'שגיאה: המשתמש %s לא נמצא.',
+ errorMissingText: 'שגיאה: חסר טקסט בהודעה.',
+ errorMissingUserName: 'שגיאה: חסר שם משתמש.',
+ errorInvalidUserName: 'Error: Invalid username.',
+ errorUserNameInUse: 'Error: Username already in use.',
+ errorMissingChannelName: 'שגיאה: חסר שם ערוץ.',
+ errorInvalidChannelName: 'שגיאה: שם ערוץ לא חוקי: %s',
+ errorPrivateMessageNotAllowed: 'שגיאה: הודעות פרטיות אסורות לשימוש.',
+ errorInviteNotAllowed: 'שגיאה: אסור לך להזמין אנשים לערוץ זה.',
+ errorUninviteNotAllowed: 'שגיאה: אסור לך לבטל הזמנות של אנשים לערוץ זה.',
+ errorNoOpenQuery: 'שגיאה: ערוץ פרטי לא פתוח.',
+ errorKickNotAllowed: 'שגיאה: אסור לך להעיף את %s.',
+ errorCommandNotAllowed: 'שגיאה: פקודה אסורה: %s',
+ errorUnknownCommand: 'שגיאה: פקודה לא ידועה: %s',
+ errorMaxMessageRate: 'Error: You exceeded the maximum number of messages per minute.',
+ errorConnectionTimeout: 'שגיאה: זמן חיבור פג. אנא נסה שנית.',
+ errorConnectionStatus: 'שגיאת חיבור: %s',
+ errorSoundIO: 'Error: Failed to load sound file (Flash IO Error).',
+ errorSocketIO: 'Error: Connection to socket server failed (Flash IO Error).',
+ errorSocketSecurity: 'Error: Connection to socket server failed (Flash Security Error).',
+ errorDOMSyntax: 'Error: Invalid DOM Syntax (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/hr.js b/library/ajaxchat/chat/js/lang/hr.js
new file mode 100644
index 000000000..6f72e64de
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/hr.js
@@ -0,0 +1,91 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: 'Korisnik %s prijavio se u brbljanje.',
+ logout: 'Korisnik %s odjavio se iz brbljanja.',
+ logoutTimeout: 'Korisnik %s je odjavljen (neaktivnost).',
+ logoutIP: 'Korisnik %s je odjavljen (nepravilna IP adresa).',
+ logoutKicked: 'Korisnik %s je odjavljen (prognan).',
+ channelEnter: 'Korisnik %s pristupa kanalu.',
+ channelLeave: 'Korisnik %s napušta kanal.',
+ privmsg: '(šapuće)',
+ privmsgto: '(šapuće korisniku %s)',
+ invite: 'Korisnik %s poziva vas da se pridružite kanalu %s.',
+ inviteto: 'Vaš poziv korisniku %s da se pridruži kanalu %s je poslan.',
+ uninvite: 'Korisnik %s povukao je svoj poziv za kanal %s.',
+ uninviteto: 'Vaš opoziv korisniku %s za pridruživanje kanalu %s je poslan.',
+ queryOpen: 'Otvoren je privatni kanal za %s.',
+ queryClose: 'Privatni kanal za %s je zatvoren.',
+ ignoreAdded: 'Korisnik %s je dodan na popis ignoriranih.',
+ ignoreRemoved: 'Korisnik %s je uklonjen s popisa ignoriranih.',
+ ignoreList: 'Ignorirani korisnici:',
+ ignoreListEmpty: 'Nema ignoriranih korisnika.',
+ who: 'Prisutni korisnici:',
+ whoChannel: 'Prisutni korisnici u kanalu %s.',
+ whoEmpty: 'U odabranom kanalu nema prisutnih korisnika.',
+ list: 'Dostupni kanali:',
+ bans: 'Zabranjeni korisnici:',
+ bansEmpty: 'Nema zabranjenih korisnika.',
+ unban: 'Opozvana je zabrana korisnika %s.',
+ whois: 'Korisnik %s - IP adresa:',
+ whereis: 'Korisnik %s je u kanalu %s.',
+ roll: 'Korisnik %s baca %s i dobiva %s.',
+ nick: 'Korisnik %s je sad poznat kao %s.',
+ toggleUserMenu: 'Prebaci korisnički zbornik za %s',
+ userMenuLogout: 'Odjava',
+ userMenuWho: 'Ispiši prisutne korisnike',
+ userMenuList: 'Ispiši dostupne kanale',
+ userMenuAction: 'Aktivnost',
+ userMenuRoll: 'Baci kocku',
+ userMenuNick: 'Promijeni korisničko ime',
+ userMenuEnterPrivateRoom: 'Pristupi privatnoj sobi',
+ userMenuSendPrivateMessage: 'Pošalji privatnu poruku',
+ userMenuDescribe: 'Pošalji privatnu aktivnost',
+ userMenuOpenPrivateChannel: 'Otvori privatni kanal',
+ userMenuClosePrivateChannel: 'Zatvori privatni kanal',
+ userMenuInvite: 'Pozovi',
+ userMenuUninvite: 'Opozovi',
+ userMenuIgnore: 'Ignoriraj / Prihvati',
+ userMenuIgnoreList: 'Ispiši ignorirane korisnike',
+ userMenuWhereis: 'Prikaži kanal',
+ userMenuKick: 'Prognaj / Zabrani',
+ userMenuBans: 'Ispiši zabranjene korisnike',
+ userMenuWhois: 'Prikaži IP',
+ unbanUser: 'Opozovi zabranu korisnika %s.',
+ joinChannel: 'Pridruži se kanalu %s',
+ cite: 'Korisnik %s je rekao:',
+ urlDialog: 'Unesite URL adresu web-stranice:',
+ deleteMessage: 'Izbriši ovu poruku',
+ deleteMessageConfirm: 'Želite li zaista izbrisati ovu poruku?',
+ errorCookiesRequired: 'Ovo brbljanje zahtjeva omogućene kolačiće.',
+ errorUserNameNotFound: 'Pogreška: Korisnik %s nije pronađen.',
+ errorMissingText: 'Pogreška: Nedostaje tekst poruke.',
+ errorMissingUserName: 'Pogreška: Nedostaje korisničko ime.',
+ errorInvalidUserName: 'Pogreška: Nepravilno korisničko ime.',
+ errorUserNameInUse: 'Pogreška: Korisničko ime već je u upotrebi.',
+ errorMissingChannelName: 'Pogreška: Nedostaje naziv kanala.',
+ errorInvalidChannelName: 'Pogreška: Nepravilan naziv kanala: %s',
+ errorPrivateMessageNotAllowed: 'Pogreška: Privatne poruke nisu dopuštene.',
+ errorInviteNotAllowed: 'Pogreška: Nemate dopuštenja za pozivanje drugih osoba u ovaj kanal.',
+ errorUninviteNotAllowed: 'Pogreška: Nemate dopuštenja za opozivanje drugih osoba u ovom kanalu.',
+ errorNoOpenQuery: 'Pogreška: Nema otvorenog privatnog kanala.',
+ errorKickNotAllowed: 'Pogreška: Nemate dopuštenja za progon korisnika %s.',
+ errorCommandNotAllowed: 'Pogreška: Naredba nije dopuštena: %s',
+ errorUnknownCommand: 'Pogreška: Nepoznata naredba: %s',
+ errorMaxMessageRate: 'Pogreška: Premašili ste najveći dopušteni broj poruka u minuti.',
+ errorConnectionTimeout: 'Pogreška: Neaktivna veza. Pokušajte ponovo.',
+ errorConnectionStatus: 'Pogreška: Stanje veze: %s',
+ errorSoundIO: 'Pogreška: Učitavanje datoteke zvuka nije uspjelo (Flash IO pogreška).',
+ errorSocketIO: 'Pogreška: Povezivanje s priključkom poslužitelja nije uspjelo (Flash IO pogreška).',
+ errorSocketSecurity: 'Pogreška: Povezivanje s priključkom poslužitelja nije uspjelo (Flash sigurnosna pogreška).',
+ errorDOMSyntax: 'Pogreška: Nepravilna DOM sintaksa (DOM ID: %s).'
+
+}
diff --git a/library/ajaxchat/chat/js/lang/hu.js b/library/ajaxchat/chat/js/lang/hu.js
new file mode 100644
index 000000000..ec2a45e14
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/hu.js
@@ -0,0 +1,91 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s belépett a chatre.',
+ logout: '%s kilépett a chatről.',
+ logoutTimeout: '%s kilépett a chatről (Időtúllépés).',
+ logoutIP: '%s kilépett a chatről (Hamis IP cím).',
+ logoutKicked: '%s ki lett rúgva a chatről.',
+ channelEnter: '%s belépett a szobába.',
+ channelLeave: '%s kilépett a szobából.',
+ privmsg: '(suttog)',
+ privmsgto: '(suttog %s felhasználónak)',
+ invite: '%s meghívott a következő szobába: %s.',
+ inviteto: 'A meghívása %s részére a(z) %s szobába elküldve.',
+ uninvite: '%s hívatlan vendégnek tart a(z) %s szobában.',
+ uninviteto: 'Hívatlan vendég jelzője %s számára elküldve a(z) %s szobában.',
+ queryOpen: 'Privát szoba megnyitva %s felhasználónak.',
+ queryClose: 'Privát szoba bezárva %s felhasználóval.',
+ ignoreAdded: '%s hozzáadva a figyelmen kívül hagyottakhoz.',
+ ignoreRemoved: '%s eltávolítva a figyelmen kívül hagyottak közül.',
+ ignoreList: 'Figyelmen kívül hagyott felhasználók:',
+ ignoreListEmpty: 'Nincsenek figyelmen kívül hagyott felhasználók.',
+ who: 'Jelenlévők:',
+ whoChannel: 'Jelenlévők a(z) %s szobában:',
+ whoEmpty: 'Senki nincs a megadott szobában.',
+ list: 'Szobák:',
+ bans: 'Kitiltott felhasználók:',
+ bansEmpty: 'Nincs kitiltott felhasználó.',
+ unban: '%s tiltása törölve.',
+ whois: '%s IP címe:',
+ whereis: '%s a következő szobákban van: %s.',
+ roll: '%s rolls %s and gets %s.',
+ nick: '%s új nickje %s.',
+ toggleUserMenu: '%s - felhasználói menüjének mutatása',
+ userMenuLogout: 'Kilépés',
+ userMenuWho: 'Jelenlévők listája',
+ userMenuList: 'Szobák listája',
+ userMenuAction: 'Akció küldése',
+ userMenuRoll: 'Dobókocka játék',
+ userMenuNick: 'Nick cseréje',
+ userMenuEnterPrivateRoom: 'Privát szobába lépés',
+ userMenuSendPrivateMessage: 'Privát üzenet küldése',
+ userMenuDescribe: 'Privát akció küldése',
+ userMenuOpenPrivateChannel: 'Privát szoba nyitása',
+ userMenuClosePrivateChannel: 'Privát szoba bezárása',
+ userMenuInvite: 'Meghívás',
+ userMenuUninvite: 'Hívatlan vendég',
+ userMenuIgnore: 'Figyelmen kívül hagy/engedélyez',
+ userMenuIgnoreList: 'Figyelmen kívül hagyottak',
+ userMenuWhereis: 'Szobák mutatása, ahol jelen van',
+ userMenuKick: 'Kirúgás/kitiltás',
+ userMenuBans: 'Kitiltottak listája',
+ userMenuWhois: 'IP megjelenítése',
+ unbanUser: '%s kitiltásának feloldása',
+ joinChannel: 'Belépés a szobába %s',
+ cite: '%s azt mondja:',
+ urlDialog: 'Kérem írja be a honlap URL-jét:',
+ deleteMessage: 'Chat üzenet törlése',
+ deleteMessageConfirm: 'Valóban törölni akarja az üzenetet?',
+ errorCookiesRequired: 'A cookiek engedélyezése szükséges a chat használatához.',
+ errorUserNameNotFound: 'Hiba: A %s felhasználó nem található.',
+ errorMissingText: 'Hiba: hiányzó üzenet.',
+ errorMissingUserName: 'Hiba: hiányzó felhasználónév.',
+ errorInvalidUserName: 'Hiba: hamis felhasználónév.',
+ errorUserNameInUse: 'Hiba: a név már használatban van.',
+ errorMissingChannelName: 'Hiba: hiányzó szoba név.',
+ errorInvalidChannelName: 'Hiba: hamis szoba név: %s',
+ errorPrivateMessageNotAllowed: 'Hiba: a privát üzenetek nem engedélyezettek.',
+ errorInviteNotAllowed: 'Hiba: nem vagy jogosult felhasználókat meghívni a szobába.',
+ errorUninviteNotAllowed: 'Hiba: nem vagy jogosult hívatlan vendégnek titulálni bárkit a szobában.',
+ errorNoOpenQuery: 'Hiba: nincs jogod szobát nyitni.',
+ errorKickNotAllowed: 'Hiba: nincs jogod kirúgni %s-t.',
+ errorCommandNotAllowed: 'Hiba: a parancs nem engedélyezett: %s',
+ errorUnknownCommand: 'Hiba: ismeretlen parancs: %s',
+ errorMaxMessageRate: 'Hiba: elérted a percenként küldhető maximális üzenet számot.',
+ errorConnectionTimeout: 'Hiba: időtúllépés! Próbáld újra!.',
+ errorConnectionStatus: 'Hiba: a kapcsolat állapota: %s',
+ errorSoundIO: 'Hiba: a hangfájl betöltése sikertelen. (I/O)',
+ errorSocketIO: 'Hiba: kapcsolódás a socket szerverhez sikertelen. (I/O)',
+ errorSocketSecurity: 'Hiba: kapcsolódás a socket szerverhez sikertelen. (Biztonsági hiba!)',
+ errorDOMSyntax: 'Hiba: Hibás DOM szintaxis (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/in.js b/library/ajaxchat/chat/js/lang/in.js
new file mode 100644
index 000000000..582b9703b
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/in.js
@@ -0,0 +1,91 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s masuk ke chat.',
+ logout: '%s keluar dari chat.',
+ logoutTimeout: '%s telah keluar dari saluran (Timeout).',
+ logoutIP: '%s elah keluar dari saluran (Invalid IP address).',
+ logoutKicked: '%s elah keluar dari saluran (Kicked).',
+ channelEnter: '%s masuk saluran.',
+ channelLeave: '%s meninggalkan.',
+ privmsg: '(berbisik)',
+ privmsgto: '(berbisik ke %s)',
+ invite: '%s mengundang anda untuk gabung ke %s.',
+ inviteto: 'Undangan anda ke %s untuk gabung saluran %s telah dikirim.',
+ uninvite: '%s membatalkan untuk mengundang anda dari saluran %s.',
+ uninviteto: 'Pembatalan undangan anda ke %s untuk salura %s telah dikirim.',
+ queryOpen: 'Saluran Privasi telah dibuka untuk %s.',
+ queryClose: 'Saluran Privasi untuk %s telah ditutup.',
+ ignoreAdded: 'Menambah %s ke daftar yang diacuhkan.',
+ ignoreRemoved: 'Mencabut %s dari daftar yang diacuhkan.',
+ ignoreList: 'Acuhkan pengguna:',
+ ignoreListEmpty: 'Tidak ada nama dalam daftar yang diacuhkan.',
+ who: 'Pengguna online:',
+ whoChannel: 'Pengguna-2 yang online di saluran %s:',
+ whoEmpty: 'Tidak ada pengguna yang online di saluran tersebut.',
+ list: 'Saluran yang tersedia:',
+ bans: 'Pengguna yang diblok:',
+ bansEmpty: 'Tidak ada pengguna yang diblok.',
+ unban: 'Pembatalan Blok pengguna %s .',
+ whois: 'Alamat IP Pengguna %s :',
+ whereis: 'Pengguna %s ada di saluran %s.',
+ roll: '%s melempar %s dan mendapatkan %s.',
+ nick: '%s sekarang dikenal sebagai %s.',
+ toggleUserMenu: 'Tombol menu pengguna untuk %s',
+ userMenuLogout: 'Keluar',
+ userMenuWho: 'Daftar pengguna yang online',
+ userMenuList: 'Daftar saluran-saluran yang tersedia',
+ userMenuAction: 'Menjelaskan tindakan',
+ userMenuRoll: 'Melempar Dadu',
+ userMenuNick: 'Mengganti Nama',
+ userMenuEnterPrivateRoom: 'Memasuki ruang privasi',
+ userMenuSendPrivateMessage: 'Kirim pesan pribadi',
+ userMenuDescribe: 'Kirim tindakan pribadi',
+ userMenuOpenPrivateChannel: 'Buka Saluran Privasi',
+ userMenuClosePrivateChannel: 'Tutup Saluran Privasi',
+ userMenuInvite: 'Mengundang',
+ userMenuUninvite: 'Tidak Mengundang',
+ userMenuIgnore: 'Acuhkan/Terima',
+ userMenuIgnoreList: 'Daftar Pengguna yang diacuhkan',
+ userMenuWhereis: 'Tampilkan Saluran',
+ userMenuKick: 'Tendang/Blok',
+ userMenuBans: 'Daftar Pengguna yang diblok',
+ userMenuWhois: 'Tampilkan IP',
+ unbanUser: 'Batalkan blok pengguna %s',
+ joinChannel: 'Gabung Saluran %s',
+ cite: '%s berkata:',
+ urlDialog: 'Mohon masukan alamat (URL) of the web:',
+ deleteMessage: 'Hapus pesan chat ini',
+ deleteMessageConfirm: 'Yakin akan menghapus pesan chat yang dipilih?',
+ errorCookiesRequired: 'Cookies diperlukan untuk chat.',
+ errorUserNameNotFound: 'Error: Pengguna %s tidak ada.',
+ errorMissingText: 'Error: Teks pesan tidak ada.',
+ errorMissingUserName: 'Error: Nama tidak ada.',
+ errorInvalidUserName: 'Error: Kesalahan pada Nama.',
+ errorUserNameInUse: 'Error: Nama telah dipakai.',
+ errorMissingChannelName: 'Error: Nama saluran belum ada.',
+ errorInvalidChannelName: 'Error: Kesalahan pada nama saluran: %s',
+ errorPrivateMessageNotAllowed: 'Error: Pesan pribadi tidak diijinkan.',
+ errorInviteNotAllowed: 'Error: Anda tidak diijinkan untuk mengundang orang lain ke saluran ini.',
+ errorUninviteNotAllowed: 'Error: Anda tidak diijinkan untuk tidak mengundang seseorang ke saluran ini.',
+ errorNoOpenQuery: 'Error: Tidak ada saluran privasi yang dibuka.',
+ errorKickNotAllowed: 'Error: Anda tidak diijinkan untuk menendang %s.',
+ errorCommandNotAllowed: 'Error: Perintah tidak diijinkan: %s',
+ errorUnknownCommand: 'Error: Perintah tidak diketahui: %s',
+ errorMaxMessageRate: 'Error: Anda telah melampaui batas pesan maksimum per menitnya.',
+ errorConnectionTimeout: 'Error: Koneksi putus. Mohon dicoba kembali.',
+ errorConnectionStatus: 'Error: Status koneksi: %s',
+ errorSoundIO: 'Error: Gagal mengeluarkan suara (Flash IO Error).',
+ errorSocketIO: 'Error: Gagal mengadakan koneksi ke server (Flash IO Error).',
+ errorSocketSecurity: 'Error: Gagal mengadakan koneksi ke server (Flash Security Error).',
+ errorDOMSyntax: 'Error: Sintaks DOM yang tidak dikenal(DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/index.html b/library/ajaxchat/chat/js/lang/index.html
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/index.html
diff --git a/library/ajaxchat/chat/js/lang/it.js b/library/ajaxchat/chat/js/lang/it.js
new file mode 100644
index 000000000..a84c47ff9
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/it.js
@@ -0,0 +1,93 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author s8s8
+ * @author Massimiliano Tiraboschi
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s entra in Chat.',
+ logout: '%s esce dalla Chat.',
+ logoutTimeout: '%s esce (TimeOut).',
+ logoutIP: '%s esce (IP non valido).',
+ logoutKicked: '%s esce (Kicked).',
+ channelEnter: '%s entra nel canale.',
+ channelLeave: '%s lascia il canale.',
+ privmsg: '(privato)',
+ privmsgto: '(privato a %s)',
+ invite: '%s ti invita a entrare in %s.',
+ inviteto: 'Il tuo invito ad entrare nel canale %s è stato inviato a %s.',
+ uninvite: '%s ha rimosso il tuo invito per %s.',
+ uninviteto: 'Rimosso invito per %s per il canale %s.',
+ queryOpen: 'Canale privato aperto con %s.',
+ queryClose: 'Canale privato con %s chiuso.',
+ ignoreAdded: '%s aggiunto agli ingorati.',
+ ignoreRemoved: '%s rimosso dagli ignorati.',
+ ignoreList: 'Utenti Ignorati:',
+ ignoreListEmpty: 'Utenti permessi.',
+ who: 'Utenti Online:',
+ whoChannel: 'Utenti Online nel canale %s:',
+ whoEmpty: 'Nessun utente in linea nel canale.',
+ list: 'Canali disponibili:',
+ bans: 'Utenti Bannati:',
+ bansEmpty: 'Nessun utente bannato in lista.',
+ unban: 'Ban di %s rimosso.',
+ whois: '%s - IP:',
+ whereis: 'User %s is in channel %s.',
+ roll: '%s lancia %s e fa %s.',
+ nick: '%s è conosciuto ora come %s.',
+ toggleUserMenu: 'Mostra/Nascondi menu per %s',
+ userMenuLogout: 'Esci',
+ userMenuWho: 'Lista utenti online',
+ userMenuList: 'Lista canali disponibili',
+ userMenuAction: 'Descrivi azione',
+ userMenuRoll: 'Getta dadi',
+ userMenuNick: 'Cambia username',
+ userMenuEnterPrivateRoom: 'Entra canale privato',
+ userMenuSendPrivateMessage: 'Invia messaggio privato',
+ userMenuDescribe: 'Invia azione privata',
+ userMenuOpenPrivateChannel: 'Apri canale privato',
+ userMenuClosePrivateChannel: 'Chiudi canale privato',
+ userMenuInvite: 'Invita',
+ userMenuUninvite: 'Disinvita',
+ userMenuIgnore: 'Ignora/Accetta',
+ userMenuIgnoreList: 'Lista utenti ignorati',
+ userMenuWhereis: 'Mostra canale',
+ userMenuKick: 'Butta fuori/Banna',
+ userMenuBans: 'Lista utenti bannati',
+ userMenuWhois: 'Mostra IP',
+ unbanUser: 'Revoca il ban per l\'utente %s',
+ joinChannel: 'Entra nel canale %s',
+ cite: '%s dice:',
+ urlDialog: 'Inserire indirizzo (URL) della pagina Web:',
+ deleteMessage: 'Cancella questo messaggio',
+ deleteMessageConfirm: 'Sicuro di cancellare il messaggio selezionato ?',
+ errorCookiesRequired: 'I Cookies sono richiesti per questa chat.',
+ errorUserNameNotFound: 'Errore: Utente %s non trovato.',
+ errorMissingText: 'Errore: Messaggio di testo non trovato.',
+ errorMissingUserName: 'Errore: Nome Utente non trovato.',
+ errorInvalidUserName: 'Error: Invalid username.',
+ errorUserNameInUse: 'Error: Username already in use.',
+ errorMissingChannelName: 'Errore: Canale non trovato.',
+ errorInvalidChannelName: 'Errore: Nome canale non valido: %s',
+ errorPrivateMessageNotAllowed: 'Errore: Messaggi privati non permessi.',
+ errorInviteNotAllowed: 'Errore: Non hai il permesso di invitare in questo canale.',
+ errorUninviteNotAllowed: 'Errore: Non hai il permesso di rimuovere inviti per queso canale.',
+ errorNoOpenQuery: 'Errore: Nessun canale privato aperto.',
+ errorKickNotAllowed: 'Errore: Non sei abilitato a Kikkare %s.',
+ errorCommandNotAllowed: 'Errore: Comando non permesso: %s',
+ errorUnknownCommand: 'Errore: Comando sconosciuto: %s',
+ errorMaxMessageRate: 'Errore: Hai superato il numero massimo di messaggi per minuto.',
+ errorConnectionTimeout: 'Errore: Connessione persa. Riprovare.',
+ errorConnectionStatus: 'Errore: Stato di Connessione: %s',
+ errorSoundIO: 'Errore: Caricamento files suono fallito (Flash IO Error).',
+ errorSocketIO: 'Errore: Connection to socket server failed (Flash IO Error).',
+ errorSocketSecurity: 'Error: Connection to socket server failed (Flash Security Error).',
+ errorDOMSyntax: 'Error: Invalid DOM Syntax (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/ja.js b/library/ajaxchat/chat/js/lang/ja.js
new file mode 100644
index 000000000..5d87d2eea
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/ja.js
@@ -0,0 +1,91 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s さんがログインしました',
+ logout: '%s さんがログアウトしました',
+ logoutTimeout: '%s さんが強制的にログアウトされました (タイムアウト)',
+ logoutIP: '%s さんが強制的にログアウトされました (不正な IPアドレス)',
+ logoutKicked: '%s さんが強制的にログアウトされました (キック).',
+ channelEnter: '%s さんが入室しました',
+ channelLeave: '%s さんが退室しました',
+ privmsg: '(プライベートメッセージ)',
+ privmsgto: '(%s さんへプライベートメッセージ)',
+ invite: '%s さんから チャンネル %s への招待 が届いています',
+ inviteto: '%s さんへ チャンネル %s への招待 を送りました',
+ uninvite: '%s さんから チャンネル %s への招待 を取り消されました',
+ uninviteto: '%s さんの チャンネル %s への招待 を取り消しました',
+ queryOpen: '二人きりモードを %s さんと開始しました',
+ queryClose: '%s さんとの二人きりモードを終了しました',
+ ignoreAdded: '%s さんを無視ユーザーリストに追加しました',
+ ignoreRemoved: '%s さんを無理ユーザーリストから削除しました',
+ ignoreList: '無視ユーザーリスト :',
+ ignoreListEmpty: 'あなたはどのユーザーも無視していません',
+ who: 'オンラインユーザー :',
+ whoChannel: 'チャンネル %s に入室中のユーザー :',
+ whoEmpty: 'そのチャンネルに入室中のユーザーは一人もいません',
+ list: '入室可能なチャンネル :',
+ bans: 'アクセス禁止ユーザーリスト :',
+ bansEmpty: 'アクセス禁止されたユーザーは一人もいません',
+ unban: 'ユーザー %s のアクセス禁止を取り消しました',
+ whois: 'ユーザー %s の IPアドレス :',
+ whereis: 'ユーザー %s はチャンネル %s にいます',
+ roll: '%s さんがサイコロを振りました。 %s - 結果 %s',
+ nick: '%s さんのニックネームは以降 %s です',
+ toggleUserMenu: '%s さんのユーザーメニューを表示する/表示しない',
+ userMenuLogout: 'ログアウト',
+ userMenuWho: 'オンラインユーザーリスト',
+ userMenuList: '入室可能なチャンネルのリスト',
+ userMenuAction: '感情を表現する',
+ userMenuRoll: 'サイコロを振る',
+ userMenuNick: 'ニックネーム',
+ userMenuEnterPrivateRoom: 'プライベートルームへ移動する',
+ userMenuSendPrivateMessage: 'プライベートメッセージを送る',
+ userMenuDescribe: '感情を表現する',
+ userMenuOpenPrivateChannel: '二人きりモードを開始する',
+ userMenuClosePrivateChannel: '二人きりモードを終了する',
+ userMenuInvite: '招待する',
+ userMenuUninvite: '招待を取り消す',
+ userMenuIgnore: '無視する/無視しない',
+ userMenuIgnoreList: '無視ユーザーリスト',
+ userMenuWhereis: 'ユーザーの居場所',
+ userMenuKick: 'キック/アクセス禁止',
+ userMenuBans: 'アクセス禁止ユーザーリスト',
+ userMenuWhois: 'IPアドレス',
+ unbanUser: 'ユーザー %s のアクセス禁止を取り消す',
+ joinChannel: 'チャンネル %s へ移動する',
+ cite: '%s さんが言いました :',
+ urlDialog: 'サイトのアドレス (URL) を入力してください :',
+ deleteMessage: 'このチャットメッセージを削除する',
+ deleteMessageConfirm: 'チャットメッセージを本当に削除してもよろしいですか?',
+ errorCookiesRequired: 'このチャットシステムを利用するには Cookie を有効にしておく必要があります',
+ errorUserNameNotFound: 'エラー : ユーザー %s が見つかりませんでした',
+ errorMissingText: 'エラー : メッセージが未入力です',
+ errorMissingUserName: 'エラー : ユーザー名が未入力です',
+ errorInvalidUserName: 'エラー : ユーザー名が正しくありません',
+ errorUserNameInUse: 'エラー : そのユーザー名は既に使われています',
+ errorMissingChannelName: 'エラー : チャンネル名が未入力です',
+ errorInvalidChannelName: 'エラー : チャンネル名が正しくありません : %s',
+ errorPrivateMessageNotAllowed: 'エラー : プライベートメッセージが許可されていません',
+ errorInviteNotAllowed: 'エラー : あなたはこのチャンネルで誰かを招待することを許可されていません',
+ errorUninviteNotAllowed: 'エラー : あなたはこのチャンネルで誰かの招待を取り消すことを許可されていません',
+ errorNoOpenQuery: 'エラー : 二人きりモードが開始されていません',
+ errorKickNotAllowed: 'エラー : あなたは %s さんをキックすることを許可されていません',
+ errorCommandNotAllowed: 'エラー : コマンドが許可されていません : %s',
+ errorUnknownCommand: 'エラー : コマンドが不正です : %s',
+ errorMaxMessageRate: 'エラー : 1分あたりに発言できる最大文字数を超えています',
+ errorConnectionTimeout: 'エラー : 接続がタイムアウトしました。再度試してください。',
+ errorConnectionStatus: 'エラー : 接続ステータス : %s',
+ errorSoundIO: 'エラー : サウンドファイルの読み込みに失敗しました (Flash IO Error)',
+ errorSocketIO: 'エラー : ソケットサーバへの接続に失敗しました (Flash IO Error)',
+ errorSocketSecurity: 'エラー : ソケットサーバへの接続に失敗しました (Flash Security Error)',
+ errorDOMSyntax: 'エラー : DOM の文法が不正です (DOM ID: %s)'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/ka.js b/library/ajaxchat/chat/js/lang/ka.js
new file mode 100644
index 000000000..6f0a24d72
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/ka.js
@@ -0,0 +1,91 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s ჩატში შემოვიდა.',
+ logout: '%s ჩატიდან გავიდა.',
+ logoutTimeout: '%s ჩატი დატოვა (დრო ამოიწურა).',
+ logoutIP: '%s ჩატი დატოვა (არასწორი IP მისამართი).',
+ logoutKicked: '%s ჩატი დატოვა (ამოარტყეს).',
+ channelEnter: '%s უერთდება არხს.',
+ channelLeave: '%s ტოვებს არხს.',
+ privmsg: '(ჩურჩულებს)',
+ privmsgto: '(%s-ს უჩურჩულებს)',
+ invite: '%s გეპაიჟებათ შეუერთდეთ %s-ს.',
+ inviteto: '%s-თვის შექმნილი მოსაწვევი, რათა შეუერთდეს არხ %s-ს, გაგზავნილია.',
+ uninvite: '%s თავის დაპატიჟებას არხ %s-თვის აუქმებს.',
+ uninviteto: '%s-თვის დაწერილი, %s არხის მოსაწვევის გაუქმება გაგხავნილია.',
+ queryOpen: 'პირადი არხი %s-სთან გასხნილია.',
+ queryClose: 'პირადი არხი %s-სთან დახურულია.',
+ ignoreAdded: '%s იგნორირების სიას დაემატა.',
+ ignoreRemoved: '%s იგნორირების სიიდან ამოღებულია.',
+ ignoreList: 'იგნორირებულები:',
+ ignoreListEmpty: 'იგნორირებული წევრები არაა.',
+ who: 'ხაზზე არიან:',
+ whoChannel: 'არხ %s-ში ხაზზე არიან:',
+ whoEmpty: 'მოცემულ არხში ხაზზე არავინაა.',
+ list: 'ხელმისაწვდომი არხები:',
+ bans: 'დაბლოკილი წევრები:',
+ bansEmpty: 'დაბლოკილი წევრები არაა.',
+ unban: '%s წევრის ბლოკი მოხსნილია.',
+ whois: '%s წევრის - IP მისამართი:',
+ whereis: 'წევრი %s იმყოფება %s არხში.',
+ roll: '%s აგდებს %s-ს და იღებს %s-ს.',
+ nick: '%s ახლა ცნობილია როგორც %s.',
+ toggleUserMenu: 'წევრის მენიუს %s-თვის ჩართვა/გათიშვა',
+ userMenuLogout: 'გასვლა',
+ userMenuWho: 'ჩამოწერე ხაზზე ვინაა',
+ userMenuList: 'ჩამოწერე ხელმისაწვდომი არხები',
+ userMenuAction: 'აღწერე ქმედება',
+ userMenuRoll: 'კამათლების გაგორება',
+ userMenuNick: 'მეტსახელის შეცვლა',
+ userMenuEnterPrivateRoom: 'პირად ოთახში შესვლა',
+ userMenuSendPrivateMessage: 'პირადი მიმოწერა',
+ userMenuDescribe: 'პირადი ქმედების გაგზავნა',
+ userMenuOpenPrivateChannel: 'გახსენი პირადი არხი',
+ userMenuClosePrivateChannel: 'დახურე პირადი არხი',
+ userMenuInvite: 'დაპატიჟება',
+ userMenuUninvite: 'დაპატიჟების გაუქმება',
+ userMenuIgnore: 'იგნორირება/მიღება',
+ userMenuIgnoreList: 'ჩამოწერე იგნორირებულები',
+ userMenuWhereis: 'მაჩვენე არხი',
+ userMenuKick: 'ამორტყმა/დაბლოკვა',
+ userMenuBans: 'დაბლოკილების ჩამოწერა',
+ userMenuWhois: 'IP-ს ჩვენება',
+ unbanUser: '%s წევრის ბლოკის მოხსნა',
+ joinChannel: '%s არხში შესვლა',
+ cite: '%s თქვა:',
+ urlDialog: 'გთხოვთ შეიყვანოთ ვებ-გვერდის მისამართი (URL):',
+ deleteMessage: 'გზავნილის წაშლა',
+ deleteMessageConfirm: 'მართლა წავშალოთ ეს გზავნილი?',
+ errorCookiesRequired: 'ჩატისთვის cookies არიან საჭირო.',
+ errorUserNameNotFound: 'შეცდომა: წევრი %s არ მოიძებნა.',
+ errorMissingText: 'შეცდომა: გზავნილის ტექსტი აკლია.',
+ errorMissingUserName: 'შეცდომა: აკლია მეტსახელი.',
+ errorInvalidUserName: 'შეცდომა: არასწორი მეტსახელი.',
+ errorUserNameInUse: 'შეცდომა: მეტსახელი დაკავებულია.',
+ errorMissingChannelName: 'შეცდომა: აკლია არხის სახელი.',
+ errorInvalidChannelName: 'შეცდომა: არხის სახელი - %s - არასწორია',
+ errorPrivateMessageNotAllowed: 'შეცდომა: პირადი მიმოწერა აკრზალულია.',
+ errorInviteNotAllowed: 'შეცდომა: უფლება არ გაქვთ მიმდინარე არხში ვინმე მოიწვიოთ.',
+ errorUninviteNotAllowed: 'შეცდომა: უფლება არ გაქავთ მინდინარე არხიდან ვინმესი გაგდება.',
+ errorNoOpenQuery: 'შეცდომა: პირადი არხები გახსნილი არაა.',
+ errorKickNotAllowed: 'შეცდომა: უფლება არ გაგჩნიათ %s-ს ამოარტყათ.',
+ errorCommandNotAllowed: 'შეცდომა: ბრზანება - %s - აკრძალულია',
+ errorUnknownCommand: 'შეცდომა: ბრძანება - %s - უცნობია',
+ errorMaxMessageRate: 'შეცდომა: თქვენ მიაღწიეთ წუთში მაქსიმალურ შესაძლებელ გზავნილების რიცხვს.',
+ errorConnectionTimeout: 'შეცდომა: კავშირს ვადა გაუვიდა. გთხოვთ, კიდევ სცადეთ.',
+ errorConnectionStatus: 'შეცდომა: კავშირის სტატუსი: %s',
+ errorSoundIO: 'შეცდომა: ხმის ფაილი ვერ ჩაიტვირთა (Flash IO Error).',
+ errorSocketIO: 'შეცდომა: სერვერის სოკეტთან დაკავშირება ჩაიშალა (Flash IO Error).',
+ errorSocketSecurity: 'შეცდომა: სერვერის სოკეტთან დაკავშირება ჩაიშალა (Flash Security Error).',
+ errorDOMSyntax: 'შეცდომა: არასწორი DOM სინტაქსი (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/kr.js b/library/ajaxchat/chat/js/lang/kr.js
new file mode 100644
index 000000000..27ef9196d
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/kr.js
@@ -0,0 +1,91 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s께서 접속하였습니다.',
+ logout: '%s님께서 접속을 종료하였습니다.',
+ logoutTimeout: '%s님께서 시간초과로 나가셨습니다.',
+ logoutIP: '%s님께서 IP주소문제로 나가셨습니다.',
+ logoutKicked: '%s님께서 추방되었습니다.',
+ channelEnter: '%s님께서 들어오셨습니다.',
+ channelLeave: '%s님께서 나가셨습니다.',
+ privmsg: '(귓속말)',
+ privmsgto: '(%s에게 귓속말)',
+ invite: '%s님께서 %s채널에서 초대하셨습니다.',
+ inviteto: '%s을 %s채널로 초대하는 메시지를 보냈습니다..',
+ uninvite: '%s님께서 %s채널로의 초대를 취소하였습니다.',
+ uninviteto: '%s님께 %s채널로의 초대를 취소하는 메시지를 보냈습니다',
+ queryOpen: '%s님의 개인채널이 열렸습니다.',
+ queryClose: '%s님의 개인채널이 닫혔습니다.',
+ ignoreAdded: '%s님을 대화차단 목록에 추가하였습니다.',
+ ignoreRemoved: '%s님을 대화차단 목록에서 삭제하였습니다.',
+ ignoreList: '차단된 사용자:',
+ ignoreListEmpty: '차단된 사용자가 없습니다.',
+ who: '접속중인 사용자:',
+ whoChannel: '%s채널에 접속중인 사용자:',
+ whoEmpty: '해당 채널에 접속중인 사용자가 없습니다.',
+ list: '사용가능한 채널:',
+ bans: '추방된 사용자:',
+ bansEmpty: '추방된 사용자가 없습니다.',
+ unban: '%s을 다시 복구하였습니다.',
+ whois: '%s - IP주소:',
+ whereis: '%s님은 %s 채널에 계십니다.',
+ roll: '%s 롤 %s 및 도착 %s.',
+ nick: '%s님의 닉네임은 %s입니다.',
+ toggleUserMenu: '에 대한 전환 사용자 메뉴 %s',
+ userMenuLogout: '로그아웃',
+ userMenuWho: '접속중인 사용자',
+ userMenuList: '채널목록',
+ userMenuAction: '작업을 설명',
+ userMenuRoll: '주사위',
+ userMenuNick: '대화명 변경',
+ userMenuEnterPrivateRoom: '개인 대화방 입장',
+ userMenuSendPrivateMessage: '귓속말 전송',
+ userMenuDescribe: '개인 작업을 보내기',
+ userMenuOpenPrivateChannel: '개인 채널 개설',
+ userMenuClosePrivateChannel: '개인 채널 닫기',
+ userMenuInvite: '초대',
+ userMenuUninvite: '초대 취소',
+ userMenuIgnore: '차단/수락',
+ userMenuIgnoreList: '대화차단 목록',
+ userMenuWhereis: '채널확인',
+ userMenuKick: '추방',
+ userMenuBans: '추방된 사용자 목록',
+ userMenuWhois: '접속주소 확인',
+ unbanUser: '%s 사용자를 추방취소',
+ joinChannel: '%s 채널에 접속',
+ cite: '%s님의 말:',
+ urlDialog: '웹페이지의 주소를 입력하세요:',
+ deleteMessage: '이 메시지 삭제',
+ deleteMessageConfirm: '선택한 메시지를 삭제하시겠습니까?',
+ errorCookiesRequired: '쿠키 사용으로 설정하세요.',
+ errorUserNameNotFound: '오류: %s님을 찾을 수 없습니다.',
+ errorMissingText: '오류: 메시지를 찾을 수 없습니다.',
+ errorMissingUserName: '오류: 대화명을 찾을 수 없습니다.',
+ errorInvalidUserName: '오류: 잘못된 대화명입니다.',
+ errorUserNameInUse: '오류: 이미 사용중인 대화명입니다.',
+ errorMissingChannelName: '오류: 채널명을 찾을 수 없습니다.',
+ errorInvalidChannelName: '오류: %s 채널이 없습니다.',
+ errorPrivateMessageNotAllowed: '오류: 귓속말을 사용할 수 없습니다.',
+ errorInviteNotAllowed: '오류: 이 채널로 다른 사용자를 초대하는 권한이 없습니다.',
+ errorUninviteNotAllowed: '오류: 다른 사용자의 초대를 취소할 권한이 없습니다.',
+ errorNoOpenQuery: '오류: 열려있는 개인 채널이 없습니다..',
+ errorKickNotAllowed: '오류: %s를 추방할 수 있는 권한이 없습니다.',
+ errorCommandNotAllowed: '오류: %s 명령을 사용할 수 없습니다.',
+ errorUnknownCommand: '오류: %s은 없는 명령어입니다.',
+ errorMaxMessageRate: '오류: 1분동안 연속해서 입력할 수 있는 메시지 수를 초과하였습니다.',
+ errorConnectionTimeout: '오류: 접속시간을 초과하였습니다.',
+ errorConnectionStatus: '오류: 접속 상태: %s',
+ errorSoundIO: '오류: 입출력 실패로 소리파일을 불러오는데 실패하였습니다.',
+ errorSocketIO: '오류: 입출력 실패로 서버에 접속하는데 실패하였습니다.',
+ errorSocketSecurity: '오류: 보안문제로 서버에 접속하는데 실패하였습니다.',
+ errorDOMSyntax: '오류: DOM 문법이 잘못되었습니다. (DOM ID: %s).'
+
+}
diff --git a/library/ajaxchat/chat/js/lang/mk.js b/library/ajaxchat/chat/js/lang/mk.js
new file mode 100644
index 000000000..8ca441112
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/mk.js
@@ -0,0 +1,9 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author Nebojsa Ilijoski
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+var ajaxChatLang={login:"%s се приклучи на четот.",logout:"%s излезе од четот.",logoutTimeout:"%s излезе автоматски од четот (Истече времето).",logoutIP:"%s излезе автоматски од четот (Погрешна IP адреса).",logoutKicked:"%s излезе автоматски од четот (Злоупотреба).",channelEnter:"%s се прилкучи на каналот.",channelLeave:"%s го напушти канала.",privmsg:"(шепоти)",privmsgto:"(шепоти на %s)",invite:"%s ве кани да се приклучите со него %s.",inviteto:"Поканата за %s да се приклучи на каналот %s беше испратена.",uninvite:"%s е отпоканет на поканата за каналот %s.",uninviteto:"Отпоканата на поканата до %s за каналот %s беше испратена.",queryOpen:"Отворен е приватен канал за %s.",queryClose:"Затворен е приватен канал за %s.",ignoreAdded:"%s е ставен на списокот на игнорирани.",ignoreRemoved:"%s беше отстранет од списокот на игнорирани.",ignoreList:"Игнорирани корисници:",ignoreListEmpty:"Нема игнорирани корисници.",who:"Оnline корисници:",whoChannel:"Online корисници на каналот %s:",whoEmpty:"На дадениот канал нема online корисници.",list:"Приватни канали:",bans:"Блокирани корисници:",bansEmpty:"Нема блокирани корисници.",unban:"Блокирањето на корисникот %s е завршено.",whois:"Корисникот %s — IP адреса:",whereis:"Корисникот %s е на канал %s.",roll:"%s фрли %s и доби %s.",nick:"%s веќе се нарекува %s.",toggleUserMenu:"Прикажување/скривање на корисничкото мени за %s",userMenuLogout:"Излези",userMenuWho:"Online корисници",userMenuList:"Приватни канали",userMenuAction:"Опис на дејство",userMenuRoll:"Фрлање на коцка",userMenuNick:"Промена на името",userMenuEnterPrivateRoom:"Влез во приватна соба",userMenuSendPrivateMessage:"Испраќање на приватна порака",userMenuDescribe:"Испраќање на приватно дејство",userMenuOpenPrivateChannel:"Отварање на приватен канал",userMenuClosePrivateChannel:"Затварање на приватен канал",userMenuInvite:"Покана",userMenuUninvite:"Одговор на покана",userMenuIgnore:"Одбивање/прифаќање",userMenuIgnoreList:"Игнорирани корисници",userMenuWhereis:"Преглед на канал",userMenuKick:"Прифаќање/Блокирање",userMenuBans:"Блокирани корисници",userMenuWhois:"Преглед на IP адреса",unbanUser:"Одблокирање на %s",joinChannel:"Присоединување кон каналот %s",cite:"%s рече:",urlDialog:"Ве молам, внесете адреса (URL) на страницата:",deleteMessage:"Бришење на пораката",deleteMessageConfirm:"Дали сте сигурни дека сакате да е избришете пораката?",errorCookiesRequired:"За четот е потребно да се активни cookies.",errorUserNameNotFound:"Грешка: Корисникот %s не е пронајден.",errorMissingText:"Грешка: Недостасува текст од пораката.",errorMissingUserName:"Грешка: Недостасува корисничкото име.",errorInvalidUserName:"Грешка: Погрешно корисничко име.",errorUserNameInUse:"Грешка: Корисничкото име веќе е во употреба.",errorMissingChannelName:"Грешка: Недостасува името на каналот.",errorInvalidChannelName:"Грешка: Името на каналот не е валидно: %s",errorPrivateMessageNotAllowed:"Грешка: Лични пораки не се дозволени.",errorInviteNotAllowed:"Грешка: Не ви е позволено да каните корисници на овој канал.",errorUninviteNotAllowed:"Грешка: Не ви е дозволено да отпоканување на овој канал.",errorNoOpenQuery:"Грешка: Не е отворен приватен канал.",errorKickNotAllowed:"Грешка: Не ви е дозволено да исфрлате %s.",errorCommandNotAllowed:"Грешка: Командата не е дозволена: %s",errorUnknownCommand:"Грешка: Непозната команда: %s",errorMaxMessageRate:"Грешка: Го надминавте максималниот број пораки во минута.",errorConnectionTimeout:"Грешка: Истече на времето на врската. Ве молам обидете се повторно!",errorConnectionStatus:"Грешка: Состојба на врската: %s",errorSoundIO:"Грешка: Неуспешно поставување на звукот (Влезно-излезна грешка на Флешот).",errorSocketIO:"Грешка: Неуспешна врска кон сокетниот сервер (Влезно-излезна грешка на Флешот).",errorSocketSecurity:"Грешка: Неуспешна врска кон сокетниот сервер (Грешка во сигурноста на Флашот).",errorDOMSyntax:"Грешка: Погрешна синтакса на DOM (DOM ID: %s)."}; \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/nl-be.js b/library/ajaxchat/chat/js/lang/nl-be.js
new file mode 100644
index 000000000..4184ce7c9
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/nl-be.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author Nic Mertens
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s komt in het chatkanaal.',
+ logout: '%s verlaat het chatkanaal.',
+ logoutTimeout: '%s verlaat het chatkanaal (Timeout).',
+ logoutIP: '%s is afgemeld (Ongeldig IP address).',
+ logoutKicked: '%s is afgemeld (Kick door admin of moderator).',
+ channelEnter: '%s komt het kanaal binnen.',
+ channelLeave: '%s verlaat het kanaal.',
+ privmsg: '(fluistert)',
+ privmsgto: '(fluistert naar %s)',
+ invite: '%s nodigt je uit om naar %s te komen.',
+ inviteto: 'Je uitnodiging naar %s om het kanaal %s te bezoeken, werd verstuurd.',
+ uninvite: '%s annuleert de uitnodiging van kanaal %s.',
+ uninviteto: 'De annulatie van je uitnodiging aan %s voor het kanaal %s werd verstuurd.',
+ queryOpen: 'Privékanaal geopend naar %s.',
+ queryClose: 'Privékanaal naar %s wordt gesloten.',
+ ignoreAdded: '%s is toegevoegd aan de negeer lijst.',
+ ignoreRemoved: '%s werd verwijderd van de negeerlijst.',
+ ignoreList: 'Genegeerde gebruikers:',
+ ignoreListEmpty: 'Er zijn geen genegeerde gebruikers.',
+ who: 'Online gebruikers:',
+ whoChannel: 'Online gebruikers in channel %s:',
+ whoEmpty: 'Er zijn geen gebruikers in het gekozen kanaal.',
+ list: 'Beschikbare kanalen:',
+ bans: 'Gebande gebruikers:',
+ bansEmpty: 'Er zijn geen gebande gebruikers.',
+ unban: 'Ban van gebruiker %s opgeheven.',
+ whois: 'Gebruiker %s - IP adres:',
+ whereis: 'User %s is in channel %s.',
+ roll: '%s smijt %s en krijgt %s.',
+ nick: '%s heet nu %s.',
+ toggleUserMenu: 'Open menu voor gebruiker %s',
+ userMenuLogout: 'Afmelden',
+ userMenuWho: 'Lijst online gebruikers',
+ userMenuList: 'Lijst beschikbaare kanalen',
+ userMenuAction: 'Beschrijf actie',
+ userMenuRoll: 'Rol dobbelsteen',
+ userMenuNick: 'Wijzig gebruikersnaam',
+ userMenuEnterPrivateRoom: 'Ga privékanaal binnen',
+ userMenuSendPrivateMessage: 'Stuur privé bericht',
+ userMenuDescribe: 'Stuur privé actie',
+ userMenuOpenPrivateChannel: 'Open privé kanaal',
+ userMenuClosePrivateChannel: 'Sluit privé kanaal',
+ userMenuInvite: 'Nodig uit',
+ userMenuUninvite: 'Uitnodiging intrekken',
+ userMenuIgnore: 'Negeren/aanvaarden',
+ userMenuIgnoreList: 'Lijst genegeerde gebruikers',
+ userMenuWhereis: 'Toon kanaal',
+ userMenuKick: 'Verwijderen/Verbannen',
+ userMenuBans: 'Lijst verbande gebruikers',
+ userMenuWhois: 'Toon IP',
+ unbanUser: 'Gebande gebruiker %s terug toelaten',
+ joinChannel: 'Betreedt kanaal %s',
+ cite: '%s zei:',
+ urlDialog: 'Gelieve het (URL) adres van de webpagina in te geven:',
+ deleteMessage: 'Verwijder dit chat bericht',
+ deleteMessageConfirm: 'Bent u zeker dat u dit bericht wil verwijderen?',
+ errorCookiesRequired: 'Cookies moeten aangeschakeld zijn voor deze chat.',
+ errorUserNameNotFound: 'Fout: Gebruiker %s werd niet gevonden.',
+ errorMissingText: 'Fout: Ontbrekende berichttekst.',
+ errorMissingUserName: 'Fout: Ontbrekende Gebruikersnaam.',
+ errorInvalidUserName: 'Error: Invalid username.',
+ errorUserNameInUse: 'Error: Gebruikersnaam wordt al gebruikt',
+ errorMissingChannelName: 'Fout: Ontbrekende kanaalnaam.',
+ errorInvalidChannelName: 'Fout: Ongeldige kanaalnaam: %s',
+ errorPrivateMessageNotAllowed: 'Error: Private berichten zijn niet toegestaan.',
+ errorInviteNotAllowed: 'Fout: Je bent niet geautoriseerd om iemand uit te nodigen naar dit kanaal.',
+ errorUninviteNotAllowed: 'Fout: Je bent niet geautoriseerd om een uitnodiging naar iemand te annuleren op dit kanaal.',
+ errorNoOpenQuery: 'Fout: Er is geen privékanaal geopend.',
+ errorKickNotAllowed: 'Fout: Je ben niet geautoriseerd om %s te kicken.',
+ errorCommandNotAllowed: 'Fout: Opdracht is niet toegestaan: %s',
+ errorUnknownCommand: 'Fout: Onbekende opdracht: %s',
+ errorMaxMessageRate: 'Error: Je hebt de limiet voor het aantal berichten per minuut overschreven.',
+ errorConnectionTimeout: 'Fout: Connection timeout. Gelieve opnieuw te proberen.',
+ errorConnectionStatus: 'Fout: Verbindingsstatus: %s',
+ errorSoundIO: 'Error: Geluidsbestand kon niet geladen worden (Flash IO Error).',
+ errorSocketIO: 'Error: Verbinding met Socket server is verloren (Flash IO Error).',
+ errorSocketSecurity: 'Error: Verbinding met Socket server is verloren (Flash Security Error).',
+ errorDOMSyntax: 'Error: Ongeldige DOM Syntax (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/nl.js b/library/ajaxchat/chat/js/lang/nl.js
new file mode 100644
index 000000000..179d0e703
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/nl.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author Dutch localisation: Patrick Donker
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s betreedt het chatkanaal.',
+ logout: '%s verlaat het chatkanaal.',
+ logoutTimeout: '%s verlaat het chatkanaal (Timeout).',
+ logoutIP: '%s is afgemeld (Ongeldig IP address).',
+ logoutKicked: '%s is afgemeld (Verbannen door admin of moderator).',
+ channelEnter: '%s betreedt het kanaal.',
+ channelLeave: '%s verlaat het kanaal.',
+ privmsg: '(fluistert)',
+ privmsgto: '(fluistert naar %s)',
+ invite: '%s nodigt je uit om naar %s te komen.',
+ inviteto: 'Je uitnodiging naar %s om het kanaal %s te bezoeken, is verzonden.',
+ uninvite: '%s annuleert de uitnodiging van kanaal %s.',
+ uninviteto: 'De annulering van je uitnodiging aan %s voor het kanaal %s is verzonden.',
+ queryOpen: 'Privékanaal geopend voor %s.',
+ queryClose: 'Privékanaal naar %s wordt gesloten.',
+ ignoreAdded: '%s is toegevoegd aan de negeer lijst.',
+ ignoreRemoved: '%s is verwijderd van de negeerlijst.',
+ ignoreList: 'Genegeerde gebruikers:',
+ ignoreListEmpty: 'Er zijn geen genegeerde gebruikers.',
+ who: 'Aanwezige gebruikers:',
+ whoChannel: 'aanwezige gebruikers in channel %s:',
+ whoEmpty: 'Het gekozen kanaal is leeg.',
+ list: 'Beschikbare kanalen:',
+ bans: 'Verbannen gebruikers:',
+ bansEmpty: 'Er zijn geen gebruikers verbannen.',
+ unban: 'Ban van gebruiker %s opgeheven.',
+ whois: 'Gebruiker %s - IP adres:',
+ whereis: 'Gebruiker %s is in kanaal %s.',
+ roll: '%s gooit %s en krijgt %s.',
+ nick: '%s heet nu %s.',
+ toggleUserMenu: 'Open gebuikersmenu %s',
+ userMenuLogout: 'Afmelden',
+ userMenuWho: 'Lijst aanwezige gebruikers',
+ userMenuList: 'Lijst beschikbare kanalen',
+ userMenuAction: 'Beschrijf actie',
+ userMenuRoll: 'Rol dobbelsteen',
+ userMenuNick: 'Wijzig gebruikersnaam',
+ userMenuEnterPrivateRoom: 'Betreed privékanaal',
+ userMenuSendPrivateMessage: 'Stuur privé bericht',
+ userMenuDescribe: 'Stuur privé actie',
+ userMenuOpenPrivateChannel: 'Open privé kanaal',
+ userMenuClosePrivateChannel: 'Sluit privé kanaal',
+ userMenuInvite: 'Nodig uit',
+ userMenuUninvite: 'Uitnodiging intrekken',
+ userMenuIgnore: 'Negeren/aanvaarden',
+ userMenuIgnoreList: 'Lijst genegeerde gebruikers',
+ userMenuWhereis: 'Toon kanaal',
+ userMenuKick: 'Verwijderen/Verbannen',
+ userMenuBans: 'Lijst verbannen gebruikers',
+ userMenuWhois: 'Toon IP adres',
+ unbanUser: 'Verbannen gebruiker %s weer toelaten',
+ joinChannel: 'Betreed kanaal %s',
+ cite: '%s zei:',
+ urlDialog: 'Geef het adres (URL) van de webpagina op:',
+ deleteMessage: 'Verwijder dit bericht',
+ deleteMessageConfirm: 'Weet u zeker dat u dit bericht wilt verwijderen?',
+ errorCookiesRequired: 'Cookies moeten ingeschakeld zijn voor deze chat.',
+ errorUserNameNotFound: 'Fout: Gebruiker %s is niet gevonden.',
+ errorMissingText: 'Fout: Ontbrekende berichttekst.',
+ errorMissingUserName: 'Fout: Ontbrekende gebruikersnaam.',
+ errorInvalidUserName: 'Error: Ongeldige gebruikersnaam.',
+ errorUserNameInUse: 'Error: Gebruikersnaam is in gebruik.',
+ errorMissingChannelName: 'Fout: Ontbrekende kanaalnaam.',
+ errorInvalidChannelName: 'Fout: Ongeldige kanaalnaam: %s',
+ errorPrivateMessageNotAllowed: 'Fout: Privéberichten zijn niet toegestaan.',
+ errorInviteNotAllowed: 'Fout: U bent niet geautoriseerd uitnodigingen te versturen voor dit kanaal.',
+ errorUninviteNotAllowed: 'Fout: U bent niet geautoriseerd uitnodigingen te annuleren voor dit kanaal.',
+ errorNoOpenQuery: 'Fout: Geen privékanaal beschikbaar.',
+ errorKickNotAllowed: 'Fout: U ben niet geautoriseerd om %s te verbannen.',
+ errorCommandNotAllowed: 'Fout: Opdracht niet toegestaan: %s',
+ errorUnknownCommand: 'Fout: Onbekende opdracht: %s',
+ errorMaxMessageRate: 'Error: U hebt het maximaal aantal berichten per minuut bereikt.',
+ errorConnectionTimeout: 'Fout: Connection timeout. Probeer opnieuw.',
+ errorConnectionStatus: 'Fout: Verbindingsstatus: %s',
+ errorSoundIO: 'Error: Geluidsbestand kan worden geladen (Flash IO Error).',
+ errorSocketIO: 'Error: Verbinding met Socket server is verbroken (Flash IO Error).',
+ errorSocketSecurity: 'Error: Verbinding met Socket server is verbroken (Flash Security Error).',
+ errorDOMSyntax: 'Error: Ongeldige DOM Syntax (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/no.js b/library/ajaxchat/chat/js/lang/no.js
new file mode 100644
index 000000000..4a9a5ac3f
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/no.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author DagArneKirkerod
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s logger inn på Chat.',
+ logout: '%s logger ut av Chat.',
+ logoutTimeout: '%s har blitt utlogget (Tidsbegrensning).',
+ logoutIP: '%s har blitt logget ut (Ugyldig IP Adresse).',
+ logoutKicked: '%s har blitt logget ut (sparket ut).',
+ channelEnter: '%s kommer inn på kanalen.',
+ channelLeave: '%s forlater kanalen.',
+ privmsg: '(hviskere)',
+ privmsgto: '(hvisker til %s)',
+ invite: '%s inviterer deg til å delta %s.',
+ inviteto: 'Din invitasjon til %s å delta på kanal %s er sendt.',
+ uninvite: '%s trekker din invitasjon fra kanal %s.',
+ uninviteto: 'Din tilbaketrekkning av invitasjon til %s for kanal %s er sendt.',
+ queryOpen: 'Privat kanal åpnet til %s.',
+ queryClose: 'Privat kanal til %s er stengt.',
+ ignoreAdded: 'Lagt %s til listen over ignorerte brukere.',
+ ignoreRemoved: 'Fjernet %s fra liste over ignorerte brukere.',
+ ignoreList: 'Ignorerte Brukere:',
+ ignoreListEmpty: 'Ingen ignorerte brukere på lista.',
+ who: 'Påloggede Brukere:',
+ whoChannel: 'Online Brukere i kanal %s:',
+ whoEmpty: 'Ingen påloggede brukere på valgt kanal.',
+ list: 'Tilgjenglige kanaler:',
+ bans: 'Utsparkede Brukere:',
+ bansEmpty: 'Ingen utsparkede brukere på lista.',
+ unban: 'Bruker %s fjernet fra liste over utsparkede brukere.',
+ whois: 'Bruker %s - IP adresse:',
+ whereis: 'User %s is in channel %s.',
+ roll: '%s triller %s og får %s.',
+ nick: '%s is now known as %s.',
+ toggleUserMenu: 'Toggle user menu for %s',
+ userMenuLogout: 'Logout',
+ userMenuWho: 'List online users',
+ userMenuList: 'List available channels',
+ userMenuAction: 'Describe action',
+ userMenuRoll: 'Roll dice',
+ userMenuNick: 'Endre brukernavn',
+ userMenuEnterPrivateRoom: 'Skriv privat rom',
+ userMenuSendPrivateMessage: 'Send en privat melding',
+ userMenuDescribe: 'Send privat handling',
+ userMenuOpenPrivateChannel: 'Åpne privat kanal',
+ userMenuClosePrivateChannel: 'Lukk privat kanal',
+ userMenuInvite: 'Invite',
+ userMenuUninvite: 'Uninvite',
+ userMenuIgnore: 'Ignore/Accept',
+ userMenuIgnoreList: 'Liste med ignorerte brukere',
+ userMenuWhereis: 'Vise kanal',
+ userMenuKick: 'Kick/Ban',
+ userMenuBans: 'Liste sperrede brukere',
+ userMenuWhois: 'Vise IP',
+ unbanUser: 'Tilbakekalle forbud av brukeren %s',
+ joinChannel: 'Delta på kanal %s',
+ cite: '%s sa:',
+ urlDialog: 'Skriv inn adressen (URL) på web siden:',
+ deleteMessage: 'Slett denne chat-melding',
+ deleteMessageConfirm: 'Vil du virkelig slette den valgte chat-melding?',
+ errorCookiesRequired: 'Cookies er påkrevet på denne chatten.',
+ errorUserNameNotFound: 'Feil: Bruker %s ble ikke funnet.',
+ errorMissingText: 'Feil: Mangler meldingstekst.',
+ errorMissingUserName: 'Feil: Mangler Brukernavn.',
+ errorInvalidUserName: 'Feil: Ugyldig brukernavn.',
+ errorUserNameInUse: 'Feil: Brukernavnet er allerede i bruk.',
+ errorMissingChannelName: 'Feil: Mangler navn på kanal.',
+ errorInvalidChannelName: 'Feil: Feil navn på kanal: %s',
+ errorPrivateMessageNotAllowed: 'Feil: Private meldinger ikke tillatt.',
+ errorInviteNotAllowed: 'Feil: Du har ikke lov til å invitere noen til denne kanalen.',
+ errorUninviteNotAllowed: 'Feil: Du har ikke lov til å fjerne invitasjon til noen brukere på denne kanalen.',
+ errorNoOpenQuery: 'Feil: Ingen private kanaler er åpne.',
+ errorKickNotAllowed: 'Feil: Du har ikke lov til å sparke ut %s.',
+ errorCommandNotAllowed: 'Feil: Kommando ikke tillatt: %s',
+ errorUnknownCommand: 'Feil: Ukjent kommando: %s',
+ errorMaxMessageRate: 'Feil: Du overskredet maksimalt antall meldinger per minutt.',
+ errorConnectionTimeout: 'Feil: Oppkoblingstid utgått. Forsøk forsøk igjen.',
+ errorConnectionStatus: 'Feil: Oppkoblingsstatus: %s',
+ errorSoundIO: 'Feil: Kunne ikke laste lydfil (Flash IO Error).',
+ errorSocketIO: 'Feil: Tilkobling til stikkontakt server mislyktes (Flash IO Error).',
+ errorSocketSecurity: 'Feil: Tilkobling til stikkontakt server mislyktes (Flash Security Error).',
+ errorDOMSyntax: 'Feil: Ugyldig DOM Syntaks (DOM ID: %s).'
+
+}
diff --git a/library/ajaxchat/chat/js/lang/pl.js b/library/ajaxchat/chat/js/lang/pl.js
new file mode 100644
index 000000000..3353d1bdd
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/pl.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author Tomasz Topa, http://tomasz.topa.pl/
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s wszedł na czat.',
+ logout: '%s wyszedł na czat.',
+ logoutTimeout: '%s został rozłączony (Przekroczony czas połączenia).',
+ logoutIP: '%s został rozłączony (Nieprawidłowy adres IP).',
+ logoutKicked: '%s został wyrzucony.',
+ channelEnter: '%s wszedł do pokoju.',
+ channelLeave: '%s wyszedł z pokoju.',
+ privmsg: '(szept)',
+ privmsgto: '(szept do %s)',
+ invite: '%s zaprasza Cię do pokoju %s.',
+ inviteto: 'Twoje zaprosznie dla %s do wejścia do pokoju %s zostało wysłane.',
+ uninvite: '%s cofa zaproszenie do pokoju %s.',
+ uninviteto: 'Twoje zaproszenie dla %s do wejścia do pokoju %s zostało wycofane.',
+ queryOpen: 'Prywatna rozmowa z %s rozpoczęta.',
+ queryClose: 'Prywatna rozmowa z %s zakończona.',
+ ignoreAdded: '%s dodany do listy ignorowanych.',
+ ignoreRemoved: '%s usunięty z listy ignorowanych.',
+ ignoreList: 'Ignorowani użytkownicy:',
+ ignoreListEmpty: 'Brak ignorowanych użytkowników.',
+ who: 'Użytkownicy online:',
+ whoChannel: 'Użytkownicy online w pokoju %s:',
+ whoEmpty: 'W wybranym pokoju nikogo obecnie nie ma.',
+ list: 'Dostępne pokoje:',
+ bans: 'Zablokowani użytkownicy:',
+ bansEmpty: 'Brak zablokowanych użytkowników',
+ unban: 'Blokada dla %s zdjęta.',
+ whois: 'Adres IP użytkownika %s:',
+ whereis: 'Użytkownik %s jest w pokoju %s.',
+ roll: '%s rzuca kostką %s i uzyskuje wynik(i): %s.',
+ nick: '%s zmienia nick na %s.',
+ toggleUserMenu: 'Włącz/wyłącz menu użytkownika %s',
+ userMenuLogout: 'Wyloguj',
+ userMenuWho: 'Użytkownicy online',
+ userMenuList: 'Dostępne pokoje',
+ userMenuAction: 'Napisz co teraz robisz',
+ userMenuRoll: 'Rzuć kostką',
+ userMenuNick: 'Zmień nick',
+ userMenuEnterPrivateRoom: 'Wejdź do prywatnego pokoju',
+ userMenuSendPrivateMessage: 'Wyślij prywatną wiadomość',
+ userMenuDescribe: 'Napisz prywatnie co teraz robisz',
+ userMenuOpenPrivateChannel: 'Rozpocznij prywatną rozmowę',
+ userMenuClosePrivateChannel: 'Zakończ prywatną rozmowę',
+ userMenuInvite: 'Zaproś',
+ userMenuUninvite: 'Wycofaj zaproszenie',
+ userMenuIgnore: 'Ignoruj/akceptuj',
+ userMenuIgnoreList: 'Lista ignorowanych użytkowników',
+ userMenuWhereis: 'Pokaż pokój',
+ userMenuKick: 'Wyrzuć/Zablokuj',
+ userMenuBans: 'Lista zablokowanych użytkowników',
+ userMenuWhois: 'Pokaż IP',
+ unbanUser: 'Zdejmij blokadę dla użytkownika %s',
+ joinChannel: 'Wejdź do pokoju %s',
+ cite: '%s powiedział:',
+ urlDialog: 'Podaj adres (URL) strony:',
+ deleteMessage: 'Usuń tę wiadomość',
+ deleteMessageConfirm: 'Na pewno usunać tę wiadomość?',
+ errorCookiesRequired: 'Do poprawnego działania czat wymaga obsługi Cookies.',
+ errorUserNameNotFound: 'Błąd: Użytkownik %s nie został znaleziony.',
+ errorMissingText: 'Błąd: Nie wpisano tekstu.',
+ errorMissingUserName: 'Błąd: Nie wpisano nicka.',
+ errorInvalidUserName: 'Error: Invalid username.',
+ errorUserNameInUse: 'Error: Username already in use.',
+ errorMissingChannelName: 'Błąd: Nie wpisano nazwy pokoju.',
+ errorInvalidChannelName: 'Błąd: Nieprawidłowa nazwa pokoju: %s',
+ errorPrivateMessageNotAllowed: 'Błąd: Prywatne wiadomości zostały zablokowane.',
+ errorInviteNotAllowed: 'Błąd: Nie możesz wysyłać zaproszeń do tego pokoju.',
+ errorUninviteNotAllowed: 'Błąd: Nie możesz cofać zaproszeń z tego pokoju.',
+ errorNoOpenQuery: 'Błąd: Brak prywatnych rozmów.',
+ errorKickNotAllowed: 'Błąd: Nie możesz wyrzucić użytkownika %s.',
+ errorCommandNotAllowed: 'Błąd: Nieprawidłowe polecenie: %s',
+ errorUnknownCommand: 'Błąd: Nieznane polecenie: %s',
+ errorMaxMessageRate: 'Błąd: Przekroczyłeś maksymalną liczbę wiadomości wysyłanych w ciągu minuty. Poczekaj chwilę...',
+ errorConnectionTimeout: 'Błąd: Czas połączenia przekroczony. Spróbuj ponownie.',
+ errorConnectionStatus: 'Błąd: Stan połączenia: %s',
+ errorSoundIO: 'Błąd: nie można pobrać pliku dźwiękowego (Flash IO Error).',
+ errorSocketIO: 'Bład: nie można połączyć się z serwerem (Flash IO Error).',
+ errorSocketSecurity: 'Błąd: Połączenie z serwerem nie powiodło się (Flash Security Error).',
+ errorDOMSyntax: 'Błąd: Nieprawidłowa składnia DOM (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/pt-br.js b/library/ajaxchat/chat/js/lang/pt-br.js
new file mode 100644
index 000000000..eebfce0df
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/pt-br.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author vitoalvaro
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s acaba de entrar no Chat.',
+ logout: '%s acaba de sair no Chat.',
+ logoutTimeout: '%s desconectou (Tempo esgotado).',
+ logoutIP: '%s desconectou (Endereço de IP inválido).',
+ logoutKicked: '%s desconectou (Expulso do canal).',
+ channelEnter: '%s entrou no canal.',
+ channelLeave: '%s saiu do canal.',
+ privmsg: '(sussurra)',
+ privmsgto: '(Sussurrar para %s)',
+ invite: '%s convida você para participar %s.',
+ inviteto: 'O seu convite para se juntar ao %s do canal %s foi enviado.',
+ uninvite: '%s desconvidou você do canal %s.',
+ uninviteto: 'Seu desconvidamento %s do canal %s foi enviada.',
+ queryOpen: 'Canal privado aberto para %s.',
+ queryClose: 'Canal privado para %s fechado.',
+ ignoreAdded: 'Adicionar %s para a lista do igrnorado.',
+ ignoreRemoved: 'Remover %s da lista do ignorado.',
+ ignoreList: 'Usuários ignorados:',
+ ignoreListEmpty: 'Nenhuma lista usuários ignorados.',
+ who: 'Usuários Online:',
+ whoChannel: 'Usuários online no canal %s:',
+ whoEmpty: 'Nenhum usuários online na determinado canal.',
+ list: 'Os canais disponíveis:',
+ bans: 'Usuários banidos:',
+ bansEmpty: 'Nenhuma lista usuários banidos.',
+ unban: 'Usuário de banido %s revogado.',
+ whois: 'Usuário %s - enderenço IP:',
+ whereis: 'Usuário %s está no canal %s.',
+ roll: '%s rolas %s e começa %s.',
+ nick: '%s é agora conhecido como %s.',
+ toggleUserMenu: 'Alternar usuário menu de %s',
+ userMenuLogout: 'Deslogar',
+ userMenuWho: 'Lista usuários online',
+ userMenuList: 'Lista os canais disponíveis',
+ userMenuAction: 'Descreva ação',
+ userMenuRoll: 'Jogar dados',
+ userMenuNick: 'Trocar usuário',
+ userMenuEnterPrivateRoom: 'Entrar sala privada',
+ userMenuSendPrivateMessage: 'Enviar mensagem privada',
+ userMenuDescribe: 'Enviar ação privada',
+ userMenuOpenPrivateChannel: 'Abrir canal privada',
+ userMenuClosePrivateChannel: 'Fechar canal privada',
+ userMenuInvite: 'Convidar',
+ userMenuUninvite: 'Desconvidar',
+ userMenuIgnore: 'Ignorar/Aceitar',
+ userMenuIgnoreList: 'Lista usuários banidos',
+ userMenuWhereis: 'Exibir canais',
+ userMenuKick: 'Kickar/Banir',
+ userMenuBans: 'Lista usuários banidos',
+ userMenuWhois: 'Exibir IP',
+ unbanUser: 'Revogar usuário de banido %s',
+ joinChannel: 'Entrar canal %s',
+ cite: '%s cita:',
+ urlDialog: 'Digite o endereço (URL) da página:',
+ deleteMessage: 'Excluir esta mensagem',
+ deleteMessageConfirm: 'Realmente apagar a mensagem selecionada chat?',
+ errorCookiesRequired: 'Os cookies são requeridas para este Chat.',
+ errorUserNameNotFound: 'Erro: Usuário %s não encontrado.',
+ errorMissingText: 'Erro: Faltando mensagem texto.',
+ errorMissingUserName: 'Erro: Usuário faltando.',
+ errorInvalidUserName: 'Erro: Usuário inválido.',
+ errorUserNameInUse: 'Erro: Usuário já em uso.',
+ errorMissingChannelName: 'Erro: Faltando nome do canal.',
+ errorInvalidChannelName: 'Erro: Inválido nome do canal: %s',
+ errorPrivateMessageNotAllowed: 'Erro: Mensagens privadas não são permitidos.',
+ errorInviteNotAllowed: 'Erro: Você não tem permissão para convidar alguém para este canal.',
+ errorUninviteNotAllowed: 'Erro: Você não está autorizado a desconvidar alguém deste canal.',
+ errorNoOpenQuery: 'Erro: Nenhum canal privado aberto.',
+ errorKickNotAllowed: 'Erro: Você não está autorizado a kickar %s.',
+ errorCommandNotAllowed: 'Erro: Comando não permitido: %s',
+ errorUnknownCommand: 'Erro: Comando desconhecido: %s',
+ errorMaxMessageRate: 'Erro: Você excedeu o número máximo de mensagens por minuto.',
+ errorConnectionTimeout: 'Erro: Intervalo de parada da conexão. Por favor, tente novamente..',
+ errorConnectionStatus: 'Erro: Status da conexão: %s',
+ errorSoundIO: 'Erro: Falha ao carregar som arquivo (Flash IO Error).',
+ errorSocketIO: 'Erro: Conexão para socket servidor falhou (Flash IO Error).',
+ errorSocketSecurity: 'Erro: Conexão para socket servidor falhou (Flash Security Error).',
+ errorDOMSyntax: 'Erro: Inválido DOM Syntax (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/pt-pt.js b/library/ajaxchat/chat/js/lang/pt-pt.js
new file mode 100644
index 000000000..fd6a0cbd5
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/pt-pt.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author of translate Carlos Rocha (aka Broas@)
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s acaba de entrar no chat.',
+ logout: '%s acaba de sair no chat.',
+ logoutTimeout: '%s desligou-se (Tempo esgotado).',
+ logoutIP: '%s desligou-se (Endereço de IP inválido).',
+ logoutKicked: '%s desligou-se (Expulso da sala).',
+ channelEnter: '%s entrou na sala.',
+ channelLeave: '%s saiu da sala.',
+ privmsg: '(Mensagem privada)',
+ privmsgto: '(Mensagem privada enviada para %s)',
+ invite: '%s convidou-te para entrar na sala %s.',
+ inviteto: 'O teu convite para %s se juntar à sala %s foi enviado.',
+ uninvite: '%s cancelou o convite para entrares na sala %s.',
+ uninviteto: 'O cancelamento do convite para %s entrar na sala %s foi enviado.',
+ queryOpen: 'Sala privada aberta para %s.',
+ queryClose: 'A sala privada para %s está fechada.',
+ ignoreAdded: 'Adicionaste %s à a lista do ignorados.',
+ ignoreRemoved: 'Removeste %s da lista de ignorados.',
+ ignoreList: 'Utilizadores ignorados:',
+ ignoreListEmpty: 'Ninguém está ignorado.',
+ who: 'Utilizadores online:',
+ whoChannel: 'Utilizadores online na sala %s:',
+ whoEmpty: 'Nenhum utilizador online na determinada sala.',
+ list: 'Salas disponíveis:',
+ bans: 'Utilizadores banidos:',
+ bansEmpty: 'Ninguém está banido.',
+ unban: 'O utilizador %s foi desbanido.',
+ whois: 'Endereço IP do utilizador %s:',
+ whereis: 'O utilizador %s está na sala %s.',
+ roll: '%s rola %s e começa com %s.',
+ nick: '%s mudou o nick para %s.',
+ toggleUserMenu: 'Menu de alternância de %s',
+ userMenuLogout: 'Logout',
+ userMenuWho: 'Lista de utilizadores online',
+ userMenuList: 'Lista de salas disponíveis',
+ userMenuAction: 'Acção administrativa',
+ userMenuRoll: 'Jogar dados',
+ userMenuNick: 'Trocar de nick',
+ userMenuEnterPrivateRoom: 'Entrar na sala privada',
+ userMenuSendPrivateMessage: 'Enviar mensagem privada',
+ userMenuDescribe: 'Enviar acção administrativa em privado',
+ userMenuOpenPrivateChannel: 'Abrir sala privada',
+ userMenuClosePrivateChannel: 'Fechar sala privada',
+ userMenuInvite: 'Convidar',
+ userMenuUninvite: 'Cancelar convite',
+ userMenuIgnore: 'Recusar/Aceitar',
+ userMenuIgnoreList: 'Lista utilizadores ignorados',
+ userMenuWhereis: 'Mostrar salas',
+ userMenuKick: 'Kickar/Banir',
+ userMenuBans: 'Lista de utilizadores banidos',
+ userMenuWhois: 'Mostrar IP',
+ unbanUser: 'Desbanir %s',
+ joinChannel: 'Entrar na sala %s',
+ cite: '%s cita:',
+ urlDialog: 'Digita o endereço (URL) da página:',
+ deleteMessage: 'Eliminar esta mensagem',
+ deleteMessageConfirm: 'Tens a certeza que queres eliminar a mensagem selecionada do chat?',
+ errorCookiesRequired: 'Os cookies são requeridos para utilizar o chat.',
+ errorUserNameNotFound: 'Erro: O utilizador %s não foi encontrado.',
+ errorMissingText: 'Erro: Falta o texto.',
+ errorMissingUserName: 'Erro: Falta o utilizador.',
+ errorInvalidUserName: 'Erro: Utilizador inválido.',
+ errorUserNameInUse: 'Erro: Utilizador em uso.',
+ errorMissingChannelName: 'Erro: Falta o nome da sala.',
+ errorInvalidChannelName: 'Erro: O nome da sala é inválido: %s',
+ errorPrivateMessageNotAllowed: 'Erro: Não são premitidas mensagens privadas.',
+ errorInviteNotAllowed: 'Erro: Não tens permissão para convidar alguém para uma sala.',
+ errorUninviteNotAllowed: 'Erro: Não estás autorizado a cancelar algum convite.',
+ errorNoOpenQuery: 'Erro: Nenhuma sala privada aberta.',
+ errorKickNotAllowed: 'Erro: Não tens permissão para kickar %s.',
+ errorCommandNotAllowed: 'Erro: O comando %s não é permitido.',
+ errorUnknownCommand: 'Erro: Comando desconhecido: %s',
+ errorMaxMessageRate: 'Erro: Excedeste o número máximo de mensagens permitidas por minuto.',
+ errorConnectionTimeout: 'Erro: O tempo de limite para a conexão esgotou. Por favor, tenta novamente..',
+ errorConnectionStatus: 'Erro: Estado da conexão: %s',
+ errorSoundIO: 'Erro: Falha ao carregar o ficheiro de som (Erro Flash IO).',
+ errorSocketIO: 'Erro: A conexão socket para o servidor falhou (Erro Flash IO).',
+ errorSocketSecurity: 'Erro: A conexão socket para o servidor falhou (Erro de segurança Flash).',
+ errorDOMSyntax: 'Erro: Síntese DOM inválida (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/ro.js b/library/ajaxchat/chat/js/lang/ro.js
new file mode 100644
index 000000000..7a03947aa
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/ro.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author K.Z.
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s se autentifică pe Chat.',
+ logout: '%s iese de pe Chat.',
+ logoutTimeout: '%s a fost scos de pe Chat (Timeout).',
+ logoutIP: '%s a fost scos de pe Chat (Adresă IP incorectă).',
+ logoutKicked: '%s a fost scos de pe Chat (Dat afară).',
+ channelEnter: '%s se alătură canalului.',
+ channelLeave: '%s părăseşte canalul.',
+ privmsg: '(şopteşte)',
+ privmsgto: '(şopteşte lui %s)',
+ invite: '%s vă invită să vă alăturaţi %s.',
+ inviteto: 'Invitaţia trimisă de dumneavoastră către %s de a se alătura canalului %s a fost trimisă.',
+ uninvite: '%s vă cere să paraşiţi canalul %s.',
+ uninviteto: 'Cererea dumnevoastră către %s de a părăsi canalul %s a fost trimisă.',
+ queryOpen: 'Canal privat deschis către %s.',
+ queryClose: 'Canalul privat către %s s-a închis.',
+ ignoreAdded: 'Am adăugat utilizatorul %s la lista de utilizatori ignoraţi.',
+ ignoreRemoved: 'Am şters utilizatorul %s din lista de utilizatori ignoraţi.',
+ ignoreList: 'Utilizatori ignoraţi:',
+ ignoreListEmpty: 'Nu a fost listat nici-un utilizator ignorat.',
+ who: 'Utilizatori activi:',
+ whoChannel: 'Online Users in channel %s:',
+ whoEmpty: 'Nici-un utilzator activ in canalul respectiv.',
+ list: 'Canale disponibile:',
+ bans: 'Utilizatori care au accesul interzis la chat:',
+ bansEmpty: 'Nu a fost listat nici-un utilizator care are accesul interzis.',
+ unban: 'Interzicerea accesului pentru utilizatorul %s a fost revocată.',
+ whois: 'Utilizatorul %s - adresă IP:',
+ whereis: 'User %s is in channel %s.',
+ roll: '%s aruncă %s si îi cade %s.',
+ nick: '%s is now known as %s.',
+ toggleUserMenu: 'Toggle user menu for %s',
+ userMenuLogout: 'Logout',
+ userMenuWho: 'List online users',
+ userMenuList: 'List available channels',
+ userMenuAction: 'Describe action',
+ userMenuRoll: 'Roll dice',
+ userMenuNick: 'Change username',
+ userMenuEnterPrivateRoom: 'Enter private room',
+ userMenuSendPrivateMessage: 'Send private message',
+ userMenuDescribe: 'Send private action',
+ userMenuOpenPrivateChannel: 'Open private channel',
+ userMenuClosePrivateChannel: 'Close private channel',
+ userMenuInvite: 'Invite',
+ userMenuUninvite: 'Uninvite',
+ userMenuIgnore: 'Ignore/Accept',
+ userMenuIgnoreList: 'List ignored users',
+ userMenuWhereis: 'Display channel',
+ userMenuKick: 'Kick/Ban',
+ userMenuBans: 'List banned users',
+ userMenuWhois: 'Display IP',
+ unbanUser: 'Revoke ban of user %s',
+ joinChannel: 'Alăturăte canalului %s',
+ cite: '%s a spus:',
+ urlDialog: 'Vă rugăm introduceţi adresa (URL) al paginii web:',
+ deleteMessage: 'Delete this chat message',
+ deleteMessageConfirm: 'Really delete the selected chat message?',
+ errorCookiesRequired: 'Aveţi nevoie de cookies activate pentru acest chat.',
+ errorUserNameNotFound: 'Eroare: Utilizatorul %s nu a fost găsit.',
+ errorMissingText: 'Eroare: Nu aţi introdus nici-un text.',
+ errorMissingUserName: 'Eroare: Nu aţi introdus nici-un nume de utilizator.',
+ errorInvalidUserName: 'Error: Invalid username.',
+ errorUserNameInUse: 'Error: Username already in use.',
+ errorMissingChannelName: 'Eroare: Nu aţi introdus nici-un canal.',
+ errorInvalidChannelName: 'Eroare: Nume de canal incorect: %s',
+ errorPrivateMessageNotAllowed: 'Eroare: Mesajele private sunt interzise.',
+ errorInviteNotAllowed: 'Eroare: Nu aveţi voie să invitaţi pe nimeni pe acest canal.',
+ errorUninviteNotAllowed: 'Eroare: Nu aveţi voie sa cereţi cuiva de pe acest canal să părăsesca canalul.',
+ errorNoOpenQuery: 'Eroare: Nici-un canal privat deschis.',
+ errorKickNotAllowed: 'Eroare: Nu aveţi voie să dati afară pe %s.',
+ errorCommandNotAllowed: 'Eroare: Comanda interzisă: %s',
+ errorUnknownCommand: 'Eroare: Comanda necunoscută: %s',
+ errorMaxMessageRate: 'Error: You exceeded the maximum number of messages per minute.',
+ errorConnectionTimeout: 'Eroare: Connection timeout. Please try again.',
+ errorConnectionStatus: 'Eroare: Statusul conexiunii: %s',
+ errorSoundIO: 'Error: Failed to load sound file (Flash IO Error).',
+ errorSocketIO: 'Error: Connection to socket server failed (Flash IO Error).',
+ errorSocketSecurity: 'Error: Connection to socket server failed (Flash Security Error).',
+ errorDOMSyntax: 'Error: Invalid DOM Syntax (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/ru.js b/library/ajaxchat/chat/js/lang/ru.js
new file mode 100644
index 000000000..847fdb82c
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/ru.js
@@ -0,0 +1,93 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author SkyKnight
+ * @author Dmitry Plyonkin
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s входит в чат.',
+ logout: '%s выходит из чата.',
+ logoutTimeout: '%s вышел из чата по таймоуту.',
+ logoutIP: '%s вышел из чата (неверный IP адрес).',
+ logoutKicked: '%s был вышвырнут из чата (Kicked).',
+ channelEnter: '%s присоединяется к каналу.',
+ channelLeave: '%s покидает канал.',
+ privmsg: '(приватное сообщение)',
+ privmsgto: '(приватное сообщение %s)',
+ invite: '%s приглашает Вас присоединиться к %s.',
+ inviteto: 'Ваше приглашение %s присоедениться к каналу %s было успешно отправлено.',
+ uninvite: '%s отзывает Ваше приглашение из канала %s.',
+ uninviteto: 'Вы отозвали приглашение пользователю %s для канала %s.',
+ queryOpen: 'Приватный канал открыт к %s.',
+ queryClose: 'Приватный канал к %s закрыт.',
+ ignoreAdded: '%s добавлен в игнорлист.',
+ ignoreRemoved: '%s удален из игнорлиста.',
+ ignoreList: 'Игнорируемые пользователи:',
+ ignoreListEmpty: 'Игнорируемых пользователей не найдено.',
+ who: 'Пользователи:',
+ whoChannel: 'Пользователи в канале %s:',
+ whoEmpty: 'В данном канале нет пользователей.',
+ list: 'Доступные каналы:',
+ bans: 'Забаненные пользователи:',
+ bansEmpty: 'Нет забаненных пользователей.',
+ unban: 'Пользователь %s разбанен.',
+ whois: 'Пользователь %s - IP адрес:',
+ whereis: 'Пользователь %s находится в канале %s.',
+ roll: '%s кинул кубики %s. Результат %s.',
+ nick: '%s сменил имя на %s.',
+ toggleUserMenu: 'Меню пользователя %s',
+ userMenuLogout: 'Выйти',
+ userMenuWho: 'Список пользователей',
+ userMenuList: 'Список каналов',
+ userMenuAction: 'Действие',
+ userMenuRoll: 'Бросить кубик',
+ userMenuNick: 'Сменить имя',
+ userMenuEnterPrivateRoom: 'Войти в комнату',
+ userMenuSendPrivateMessage: 'Отправить приватное сообщение',
+ userMenuDescribe: 'Приватное действие',
+ userMenuOpenPrivateChannel: 'Открыть приватный канал',
+ userMenuClosePrivateChannel: 'Закрыть приватный канал',
+ userMenuInvite: 'Пригласить',
+ userMenuUninvite: 'Отменить приглашение',
+ userMenuIgnore: 'Игнорировать/Принять',
+ userMenuIgnoreList: 'Список игнорируемых',
+ userMenuWhereis: 'В каком канале?',
+ userMenuKick: 'Выкинуть/Забанить',
+ userMenuBans: 'Список забаненных',
+ userMenuWhois: 'Показать IP',
+ unbanUser: 'Отменить бан пользователя %s',
+ joinChannel: ' %s присоединился к каналу',
+ cite: '%s сказал:',
+ urlDialog: 'Пожалуйста введите адрес (URL) Web-страницы:',
+ deleteMessage: 'Удалить сообщение',
+ deleteMessageConfirm: 'Вы действительно хотите удалить это сообщение?',
+ errorCookiesRequired: 'Необходимо включить Cookies.',
+ errorUserNameNotFound: 'Ошибка: Пользователь %s не найдет.',
+ errorMissingText: 'Ошибка: Отсутствует текст сообщения.',
+ errorMissingUserName: 'Ошибка: Отсутствует имя.',
+ errorInvalidUserName: 'Error: Invalid username.',
+ errorUserNameInUse: 'Error: Username already in use.',
+ errorMissingChannelName: 'Ошибка: Отсутствует имя канала.',
+ errorInvalidChannelName: 'Ошибка: Не верное имя канала: %s',
+ errorPrivateMessageNotAllowed: 'Ошибка: Приватные сообщения не разрешены.',
+ errorInviteNotAllowed: 'Ошибка: У Вас нет прав приглашать кого-либо в этот канал.',
+ errorUninviteNotAllowed: 'Ошибка: У Вас нет прав отозвать приглашение из этого канала.',
+ errorNoOpenQuery: 'Ошибка: Приватный канал не открыт.',
+ errorKickNotAllowed: 'Ошибка: У Вас нет прав забанить %s.',
+ errorCommandNotAllowed: 'Ошибка: Команда недоступна: %s',
+ errorUnknownCommand: 'Ошибка: Неизвестная команда: %s',
+ errorMaxMessageRate: 'Ошибка: Вы превысили ограничение на количество сообщений, отправленных за минуту.',
+ errorConnectionTimeout: 'Ошибка: Соединение не установлено. Пожалуйста, попробуйте еще раз.',
+ errorConnectionStatus: 'Ошибка: Статус соединения: %s',
+ errorSoundIO: 'Ошибка: Не получается загрузить звуковой файл (Flash IO Error).',
+ errorSocketIO: 'Ошибка: Не удалось открыть сокет (Flash IO Error).',
+ errorSocketSecurity: 'Ошибка: Не удалость открыть сокет (Flash Security Error).',
+ errorDOMSyntax: 'Ошибка: Некорректный синтаксис DOM (DOM ID: %s).'
+
+}
diff --git a/library/ajaxchat/chat/js/lang/sk.js b/library/ajaxchat/chat/js/lang/sk.js
new file mode 100644
index 000000000..3b9b06945
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/sk.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author Peter
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s sa prihlásil do chatu.',
+ logout: '%s sa odhlásil z chatu.',
+ logoutTimeout: '%s bol odhlásený pre neaktivitu.',
+ logoutIP: '%s bol odhlásený (nesprávna IP adresa).',
+ logoutKicked: '%s bol odhlásený (vylúčený).',
+ channelEnter: '%s vstúpil do kanálu.',
+ channelLeave: '%s opustil kanál.',
+ privmsg: '(súkromný hovor)',
+ privmsgto: '(súkromne hovorí s %s)',
+ invite: '%s vás pozýva na rozhovor %s.',
+ inviteto: 'Vaša pozvánka na rozhovor s %s v kanáli %s dola odoslaná.',
+ uninvite: '%s neprijal Vaše pozvanie z kanálu %s.',
+ uninviteto: 'Vaše pozvanie pre %s v kanáli %s bolo poslané.',
+ queryOpen: 'Súkromný kanál s %s otvorený.',
+ queryClose: 'Súkromný kanál s %s zatvorený.',
+ ignoreAdded: '%s je pridaný do zoznamu zamietnutých.',
+ ignoreRemoved: '%s je odstránený zo zoznamu zamietnutých.',
+ ignoreList: 'Zamietnutí užívatelia:',
+ ignoreListEmpty: 'Zoznam zamietnutých užívateľov je prázdny.',
+ who: 'Pripojení užívatelia:',
+ whoChannel: 'Online Users in channel %s:',
+ whoEmpty: 'Žiadni pripojení užívatelia na danom kanáli.',
+ list: 'Dostupné kanály:',
+ bans: 'Vylúčení užívatelia:',
+ bansEmpty: 'Zoznam vylúčených užívateľov je prázdny.',
+ unban: 'Vylúčenie užívateľa %s je zrušené.',
+ whois: 'Užívateľová %s - IP adresa:',
+ whereis: 'User %s is in channel %s.',
+ roll: '%s hodil %s a padlo mu číslo %s.',
+ nick: '%s is now known as %s.',
+ toggleUserMenu: 'Toggle user menu for %s',
+ userMenuLogout: 'Logout',
+ userMenuWho: 'List online users',
+ userMenuList: 'List available channels',
+ userMenuAction: 'Describe action',
+ userMenuRoll: 'Roll dice',
+ userMenuNick: 'Change username',
+ userMenuEnterPrivateRoom: 'Enter private room',
+ userMenuSendPrivateMessage: 'Send private message',
+ userMenuDescribe: 'Send private action',
+ userMenuOpenPrivateChannel: 'Open private channel',
+ userMenuClosePrivateChannel: 'Close private channel',
+ userMenuInvite: 'Invite',
+ userMenuUninvite: 'Uninvite',
+ userMenuIgnore: 'Ignore/Accept',
+ userMenuIgnoreList: 'List ignored users',
+ userMenuWhereis: 'Display channel',
+ userMenuKick: 'Kick/Ban',
+ userMenuBans: 'List banned users',
+ userMenuWhois: 'Display IP',
+ unbanUser: 'Revoke ban of user %s',
+ joinChannel: 'Pripojiť kanál %s',
+ cite: '%s povedal:',
+ urlDialog: 'Prosím, vložte adresu (URL) webstránky:',
+ deleteMessage: 'Delete this chat message',
+ deleteMessageConfirm: 'Really delete the selected chat message?',
+ errorCookiesRequired: 'Tento chat vyžaduje mať povolené Cookies.',
+ errorUserNameNotFound: 'Chyba: Užívateľ %s nenájdený.',
+ errorMissingText: 'Chyba: Chýba text správy.',
+ errorMissingUserName: 'Chyba: Chýba meno užívateľa.',
+ errorInvalidUserName: 'Error: Invalid username.',
+ errorUserNameInUse: 'Error: Username already in use.',
+ errorMissingChannelName: 'Chyba: Chýba meno kanálu.',
+ errorInvalidChannelName: 'Chyba: Nesprávne meno kanálu: %s',
+ errorPrivateMessageNotAllowed: 'Chyba: Súkromné správy nie sú povolené.',
+ errorInviteNotAllowed: 'Chyba: Nemáte povolenie pozívať užívateľov do tohoto kanálu.',
+ errorUninviteNotAllowed: 'Chyba: Nemáte povolenie zamietnuť pozvanie užívateľov z tohoto kanálu.',
+ errorNoOpenQuery: 'Chyba: Súkromný kanál nie je otvorený.',
+ errorKickNotAllowed: 'Chyba: Nie ste oprávnený vylúčiť %s.',
+ errorCommandNotAllowed: 'Chyba: Príkaz nie je povolený: %s',
+ errorUnknownCommand: 'Chyba: Neznámy príkaz: %s',
+ errorMaxMessageRate: 'Error: You exceeded the maximum number of messages per minute.',
+ errorConnectionTimeout: 'Chyba: Vypršal časový limit pripojenia. Skúste prosím znovu.',
+ errorConnectionStatus: 'Chyba: Stav pripojenia: %s',
+ errorSoundIO: 'Error: Failed to load sound file (Flash IO Error).',
+ errorSocketIO: 'Error: Connection to socket server failed (Flash IO Error).',
+ errorSocketSecurity: 'Error: Connection to socket server failed (Flash Security Error).',
+ errorDOMSyntax: 'Error: Invalid DOM Syntax (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/sl.js b/library/ajaxchat/chat/js/lang/sl.js
new file mode 100644
index 000000000..9b9b4b4ae
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/sl.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author Valter Pepelkoˇ
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s prijavljen-a na Klepetu.',
+ logout: '%s odjavljen-a iz Klepeta.',
+ logoutTimeout: '%s je prijava potekla (Timeout).',
+ logoutIP: '%s je prijava potekla (Nepopolna IP adresa).',
+ logoutKicked: '%s je prijava potekla (Kicked).',
+ channelEnter: '%s je vstopil-a v sobo.',
+ channelLeave: '%s odšel-a iz sobe.',
+ privmsg: '(privatno sporoÄŤilo)',
+ privmsgto: '(se privatno pogovarja z %s)',
+ invite: '%s vas vabi na razgovor v %s.',
+ inviteto: 'Vaše vabilo za razgovor z %s v sobi %s je poslano.',
+ uninvite: '%s se ne želi odzvati vašemu vabilu v sobi %s.',
+ uninviteto: 'Vaš preklic vabila za %s v sobi %s je poslano.',
+ queryOpen: 'Privatna soba za %s je odprta.',
+ queryClose: 'Privatna soba za %s je zaprta.',
+ ignoreAdded: '%s je dodan na seznam ignoriranih.',
+ ignoreRemoved: '%s je odstranjen iz seznama ignoriranih.',
+ ignoreList: 'Ignorirani uporabniki:',
+ ignoreListEmpty: 'Seznam ignoriranih uporabnikov je prazen.',
+ who: 'Prisotni:',
+ whoChannel: 'Prisotni v sobi %s:',
+ whoEmpty: 'V tej sobi ni uporabnikov.',
+ list: 'Dostopne sobe:',
+ bans: 'Uporabniki s prepovedjo dostopa:',
+ bansEmpty: 'Seznam uporabnikov s prepovedjo dostopa je prazen.',
+ unban: 'Prepoved dostopa uporabniku je preklicana.',
+ whois: 'Uporabnik %s - IP adresa:',
+ whereis: 'Uporabnik %s je v sobi %s.',
+ roll: '%s je vrgel %s Rezultat je: %s.',
+ nick: '%s sedaj uporablja nick %s.',
+ toggleUserMenu: 'Preklopi uporabniški meni za %s',
+ userMenuLogout: 'Odjava',
+ userMenuWho: 'Seznam prisotnih uporabnikov',
+ userMenuList: 'Seznam dostopnih sob',
+ userMenuAction: 'Opiši akcijo',
+ userMenuRoll: 'Vrzi kocko',
+ userMenuNick: 'Zamenjaj uporabniško ime',
+ userMenuEnterPrivateRoom: 'Vstopi v privatno sobo',
+ userMenuSendPrivateMessage: 'Pošlji privatno sporočilo',
+ userMenuDescribe: 'Pošlji privatno akcijo',
+ userMenuOpenPrivateChannel: 'Odpri privatno sobo',
+ userMenuClosePrivateChannel: 'Zapri privatno sobo',
+ userMenuInvite: 'Poklicati',
+ userMenuUninvite: 'Preklicati',
+ userMenuIgnore: 'Ignoriraj/Sprejemi',
+ userMenuIgnoreList: 'Seznam ignoriranih uporabnikov',
+ userMenuWhereis: 'PrikaĹľi sobo',
+ userMenuKick: 'IzvrĹľeen/Prepovedan',
+ userMenuBans: 'Seznam prepovedanih uporabnikov',
+ userMenuWhois: 'PrikaĹľi IP adreso',
+ unbanUser: 'Preklicati prepoved uporabniku %s',
+ joinChannel: 'Vstopi v sobo %s',
+ cite: '%s pravi:',
+ urlDialog: 'Prosimo vas, vnesite naslov (URL) web strani:',
+ deleteMessage: 'Izbriši to sporočilo',
+ deleteMessageConfirm: 'Ali res izbrišem izbrano sporočilo?',
+ errorCookiesRequired: 'Pozor: uporaba piškotkov (cookies) je nujna za to klepetalnico!',
+ errorUserNameNotFound: 'Napaka: uporabnik %s ni najden!',
+ errorMissingText: 'Napaka: manjka besedilo sporoÄŤila!',
+ errorMissingUserName: 'Napaka: manjka uporabniško ime!',
+ errorInvalidUserName: 'Napaka: Nepravilno uporabniško ime!',
+ errorUserNameInUse: 'Napaka: uporabniško ime je že v uporabi!',
+ errorMissingChannelName: 'Napaka: ni imena sobe!',
+ errorInvalidChannelName: 'Napaka: napaÄŤno ime sobe: %s',
+ errorPrivateMessageNotAllowed: 'Napaka: privatna sporoÄŤila niso dovoljena!',
+ errorInviteNotAllowed: 'Napaka: Nimate dovoljenja, da lahko druge vabite v to sobo!',
+ errorUninviteNotAllowed: 'Napaka: Nimate dovoljenja, da lahko druge vrĹľete iz te sobe!',
+ errorNoOpenQuery: 'Napaka: Privatna soba ni odprta!',
+ errorKickNotAllowed: 'NApaka: Nimate dovoljenja, da lahko vrĹľete %s',
+ errorCommandNotAllowed: 'Napaka: Ukaz ni dozvoljen: %s',
+ errorUnknownCommand: 'Napaka: Neznan ukaz: %s',
+ errorMaxMessageRate: 'NApaka: Presegli ste največje dovoljeno število sporočil na minuto!.',
+ errorConnectionTimeout: 'Napaka: ÄŤas povezave se je iztekel. Poskusite znova!',
+ errorConnectionStatus: 'Napaka: Status povezave: %s',
+ errorSoundIO: 'Napaka: ZvoÄŤne datoteke ni bilo mogoÄŤe naloĹľiti (Napaka Flash IO)!',
+ errorSocketIO: 'Napaka: Povezava na server ni uspela (Napaka Flash IO)!',
+ errorSocketSecurity: 'Napaka: Povezava na server ni uspela (Napaka Flash Security)!',
+ errorDOMSyntax: 'Napaka: Nepopolna DOM Syntaxa (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/sr.js b/library/ajaxchat/chat/js/lang/sr.js
new file mode 100644
index 000000000..b5367b1e2
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/sr.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author Saša Stojanović
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s prijavljen-a na Chat.',
+ logout: '%s odjavljen-a sa Chata.',
+ logoutTimeout: '%s je prijava istekla (Timeout).',
+ logoutIP: '%s je prijava istekla (Invalid IP address).',
+ logoutKicked: '%s je prijava istekla (Kicked).',
+ channelEnter: '%s je ušao-la u sobu.',
+ channelLeave: '%s izašao-la iz sobe.',
+ privmsg: '(privatna poruka)',
+ privmsgto: '(privatno razgovara sa %s)',
+ invite: '%s vas poziva na razgovor u %s.',
+ inviteto: 'Vaš poziv za razgovor sa %s u sobu %s je poslat.',
+ uninvite: '%s vam otkazuje pozivnicu u sobi %s.',
+ uninviteto: 'Vaše otkazivanje pozivnice za %s u sobi %s je poslato.',
+ queryOpen: 'Privatna soba za %s je otvorena.',
+ queryClose: 'Privatna soba za %s je zatvorena.',
+ ignoreAdded: '%s je dodat u listu ignorisanih.',
+ ignoreRemoved: '%s je uklonjen iz liste ignorisanih.',
+ ignoreList: 'Ignorisani korisnici:',
+ ignoreListEmpty: 'Lista ignorisanih korisnika je prazna.',
+ who: 'Prisutni korisnici:',
+ whoChannel: 'Prisutni korisnici u sobi %s:',
+ whoEmpty: 'Nema prisutnih korisnika u toj sobi.',
+ list: 'Dostupne sobe:',
+ bans: 'Zabranjeni korisnici:',
+ bansEmpty: 'Lista zabranjenih korisnika je prazna.',
+ unban: 'Zabrana korisnika %s je povučena.',
+ whois: 'Korisnik %s - IP adresa:',
+ whereis: 'Korisnik %s je u sobi %s.',
+ roll: '%s je bacio %s Rezultat %s.',
+ nick: '%s je sada poznat kao %s.',
+ toggleUserMenu: 'Preklopi korisnički meni za %s',
+ userMenuLogout: 'Odjavljivanje',
+ userMenuWho: 'Lista prisutnih korisnika',
+ userMenuList: 'Lista dostupnih soba',
+ userMenuAction: 'Opiši akciju',
+ userMenuRoll: 'Baci kocku',
+ userMenuNick: 'Promeni korisničko ime',
+ userMenuEnterPrivateRoom: 'Uđi u privatnu sobu',
+ userMenuSendPrivateMessage: 'Pošalji privatnu poruku',
+ userMenuDescribe: 'Pošalji privatnu akciju',
+ userMenuOpenPrivateChannel: 'Otvori privatnu sobu',
+ userMenuClosePrivateChannel: 'Zatvori privatnu sobu',
+ userMenuInvite: 'Pozvati',
+ userMenuUninvite: 'Opozvati',
+ userMenuIgnore: 'Ignorisati/Prihvatiti',
+ userMenuIgnoreList: 'Lista ignorisanih korisnika',
+ userMenuWhereis: 'Prikaži sobu',
+ userMenuKick: 'Izbačen/Zabranjen',
+ userMenuBans: 'Lista zabranjenih korisnika',
+ userMenuWhois: 'Prikaži IP',
+ unbanUser: 'Opozvati zabranu korisnika %s',
+ joinChannel: 'Pristupi sobi %s',
+ cite: '%s reče:',
+ urlDialog: 'Molimo vas, unesite adresu (URL) web stranice:',
+ deleteMessage: 'Delete this chat message',
+ deleteMessageConfirm: 'Really delete the selected chat message?',
+ errorCookiesRequired: 'Pažnja: kolačići su neophodni za ovaj Chat.',
+ errorUserNameNotFound: 'Greška: korisnik %s nije pronađen.',
+ errorMissingText: 'Greška: nedostaje tekst poruke.',
+ errorMissingUserName: 'Greška: nedostaje korisničko ime.',
+ errorInvalidUserName: 'Error: Invalid username.',
+ errorUserNameInUse: 'Error: Username already in use.',
+ errorMissingChannelName: 'Greška: nedostaje ime sobe.',
+ errorInvalidChannelName: 'Greška: pogrešno ime sobe: %s',
+ errorPrivateMessageNotAllowed: 'Greška: privatne poruke nisu dozvoljene.',
+ errorInviteNotAllowed: 'Greška: Nije vam dozvoljeno da pozivate nekoga u ovu sobu.',
+ errorUninviteNotAllowed: 'Greška: Nije vam dozvoljeno da nekoga opozovete iz ove sobe.',
+ errorNoOpenQuery: 'Greška: Privatna soba nije otvorena.',
+ errorKickNotAllowed: 'Greška: Nije vam dozvoljeno da izbacite %s.',
+ errorCommandNotAllowed: 'Greška: Komanda nije dozvoljena: %s',
+ errorUnknownCommand: 'Greška: Nepoznata komanda: %s',
+ errorMaxMessageRate: 'Error: You exceeded the maximum number of messages per minute.',
+ errorConnectionTimeout: 'Greška: Vreme konekcije je isteklo. Molimo vas pokušajte ponovo.',
+ errorConnectionStatus: 'Greška: Status konekcije: %s',
+ errorSoundIO: 'Error: Failed to load sound file (Flash IO Error).',
+ errorSocketIO: 'Error: Connection to socket server failed (Flash IO Error).',
+ errorSocketSecurity: 'Error: Connection to socket server failed (Flash Security Error).',
+ errorDOMSyntax: 'Error: Invalid DOM Syntax (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/sv.js b/library/ajaxchat/chat/js/lang/sv.js
new file mode 100644
index 000000000..6c8ded6cc
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/sv.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author Eric [June 7,2008]
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s loggade in på Chatten.',
+ logout: '%s loggade ut från Chatten.',
+ logoutTimeout: '%s loggades ut (Timeout).',
+ logoutIP: '%s loggades ut (Felaktig IPadress).',
+ logoutKicked: '%s har loggats ut (Utsparkad).',
+ channelEnter: '%s ansluter till kanalen.',
+ channelLeave: '%s lämnade kanalen.',
+ privmsg: '(Viskning)',
+ privmsgto: '(Viskar till %s)',
+ invite: '%s bjuder in dig att ansluta till %s.',
+ inviteto: 'Din inbjudan till %s att ansluta till kanalen %s har skickats.',
+ uninvite: '%s upphävde inbjudan till dig från kanalen %s.',
+ uninviteto: 'Din uphävning av inbjudan till %s för kanalen %s har skickats.',
+ queryOpen: 'Privat kanal öppnad för %s.',
+ queryClose: 'Privat kanal för %s är stängd.',
+ ignoreAdded: '%s blev inlagd i ignoreringslistan.',
+ ignoreRemoved: 'Ta bort %s från ignoreringslistan.',
+ ignoreList: 'Ignorerade användare:',
+ ignoreListEmpty: 'Inga ignorerade Användare.',
+ who: 'Användare OnLine:',
+ whoChannel: 'Användare OnLine i kanalen %s:',
+ whoEmpty: 'Inga användare OnLine i kanalen.',
+ list: 'Tillgängliga kanaler:',
+ bans: 'Bannade Användare:',
+ bansEmpty: 'Inga bannade Användare.',
+ unban: 'Banningen av %s är upphävd.',
+ whois: '%s - IPadress:',
+ whereis: '%s är i kanalen %s.',
+ roll: '%s rullar %s och får %s.',
+ nick: '%s har bytt namn till %s.',
+ toggleUserMenu: 'Skifta användarmeny för %s',
+ userMenuLogout: 'Logga Ut',
+ userMenuWho: 'Lista användare OnLine',
+ userMenuList: 'Lista tillgängliga kanaler',
+ userMenuAction: 'Beskriv händelse',
+ userMenuRoll: 'Rulla tärningar',
+ userMenuNick: 'Ändra användarnamn',
+ userMenuEnterPrivateRoom: 'Gå in i privat rum',
+ userMenuSendPrivateMessage: 'Skicka privat meddelande',
+ userMenuDescribe: 'Skicka privat händelse',
+ userMenuOpenPrivateChannel: 'Öppna privat kanal',
+ userMenuClosePrivateChannel: 'Stäng privat kanal',
+ userMenuInvite: 'Bjud in',
+ userMenuUninvite: 'Upphäv inbjudan',
+ userMenuIgnore: 'Ignorera/Acceptera',
+ userMenuIgnoreList: 'Lista ignorerade användare',
+ userMenuWhereis: 'Visa kanal',
+ userMenuKick: 'Sparka ut/Banna',
+ userMenuBans: 'Lista bannade användare',
+ userMenuWhois: 'Visa IP',
+ unbanUser: 'Upphäv banningen av %s',
+ joinChannel: 'Anslut till kanalen %s',
+ cite: '%s sa:',
+ urlDialog: 'Skriv in adressen (URL) till websidan:',
+ deleteMessage: 'Radera detta meddelande',
+ deleteMessageConfirm: 'Vill du radera det valda meddelandet?',
+ errorCookiesRequired: 'Cookies[kakor] krävs för denna Chat.',
+ errorUserNameNotFound: 'Error: Användaren %s hittades inte.',
+ errorMissingText: 'Error: Meddelandetext saknas.',
+ errorMissingUserName: 'Error: Användarnamn saknas.',
+ errorInvalidUserName: 'Error: Ogiltigt användarnamn.',
+ errorUserNameInUse: 'Error: Användarnamnet används redan.',
+ errorMissingChannelName: 'Error: Kanalnamn saknas.',
+ errorInvalidChannelName: 'Error: Felaktigt kanalnamn: %s',
+ errorPrivateMessageNotAllowed: 'Error: Privata meddelanden är inte tillåtna.',
+ errorInviteNotAllowed: 'Error: Du saknar rättighet att bjuda in någon till denna kanalen.',
+ errorUninviteNotAllowed: 'Error: Du saknar rättighet att upphäva en inbjudan till någon i denna kanalen.',
+ errorNoOpenQuery: 'Error: Ingen privat kanal öppen.',
+ errorKickNotAllowed: 'Error: Du saknar rättighet att sparka %s.',
+ errorCommandNotAllowed: 'Error: Otillåtet kommando: %s',
+ errorUnknownCommand: 'Error: Okänt kommando: %s',
+ errorMaxMessageRate: 'Error: Du överskred det maxiamala antalet meddelanden per minut.',
+ errorConnectionTimeout: 'Error: Anslutningen fick "timeout". Var vänlig och prova igen.',
+ errorConnectionStatus: 'Error: Anslutningens status: %s',
+ errorSoundIO: 'Error: Misslyckades att ladda ljudfil (Flash IO Error).',
+ errorSocketIO: 'Error: Anslutningen till "socket server" misslyckades (Flash IO Error).',
+ errorSocketSecurity: 'Error: Anslutningen till "socket server" misslyckades (Flash Security Error).',
+ errorDOMSyntax: 'Error: Ogiltig DOM Syntax (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/th.js b/library/ajaxchat/chat/js/lang/th.js
new file mode 100644
index 000000000..35c60a51b
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/th.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ * @Translate by Charge01 @ http://www.thaira2lovers.co.cc
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s เข้าสู่ห้องแชท',
+ logout: '%s ออกจากห้องแชท',
+ logoutTimeout: '%s ออกจากห้องแชทแล้ว (Timeout).',
+ logoutIP: '%s ออกจากระบบแล้ว (IP address ไม่ถูกต้อง).',
+ logoutKicked: '%s ออกจากระบบแล้ว (ถูกไล่).',
+ channelEnter: '%s เข้าห้องมา',
+ channelLeave: '%s ออกห้องไป',
+ privmsg: '(กระซิบ)',
+ privmsgto: '(กระซิบไป %s)',
+ invite: '%s เชิญให้ %s เข้าร่วม',
+ inviteto: 'การเชิญ %s เพื่อเข้าสู่ห้อง %s ถูกส่งแล้ว',
+ uninvite: '%s ถอนคำเชิญออกจากห้อง %s.',
+ uninviteto: 'การเชิญ %s สำหรับห้อง %s ถูกส่งแล้ว',
+ queryOpen: 'ห้องส่วนตัวถูกเปิดที่ %s',
+ queryClose: 'ห้องส่วนตัว %s ถูกปิด',
+ ignoreAdded: 'เพิ่ม %s สู่รายการไม่สนใจ',
+ ignoreRemoved: 'ลบ %s ออกจากรายการไม่สนใจ',
+ ignoreList: 'ผู้ใช้ที่ถูกไม่สนใจ:',
+ ignoreListEmpty: 'ไม่มีผู้ใช้ที่ไม่สนใจ',
+ who: 'ผู้ใช้ออนไลนอยู่:',
+ whoChannel: 'ผู้ใช้ออนไลน์ในห้อง %s:',
+ whoEmpty: 'ไม่มีผู้ใช้ออนไลน์อยู่ในห้อง',
+ list: 'ห้องแชทที่มีอยู่:',
+ bans: 'ผู้ใช้ถูกแบน:',
+ bansEmpty: 'ไม่มีผู้ใช้ที่ถูกแบน',
+ unban: 'การแบนของ %s ถูกยกเลิก',
+ whois: 'ผู้ใช้ %s - IP address:',
+ whereis: 'ผู้ใช้ %s อยู่ในห้อง %s.',
+ roll: '%s rolls %s and gets %s.',
+ nick: '%s ตอนนี้เปลี่ยนชื่อเป็น %s.',
+ toggleUserMenu: 'เปิดเมนูสำหรับ %s',
+ userMenuLogout: 'ออกจากระบบ',
+ userMenuWho: 'รายชื่อผู้ใช้',
+ userMenuList: 'รายชื่อห้องที่ปรากฎ',
+ userMenuAction: 'บอกกล่าวการกระทำ',
+ userMenuRoll: 'ทอยลูกเต๋า',
+ userMenuNick: 'เปลี่ยนชื่อ',
+ userMenuEnterPrivateRoom: 'เข้้าห้องส่วนตัว',
+ userMenuSendPrivateMessage: 'ส่งข้อความส่วนตัว',
+ userMenuDescribe: 'ส่งการกระทำส่วนตัว',
+ userMenuOpenPrivateChannel: 'เปิดห้องแชทส่วนตัว',
+ userMenuClosePrivateChannel: 'ปิดห้องแชทส่วนตัว',
+ userMenuInvite: 'เชิญ',
+ userMenuUninvite: 'ถอนคำเชิญ',
+ userMenuIgnore: 'ไม่สนใจ/ยอมรับ',
+ userMenuIgnoreList: 'รายชื่อผู้ใช้ที่ไม่สนใจ',
+ userMenuWhereis: 'แสดงห้องแชท',
+ userMenuKick: 'ไล่/แบน',
+ userMenuBans: 'รายชื่อที่ถูกแบน',
+ userMenuWhois: 'แสดง IP',
+ unbanUser: 'ปลดการแบนของผู้ใช้ %s',
+ joinChannel: 'ร่วมห้อง %s',
+ cite: '%s พูด:',
+ urlDialog: 'กรุณาใส่ที่อยู่เว็บ (URL):',
+ deleteMessage: 'ลบข้อความแชทนี้',
+ deleteMessageConfirm: 'แน่ใจว่าจะลบข้อความที่เลือกนี้?',
+ errorCookiesRequired: 'ห้องแชทนี้ต้องการใช้งานคุกกี้',
+ errorUserNameNotFound: 'Error: ไม่พบผู้ใช้ %s',
+ errorMissingText: 'Error: ข้อความหายไป',
+ errorMissingUserName: 'Error: ผู้ใช้หายไป',
+ errorInvalidUserName: 'Error: ผู้ใช้ไม่ถูกต้อง',
+ errorUserNameInUse: 'Error: ผู้ใช้นี้ถูกใช้งานอยู่',
+ errorMissingChannelName: 'Error: ชื่อห้องแชทหายไป',
+ errorInvalidChannelName: 'Error: ชื่อห้องแชทไม่ถูกต้อง: %s',
+ errorPrivateMessageNotAllowed: 'Error: ไม่อนุญาตข้อความส่วนตัว',
+ errorInviteNotAllowed: 'Error: ไม่อนุญาตให้คุณเชิญใครในห้องนี้',
+ errorUninviteNotAllowed: 'Error: ไม่อนุญาตให้คุณถอดการเชิญในห้องนี้',
+ errorNoOpenQuery: 'Error: ไม่เปิดห้องส่วนตัว',
+ errorKickNotAllowed: 'Error: ไม่อนุญาตให้คุณไล่ %s.',
+ errorCommandNotAllowed: 'Error: ไม่อนุญาตคำสั่ง : %s',
+ errorUnknownCommand: 'Error: คำสั่งอะไรเนีย: %s',
+ errorMaxMessageRate: 'Error: ส่งข้อความเกินกำหนดใน 1 นาที',
+ errorConnectionTimeout: 'Error: การเชื่อมต่อหมดเวลา กรุณาลองอีกครั้ง',
+ errorConnectionStatus: 'Error: สถานะการเชื่อมต่อ: %s',
+ errorSoundIO: 'Error: โหลดไฟล์เสียงผิดพลาด (อาจเกิดจาก Flash IO Error, โปรแกรมช่วยดาวน์โหลด).',
+ errorSocketIO: 'Error: การเชื่อมต่อถึง socket เซิร์ฟเวอร์ผิดพลาด (อาจเกิดจาก Flash IO Error).',
+ errorSocketSecurity: 'Error: การเชื่อมต่อถึง socket เซิร์ฟเวอร์ผิดพลาด (Flash Security Error).',
+ errorDOMSyntax: 'Error: DOM Syntax ไม่ถูกต้อง (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/tr.js b/library/ajaxchat/chat/js/lang/tr.js
new file mode 100644
index 000000000..63d9b5aee
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/tr.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author Cydonian
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s sohbet odasına girdi.',
+ logout: '%s sohbet odasından çıktı.',
+ logoutTimeout: '%s sohbetten çıkarıldı (Bağlantı Gecikmesi).',
+ logoutIP: '%s sohbetten çıkarıldı (Geçersiz IP adresi).',
+ logoutKicked: '%s sohbetten çıkarıldı (Atıldı).',
+ channelEnter: '%s kanala girdi.',
+ channelLeave: '%s kanaldan çıktı.',
+ privmsg: '(fısıldıyor)',
+ privmsgto: '(%s size fısıldıyor)',
+ invite: '%s sizi %s odasına davet ediyor.',
+ inviteto: '%s kanalı için davetiniz %s e gönderildi.',
+ uninvite: '%s sizi %s kanalından çıkmaya çağırıyor.',
+ uninviteto: '%s kanalından çıkma davetiniz %s e gönderildi',
+ queryOpen: '%s e özel kanal açıldı.',
+ queryClose: '%s e özel kanal kapatıldı.',
+ ignoreAdded: '%s blok listesine eklendi.',
+ ignoreRemoved: '%s blok listesinden çıkarıldı.',
+ ignoreList: 'Blok edilen üyeler:',
+ ignoreListEmpty: 'Blok Listesi boş.',
+ who: 'Çevrimiçi üyeler:',
+ whoChannel: '%s kanalındaki çevrimiçi üyeler:',
+ whoEmpty: 'Kanalda çevrimiçi üye yoktur.',
+ list: 'Açık Odalar:',
+ bans: 'Yasaklanan Üyeler:',
+ bansEmpty: 'Yasaklı Listesi boş.',
+ unban: '%s adlı üyenin yasağı kaldırıldı.',
+ whois: 'Üye %s - IP adresi:',
+ whereis: '%s adlı üye %s kanalında.',
+ roll: '%s sallar %s ve alır %s.',
+ nick: '%s rumuzunu %s yaptı.',
+ toggleUserMenu: 'Toggle user menu for %s',
+ userMenuLogout: 'Çıkış',
+ userMenuWho: 'Çevrimiçi üyeleri göster',
+ userMenuList: 'Uygun odaları göster',
+ userMenuAction: 'Aksiyon:',
+ userMenuRoll: 'Zarları at',
+ userMenuNick: 'Rumuz değiştir',
+ userMenuEnterPrivateRoom: 'Özel odaya gir',
+ userMenuSendPrivateMessage: 'Özel mesaj gönder',
+ userMenuDescribe: 'Özel aksiyon gönder',
+ userMenuOpenPrivateChannel: 'Özel kanal aç',
+ userMenuClosePrivateChannel: 'Özel kanalı kapat',
+ userMenuInvite: 'Davet et',
+ userMenuUninvite: 'Davet etme',
+ userMenuIgnore: 'İptal/Kabul',
+ userMenuIgnoreList: 'Bloklanmış üyeleri göster',
+ userMenuWhereis: 'Kanalı göster',
+ userMenuKick: 'At/Yasakla',
+ userMenuBans: 'Yasaklanmış üyeleri göster',
+ userMenuWhois: 'IP göster',
+ unbanUser: 'Üye %s nin yasağını kaldır',
+ joinChannel: '%s kanalına Gir',
+ cite: '%s :',
+ urlDialog: 'Web sayfasının adresini (URL) giriniz:',
+ deleteMessage: 'Bu mesajı sil',
+ deleteMessageConfirm: 'İşaretli mesajı gerçekten silmek istiyor musunuz?',
+ errorCookiesRequired: 'Bu sohbet için Cookies açık olmalıdır.',
+ errorUserNameNotFound: 'Hata: %s adlı üye bulunamadı.',
+ errorMissingText: 'Hata: Mesaj yazısı yok.',
+ errorMissingUserName: 'Hata: Üye adı yok.',
+ errorInvalidUserName: 'Hata: Geçersiz üye adı.',
+ errorUserNameInUse: 'Hata: Üye adı kullanımda.',
+ errorMissingChannelName: 'Hata: Kanal adı yok.',
+ errorInvalidChannelName: 'Hata: Geçersiz kanal adı: %s',
+ errorPrivateMessageNotAllowed: 'Hata: Özel mesajlara izin verilmiyor.',
+ errorInviteNotAllowed: 'Hata: Başka bir üyeyi bu kanala davet etme izniniz yok.',
+ errorUninviteNotAllowed: 'Hata: Başka bir üyeyi bu kanaldan dışarı davete izniniz yok.',
+ errorNoOpenQuery: 'Hata: Açık özel kanal yok.',
+ errorKickNotAllowed: 'Hata: %s adlı üyeyi atma yetkiniz yok.',
+ errorCommandNotAllowed: 'Hata: Bu komuta izin yok: %s',
+ errorUnknownCommand: 'Hata: Bilinmeyen komut: %s',
+ errorMaxMessageRate: 'Hata: Bir dakika içinde atılabilecek maksimum mesaj sayısına ulaştınız.',
+ errorConnectionTimeout: 'Hata: Bağlantı süresi aşımı. Lütfen tekrar deneyin.',
+ errorConnectionStatus: 'Hata: Bağlantı durumu: %s',
+ errorSoundIO: 'Hata: Ses dosyası yüklenemedi (Flash IO Hatası).',
+ errorSocketIO: 'Hata: Socket server bağlantısı yapılamadı (Flash IO Hatası).',
+ errorSocketSecurity: 'Hata: Socket server bağlantısı yapılamadı(Flash Güvenlik Hatası).',
+ errorDOMSyntax: 'Hata: Geçersiz DOM Sözdizimi (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/uk.js b/library/ajaxchat/chat/js/lang/uk.js
new file mode 100644
index 000000000..42f61804e
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/uk.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author Yuriy Smetana (yura@stryi.com.ua, http://joomla.org.ua)
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s заходить до Чату.',
+ logout: '%s виходить з Чату.',
+ logoutTimeout: '%s залишає чат (був неактивний).',
+ logoutIP: '%s залишає чат (неправильна IP адреса).',
+ logoutKicked: '%s залишає чат (примусово).',
+ channelEnter: '%s заходить до кімнати.',
+ channelLeave: '%s залишає кімнату.',
+ privmsg: '(пошепки)',
+ privmsgto: '(пошепки до %s)',
+ invite: '%s запрошує відвідати кімнату %s.',
+ inviteto: 'Запрошення до %s відвідати кімнату %s надіслано.',
+ uninvite: '%s відмовив в запрошенні до кімнати %s.',
+ uninviteto: 'Відміну запрошення %s до кімнати %s було надіслано.',
+ queryOpen: 'Створено приватну кімнату з %s.',
+ queryClose: 'Приватну кімнату з %s зачинено.',
+ ignoreAdded: '%s додано до переліку ігнорованих осіб.',
+ ignoreRemoved: '%s вилучено з переліку ігнорованих осіб.',
+ ignoreList: 'Ігроновані особи:',
+ ignoreListEmpty: 'Ігнорованих осіб немає.',
+ who: 'Зараз в Чаті:',
+ whoChannel: 'Зараз в кімнаті %s такі користувачі:',
+ whoEmpty: 'Ця кімната порожня.',
+ list: 'Інші кімнати:',
+ bans: 'Заблоковані користувачі:',
+ bansEmpty: 'Немає заблокованих користувачів.',
+ unban: 'Блокування користувача %s відмінено.',
+ whois: 'Користувач %s - IP адреса:',
+ whereis: 'Користувач %s в кімнаті %s.',
+ roll: 'Користувачем %s кинуто %s, випало %s.',
+ nick: 'Користувач %s відтепер буде називатись %s.',
+ toggleUserMenu: 'Меню користувача %s',
+ userMenuLogout: 'Вийти',
+ userMenuWho: 'Показати присутніх',
+ userMenuList: 'Показати кімнати',
+ userMenuAction: 'Описати чим зараз займаєтесь',
+ userMenuRoll: 'Кинути кості',
+ userMenuNick: 'Змінити собі ім\'я',
+ userMenuEnterPrivateRoom: 'Увійти до приватної кімнати',
+ userMenuSendPrivateMessage: 'Надіслати особисте повідомлення',
+ userMenuDescribe: 'Описати чим займаєтесь (приватно)',
+ userMenuOpenPrivateChannel: 'Створити приватну кімнату',
+ userMenuClosePrivateChannel: 'Закрити приватну кімнату',
+ userMenuInvite: 'Запросити',
+ userMenuUninvite: 'Відмовити',
+ userMenuIgnore: 'Ігнорувати/Приймати',
+ userMenuIgnoreList: 'Перелік ігнорованих',
+ userMenuWhereis: 'Показати кімнати',
+ userMenuKick: 'Викинути/Заблокувати',
+ userMenuBans: 'Перелік заблокованих користувачів',
+ userMenuWhois: 'Показати IP',
+ unbanUser: 'Відмінити блокування користувача %s',
+ joinChannel: 'Зайти в кімнату %s',
+ cite: '%s пише:',
+ urlDialog: 'Будь-ласка, введіть адресу веб-сторінки:',
+ deleteMessage: 'Видалити це повідомлення',
+ deleteMessageConfirm: 'Справді видалити це повідомлення?',
+ errorCookiesRequired: 'Для Чату необхідно дозволити Cookies.',
+ errorUserNameNotFound: 'Помилка: користувач %s не існує.',
+ errorMissingText: 'Помилка: повідомлення відсутнє.',
+ errorMissingUserName: 'Помилка: відсутнє ім\'я користувача.',
+ errorInvalidUserName: 'Error: Invalid username.',
+ errorUserNameInUse: 'Error: Username already in use.',
+ errorMissingChannelName: 'Помилка: відсутня назва кімнати.',
+ errorInvalidChannelName: 'Помилка: хибна назва кімнати: %s',
+ errorPrivateMessageNotAllowed: 'Помилка: приватні повідомлення заборонені.',
+ errorInviteNotAllowed: 'Помилка: Вам заборонено запрошувати до цієї кімнати.',
+ errorUninviteNotAllowed: 'Помилка: Вам заборонено відмовляти в запрошенні до цієї кімнати.',
+ errorNoOpenQuery: 'Помилка: не існує приватних кімнат.',
+ errorKickNotAllowed: 'Помилка: Вам недозволено викидати користувачів %s.',
+ errorCommandNotAllowed: 'Помилка: недозволена команда: %s',
+ errorUnknownCommand: 'Помилка: хибна команда: %s',
+ errorMaxMessageRate: 'Помилка: Ви досягли максимальної кількості повідомлень за хвилину.',
+ errorConnectionTimeout: 'Помилка: час очікування минув. Будь-ласка, спробуйте знову.',
+ errorConnectionStatus: 'Помилка: стан з\'єднання: %s',
+ errorSoundIO: 'Помилка: Неможливо відкрити звуковий файл (Flash IO Error).',
+ errorSocketIO: 'Помилка: З\'єднання з сервером невдалося (Flash IO Error).',
+ errorSocketSecurity: 'Помилка: З\'єднання з сервером невдалося (Flash Security Error).',
+ errorDOMSyntax: 'Помилка: Invalid DOM Syntax (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/zh-tw.js b/library/ajaxchat/chat/js/lang/zh-tw.js
new file mode 100644
index 000000000..c6b971953
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/zh-tw.js
@@ -0,0 +1,91 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s已登入',
+ logout: '%s已登出',
+ logoutTimeout: '%s已登出(連線逾時)',
+ logoutIP: '%s已登出(無效的IP address)',
+ logoutKicked: '%s已登出(被踢掉了)',
+ channelEnter: '%s已進入',
+ channelLeave: '%s已離開',
+ privmsg: '(悄悄話)',
+ privmsgto: '(給 %s 的悄悄話)',
+ invite: '%s 邀請您進入 %s .',
+ inviteto: '請 %s 進入 %s 的邀請函已發送',
+ uninvite: '%s 於 %s 收回了邀請函',
+ uninviteto: '請 %s 進入 %s 的邀請函已收回',
+ queryOpen: '允許 %s 進入私人房',
+ queryClose: '已不允許 %s 進入私人房',
+ ignoreAdded: '增加 %s 至忽略清單',
+ ignoreRemoved: '移除 %s 自忽略清單',
+ ignoreList: '已忽略來自以下人士的訊息:',
+ ignoreListEmpty: '忽略清單是空的。',
+ who: '已上線會員:',
+ whoChannel: '在 %s 的已上線會員:',
+ whoEmpty: '沒有人在那裡。',
+ list: '可進入的房間:',
+ bans: '被禁止使用的人:',
+ bansEmpty: '沒有被禁止使用的人。',
+ unban: '開放之前被禁的使用者 %s :',
+ whois: '使用者 %s - IP address:',
+ whereis: '使用者 %s 正在 %s 。',
+ roll: '%s 擲了 %s 得到了 %s 。',
+ nick: '%s 現在暱稱改為 %s',
+ toggleUserMenu: '開啟為 %s 特製的功能表',
+ userMenuLogout: '登出',
+ userMenuWho: '顯示已上線會員',
+ userMenuList: '顯示可進入的房間',
+ userMenuAction: '描述動作',
+ userMenuRoll: '擲骰子',
+ userMenuNick: '換暱稱',
+ userMenuEnterPrivateRoom: '進入私人房',
+ userMenuSendPrivateMessage: '傳送悄悄話',
+ userMenuDescribe: '傳送私人動作',
+ userMenuOpenPrivateChannel: '允許進入私人房',
+ userMenuClosePrivateChannel: '不允許進入私人房',
+ userMenuInvite: '邀請某人(進入自己的私人房)',
+ userMenuUninvite: '收回邀請',
+ userMenuIgnore: '忽略/接受某人的訊息',
+ userMenuIgnoreList: '顯示忽略清單',
+ userMenuWhereis: '顯示所在地',
+ userMenuKick: '踢掉/禁人',
+ userMenuBans: '顯示被禁的使用者',
+ userMenuWhois: '顯示 IP',
+ unbanUser: '開放之前被禁的使用者 %s ',
+ joinChannel: '進入 %s',
+ cite: '%s 說:',
+ urlDialog: '請輸入網址(URL):',
+ deleteMessage: '刪除這條訊息',
+ deleteMessageConfirm: '真的要刪除這條訊息嗎?',
+ errorCookiesRequired: '請打開Cookies!',
+ errorUserNameNotFound: '錯誤:沒有使用者 %s ……',
+ errorMissingText: '錯誤:未輸入訊息……',
+ errorMissingUserName: '錯誤:未輸入使用者帳號……',
+ errorInvalidUserName: '錯誤:帳號錯誤……',
+ errorUserNameInUse: '錯誤:帳號使用中……',
+ errorMissingChannelName: '錯誤:不存在的房間……',
+ errorInvalidChannelName: '錯誤:不存在的房間: %s ……',
+ errorPrivateMessageNotAllowed: '錯誤:不允許使用悄悄話功能……',
+ errorInviteNotAllowed: '錯誤:不允許邀請別人來這裡……',
+ errorUninviteNotAllowed: '錯誤:不允許收回邀請……',
+ errorNoOpenQuery: '錯誤:沒有私人房是開放的……',
+ errorKickNotAllowed: '錯誤:你不能把 %s 踢掉!',
+ errorCommandNotAllowed: '錯誤:不允許使用的指令: %s ……',
+ errorUnknownCommand: '錯誤:無法辨識的命令: %s ……',
+ errorMaxMessageRate: '錯誤:已達到一分鐘所能發送的最大訊息數量……',
+ errorConnectionTimeout: '錯誤:連線逾時,請再連一次……',
+ errorConnectionStatus: '錯誤:連線狀態: %s ',
+ errorSoundIO: '錯誤:無法讀取音效檔 (Flash IO Error).',
+ errorSocketIO: '錯誤:無法連線到伺服器的socket (Flash IO Error).',
+ errorSocketSecurity: '錯誤:無法連線到伺服器的socket (Flash Security Error).',
+ errorDOMSyntax: '錯誤:無效的 DOM 語法 (DOM ID: %s).'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/lang/zh.js b/library/ajaxchat/chat/js/lang/zh.js
new file mode 100644
index 000000000..ba41fad7f
--- /dev/null
+++ b/library/ajaxchat/chat/js/lang/zh.js
@@ -0,0 +1,92 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @author mikespook
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Ajax Chat language Object:
+var ajaxChatLang = {
+
+ login: '%s 进入聊天室。',
+ logout: '%s 退出聊天室。',
+ logoutTimeout: '%s 因超时,退出聊天室。',
+ logoutIP: '%s 因不合法的 IP 地址退出。',
+ logoutKicked: '%s 被踢出聊天室。',
+ channelEnter: '%s 进入频道。',
+ channelLeave: '%s 退出频道。',
+ privmsg: '(悄悄话)',
+ privmsgto: '(对 %s 说悄悄话)',
+ invite: '%s 邀请你加入 %s。',
+ inviteto: '对 %s 在频道 %s 的邀请已经发送。',
+ uninvite: '%s 撤销了你在频道 %s 的邀请。',
+ uninviteto: '对 %s 在频道 %s 的撤销邀请已经发送。',
+ queryOpen: '私人频道对 %s 打开。',
+ queryClose: '私人频道对 %s 关闭。',
+ ignoreAdded: '将 %s 加入忽略列表。',
+ ignoreRemoved: '从忽略列表中移除 %s。',
+ ignoreList: '已忽略用户:',
+ ignoreListEmpty: '已列出未忽略用户。',
+ who: '在线用户:',
+ whoChannel: '频道 %s 的在线用户:',
+ whoEmpty: '指定频道中没有在线用户。',
+ list: '可用频道:',
+ bans: '已禁言用户:',
+ bansEmpty: '已列出未禁言用户。',
+ unban: '用户 %s 的禁言已取消。',
+ whois: '用户 %s - IP 地址:',
+ whereis: '用户 %s 进入频道 %s.',
+ roll: '%s 摇出了 %s 并且得到了 %s。',
+ nick: '%s 改名为 %s。',
+ toggleUserMenu: '切换用户 %s 的菜单',
+ userMenuLogout: '退出',
+ userMenuWho: '列出在线用户',
+ userMenuList: '列出可用的频道',
+ userMenuAction: '动作描述',
+ userMenuRoll: '摇骰子',
+ userMenuNick: '修改用户名',
+ userMenuEnterPrivateRoom: '进入私人房间',
+ userMenuSendPrivateMessage: '发送私人消息',
+ userMenuDescribe: '发送私人动作',
+ userMenuOpenPrivateChannel: '打开私人频道',
+ userMenuClosePrivateChannel: '关闭私人频道',
+ userMenuInvite: '邀请',
+ userMenuUninvite: '撤销邀请',
+ userMenuIgnore: '忽略/接收',
+ userMenuIgnoreList: '列出忽略的用户',
+ userMenuWhereis: '显示频道',
+ userMenuKick: '踢/禁',
+ userMenuBans: '列出禁言的用户',
+ userMenuWhois: '显示 IP',
+ unbanUser: '撤销用户 %s 禁言',
+ joinChannel: '加入频道 %s',
+ cite: '%s 说:',
+ urlDialog: '请输入网页地址(URL):',
+ deleteMessage: '删除聊天记录',
+ deleteMessageConfirm: '要删除已经发出的聊天记录吗?',
+ errorCookiesRequired: '聊天室需要开启 Cookie 功能。',
+ errorUserNameNotFound: '错误:未找到用户 %s。',
+ errorMissingText: '错误:缺少消息内容。',
+ errorMissingUserName: '错误:缺少用户名。',
+ errorInvalidUserName: 'Error: Invalid username.',
+ errorUserNameInUse: 'Error: Username already in use.',
+ errorMissingChannelName: '错误:缺少频道名。',
+ errorInvalidChannelName: '错误:错误的频道名:%s',
+ errorPrivateMessageNotAllowed: '错误:不允许发送私人消息。',
+ errorInviteNotAllowed: '错误:你在这个频道没有权限邀请他人。',
+ errorUninviteNotAllowed: '错误:你在这个频道没有权限取消邀请。',
+ errorNoOpenQuery: '错误:没有私人频道开放。',
+ errorKickNotAllowed: '错误:没有权限提出 %s。',
+ errorCommandNotAllowed: '错误:不允许的命令:%s',
+ errorUnknownCommand: '错误:未知命令:%s',
+ errorMaxMessageRate: '错误:超出了每分钟最大讯息数。',
+ errorConnectionTimeout: '错误:连接超时,请重试。',
+ errorConnectionStatus: '错误:连接状态:%s',
+ errorSoundIO: '错误:加载声音文件失败(Flash IO 错误)。',
+ errorSocketIO: '错误:连接 Socket 服务器失败(Flash IO 错误)。',
+ errorSocketSecurity: '错误:连接 Socket 服务器失败(Flash 安全错误)。',
+ errorDOMSyntax: '错误:错误的 DOM 语法(DOM ID:%s)。'
+
+} \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/logs.js b/library/ajaxchat/chat/js/logs.js
new file mode 100644
index 000000000..9ec694cee
--- /dev/null
+++ b/library/ajaxchat/chat/js/logs.js
@@ -0,0 +1,128 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Overrides client-side functionality for the logs view:
+
+ ajaxChat.logsMonitorMode = null;
+ ajaxChat.logsLastID = null;
+ ajaxChat.logsCommand = null;
+
+ ajaxChat.startChatUpdate = function() {
+ var infos = 'userID,userName,userRole';
+ if(this.socketServerEnabled) {
+ infos += ',socketRegistrationID';
+ }
+ this.updateChat('&getInfos=' + this.encodeText(infos));
+ }
+
+ ajaxChat.updateChat = function(paramString) {
+ // Only update if we have parameters, are in monitor mode or the lastID has changed since the last update:
+ if(paramString || this.logsMonitorMode || !this.logsLastID || this.lastID != this.logsLastID) {
+ // Update the logsLastID for the lastID check:
+ this.logsLastID = this.lastID;
+
+ var requestUrl = this.ajaxURL
+ + '&lastID='
+ + this.lastID;
+ if(paramString) {
+ requestUrl += paramString;
+ }
+ requestUrl += '&' + this.getLogsCommand();
+ this.makeRequest(requestUrl,'GET',null);
+ } else {
+ this.logsLastID = null;
+ }
+ }
+
+ ajaxChat.sendMessage = function() {
+ this.getLogs();
+ }
+
+ ajaxChat.getLogs = function() {
+ clearTimeout(this.timer);
+ this.clearChatList();
+ this.lastID = 0;
+ this.logsCommand = null;
+ this.makeRequest(this.ajaxURL,'POST',this.getLogsCommand());
+ }
+
+ ajaxChat.getLogsCommand = function() {
+ if(!this.logsCommand) {
+ if(!this.dom['inputField'].value &&
+ parseInt(this.dom['yearSelection'].value) <= 0 &&
+ parseInt(this.dom['hourSelection'].value) <= 0) {
+ this.logsMonitorMode = true;
+ } else {
+ this.logsMonitorMode = false;
+ }
+ this.logsCommand = 'command=getLogs'
+ + '&channelID=' + this.dom['channelSelection'].value
+ + '&year=' + this.dom['yearSelection'].value
+ + '&month=' + this.dom['monthSelection'].value
+ + '&day=' + this.dom['daySelection'].value
+ + '&hour=' + this.dom['hourSelection'].value
+ + '&search=' + this.encodeText(this.dom['inputField'].value);
+ }
+ return this.logsCommand;
+ }
+
+ ajaxChat.onNewMessage = function(dateObject, userID, userName, userRoleClass, messageID, messageText, channelID, ip) {
+ if(messageText.indexOf('/delete') == 0) {
+ return false;
+ }
+ if(this.logsMonitorMode) {
+ this.blinkOnNewMessage(dateObject, userID, userName, userRoleClass, messageID, messageText, channelID, ip);
+ this.playSoundOnNewMessage(
+ dateObject, userID, userName, userRoleClass, messageID, messageText, channelID, ip
+ );
+ }
+ return true;
+ }
+
+ ajaxChat.logout = function() {
+ clearTimeout(this.timer);
+ this.makeRequest(this.ajaxURL,'POST','logout=true');
+ }
+
+ ajaxChat.switchLanguage = function(langCode) {
+ window.location.search = '?view=logs&lang='+langCode;
+ }
+
+ ajaxChat.setChatUpdateTimer = function() {
+ clearTimeout(this.timer);
+ var timeout;
+ if(this.socketIsConnected && this.logsLastID && this.lastID == this.logsLastID) {
+ timeout = this.socketTimerRate;
+ } else {
+ timeout = this.timerRate;
+ if(this.socketServerEnabled && !this.socketReconnectTimer) {
+ // If the socket connection fails try to reconnect once in a minute:
+ this.socketReconnectTimer = setTimeout('ajaxChat.socketConnect();', 60000);
+ }
+ }
+ this.timer = setTimeout('ajaxChat.updateChat(null);', timeout);
+ }
+
+ ajaxChat.socketUpdate = function(data) {
+ if(this.logsMonitorMode) {
+ var xmlDoc = this.loadXML(data);
+ if(xmlDoc) {
+ var selectedChannelID = parseInt(this.dom['channelSelection'].value);
+ var channelID = parseInt(xmlDoc.firstChild.getAttribute('channelID'));
+ if(selectedChannelID == -3 || channelID == selectedChannelID ||
+ selectedChannelID == -2 && channelID >= this.privateMessageDiff ||
+ selectedChannelID == -1
+ && channelID >= this.privateChannelDiff
+ && channelID < this.privateMessageDiff
+ ) {
+ this.handleChatMessages(xmlDoc.getElementsByTagName('message'));
+ }
+ }
+ }
+ }
+ \ No newline at end of file
diff --git a/library/ajaxchat/chat/js/shoutbox.js b/library/ajaxchat/chat/js/shoutbox.js
new file mode 100644
index 000000000..b283277a7
--- /dev/null
+++ b/library/ajaxchat/chat/js/shoutbox.js
@@ -0,0 +1,12 @@
+/*
+ * @package AJAX_Chat
+ * @author Sebastian Tschan
+ * @copyright (c) Sebastian Tschan
+ * @license Modified MIT License
+ * @link https://blueimp.net/ajax/
+ */
+
+// Overrides functionality for the shoutbox view:
+
+ ajaxChat.handleLogout = function() {
+ }