Use jed to handle translatable strings
authorJack Allnutt <jack@allnutt.eu>
Thu, 4 Jul 2013 03:28:20 +0000 (04:28 +0100)
committerJack Allnutt <jack@allnutt.eu>
Thu, 4 Jul 2013 03:28:20 +0000 (04:28 +0100)
17 files changed:
client/assets/libs/jed.js [new file with mode: 0755]
client/assets/src/app.js
client/assets/src/applets/chanlist.js
client/assets/src/applets/scripteditor.js
client/assets/src/applets/settings.js
client/assets/src/index.html.tmpl
client/assets/src/models/applet.js
client/assets/src/models/application.js
client/assets/src/models/channel.js
client/assets/src/models/network.js
client/assets/src/views/application.js
client/assets/src/views/channel.js
client/assets/src/views/mediamessage.js
client/assets/src/views/nickchangebox.js
client/assets/src/views/panel.js
client/assets/src/views/serverselect.js
client/assets/src/views/userbox.js

diff --git a/client/assets/libs/jed.js b/client/assets/libs/jed.js
new file mode 100755 (executable)
index 0000000..44242bb
--- /dev/null
@@ -0,0 +1,1005 @@
+/*\r
+jed.js\r
+v0.5.0beta\r
+\r
+https://github.com/SlexAxton/Jed\r
+-----------\r
+A gettext compatible i18n library for modern JavaScript Applications\r
+\r
+by Alex Sexton - AlexSexton [at] gmail - @SlexAxton\r
+WTFPL license for use\r
+Dojo CLA for contributions\r
+\r
+Jed offers the entire applicable GNU gettext spec'd set of\r
+functions, but also offers some nicer wrappers around them.\r
+The api for gettext was written for a language with no function\r
+overloading, so Jed allows a little more of that.\r
+\r
+Many thanks to Joshua I. Miller - unrtst@cpan.org - who wrote\r
+gettext.js back in 2008. I was able to vet a lot of my ideas\r
+against his. I also made sure Jed passed against his tests\r
+in order to offer easy upgrades -- jsgettext.berlios.de\r
+*/\r
+(function (root, undef) {\r
+\r
+  // Set up some underscore-style functions, if you already have\r
+  // underscore, feel free to delete this section, and use it\r
+  // directly, however, the amount of functions used doesn't\r
+  // warrant having underscore as a full dependency.\r
+  // Underscore 1.3.0 was used to port and is licensed\r
+  // under the MIT License by Jeremy Ashkenas.\r
+  var ArrayProto    = Array.prototype,\r
+      ObjProto      = Object.prototype,\r
+      slice         = ArrayProto.slice,\r
+      hasOwnProp    = ObjProto.hasOwnProperty,\r
+      nativeForEach = ArrayProto.forEach,\r
+      breaker       = {};\r
+\r
+  // We're not using the OOP style _ so we don't need the\r
+  // extra level of indirection. This still means that you\r
+  // sub out for real `_` though.\r
+  var _ = {\r
+    forEach : function( obj, iterator, context ) {\r
+      var i, l, key;\r
+      if ( obj === null ) {\r
+        return;\r
+      }\r
+\r
+      if ( nativeForEach && obj.forEach === nativeForEach ) {\r
+        obj.forEach( iterator, context );\r
+      }\r
+      else if ( obj.length === +obj.length ) {\r
+        for ( i = 0, l = obj.length; i < l; i++ ) {\r
+          if ( i in obj && iterator.call( context, obj[i], i, obj ) === breaker ) {\r
+            return;\r
+          }\r
+        }\r
+      }\r
+      else {\r
+        for ( key in obj) {\r
+          if ( hasOwnProp.call( obj, key ) ) {\r
+            if ( iterator.call (context, obj[key], key, obj ) === breaker ) {\r
+              return;\r
+            }\r
+          }\r
+        }\r
+      }\r
+    },\r
+    extend : function( obj ) {\r
+      this.forEach( slice.call( arguments, 1 ), function ( source ) {\r
+        for ( var prop in source ) {\r
+          obj[prop] = source[prop];\r
+        }\r
+      });\r
+      return obj;\r
+    }\r
+  };\r
+  // END Miniature underscore impl\r
+\r
+  // Jed is a constructor function\r
+  var Jed = function ( options ) {\r
+    // Some minimal defaults\r
+    this.defaults = {\r
+      "locale_data" : {\r
+        "messages" : {\r
+          "" : {\r
+            "domain"       : "messages",\r
+            "lang"         : "en",\r
+            "plural_forms" : "nplurals=2; plural=(n != 1);"\r
+          }\r
+          // There are no default keys, though\r
+        }\r
+      },\r
+      // The default domain if one is missing\r
+      "domain" : "messages"\r
+    };\r
+\r
+    // Mix in the sent options with the default options\r
+    this.options = _.extend( {}, this.defaults, options );\r
+    this.textdomain( this.options.domain );\r
+\r
+    if ( this.options.domain && ! this.options.locale_data[ this.options.domain ] ) {\r
+      throw new Error('Text domain set to non-existent domain: `' + this.options.domain + '`');\r
+    }\r
+  };\r
+\r
+  // The gettext spec sets this character as the default\r
+  // delimiter for context lookups.\r
+  // e.g.: context\u0004key\r
+  // If your translation company uses something different,\r
+  // just change this at any time and it will use that instead.\r
+  Jed.context_delimiter = String.fromCharCode( 4 );\r
+\r
+  function getPluralFormFunc ( plural_form_string ) {\r
+    return Jed.PF.compile( plural_form_string || "nplurals=2; plural=(n != 1);");\r
+  }\r
+\r
+  function Chain( key, i18n ){\r
+    this._key = key;\r
+    this._i18n = i18n;\r
+  }\r
+\r
+  // Create a chainable api for adding args prettily\r
+  _.extend( Chain.prototype, {\r
+    onDomain : function ( domain ) {\r
+      this._domain = domain;\r
+      return this;\r
+    },\r
+    withContext : function ( context ) {\r
+      this._context = context;\r
+      return this;\r
+    },\r
+    ifPlural : function ( num, pkey ) {\r
+      this._val = num;\r
+      this._pkey = pkey;\r
+      return this;\r
+    },\r
+    fetch : function ( sArr ) {\r
+      if ( {}.toString.call( sArr ) != '[object Array]' ) {\r
+        sArr = [].slice.call(arguments);\r
+      }\r
+      return ( sArr && sArr.length ? Jed.sprintf : function(x){ return x; } )(\r
+        this._i18n.dcnpgettext(this._domain, this._context, this._key, this._pkey, this._val),\r
+        sArr\r
+      );\r
+    }\r
+  });\r
+\r
+  // Add functions to the Jed prototype.\r
+  // These will be the functions on the object that's returned\r
+  // from creating a `new Jed()`\r
+  // These seem redundant, but they gzip pretty well.\r
+  _.extend( Jed.prototype, {\r
+    // The sexier api start point\r
+    translate : function ( key ) {\r
+      return new Chain( key, this );\r
+    },\r
+\r
+    textdomain : function ( domain ) {\r
+      if ( ! domain ) {\r
+        return this._textdomain;\r
+      }\r
+      this._textdomain = domain;\r
+    },\r
+\r
+    gettext : function ( key ) {\r
+      return this.dcnpgettext.call( this, undef, undef, key );\r
+    },\r
+\r
+    dgettext : function ( domain, key ) {\r
+     return this.dcnpgettext.call( this, domain, undef, key );\r
+    },\r
+\r
+    dcgettext : function ( domain , key /*, category */ ) {\r
+      // Ignores the category anyways\r
+      return this.dcnpgettext.call( this, domain, undef, key );\r
+    },\r
+\r
+    ngettext : function ( skey, pkey, val ) {\r
+      return this.dcnpgettext.call( this, undef, undef, skey, pkey, val );\r
+    },\r
+\r
+    dngettext : function ( domain, skey, pkey, val ) {\r
+      return this.dcnpgettext.call( this, domain, undef, skey, pkey, val );\r
+    },\r
+\r
+    dcngettext : function ( domain, skey, pkey, val/*, category */) {\r
+      return this.dcnpgettext.call( this, domain, undef, skey, pkey, val );\r
+    },\r
+\r
+    pgettext : function ( context, key ) {\r
+      return this.dcnpgettext.call( this, undef, context, key );\r
+    },\r
+\r
+    dpgettext : function ( domain, context, key ) {\r
+      return this.dcnpgettext.call( this, domain, context, key );\r
+    },\r
+\r
+    dcpgettext : function ( domain, context, key/*, category */) {\r
+      return this.dcnpgettext.call( this, domain, context, key );\r
+    },\r
+\r
+    npgettext : function ( context, skey, pkey, val ) {\r
+      return this.dcnpgettext.call( this, undef, context, skey, pkey, val );\r
+    },\r
+\r
+    dnpgettext : function ( domain, context, skey, pkey, val ) {\r
+      return this.dcnpgettext.call( this, domain, context, skey, pkey, val );\r
+    },\r
+\r
+    // The most fully qualified gettext function. It has every option.\r
+    // Since it has every option, we can use it from every other method.\r
+    // This is the bread and butter.\r
+    // Technically there should be one more argument in this function for 'Category',\r
+    // but since we never use it, we might as well not waste the bytes to define it.\r
+    dcnpgettext : function ( domain, context, singular_key, plural_key, val ) {\r
+      // Set some defaults\r
+\r
+      plural_key = plural_key || singular_key;\r
+\r
+      // Use the global domain default if one\r
+      // isn't explicitly passed in\r
+      domain = domain || this._textdomain;\r
+\r
+      // Default the value to the singular case\r
+      val = typeof val == 'undefined' ? 1 : val;\r
+\r
+      var fallback;\r
+\r
+      // Handle special cases\r
+\r
+      // No options found\r
+      if ( ! this.options ) {\r
+        // There's likely something wrong, but we'll return the correct key for english\r
+        // We do this by instantiating a brand new Jed instance with the default set\r
+        // for everything that could be broken.\r
+        fallback = new Jed();\r
+        return fallback.dcnpgettext.call( fallback, undefined, undefined, singular_key, plural_key, val );\r
+      }\r
+\r
+      // No translation data provided\r
+      if ( ! this.options.locale_data ) {\r
+        throw new Error('No locale data provided.');\r
+      }\r
+\r
+      if ( ! this.options.locale_data[ domain ] ) {\r
+        throw new Error('Domain `' + domain + '` was not found.');\r
+      }\r
+\r
+      if ( ! this.options.locale_data[ domain ][ "" ] ) {\r
+        throw new Error('No locale meta information provided.');\r
+      }\r
+\r
+      // Make sure we have a truthy key. Otherwise we might start looking\r
+      // into the empty string key, which is the options for the locale\r
+      // data.\r
+      if ( ! singular_key ) {\r
+        throw new Error('No translation key found.');\r
+      }\r
+\r
+      // Handle invalid numbers, but try casting strings for good measure\r
+      if ( typeof val != 'number' ) {\r
+        val = parseInt( val, 10 );\r
+\r
+        if ( isNaN( val ) ) {\r
+          throw new Error('The number that was passed in is not a number.');\r
+        }\r
+      }\r
+\r
+      var key  = context ? context + Jed.context_delimiter + singular_key : singular_key,\r
+          locale_data = this.options.locale_data,\r
+          dict = locale_data[ domain ],\r
+          pluralForms = dict[""].plural_forms || (locale_data.messages || this.defaults.locale_data.messages)[""].plural_forms,\r
+          val_idx = getPluralFormFunc(pluralForms)(val) + 1,\r
+          val_list,\r
+          res;\r
+\r
+      // Throw an error if a domain isn't found\r
+      if ( ! dict ) {\r
+        throw new Error('No domain named `' + domain + '` could be found.');\r
+      }\r
+\r
+      val_list = dict[ key ];\r
+\r
+      // If there is no match, then revert back to\r
+      // english style singular/plural with the keys passed in.\r
+      if ( ! val_list || val_idx >= val_list.length ) {\r
+        res = [ null, singular_key, plural_key ];\r
+        return res[ getPluralFormFunc(pluralForms)( val ) + 1 ];\r
+      }\r
+\r
+      res = val_list[ val_idx ];\r
+\r
+      // This includes empty strings on purpose\r
+      if ( ! res  ) {\r
+        res = [ null, singular_key, plural_key ];\r
+        return res[ getPluralFormFunc(pluralForms)( val ) + 1 ];\r
+      }\r
+      return res;\r
+    }\r
+  });\r
+\r
+\r
+  // We add in sprintf capabilities for post translation value interolation\r
+  // This is not internally used, so you can remove it if you have this\r
+  // available somewhere else, or want to use a different system.\r
+\r
+  // We _slightly_ modify the normal sprintf behavior to more gracefully handle\r
+  // undefined values.\r
+\r
+  /**\r
+   sprintf() for JavaScript 0.7-beta1\r
+   http://www.diveintojavascript.com/projects/javascript-sprintf\r
+\r
+   Copyright (c) Alexandru Marasteanu <alexaholic [at) gmail (dot] com>\r
+   All rights reserved.\r
+\r
+   Redistribution and use in source and binary forms, with or without\r
+   modification, are permitted provided that the following conditions are met:\r
+       * Redistributions of source code must retain the above copyright\r
+         notice, this list of conditions and the following disclaimer.\r
+       * Redistributions in binary form must reproduce the above copyright\r
+         notice, this list of conditions and the following disclaimer in the\r
+         documentation and/or other materials provided with the distribution.\r
+       * Neither the name of sprintf() for JavaScript nor the\r
+         names of its contributors may be used to endorse or promote products\r
+         derived from this software without specific prior written permission.\r
+\r
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\r
+   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
+   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
+   DISCLAIMED. IN NO EVENT SHALL Alexandru Marasteanu BE LIABLE FOR ANY\r
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
+   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+  */\r
+  var sprintf = (function() {\r
+    function get_type(variable) {\r
+      return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();\r
+    }\r
+    function str_repeat(input, multiplier) {\r
+      for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}\r
+      return output.join('');\r
+    }\r
+\r
+    var str_format = function() {\r
+      if (!str_format.cache.hasOwnProperty(arguments[0])) {\r
+        str_format.cache[arguments[0]] = str_format.parse(arguments[0]);\r
+      }\r
+      return str_format.format.call(null, str_format.cache[arguments[0]], arguments);\r
+    };\r
+\r
+    str_format.format = function(parse_tree, argv) {\r
+      var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;\r
+      for (i = 0; i < tree_length; i++) {\r
+        node_type = get_type(parse_tree[i]);\r
+        if (node_type === 'string') {\r
+          output.push(parse_tree[i]);\r
+        }\r
+        else if (node_type === 'array') {\r
+          match = parse_tree[i]; // convenience purposes only\r
+          if (match[2]) { // keyword argument\r
+            arg = argv[cursor];\r
+            for (k = 0; k < match[2].length; k++) {\r
+              if (!arg.hasOwnProperty(match[2][k])) {\r
+                throw(sprintf('[sprintf] property "%s" does not exist', match[2][k]));\r
+              }\r
+              arg = arg[match[2][k]];\r
+            }\r
+          }\r
+          else if (match[1]) { // positional argument (explicit)\r
+            arg = argv[match[1]];\r
+          }\r
+          else { // positional argument (implicit)\r
+            arg = argv[cursor++];\r
+          }\r
+\r
+          if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {\r
+            throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));\r
+          }\r
+\r
+          // Jed EDIT\r
+          if ( typeof arg == 'undefined' || arg === null ) {\r
+            arg = '';\r
+          }\r
+          // Jed EDIT\r
+\r
+          switch (match[8]) {\r
+            case 'b': arg = arg.toString(2); break;\r
+            case 'c': arg = String.fromCharCode(arg); break;\r
+            case 'd': arg = parseInt(arg, 10); break;\r
+            case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;\r
+            case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;\r
+            case 'o': arg = arg.toString(8); break;\r
+            case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;\r
+            case 'u': arg = Math.abs(arg); break;\r
+            case 'x': arg = arg.toString(16); break;\r
+            case 'X': arg = arg.toString(16).toUpperCase(); break;\r
+          }\r
+          arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);\r
+          pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';\r
+          pad_length = match[6] - String(arg).length;\r
+          pad = match[6] ? str_repeat(pad_character, pad_length) : '';\r
+          output.push(match[5] ? arg + pad : pad + arg);\r
+        }\r
+      }\r
+      return output.join('');\r
+    };\r
+\r
+    str_format.cache = {};\r
+\r
+    str_format.parse = function(fmt) {\r
+      var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;\r
+      while (_fmt) {\r
+        if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {\r
+          parse_tree.push(match[0]);\r
+        }\r
+        else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {\r
+          parse_tree.push('%');\r
+        }\r
+        else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {\r
+          if (match[2]) {\r
+            arg_names |= 1;\r
+            var field_list = [], replacement_field = match[2], field_match = [];\r
+            if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {\r
+              field_list.push(field_match[1]);\r
+              while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {\r
+                if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {\r
+                  field_list.push(field_match[1]);\r
+                }\r
+                else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {\r
+                  field_list.push(field_match[1]);\r
+                }\r
+                else {\r
+                  throw('[sprintf] huh?');\r
+                }\r
+              }\r
+            }\r
+            else {\r
+              throw('[sprintf] huh?');\r
+            }\r
+            match[2] = field_list;\r
+          }\r
+          else {\r
+            arg_names |= 2;\r
+          }\r
+          if (arg_names === 3) {\r
+            throw('[sprintf] mixing positional and named placeholders is not (yet) supported');\r
+          }\r
+          parse_tree.push(match);\r
+        }\r
+        else {\r
+          throw('[sprintf] huh?');\r
+        }\r
+        _fmt = _fmt.substring(match[0].length);\r
+      }\r
+      return parse_tree;\r
+    };\r
+\r
+    return str_format;\r
+  })();\r
+\r
+  var vsprintf = function(fmt, argv) {\r
+    argv.unshift(fmt);\r
+    return sprintf.apply(null, argv);\r
+  };\r
+\r
+  Jed.parse_plural = function ( plural_forms, n ) {\r
+    plural_forms = plural_forms.replace(/n/g, n);\r
+    return Jed.parse_expression(plural_forms);\r
+  };\r
+\r
+  Jed.sprintf = function ( fmt, args ) {\r
+    if ( {}.toString.call( args ) == '[object Array]' ) {\r
+      return vsprintf( fmt, [].slice.call(args) );\r
+    }\r
+    return sprintf.apply(this, [].slice.call(arguments) );\r
+  };\r
+\r
+  Jed.prototype.sprintf = function () {\r
+    return Jed.sprintf.apply(this, arguments);\r
+  };\r
+  // END sprintf Implementation\r
+\r
+  // Start the Plural forms section\r
+  // This is a full plural form expression parser. It is used to avoid\r
+  // running 'eval' or 'new Function' directly against the plural\r
+  // forms.\r
+  //\r
+  // This can be important if you get translations done through a 3rd\r
+  // party vendor. I encourage you to use this instead, however, I\r
+  // also will provide a 'precompiler' that you can use at build time\r
+  // to output valid/safe function representations of the plural form\r
+  // expressions. This means you can build this code out for the most\r
+  // part.\r
+  Jed.PF = {};\r
+\r
+  Jed.PF.parse = function ( p ) {\r
+    var plural_str = Jed.PF.extractPluralExpr( p );\r
+    return Jed.PF.parser.parse.call(Jed.PF.parser, plural_str);\r
+  };\r
+\r
+  Jed.PF.compile = function ( p ) {\r
+    // Handle trues and falses as 0 and 1\r
+    function imply( val ) {\r
+      return (val === true ? 1 : val ? val : 0);\r
+    }\r
+\r
+    var ast = Jed.PF.parse( p );\r
+    return function ( n ) {\r
+      return imply( Jed.PF.interpreter( ast )( n ) );\r
+    };\r
+  };\r
+\r
+  Jed.PF.interpreter = function ( ast ) {\r
+    return function ( n ) {\r
+      var res;\r
+      switch ( ast.type ) {\r
+        case 'GROUP':\r
+          return Jed.PF.interpreter( ast.expr )( n );\r
+        case 'TERNARY':\r
+          if ( Jed.PF.interpreter( ast.expr )( n ) ) {\r
+            return Jed.PF.interpreter( ast.truthy )( n );\r
+          }\r
+          return Jed.PF.interpreter( ast.falsey )( n );\r
+        case 'OR':\r
+          return Jed.PF.interpreter( ast.left )( n ) || Jed.PF.interpreter( ast.right )( n );\r
+        case 'AND':\r
+          return Jed.PF.interpreter( ast.left )( n ) && Jed.PF.interpreter( ast.right )( n );\r
+        case 'LT':\r
+          return Jed.PF.interpreter( ast.left )( n ) < Jed.PF.interpreter( ast.right )( n );\r
+        case 'GT':\r
+          return Jed.PF.interpreter( ast.left )( n ) > Jed.PF.interpreter( ast.right )( n );\r
+        case 'LTE':\r
+          return Jed.PF.interpreter( ast.left )( n ) <= Jed.PF.interpreter( ast.right )( n );\r
+        case 'GTE':\r
+          return Jed.PF.interpreter( ast.left )( n ) >= Jed.PF.interpreter( ast.right )( n );\r
+        case 'EQ':\r
+          return Jed.PF.interpreter( ast.left )( n ) == Jed.PF.interpreter( ast.right )( n );\r
+        case 'NEQ':\r
+          return Jed.PF.interpreter( ast.left )( n ) != Jed.PF.interpreter( ast.right )( n );\r
+        case 'MOD':\r
+          return Jed.PF.interpreter( ast.left )( n ) % Jed.PF.interpreter( ast.right )( n );\r
+        case 'VAR':\r
+          return n;\r
+        case 'NUM':\r
+          return ast.val;\r
+        default:\r
+          throw new Error("Invalid Token found.");\r
+      }\r
+    };\r
+  };\r
+\r
+  Jed.PF.extractPluralExpr = function ( p ) {\r
+    // trim first\r
+    p = p.replace(/^\s\s*/, '').replace(/\s\s*$/, '');\r
+\r
+    if (! /;\s*$/.test(p)) {\r
+      p = p.concat(';');\r
+    }\r
+\r
+    var nplurals_re = /nplurals\=(\d+);/,\r
+        plural_re = /plural\=(.*);/,\r
+        nplurals_matches = p.match( nplurals_re ),\r
+        res = {},\r
+        plural_matches;\r
+\r
+    // Find the nplurals number\r
+    if ( nplurals_matches.length > 1 ) {\r
+      res.nplurals = nplurals_matches[1];\r
+    }\r
+    else {\r
+      throw new Error('nplurals not found in plural_forms string: ' + p );\r
+    }\r
+\r
+    // remove that data to get to the formula\r
+    p = p.replace( nplurals_re, "" );\r
+    plural_matches = p.match( plural_re );\r
+\r
+    if (!( plural_matches && plural_matches.length > 1 ) ) {\r
+      throw new Error('`plural` expression not found: ' + p);\r
+    }\r
+    return plural_matches[ 1 ];\r
+  };\r
+\r
+  /* Jison generated parser */\r
+  Jed.PF.parser = (function(){\r
+\r
+var parser = {trace: function trace() { },\r
+yy: {},\r
+symbols_: {"error":2,"expressions":3,"e":4,"EOF":5,"?":6,":":7,"||":8,"&&":9,"<":10,"<=":11,">":12,">=":13,"!=":14,"==":15,"%":16,"(":17,")":18,"n":19,"NUMBER":20,"$accept":0,"$end":1},\r
+terminals_: {2:"error",5:"EOF",6:"?",7:":",8:"||",9:"&&",10:"<",11:"<=",12:">",13:">=",14:"!=",15:"==",16:"%",17:"(",18:")",19:"n",20:"NUMBER"},\r
+productions_: [0,[3,2],[4,5],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,3],[4,1],[4,1]],\r
+performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {\r
+\r
+var $0 = $$.length - 1;\r
+switch (yystate) {\r
+case 1: return { type : 'GROUP', expr: $$[$0-1] }; \r
+break;\r
+case 2:this.$ = { type: 'TERNARY', expr: $$[$0-4], truthy : $$[$0-2], falsey: $$[$0] }; \r
+break;\r
+case 3:this.$ = { type: "OR", left: $$[$0-2], right: $$[$0] };\r
+break;\r
+case 4:this.$ = { type: "AND", left: $$[$0-2], right: $$[$0] };\r
+break;\r
+case 5:this.$ = { type: 'LT', left: $$[$0-2], right: $$[$0] }; \r
+break;\r
+case 6:this.$ = { type: 'LTE', left: $$[$0-2], right: $$[$0] };\r
+break;\r
+case 7:this.$ = { type: 'GT', left: $$[$0-2], right: $$[$0] };\r
+break;\r
+case 8:this.$ = { type: 'GTE', left: $$[$0-2], right: $$[$0] };\r
+break;\r
+case 9:this.$ = { type: 'NEQ', left: $$[$0-2], right: $$[$0] };\r
+break;\r
+case 10:this.$ = { type: 'EQ', left: $$[$0-2], right: $$[$0] };\r
+break;\r
+case 11:this.$ = { type: 'MOD', left: $$[$0-2], right: $$[$0] };\r
+break;\r
+case 12:this.$ = { type: 'GROUP', expr: $$[$0-1] }; \r
+break;\r
+case 13:this.$ = { type: 'VAR' }; \r
+break;\r
+case 14:this.$ = { type: 'NUM', val: Number(yytext) }; \r
+break;\r
+}\r
+},\r
+table: [{3:1,4:2,17:[1,3],19:[1,4],20:[1,5]},{1:[3]},{5:[1,6],6:[1,7],8:[1,8],9:[1,9],10:[1,10],11:[1,11],12:[1,12],13:[1,13],14:[1,14],15:[1,15],16:[1,16]},{4:17,17:[1,3],19:[1,4],20:[1,5]},{5:[2,13],6:[2,13],7:[2,13],8:[2,13],9:[2,13],10:[2,13],11:[2,13],12:[2,13],13:[2,13],14:[2,13],15:[2,13],16:[2,13],18:[2,13]},{5:[2,14],6:[2,14],7:[2,14],8:[2,14],9:[2,14],10:[2,14],11:[2,14],12:[2,14],13:[2,14],14:[2,14],15:[2,14],16:[2,14],18:[2,14]},{1:[2,1]},{4:18,17:[1,3],19:[1,4],20:[1,5]},{4:19,17:[1,3],19:[1,4],20:[1,5]},{4:20,17:[1,3],19:[1,4],20:[1,5]},{4:21,17:[1,3],19:[1,4],20:[1,5]},{4:22,17:[1,3],19:[1,4],20:[1,5]},{4:23,17:[1,3],19:[1,4],20:[1,5]},{4:24,17:[1,3],19:[1,4],20:[1,5]},{4:25,17:[1,3],19:[1,4],20:[1,5]},{4:26,17:[1,3],19:[1,4],20:[1,5]},{4:27,17:[1,3],19:[1,4],20:[1,5]},{6:[1,7],8:[1,8],9:[1,9],10:[1,10],11:[1,11],12:[1,12],13:[1,13],14:[1,14],15:[1,15],16:[1,16],18:[1,28]},{6:[1,7],7:[1,29],8:[1,8],9:[1,9],10:[1,10],11:[1,11],12:[1,12],13:[1,13],14:[1,14],15:[1,15],16:[1,16]},{5:[2,3],6:[2,3],7:[2,3],8:[2,3],9:[1,9],10:[1,10],11:[1,11],12:[1,12],13:[1,13],14:[1,14],15:[1,15],16:[1,16],18:[2,3]},{5:[2,4],6:[2,4],7:[2,4],8:[2,4],9:[2,4],10:[1,10],11:[1,11],12:[1,12],13:[1,13],14:[1,14],15:[1,15],16:[1,16],18:[2,4]},{5:[2,5],6:[2,5],7:[2,5],8:[2,5],9:[2,5],10:[2,5],11:[2,5],12:[2,5],13:[2,5],14:[2,5],15:[2,5],16:[1,16],18:[2,5]},{5:[2,6],6:[2,6],7:[2,6],8:[2,6],9:[2,6],10:[2,6],11:[2,6],12:[2,6],13:[2,6],14:[2,6],15:[2,6],16:[1,16],18:[2,6]},{5:[2,7],6:[2,7],7:[2,7],8:[2,7],9:[2,7],10:[2,7],11:[2,7],12:[2,7],13:[2,7],14:[2,7],15:[2,7],16:[1,16],18:[2,7]},{5:[2,8],6:[2,8],7:[2,8],8:[2,8],9:[2,8],10:[2,8],11:[2,8],12:[2,8],13:[2,8],14:[2,8],15:[2,8],16:[1,16],18:[2,8]},{5:[2,9],6:[2,9],7:[2,9],8:[2,9],9:[2,9],10:[2,9],11:[2,9],12:[2,9],13:[2,9],14:[2,9],15:[2,9],16:[1,16],18:[2,9]},{5:[2,10],6:[2,10],7:[2,10],8:[2,10],9:[2,10],10:[2,10],11:[2,10],12:[2,10],13:[2,10],14:[2,10],15:[2,10],16:[1,16],18:[2,10]},{5:[2,11],6:[2,11],7:[2,11],8:[2,11],9:[2,11],10:[2,11],11:[2,11],12:[2,11],13:[2,11],14:[2,11],15:[2,11],16:[2,11],18:[2,11]},{5:[2,12],6:[2,12],7:[2,12],8:[2,12],9:[2,12],10:[2,12],11:[2,12],12:[2,12],13:[2,12],14:[2,12],15:[2,12],16:[2,12],18:[2,12]},{4:30,17:[1,3],19:[1,4],20:[1,5]},{5:[2,2],6:[1,7],7:[2,2],8:[1,8],9:[1,9],10:[1,10],11:[1,11],12:[1,12],13:[1,13],14:[1,14],15:[1,15],16:[1,16],18:[2,2]}],\r
+defaultActions: {6:[2,1]},\r
+parseError: function parseError(str, hash) {\r
+    throw new Error(str);\r
+},\r
+parse: function parse(input) {\r
+    var self = this,\r
+        stack = [0],\r
+        vstack = [null], // semantic value stack\r
+        lstack = [], // location stack\r
+        table = this.table,\r
+        yytext = '',\r
+        yylineno = 0,\r
+        yyleng = 0,\r
+        recovering = 0,\r
+        TERROR = 2,\r
+        EOF = 1;\r
+\r
+    //this.reductionCount = this.shiftCount = 0;\r
+\r
+    this.lexer.setInput(input);\r
+    this.lexer.yy = this.yy;\r
+    this.yy.lexer = this.lexer;\r
+    if (typeof this.lexer.yylloc == 'undefined')\r
+        this.lexer.yylloc = {};\r
+    var yyloc = this.lexer.yylloc;\r
+    lstack.push(yyloc);\r
+\r
+    if (typeof this.yy.parseError === 'function')\r
+        this.parseError = this.yy.parseError;\r
+\r
+    function popStack (n) {\r
+        stack.length = stack.length - 2*n;\r
+        vstack.length = vstack.length - n;\r
+        lstack.length = lstack.length - n;\r
+    }\r
+\r
+    function lex() {\r
+        var token;\r
+        token = self.lexer.lex() || 1; // $end = 1\r
+        // if token isn't its numeric value, convert\r
+        if (typeof token !== 'number') {\r
+            token = self.symbols_[token] || token;\r
+        }\r
+        return token;\r
+    }\r
+\r
+    var symbol, preErrorSymbol, state, action, a, r, yyval={},p,len,newState, expected;\r
+    while (true) {\r
+        // retreive state number from top of stack\r
+        state = stack[stack.length-1];\r
+\r
+        // use default actions if available\r
+        if (this.defaultActions[state]) {\r
+            action = this.defaultActions[state];\r
+        } else {\r
+            if (symbol == null)\r
+                symbol = lex();\r
+            // read action for current state and first input\r
+            action = table[state] && table[state][symbol];\r
+        }\r
+\r
+        // handle parse error\r
+        _handle_error:\r
+        if (typeof action === 'undefined' || !action.length || !action[0]) {\r
+\r
+            if (!recovering) {\r
+                // Report error\r
+                expected = [];\r
+                for (p in table[state]) if (this.terminals_[p] && p > 2) {\r
+                    expected.push("'"+this.terminals_[p]+"'");\r
+                }\r
+                var errStr = '';\r
+                if (this.lexer.showPosition) {\r
+                    errStr = 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+expected.join(', ') + ", got '" + this.terminals_[symbol]+ "'";\r
+                } else {\r
+                    errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " +\r
+                                  (symbol == 1 /*EOF*/ ? "end of input" :\r
+                                              ("'"+(this.terminals_[symbol] || symbol)+"'"));\r
+                }\r
+                this.parseError(errStr,\r
+                    {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected});\r
+            }\r
+\r
+            // just recovered from another error\r
+            if (recovering == 3) {\r
+                if (symbol == EOF) {\r
+                    throw new Error(errStr || 'Parsing halted.');\r
+                }\r
+\r
+                // discard current lookahead and grab another\r
+                yyleng = this.lexer.yyleng;\r
+                yytext = this.lexer.yytext;\r
+                yylineno = this.lexer.yylineno;\r
+                yyloc = this.lexer.yylloc;\r
+                symbol = lex();\r
+            }\r
+\r
+            // try to recover from error\r
+            while (1) {\r
+                // check for error recovery rule in this state\r
+                if ((TERROR.toString()) in table[state]) {\r
+                    break;\r
+                }\r
+                if (state == 0) {\r
+                    throw new Error(errStr || 'Parsing halted.');\r
+                }\r
+                popStack(1);\r
+                state = stack[stack.length-1];\r
+            }\r
+\r
+            preErrorSymbol = symbol; // save the lookahead token\r
+            symbol = TERROR;         // insert generic error symbol as new lookahead\r
+            state = stack[stack.length-1];\r
+            action = table[state] && table[state][TERROR];\r
+            recovering = 3; // allow 3 real symbols to be shifted before reporting a new error\r
+        }\r
+\r
+        // this shouldn't happen, unless resolve defaults are off\r
+        if (action[0] instanceof Array && action.length > 1) {\r
+            throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol);\r
+        }\r
+\r
+        switch (action[0]) {\r
+\r
+            case 1: // shift\r
+                //this.shiftCount++;\r
+\r
+                stack.push(symbol);\r
+                vstack.push(this.lexer.yytext);\r
+                lstack.push(this.lexer.yylloc);\r
+                stack.push(action[1]); // push state\r
+                symbol = null;\r
+                if (!preErrorSymbol) { // normal execution/no error\r
+                    yyleng = this.lexer.yyleng;\r
+                    yytext = this.lexer.yytext;\r
+                    yylineno = this.lexer.yylineno;\r
+                    yyloc = this.lexer.yylloc;\r
+                    if (recovering > 0)\r
+                        recovering--;\r
+                } else { // error just occurred, resume old lookahead f/ before error\r
+                    symbol = preErrorSymbol;\r
+                    preErrorSymbol = null;\r
+                }\r
+                break;\r
+\r
+            case 2: // reduce\r
+                //this.reductionCount++;\r
+\r
+                len = this.productions_[action[1]][1];\r
+\r
+                // perform semantic action\r
+                yyval.$ = vstack[vstack.length-len]; // default to $$ = $1\r
+                // default location, uses first token for firsts, last for lasts\r
+                yyval._$ = {\r
+                    first_line: lstack[lstack.length-(len||1)].first_line,\r
+                    last_line: lstack[lstack.length-1].last_line,\r
+                    first_column: lstack[lstack.length-(len||1)].first_column,\r
+                    last_column: lstack[lstack.length-1].last_column\r
+                };\r
+                r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);\r
+\r
+                if (typeof r !== 'undefined') {\r
+                    return r;\r
+                }\r
+\r
+                // pop off stack\r
+                if (len) {\r
+                    stack = stack.slice(0,-1*len*2);\r
+                    vstack = vstack.slice(0, -1*len);\r
+                    lstack = lstack.slice(0, -1*len);\r
+                }\r
+\r
+                stack.push(this.productions_[action[1]][0]);    // push nonterminal (reduce)\r
+                vstack.push(yyval.$);\r
+                lstack.push(yyval._$);\r
+                // goto new state = table[STATE][NONTERMINAL]\r
+                newState = table[stack[stack.length-2]][stack[stack.length-1]];\r
+                stack.push(newState);\r
+                break;\r
+\r
+            case 3: // accept\r
+                return true;\r
+        }\r
+\r
+    }\r
+\r
+    return true;\r
+}};/* Jison generated lexer */\r
+var lexer = (function(){\r
+\r
+var lexer = ({EOF:1,\r
+parseError:function parseError(str, hash) {\r
+        if (this.yy.parseError) {\r
+            this.yy.parseError(str, hash);\r
+        } else {\r
+            throw new Error(str);\r
+        }\r
+    },\r
+setInput:function (input) {\r
+        this._input = input;\r
+        this._more = this._less = this.done = false;\r
+        this.yylineno = this.yyleng = 0;\r
+        this.yytext = this.matched = this.match = '';\r
+        this.conditionStack = ['INITIAL'];\r
+        this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0};\r
+        return this;\r
+    },\r
+input:function () {\r
+        var ch = this._input[0];\r
+        this.yytext+=ch;\r
+        this.yyleng++;\r
+        this.match+=ch;\r
+        this.matched+=ch;\r
+        var lines = ch.match(/\n/);\r
+        if (lines) this.yylineno++;\r
+        this._input = this._input.slice(1);\r
+        return ch;\r
+    },\r
+unput:function (ch) {\r
+        this._input = ch + this._input;\r
+        return this;\r
+    },\r
+more:function () {\r
+        this._more = true;\r
+        return this;\r
+    },\r
+pastInput:function () {\r
+        var past = this.matched.substr(0, this.matched.length - this.match.length);\r
+        return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");\r
+    },\r
+upcomingInput:function () {\r
+        var next = this.match;\r
+        if (next.length < 20) {\r
+            next += this._input.substr(0, 20-next.length);\r
+        }\r
+        return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, "");\r
+    },\r
+showPosition:function () {\r
+        var pre = this.pastInput();\r
+        var c = new Array(pre.length + 1).join("-");\r
+        return pre + this.upcomingInput() + "\n" + c+"^";\r
+    },\r
+next:function () {\r
+        if (this.done) {\r
+            return this.EOF;\r
+        }\r
+        if (!this._input) this.done = true;\r
+\r
+        var token,\r
+            match,\r
+            col,\r
+            lines;\r
+        if (!this._more) {\r
+            this.yytext = '';\r
+            this.match = '';\r
+        }\r
+        var rules = this._currentRules();\r
+        for (var i=0;i < rules.length; i++) {\r
+            match = this._input.match(this.rules[rules[i]]);\r
+            if (match) {\r
+                lines = match[0].match(/\n.*/g);\r
+                if (lines) this.yylineno += lines.length;\r
+                this.yylloc = {first_line: this.yylloc.last_line,\r
+                               last_line: this.yylineno+1,\r
+                               first_column: this.yylloc.last_column,\r
+                               last_column: lines ? lines[lines.length-1].length-1 : this.yylloc.last_column + match[0].length}\r
+                this.yytext += match[0];\r
+                this.match += match[0];\r
+                this.matches = match;\r
+                this.yyleng = this.yytext.length;\r
+                this._more = false;\r
+                this._input = this._input.slice(match[0].length);\r
+                this.matched += match[0];\r
+                token = this.performAction.call(this, this.yy, this, rules[i],this.conditionStack[this.conditionStack.length-1]);\r
+                if (token) return token;\r
+                else return;\r
+            }\r
+        }\r
+        if (this._input === "") {\r
+            return this.EOF;\r
+        } else {\r
+            this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(), \r
+                    {text: "", token: null, line: this.yylineno});\r
+        }\r
+    },\r
+lex:function lex() {\r
+        var r = this.next();\r
+        if (typeof r !== 'undefined') {\r
+            return r;\r
+        } else {\r
+            return this.lex();\r
+        }\r
+    },\r
+begin:function begin(condition) {\r
+        this.conditionStack.push(condition);\r
+    },\r
+popState:function popState() {\r
+        return this.conditionStack.pop();\r
+    },\r
+_currentRules:function _currentRules() {\r
+        return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules;\r
+    },\r
+topState:function () {\r
+        return this.conditionStack[this.conditionStack.length-2];\r
+    },\r
+pushState:function begin(condition) {\r
+        this.begin(condition);\r
+    }});\r
+lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {\r
+\r
+var YYSTATE=YY_START;\r
+switch($avoiding_name_collisions) {\r
+case 0:/* skip whitespace */\r
+break;\r
+case 1:return 20\r
+break;\r
+case 2:return 19\r
+break;\r
+case 3:return 8\r
+break;\r
+case 4:return 9\r
+break;\r
+case 5:return 6\r
+break;\r
+case 6:return 7\r
+break;\r
+case 7:return 11\r
+break;\r
+case 8:return 13\r
+break;\r
+case 9:return 10\r
+break;\r
+case 10:return 12\r
+break;\r
+case 11:return 14\r
+break;\r
+case 12:return 15\r
+break;\r
+case 13:return 16\r
+break;\r
+case 14:return 17\r
+break;\r
+case 15:return 18\r
+break;\r
+case 16:return 5\r
+break;\r
+case 17:return 'INVALID'\r
+break;\r
+}\r
+};\r
+lexer.rules = [/^\s+/,/^[0-9]+(\.[0-9]+)?\b/,/^n\b/,/^\|\|/,/^&&/,/^\?/,/^:/,/^<=/,/^>=/,/^</,/^>/,/^!=/,/^==/,/^%/,/^\(/,/^\)/,/^$/,/^./];\r
+lexer.conditions = {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17],"inclusive":true}};return lexer;})()\r
+parser.lexer = lexer;\r
+return parser;\r
+})();\r
+// End parser\r
+\r
+  // Handle node, amd, and global systems\r
+  if (typeof exports !== 'undefined') {\r
+    if (typeof module !== 'undefined' && module.exports) {\r
+      exports = module.exports = Jed;\r
+    }\r
+    exports.Jed = Jed;\r
+  }\r
+  else {\r
+    if (typeof define === 'function' && define.amd) {\r
+      define('jed', function() {\r
+        return Jed;\r
+      });\r
+    }\r
+    // Leak a global regardless of module system\r
+    root['Jed'] = Jed;\r
+  }\r
+\r
+})(this);\r
index 7eeeae0fdc21603e5240d85c1bef629ac8a48551..16f2b7ccf4db4f4c7267aa7733c6c20ebcca433c 100644 (file)
@@ -113,6 +113,8 @@ _kiwi.global = {
         _kiwi.global.settings = _kiwi.model.DataStore.instance('kiwi.settings');\r
         _kiwi.global.settings.load();\r
 \r
+        _kiwi.global.i18n = new Jed();\r
+\r
                _kiwi.app = new _kiwi.model.Application(opts);\r
 \r
                if (opts.kiwi_server) {\r
index e64727faaee45f970b251aa43dc31d8ed3e546b6..efbf0199969cab4f5e00e81bbec48e52c1e7fc11 100644 (file)
@@ -7,7 +7,12 @@
 \r
 \r
         initialize: function (options) {\r
-            this.$el = $($('#tmpl_channel_list').html().trim());\r
+            var text = {\r
+                channel_name: _kiwi.global.i18n.translate('Channel Name').fetch(),\r
+                users: _kiwi.global.i18n.translate('Users').fetch(),\r
+                topic: _kiwi.global.i18n.translate('Topic').fetch()\r
+            };\r
+            this.$el = $(_.template($('#tmpl_channel_list').html().trim(), text));\r
 \r
             this.channels = [];\r
 \r
@@ -50,7 +55,7 @@
 \r
     var Applet = Backbone.Model.extend({\r
         initialize: function () {\r
-            this.set('title', 'Channel List');\r
+            this.set('title', _kiwi.global.i18n.translate('Channel List').fetch());\r
             this.view = new View();\r
 \r
             this.network = _kiwi.global.components.Network();\r
index ef804f2e16a9f37a288b642e08100e14d6e8f8f6..a1965941987111b324a3b30083959b3fafecd38e 100644 (file)
@@ -5,8 +5,11 @@
             },
 
             initialize: function (options) {
-                var that = this;
-                this.$el = $($('#tmpl_script_editor').html().trim());
+                var that = this,
+                    text = {
+                        save: _kiwi.global.i18n.translate('Save').fetch()
+                    };
+                this.$el = $(_.template($('#tmpl_script_editor').html().trim(), text));
 
                 this.model.on('applet_loaded', function () {
                     that.$el.parent().css('height', '100%');
@@ -53,7 +56,7 @@
                     _kiwi.user_script = new user_fn();
 
                 } catch (err) {
-                    this.setStatus('Script error. ' + err.toString());
+                    this.setStatus(_kiwi.global.i18n.translate('Script error. %s').fetch(err.toString()));
                     return;
                 }
 
@@ -61,7 +64,7 @@
                 _kiwi.global.settings.set('user_script', this.editor.getValue());
                 _kiwi.global.settings.save();
 
-                this.setStatus('Your script has been saved and is now active :)');
+                this.setStatus(_kiwi.global.i18n.translate('Your script has been saved and is now active').fetch() + ' :)');
             },
 
 
@@ -82,8 +85,8 @@
             initialize: function () {
                 var that = this;
 
-                this.set('title', 'Script Editor');
-                this.view = new view({model: this})
+                this.set('title', _kiwi.global.i18n.translate('Script Editor').fetch());
+                this.view = new view({model: this});
 
             }
         });
index 067952712b2f5ac69ce64e705ab7d1b6cab6c20e..50b2475165b899c3716abfac0257512d27c51083 100644 (file)
@@ -7,7 +7,19 @@
         },\r
 \r
         initialize: function (options) {\r
-            this.$el = $($('#tmpl_applet_settings').html().trim());\r
+            var text = {\r
+                tabs: _kiwi.global.i18n.translate('Tabs').fetch(),\r
+                list: _kiwi.global.i18n.translate('List').fetch(),\r
+                large_amounts_of_chans: _kiwi.global.i18n.translate('for large amouts of channels').fetch(),\r
+                join_part: _kiwi.global.i18n.translate('Join/part channel notifications').fetch(),\r
+                timestamps: _kiwi.global.i18n.translate('Timestamps').fetch(),\r
+                mute: _kiwi.global.i18n.translate('Mute sound notifications').fetch(),\r
+                scroll_history: _kiwi.global.i18n.translate('messages in scroll history').fetch(),\r
+                default_client: _kiwi.global.i18n.translate('Default IRC client').fetch(),\r
+                make_default: _kiwi.global.i18n.translate('Make Kiwi my default IRC client').fetch(),\r
+                default_note: _kiwi.global.i18n.translate('Note: Chrome or Chromium browser users may need to check their settings via %s if nothing happens').fetch('<a href="chrome://settings/handlers">chrome://settings/handlers</a>')\r
+            };\r
+            this.$el = $(_.template($('#tmpl_applet_settings').html().trim(), text));\r
 \r
             if (!navigator.registerProtocolHandler) {\r
                 this.$el.find('.protocol_handler').remove();\r
 \r
     var Applet = Backbone.Model.extend({\r
         initialize: function () {\r
-            this.set('title', 'Settings');\r
+            this.set('title', _kiwi.global.i18n.translate('Settings').fetch());\r
             this.view = new View();\r
         }\r
     });\r
index 63038a4063a4173d91194e12e374e2d87fa1cbbd..c94f221c1983eacf207ee49299ce1a33bcb59de5 100644 (file)
     \r
     <script type="text/html" id="tmpl_userbox">\r
         <div class="userbox">\r
-            <a class="if_op op"><i class="icon-star"></i>Op</a>\r
-            <a class="if_op deop"><i class="icon-star-empty"></i>De-op</a>\r
-            <a class="if_op voice"><i class="icon-volume-up"></i>Voice</a>\r
-            <a class="if_op devoice"><i class="icon-volume-off"></i>De-voice</a>\r
-            <a class="if_op kick"><i class="icon-remove"></i>Kick</a>\r
-            <a class="if_op ban"><i class="icon-ban-circle"></i>Ban</a>\r
-\r
-            <a class="query"><i class="icon-comment"></i>Message</a>\r
-            <a class="info"><i class="icon-info-sign"></i>Info</a>\r
-            <a class="slap"><i class="icon-user-md"></i>Slap!</a>\r
+            <a class="if_op op"><i class="icon-star"></i><%= op %></a>\r
+            <a class="if_op deop"><i class="icon-star-empty"></i><%= de_op %></a>\r
+            <a class="if_op voice"><i class="icon-volume-up"></i><%= voice %></a>\r
+            <a class="if_op devoice"><i class="icon-volume-off"></i><%= de_voice %></a>\r
+            <a class="if_op kick"><i class="icon-remove"></i><%= kick %></a>\r
+            <a class="if_op ban"><i class="icon-ban-circle"></i><%= ban %></a>\r
+\r
+            <a class="query"><i class="icon-comment"></i><%= message %></a>\r
+            <a class="info"><i class="icon-info-sign"></i><%= info %></a>\r
+            <a class="slap"><i class="icon-user-md"></i><%= slap %></a>\r
         </div>\r
     </script>\r
     \r
     <script type="text/html" id="tmpl_nickchange">\r
         <form class="nickchange">\r
-            <label for="nickchange">New nick:</label> <input type="text" mozactionhint="done" autocomplete="off" spellcheck="false"/> <button>Change</button> <a class="cancel">Cancel</a>\r
+            <label for="nickchange"><%= new_nick %>:</label> <input type="text" mozactionhint="done" autocomplete="off" spellcheck="false"/> <button><%= change %></button> <a class="cancel"><%= cancel %></a>\r
         </form>\r
     </script>\r
 \r
             </div>\r
 \r
             <div class="server_details" style="position:relative;width:320px;">\r
-                <div class="status">Think of a nickname..</div>\r
+                <div class="status"><%= think_nick %></div>\r
 \r
                 <form>\r
                     <div class="basic">\r
                         <table>\r
                             <tr class="nick">\r
-                                <td><label for="server_select_nick">Nickname</label></td>\r
+                                <td><label for="server_select_nick"><%= nickname %></label></td>\r
                                 <td><input type="text" class="nick" id="server_select_nick"></td>\r
                             </tr>\r
 \r
                             <tr class="have_pass">\r
                                 <td colspan="2">\r
-                                    <label for="server_select_show_pass">I have a password</label> <input type="checkbox" id="server_select_show_pass" style="width:auto;" />\r
+                                    <label for="server_select_show_pass"><%= have_password %></label> <input type="checkbox" id="server_select_show_pass" style="width:auto;" />\r
                                 </td>\r
                             </tr>\r
 \r
                             <tr class="pass">\r
-                                <td><label for="server_select_password">Password</label></td>\r
+                                <td><label for="server_select_password"><%= password %></label></td>\r
                                 <td><input type="password" class="password" id="server_select_password"></td>\r
                             </tr>\r
 \r
                             <tr class="channel">\r
-                                <td><label for="server_select_channel">Channel</label></td>\r
+                                <td><label for="server_select_channel"><%= channel %></label></td>\r
                                 <td>\r
                                     <div style="position:relative;">\r
                                         <input type="text" class="channel" id="server_select_channel">\r
-                                        <i class="icon-key" title="Channel Key"></i>\r
+                                        <i class="icon-key" title="<%= channel_key %>"></i>\r
                                     </div>\r
                                 </td>\r
                             </tr>\r
 \r
                             <tr class="have_key">\r
                                 <td colspan="2">\r
-                                    <label for="server_select_show_channel_key">Channel requires a key</label> <input type="checkbox" id="server_select_show_channel_key" style="width:auto;" />\r
+                                    <label for="server_select_show_channel_key"><%= require_key %></label> <input type="checkbox" id="server_select_show_channel_key" style="width:auto;" />\r
                                 </td>\r
                             </tr>\r
 \r
                             <tr class="key">\r
-                                <td><label for="server_select_channel_key">Key</label></td>\r
+                                <td><label for="server_select_channel_key"><%= key %></label></td>\r
                                 <td><input type="password" class="channel_key" id="server_select_channel_key"></td>\r
                             </tr>\r
 \r
                             <tr class="start">\r
-                                <td colspan="2"><button type="submit">Start..</button></td>\r
+                                <td colspan="2"><button type="submit"><%= start %></button></td>\r
                             </tr>\r
                         </table>\r
 \r
-                        <a href="" onclick="return false;" class="show_more">Server and network</a>\r
+                        <a href="" onclick="return false;" class="show_more"><%= server_network %></a>\r
                     </div>\r
 \r
 \r
                     <div class="more">\r
                         <table>\r
                             <tr class="server">\r
-                                <td><label for="server_select_server">Server</label></td>\r
+                                <td><label for="server_select_server"><%= server %></label></td>\r
                                 <td><input type="text" class="server" id="server_select_server"></td>\r
                             <tr>\r
 \r
                             <tr class="port">\r
-                                <td><label for="server_select_port">Port</label></td>\r
+                                <td><label for="server_select_port"><%= port %></label></td>\r
                                 <td><input type="text" class="port" id="server_select_port"></td>\r
                             </tr>\r
 \r
                 </form>\r
 \r
                 <a class="kiwi_logo" href="https://kiwiirc.com/" target="_blank">\r
-                    <h1><span>Powered by Kiwi IRC</span> <img src="<%base_path%>/assets/img/ico.png" alt="KiwiIRC Logo" title="Kiwi IRC" /></h1>\r
+                    <h1><span><%= powered_by %></span> <img src="<%base_path%>/assets/img/ico.png" alt="KiwiIRC Logo" title="Kiwi IRC" /></h1>\r
                 </a>\r
             </div>\r
         </div>\r
                     <div class="radio">\r
                         <label>\r
                             <input type="radio" name="channel_list_style" data-setting="channel_list_style" value="tabs">\r
-                            Tabs\r
+                            <%= tabs %>\r
                         </label>\r
                     </div>\r
                     <div class="radio">\r
                         <label>\r
                             <input type="radio" name="channel_list_style" data-setting="channel_list_style" value="list">\r
-                            List <small class="text-muted">(for large amouts of channels)</small>\r
+                            <%= list %><small class="text-muted">(<%= large_amounts_of_chans %>)</small>\r
                         </label>\r
                     </div>\r
                 </div>\r
                     <div class="checkbox">\r
                         <label>\r
                             <input data-setting="show_joins_parts" type="checkbox">\r
-                            Join/part channel notifications\r
+                            <%= join_part %>\r
                         </label>\r
                     </div>\r
                     <div class="checkbox">\r
                         <label>\r
                             <input data-setting="show_timestamps" type="checkbox">\r
-                            Timestamps\r
+                            <%= timestamps %>\r
                         </label>\r
                     </div>\r
                     <div class="checkbox">\r
                         <label>\r
                             <input data-setting="mute_sounds" type="checkbox">\r
-                            Mute sound notifications\r
+                            <%= mute %>\r
                         </label>\r
                     </div>\r
                     <label>\r
                         <input data-setting="scrollback" class="input-small" type="text" size="4" pattern="\d*">\r
-                        <span>messages in scroll history</span>\r
+                        <span><%= scroll_history %></span>\r
                     </label>\r
                 </div>\r
             </section>\r
 \r
             <section class="protocol_handler">\r
-                <h6>Default IRC client</h6>\r
+                <h6><%= default_client %></h6>\r
                 <div class="control-group">\r
-                    <button class="register_protocol">Make Kiwi my default IRC client</button>\r
+                    <button class="register_protocol"><%= make_default %></button>\r
                     <br>\r
-                    <small>Note: Chrome or Chromium browser users may need to check their settings via <a href="chrome://settings/handlers">chrome://settings/handlers</a> if nothing happens</small>\r
+                    <small><%= default_note %></small>\r
                 </div>\r
             </section>\r
         </div>\r
             <table style="margin:1em 2em;">\r
                 <thead style="font-weight: bold;">\r
                     <tr>\r
-                        <td>Channel Name</td>\r
-                        <td>Users</td>\r
-                        <td style="padding-left: 2em;">Topic</td>\r
+                        <td><%= channel_name %></td>\r
+                        <td><%= users %></td>\r
+                        <td style="padding-left: 2em;"><%= topic %></td>\r
                     </tr>\r
                 </thead>\r
                 <tbody style="vertical-align: top;">\r
                 #kiwi .script_editor .se_toolbar button i { font-size:1.2em; margin-left:3px; }\r
             </style>\r
             <div class="script_editor" style="height:100%; position:relative;">\r
-                <div class="se_toolbar"><button class="btn_save">Save <i class="icon-save"></i></button><span class="status"></span></div>\r
+                <div class="se_toolbar"><button class="btn_save"><%= save %><i class="icon-save"></i></button><span class="status"></span></div>\r
                 <div class="editor" style="position:absolute;top:50px;bottom:0px;left:0px;right:0px;"></div>\r
             </div>\r
         </div>\r
         // Common dependancies that are required at all times\r
         var scripts = [\r
             ['libs/jquery-1.9.1.min.js', 'libs/lodash.min.js'],\r
-            'libs/backbone.min.js'\r
+            'libs/backbone.min.js', 'libs/jed.js'\r
         ];\r
 \r
         // If in debug mode, load each development script\r
index 0dca6377fd21776d18a62797659fcdd47174956d..495e7d33c5b681ecdf5439008f10f29cd1e4569b 100644 (file)
@@ -25,7 +25,7 @@ _kiwi.model.Applet = _kiwi.model.Panel.extend({
             if (applet_object.get || applet_object.extend) {\r
 \r
                 // Try find a title for the applet\r
-                this.set('title', applet_object.get('title') || 'Unknown Applet');\r
+                this.set('title', applet_object.get('title') || _kiwi.global.i18n.translate('Unknown Applet').fetch());\r
 \r
                 // Update the tabs title if the applet changes it\r
                 applet_object.bind('change:title', function (obj, new_value) {\r
@@ -56,11 +56,11 @@ _kiwi.model.Applet = _kiwi.model.Panel.extend({
     loadFromUrl: function(applet_url, applet_name) {\r
         var that = this;\r
 \r
-        this.view.$el.html('Loading..');\r
+        this.view.$el.html(_kiwi.global.i18n.translate('Loading..').fetch());\r
         $script(applet_url, function () {\r
             // Check if the applet loaded OK\r
             if (!_kiwi.applets[applet_name]) {\r
-                that.view.$el.html('Not found');\r
+                that.view.$el.html(_kiwi.global.i18n.translate('Not found').fetch());\r
                 return;\r
             }\r
 \r
index 023d921e27fa39ee1f80dcdb71a2252e638936cb..1ce101e4a8e79661f2d9184fc54d1222cb3dc78b 100644 (file)
@@ -341,7 +341,7 @@ _kiwi.model.Application = function () {
                 var gw_stat = 0;\r
 \r
                 gw.on('disconnect', function (event) {\r
-                    var msg = 'You have been disconnected. Attempting to reconnect for you..';\r
+                    var msg = _kiwi.global.i18n.translate('You have been disconnected. Attempting to reconnect for you').fetch() + '...';\r
                     that.message.text(msg, {timeout: 10000});\r
 \r
                     that.view.$el.removeClass('connected');\r
@@ -363,7 +363,7 @@ _kiwi.model.Application = function () {
 \r
 \r
                 gw.on('reconnecting', function (event) {\r
-                    var msg = 'You have been disconnected. Attempting to reconnect again in ' + (event.delay/1000) + ' seconds..';\r
+                    var msg = _kiwi.global.i18n.translate('You have been disconnected. Attempting to reconnect again in %d seconds').fetch(event.delay/1000) + '...';\r
 \r
                     // Only need to mention the repeating re-connection messages on server panels\r
                     _kiwi.app.connections.forEach(function(connection) {\r
@@ -376,7 +376,7 @@ _kiwi.model.Application = function () {
                     that.view.$el.addClass('connected');\r
                     if (gw_stat !== 1) return;\r
 \r
-                    var msg = 'It\'s OK, you\'re connected again :)';\r
+                    var msg = _kiwi.global.i18n.translate('It\'s OK, you\'re connected again').fetch() + ':)';\r
                     that.message.text(msg, {timeout: 5000});\r
 \r
                     // Mention the disconnection on every channel\r
@@ -510,7 +510,7 @@ _kiwi.model.Application = function () {
 \r
             controlbox.on('command:save', function (ev) {\r
                 _kiwi.global.settings.save();\r
-                _kiwi.app.panels().active.addMsg('', 'Settings have been saved');\r
+                _kiwi.app.panels().active.addMsg('', _kiwi.global.i18n.translate('Settings have been saved').fetch());\r
             });\r
 \r
 \r
@@ -552,12 +552,12 @@ _kiwi.model.Application = function () {
                 // No parameters passed so list them\r
                 if (!ev.params[0]) {\r
                     if (list.length > 0) {\r
-                        _kiwi.app.panels().active.addMsg(' ', 'Ignored nicks:');\r
+                        _kiwi.app.panels().active.addMsg(' ', _kiwi.global.i18n.translate('Ignored nicks').fetch() + ':');\r
                         $.each(list, function (idx, ignored_pattern) {\r
                             _kiwi.app.panels().active.addMsg(' ', ignored_pattern);\r
                         });\r
                     } else {\r
-                        _kiwi.app.panels().active.addMsg(' ', 'Not ignoring anybody');\r
+                        _kiwi.app.panels().active.addMsg(' ', _kiwi.global.i18n.translate('Not ignoring anybody').fetch());\r
                     }\r
                     return;\r
                 }\r
@@ -565,7 +565,7 @@ _kiwi.model.Application = function () {
                 // We have a parameter, so add it\r
                 list.push(ev.params[0]);\r
                 _kiwi.gateway.set('ignore_list', list);\r
-                _kiwi.app.panels().active.addMsg(' ', 'Ignoring ' + ev.params[0]);\r
+                _kiwi.app.panels().active.addMsg(' ', _kiwi.global.i18n.translate('Ignoring %s').fetch(ev.params[0]));\r
             });\r
 \r
 \r
@@ -573,7 +573,7 @@ _kiwi.model.Application = function () {
                 var list = _kiwi.gateway.get('ignore_list');\r
 \r
                 if (!ev.params[0]) {\r
-                    _kiwi.app.panels().active.addMsg(' ', 'Specifiy which nick you wish to stop ignoring');\r
+                    _kiwi.app.panels().active.addMsg(' ', _kiwi.global.i18n.translate('Specifiy which nick you wish to stop ignoring').fetch());\r
                     return;\r
                 }\r
 \r
@@ -583,7 +583,7 @@ _kiwi.model.Application = function () {
 \r
                 _kiwi.gateway.set('ignore_list', list);\r
 \r
-                _kiwi.app.panels().active.addMsg(' ', 'Stopped ignoring ' + ev.params[0]);\r
+                _kiwi.app.panels().active.addMsg(' ', _kiwi.global.i18n.translate('Stopped ignoring %s').fetch(ev.params[0]));\r
             });\r
 \r
 \r
@@ -753,7 +753,7 @@ _kiwi.model.Application = function () {
                 if (_kiwi.applets[ev.params[0]]) {\r
                     panel.load(new _kiwi.applets[ev.params[0]]());\r
                 } else {\r
-                    _kiwi.app.panels().server.addMsg('', 'Applet "' + ev.params[0] + '" does not exist');\r
+                    _kiwi.app.panels().server.addMsg('', _kiwi.global.i18n.translate('Applet "%s" does not exist').fetch(ev.params[0]));\r
                     return;\r
                 }\r
             }\r
@@ -794,14 +794,14 @@ _kiwi.model.Application = function () {
             if (ev.params[0]) {\r
                 _kiwi.gateway.setEncoding(null, ev.params[0], function (success) {\r
                     if (success) {\r
-                        _kiwi.app.panels().active.addMsg('', "Encoding modified to "+ev.params[0]);\r
+                        _kiwi.app.panels().active.addMsg('', _kiwi.global.i18n.translate('Encoding modified to %s').fetch(ev.params[0]));\r
                     } else {\r
-                        _kiwi.app.panels().active.addMsg('', ev.params[0]+' is not a valid encoding');\r
+                        _kiwi.app.panels().active.addMsg('', _kiwi.global.i18n.translate('%s is not a valid encoding').fetch(ev.params[0]));\r
                     }\r
                 });\r
             } else {\r
-                _kiwi.app.panels().active.addMsg('', 'Encoding not specified');\r
-                _kiwi.app.panels().active.addMsg('', 'Usage: /encoding [NEW-ENCODING]');\r
+                _kiwi.app.panels().active.addMsg('', _kiwi.global.i18n.translate('Encoding not specified').fetch());\r
+                _kiwi.app.panels().active.addMsg('', _kiwi.global.i18n.translate('Usage: /encoding [NEW-ENCODING]').fetch());\r
             }\r
         }\r
 \r
@@ -811,7 +811,7 @@ _kiwi.model.Application = function () {
 \r
             // If no server address given, show the new connection dialog\r
             if (!ev.params[0]) {\r
-                tmp = new _kiwi.view.MenuBox('New Connection');\r
+                tmp = new _kiwi.view.MenuBox(_kiwi.global.i18n.translate('New Connection').fetch());\r
                 tmp.addItem('new_connection', new _kiwi.model.NewConnection().view.$el);\r
                 tmp.show();\r
 \r
@@ -854,7 +854,7 @@ _kiwi.model.Application = function () {
             // Use the same nick as we currently have\r
             nick = _kiwi.app.connections.active_connection.get('nick');\r
 \r
-            _kiwi.app.panels().active.addMsg('', 'Connecting to ' + server + ':' + port.toString() + '..');\r
+            _kiwi.app.panels().active.addMsg('', _kiwi.global.i18n.translate('Connecting to %s:%s...').fetch(server, port.toString()));\r
 \r
             _kiwi.gateway.newConnection({\r
                 nick: nick,\r
@@ -864,7 +864,7 @@ _kiwi.model.Application = function () {
                 password: password\r
             }, function(err, new_connection) {\r
                 if (err)\r
-                    _kiwi.app.panels().active.addMsg('', 'Error connecting to ' + server + ':' + port.toString() + ' (' + err.toString() + ')');\r
+                    _kiwi.app.panels().active.addMsg('', _kiwi.global.i18n.translate('Error connecting to %s:%s (%s)').fetch(server, port.toString(), err.toString()));\r
             });\r
         }\r
 \r
index cbd921b4e8e5ba8839fe0c3d65352ca421bf4d5d..369f38931906ad37b58df5de796b2f6c3617615a 100644 (file)
@@ -22,7 +22,7 @@ _kiwi.model.Channel = _kiwi.model.Panel.extend({
                 return;\r
             }\r
 \r
-            this.addMsg(' ', '== ' + member.displayNick(true) + ' has joined', 'action join');\r
+            this.addMsg(' ', '== ' + _kiwi.global.i18n.translate('%s has joined').fetch(member.displayNick(true)), 'action join');\r
         }, this);\r
 \r
         members.bind("remove", function (member, members, options) {\r
@@ -30,21 +30,21 @@ _kiwi.model.Channel = _kiwi.model.Panel.extend({
             var msg = (options.message) ? '(' + options.message + ')' : '';\r
 \r
             if (options.type === 'quit' && show_message) {\r
-                this.addMsg(' ', '== ' + member.displayNick(true) + ' has quit ' + msg, 'action quit');\r
+                this.addMsg(' ', '== ' + _kiwi.global.i18n.translate('%s has quit %s').fetch(member.displayNick(true), msg), 'action quit');\r
 \r
             } else if(options.type === 'kick') {\r
 \r
                 if (!options.current_user_kicked) {\r
                     //If user kicked someone, show the message regardless of settings.\r
                     if (show_message || options.current_user_initiated) {\r
-                        this.addMsg(' ', '== ' + member.displayNick(true) + ' was kicked by ' + options.by + ' ' + msg, 'action kick');\r
+                        this.addMsg(' ', '== ' + _kiwi.global.i18n.translate('%s was kicked by %s %s').fetch(member.displayNick(true), options.by, msg), 'action kick');\r
                     }\r
                 } else {\r
-                    this.addMsg(' ', '== You have been kicked by ' + options.by + ' ' + msg, 'action kick');\r
+                    this.addMsg(' ', '== ' + _kiwi.global.i18n.translate('You have been kicked by %s %s').fetch(options.by, msg), 'action kick');\r
                 }\r
             } else if (show_message) {\r
 \r
-                this.addMsg(' ', '== ' + member.displayNick(true) + ' has left ' + msg, 'action part');\r
+                this.addMsg(' ', '== ' + _kiwi.global.i18n.translate('%s has left %s').fetch(member.displayNick(true), msg), 'action part');\r
             }\r
         }, this);\r
     }\r
index b6310b91f734afc79838aee649565a1c3fd13371..84ab23912c4cdf99c801c67f8b24b4df15293eaf 100644 (file)
 
                 // If not a valid channel name, display a warning
                 if (!_kiwi.app.isChannelName(channel_name)) {
-                    that.panels.server.addMsg('', channel_name + ' is not a valid channel name');
-                    _kiwi.app.message.text(channel_name + ' is not a valid channel name', {timeout: 5000});
+                    that.panels.server.addMsg('', _kiwi.global.i18n.translate('%s is not a valid channel name').fetch(channel_name));
+                    _kiwi.app.message.text(_kiwi.global.i18n.translate('%s is not a valid channel name').fetch(channel_name), {timeout: 5000});
                     return;
                 }
 
     
     function onDisconnect(event) {
         $.each(this.panels.models, function (index, panel) {
-            panel.addMsg('', 'Disconnected from the IRC network', 'action quit');
+            panel.addMsg('', _kiwi.global.i18n.translate('Disconnected from the IRC network').fetch(), 'action quit');
         });
     }
 
             member = panel.get('members').getByNick(event.nick);
             if (member) {
                 member.set('nick', event.newnick);
-                panel.addMsg('', '== ' + event.nick + ' is now known as ' + event.newnick, 'action nick');
+                panel.addMsg('', '== ' + _kiwi.global.i18n.translate('%s is now known as %s').fetch(event.nick, event.newnick) , 'action nick');
             }
         });
     }
         if (!c) return;
 
         when = formatDate(new Date(event.when * 1000));
-        c.addMsg('', 'Topic set by ' + event.nick + ' at ' + when, 'topic');
+        c.addMsg('', _kiwi.global.i18n.translate('Topic set by %s at %s').fetch(event.nick, when), 'topic');
     }
 
 
                 }
             }
 
-            channel.addMsg('', '== ' + event.nick + ' sets mode ' + friendlyModeString(), 'action mode');
+            channel.addMsg('', '== ' + _kiwi.global.i18n.translate('%s sets mode %s').fetch(event.nick, friendlyModeString()), 'action mode');
         } else {
             // This is probably a mode being set on us.
             if (event.target.toLowerCase() === this.get("nick").toLowerCase()) {
-                this.panels.server.addMsg('', '== ' + event.nick + ' set mode ' + friendlyModeString(), 'action mode');
+                this.panels.server.addMsg('', '== ' + _kiwi.global.i18n.translate('%s set mode %s').fetch(event.nick, friendlyModeString()), 'action mode');
             } else {
                console.log('MODE command recieved for unknown target %s: ', event.target, event);
             }
         if (event.ident) {
             panel.addMsg(event.nick, event.nick + ' [' + event.nick + '!' + event.ident + '@' + event.host + '] * ' + event.msg, 'whois');
         } else if (event.chans) {
-            panel.addMsg(event.nick, 'Channels: ' + event.chans, 'whois');
+            panel.addMsg(event.nick, _kiwi.global.i18n.translate('Channels: %s').fetch(event.chans), 'whois');
         } else if (event.irc_server) {
-            panel.addMsg(event.nick, 'Connected to server: ' + event.irc_server + ' ' + event.server_info, 'whois');
+            panel.addMsg(event.nick, _kiwi.global.i18n.translate('Connected to server: %s %s').fetch(event.irc_server, event.server_info), 'whois');
         } else if (event.msg) {
             panel.addMsg(event.nick, event.msg, 'whois');
         } else if (event.logon) {
             logon_date.setTime(event.logon * 1000);
             logon_date = formatDate(logon_date);
 
-            panel.addMsg(event.nick, 'idle for ' + idle_time + ', signed on ' + logon_date, 'whois');
+            panel.addMsg(event.nick, _kiwi.global.i18n.translate('Idle for %s, signed on %s').fetch(idle_time, logon_date), 'whois');
         } else if (event.away_reason) {
-            panel.addMsg(event.nick, 'Away: ' + event.away_reason, 'whois');
+            panel.addMsg(event.nick, _kiwi.global.i18n.translate('Away: %s').fetch(event.away_reason), 'whois');
         } else {
-            panel.addMsg(event.nick, 'idle for ' + idle_time, 'whois');
+            panel.addMsg(event.nick, _kiwi.global.i18n.translate('Idle for %s').fetch(idle_time), 'whois');
         }
     }
 
         if (event.host) {
             panel.addMsg(event.nick, event.nick + ' [' + event.nick + ((event.ident)? '!' + event.ident : '') + '@' + event.host + '] * ' + event.real_name, 'whois');
         } else {
-            panel.addMsg(event.nick, 'No such nick', 'whois');
+            panel.addMsg(event.nick, _kiwi.global.i18n.translate('No such nick').fetch(), 'whois');
         }
     }
 
 
         switch (event.error) {
         case 'banned_from_channel':
-            panel.addMsg(' ', '== You are banned from ' + event.channel + '. ' + event.reason, 'status');
-            _kiwi.app.message.text('You are banned from ' + event.channel + '. ' + event.reason);
+            panel.addMsg(' ', '== ' + _kiwi.global.i18n.translate('You are banned from %s. %s').fetch(event.channel, event.reason), 'status');
+            _kiwi.app.message.text(_kiwi.global.i18n.translate('You are banned from %s. %s').fetch(event.channel, event.reason));
             break;
         case 'bad_channel_key':
-            panel.addMsg(' ', '== Bad channel key for ' + event.channel, 'status');
-            _kiwi.app.message.text('Bad channel key or password for ' + event.channel);
+            panel.addMsg(' ', '== ' + _kiwi.global.i18n.translate('Bad channel key for %s').fetch(event.channel), 'status');
+            _kiwi.app.message.text(_kiwi.global.i18n.translate('Bad channel key for %s').fetch(event.channel));
             break;
         case 'invite_only_channel':
-            panel.addMsg(' ', '== ' + event.channel + ' is invite only.', 'status');
-            _kiwi.app.message.text(event.channel + ' is invite only');
+            panel.addMsg(' ', '== ' + _kiwi.global.i18n.translate('%s is invite only.').fetch(event.channel), 'status');
+            _kiwi.app.message.text(_kiwi.global.i18n.translate('%s is invite only').fetch(event.channel));
             break;
         case 'channel_is_full':
-            panel.addMsg(' ', '== ' + event.channel + ' is full.', 'status');
-            _kiwi.app.message.text(event.channel + ' is full');
+            panel.addMsg(' ', '== ' + _kiwi.global.i18n.translate('%s is full.').fetch(event.channel), 'status');
+            _kiwi.app.message.text(_kiwi.global.i18n.translate('%s is full').fetch(event.channel));
             break;
         case 'chanop_privs_needed':
             panel.addMsg(' ', '== ' + event.reason, 'status');
             }
             break;
         case 'nickname_in_use':
-            this.panels.server.addMsg(' ', '== The nickname ' + event.nick + ' is already in use. Please select a new nickname', 'status');
+            this.panels.server.addMsg(' ', '== ' + _kiwi.global.i18n.translate('The nickname "%s" is already in use. Please select a new nickname').fetch( event.nick), 'status');
             if (this.panels.server !== this.panels.active) {
-                _kiwi.app.message.text('The nickname "' + event.nick + '" is already in use. Please select a new nickname');
+                _kiwi.app.message.text(_kiwi.global.i18n.translate('The nickname "%s" is already in use. Please select a new nickname').fetch(event.nick));
             }
 
             // Only show the nickchange component if the controlbox is open
             break;
 
         case 'password_mismatch':
-            this.panels.server.addMsg(' ', '== Incorrect password given', 'status');
+            this.panels.server.addMsg(' ', '== ' + _kiwi.global.i18n.translate('Incorrect password given').fetch(), 'status');
             break;
         default:
             // We don't know what data contains, so don't do anything with it.
index 17a59415e9c826a9b8bd569f6fcbbb00c60ac4b8..b252a37e09f4200e4254ce616979daf20efbd21d 100644 (file)
@@ -23,7 +23,7 @@ _kiwi.view.Application = Backbone.View.extend({
         // Confirmation require to leave the page
         window.onbeforeunload = function () {
             if (_kiwi.gateway.isConnected()) {
-                return 'This will close all KiwiIRC conversations. Are you sure you want to close this window?';
+                return _kiwi.global.i18n.translate('This will close all KiwiIRC conversations. Are you sure you want to close this window?').fetch();
             }
         };
 
index aaef808188ee16e0e09240ea2a931c31043d5285..0eb2cb3acc9f6b950e1c68f526b099e011e71ce1 100644 (file)
@@ -26,7 +26,7 @@ _kiwi.view.Channel = _kiwi.view.Panel.extend({
 
         // Only show the loader if this is a channel (ie. not a query)
         if (this.model.isChannel()) {
-            this.$el.append('<div class="initial_loader" style="margin:1em;text-align:center;">Joining channel.. <span class="loader"></span></div>');
+            this.$el.append('<div class="initial_loader" style="margin:1em;text-align:center;"> ' + _kiwi.global.i18n.translate('Joining channel..').fetch() + ' <span class="loader"></span></div>');
         }
     },
 
@@ -40,7 +40,7 @@ _kiwi.view.Channel = _kiwi.view.Panel.extend({
             topic = this.model.get("topic");
         }
 
-        this.model.addMsg('', '== Topic for ' + this.model.get('name') + ' is: ' + topic, 'topic');
+        this.model.addMsg('', '== ' + _kiwi.global.i18n.translate('Topic for %s is: %s').fetch(this.model.get('name'), topic), 'topic');
 
         // If this is the active channel then update the topic bar
         if (_kiwi.app.panels().active === this) {
index 9a86d0d1876d5266a767a9706384870031fe0570..587b74d4046bed797223a6c748e94e62c0ca56ad 100644 (file)
@@ -20,8 +20,8 @@ _kiwi.view.MediaMessage = Backbone.View.extend({
     open: function () {
         // Create the content div if we haven't already
         if (!this.$content) {
-            this.$content = $('<div class="media_content"><a class="media_close"><i class="icon-chevron-up"></i> Close media</a><br /><div class="content"></div></div>');
-            this.$content.find('.content').append(this.mediaTypes[this.$el.data('type')].apply(this, []) || 'Not found :(');
+            this.$content = $('<div class="media_content"><a class="media_close"><i class="icon-chevron-up"></i> ' + _kiwi.global.i18n.translate('Close media').fetch() + '</a><br /><div class="content"></div></div>');
+            this.$content.find('.content').append(this.mediaTypes[this.$el.data('type')].apply(this, []) || _kiwi.global.i18n.translate('Not found').fetch() + ' :(');
         }
 
         // Now show the content if not already
@@ -47,7 +47,7 @@ _kiwi.view.MediaMessage = Backbone.View.extend({
                 that.$content.find('.content').html(data.html);
             });
 
-            return $('<div>Loading tweet..</div>');
+            return $('<div>' + _kiwi.global.i18n.translate('Loading tweet').fetch() + '...</div>');
         },
 
 
@@ -64,7 +64,7 @@ _kiwi.view.MediaMessage = Backbone.View.extend({
                 that.$content.find('.content').html(img_html);
             });
 
-            return $('<div>Loading image..</div>');
+            return $('<div>' + _kiwi.global.i18n.translate('Loading image').fetch() + '...</div>');
         },
 
 
@@ -100,7 +100,7 @@ _kiwi.view.MediaMessage = Backbone.View.extend({
                 that.$content.find('.content').html(_.template(tmpl, post));
             });
 
-            return $('<div>Loading Reddit thread..</div>');
+            return $('<div>' + _kiwi.global.i18n.translate('Loading Reddit thread').fetch() + '...</div>');
         },
 
 
@@ -123,7 +123,7 @@ _kiwi.view.MediaMessage = Backbone.View.extend({
                 that.$content.find('.content').html(data.div);
             });
 
-            return $('<div>Loading gist..</div>');
+            return $('<div>' + _kiwi.global.i18n.translate('Loading gist').fetch() + '...</div>');
         }
     }
     }, {
index 8cea5e1b9a557a77bfff9d6b320675060f85d3a2..b75fc99ef65c6ac5ad40858adfe5469ed8db87e8 100644 (file)
@@ -3,11 +3,16 @@ _kiwi.view.NickChangeBox = Backbone.View.extend({
         'submit': 'changeNick',
         'click .cancel': 'close'
     },
-    
+
     initialize: function () {
-        this.$el = $($('#tmpl_nickchange').html().trim());
+        var text = {
+            new_nick: _kiwi.global.i18n.translate('New nick').fetch(),
+            change: _kiwi.global.i18n.translate('Change').fetch(),
+            cancel: _kiwi.global.i18n.translate('Cancel').fetch()
+        };
+        this.$el = $(_.template($('#tmpl_nickchange').html().trim(), text));
     },
-    
+
     render: function () {
         // Add the UI component and give it focus
         _kiwi.app.controlbox.$el.prepend(this.$el);
index 0ab799d48a310fd8c0ada59cd2693ae9f03af58c..9546f1fa676a5b5ab194f306e31c2f093594b178 100644 (file)
@@ -133,7 +133,7 @@ _kiwi.view.Panel = Backbone.View.extend({
             this.alert('action');
 
         } else if (is_highlight) {
-            _kiwi.app.view.alertWindow('* People are talking!');
+            _kiwi.app.view.alertWindow('* ' + _kiwi.global.i18n.translate('People are talking!').fetch());
             _kiwi.app.view.favicon.newHighlight();
             _kiwi.app.view.playSound('highlight');
             this.alert('highlight');
@@ -141,13 +141,13 @@ _kiwi.view.Panel = Backbone.View.extend({
         } else {
             // If this is the active panel, send an alert out
             if (this.model.isActive()) {
-                _kiwi.app.view.alertWindow('* People are talking!');
+                _kiwi.app.view.alertWindow('* ' + _kiwi.global.i18n.translate('People are talking!').fetch());
             }
             this.alert('activity');
         }
 
         if (this.model.isQuery() && !this.model.isActive()) {
-            _kiwi.app.view.alertWindow('* People are talking!');
+            _kiwi.app.view.alertWindow('* ' + _kiwi.global.i18n.translate('People are talking!').fetch());
             if (!is_highlight) {
                 _kiwi.app.view.favicon.newHighlight();
             }
index eebdd6451f6b1cadec175e38142939dee5e5b2ab..a6dda5be8cfa5191e165f15f175494d72a66ce53 100644 (file)
@@ -12,9 +12,24 @@ _kiwi.view.ServerSelect = function () {
         },
 
         initialize: function () {
-            var that = this;
-
-            this.$el = $($('#tmpl_server_select').html().trim());
+            var that = this,
+                text = {
+                    think_nick: _kiwi.global.i18n.translate('Think of a nickname...').fetch(),
+                    nickname: _kiwi.global.i18n.translate('Nickname').fetch(),
+                    have_password: _kiwi.global.i18n.translate('I have a password').fetch(),
+                    password: _kiwi.global.i18n.translate('Password').fetch(),
+                    channel: _kiwi.global.i18n.translate('Channel').fetch(),
+                    channel_key: _kiwi.global.i18n.translate('Channel Key').fetch(),
+                    require_key: _kiwi.global.i18n.translate('Channel requires a key').fetch(),
+                    key: _kiwi.global.i18n.translate('Key').fetch(),
+                    start: _kiwi.global.i18n.translate('Start...').fetch(),
+                    server_network: _kiwi.global.i18n.translate('Server and network').fetch(),
+                    server: _kiwi.global.i18n.translate('Server').fetch(),
+                    port: _kiwi.global.i18n.translate('Port').fetch(),
+                    powered_by: _kiwi.global.i18n.translate('Powered by Kiwi IRC').fetch()
+                };
+
+            this.$el = $(_.template($('#tmpl_server_select').html().trim(), text));
 
             // Remove the 'more' link if the server has disabled server changing
             if (_kiwi.app.server_settings && _kiwi.app.server_settings.connection) {
@@ -42,7 +57,7 @@ _kiwi.view.ServerSelect = function () {
 
             // Make sure a nick is chosen
             if (!$('input.nick', this.$el).val().trim()) {
-                this.setStatus('Select a nickname first!');
+                this.setStatus(_kiwi.global.i18n.translate('Select a nickname first!').fetch());
                 $('input.nick', this.$el).select();
                 return;
             }
@@ -196,12 +211,12 @@ _kiwi.view.ServerSelect = function () {
         },
 
         networkConnected: function (event) {
-            this.setStatus('Connected :)', 'ok');
+            this.setStatus(_kiwi.global.i18n.translate('Connected').fetch() + ' :)', 'ok');
             $('form', this.$el).hide();
         },
 
         networkConnecting: function (event) {
-            this.setStatus('Connecting..', 'ok');
+            this.setStatus(_kiwi.global.i18n.translate('Connecting..').fetch(), 'ok');
         },
 
         onIrcError: function (data) {
@@ -209,17 +224,17 @@ _kiwi.view.ServerSelect = function () {
 
             switch(data.error) {
             case 'nickname_in_use':
-                this.setStatus('Nickname already taken');
+                this.setStatus(_kiwi.global.i18n.translate('Nickname already taken').fetch());
                 this.show('nick_change');
                 this.$el.find('.nick').select();
                 break;
             case 'erroneus_nickname':
-                this.setStatus('Erroneus nickname');
+                this.setStatus(_kiwi.global.i18n.translate('Erroneus nickname').fetch());
                 this.show('nick_change');
                 this.$el.find('.nick').select();
                 break;
             case 'password_mismatch':
-                this.setStatus('Incorrect Password');
+                this.setStatus(_kiwi.global.i18n.translate('Incorrect Password').fetch());
                 this.show('nick_change');
                 this.$el.find('.password').select();
                 break;
@@ -227,16 +242,16 @@ _kiwi.view.ServerSelect = function () {
         },
 
         showError: function (error_reason) {
-            var err_text = 'Error Connecting';
+            var err_text = _kiwi.global.i18n.translate('Error Connecting').fetch();
 
             if (error_reason) {
                 switch (error_reason) {
                 case 'ENOTFOUND':
-                    err_text = 'Server not found';
+                    err_text = _kiwi.global.i18n.translate('Server not found').fetch();
                     break;
 
                 case 'ECONNREFUSED':
-                    err_text += ' (Connection refused)';
+                    err_text += ' (' + _kiwi.global.i18n.translate('Connection refused').fetch() + ')';
                     break;
 
                 default:
index 416e5c93964db12c20af3e0b0e3e02ed1f1f8ea1..de9d0c33cbf7d53c3d0f3d0a6c8ad6be80531a68 100644 (file)
@@ -12,7 +12,18 @@ _kiwi.view.UserBox = Backbone.View.extend({
     },
 
     initialize: function () {
-        this.$el = $($('#tmpl_userbox').html().trim());
+        var text = {
+            op: _kiwi.global.i18n.translate('Op').fetch(),
+            de_op: _kiwi.global.i18n.translate('De-op').fetch(),
+            voice: _kiwi.global.i18n.translate('Voice').fetch(),
+            de_voice: _kiwi.global.i18n.translate('De-voice').fetch(),
+            kick: _kiwi.global.i18n.translate('Kick').fetch(),
+            ban: _kiwi.global.i18n.translate('Ban').fetch(),
+            message: _kiwi.global.i18n.translate('Message').fetch(),
+            info: _kiwi.global.i18n.translate('Info').fetch(),
+            slap: _kiwi.global.i18n.translate('Slap!').fetch()
+        };
+        this.$el = $(_.template($('#tmpl_userbox').html().trim(), text));
     },
 
     queryClick: function (event) {