text: // i18next, v1.9.0
  // Copyright (c)2015 Jan Mühlemann (jamuhl).
  // Distributed under MIT license
  // http://i18next.com
  (function(root) {
  
      // add indexOf to non ECMA-262 standard compliant browsers
      if (!Array.prototype.indexOf) {
          Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
              "use strict";
              if (this == null) {
                  throw new TypeError();
              }
              var t = Object(this);
              var len = t.length >>> 0;
              if (len === 0) {
                  return -1;
              }
              var n = 0;
              if (arguments.length > 0) {
                  n = Number(arguments[1]);
                  if (n != n) { // shortcut for verifying if it's NaN
                      n = 0;
                  } else if (n != 0 && n != Infinity && n != -Infinity) {
                      n = (n > 0 || -1) * Math.floor(Math.abs(n));
                  }
              }
              if (n >= len) {
                  return -1;
              }
              var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
              for (; k < len; k++) {
                  if (k in t && t[k] === searchElement) {
                      return k;
                  }
              }
              return -1;
          }
      }
      
      // add lastIndexOf to non ECMA-262 standard compliant browsers
      if (!Array.prototype.lastIndexOf) {
          Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/) {
              "use strict";
              if (this == null) {
                  throw new TypeError();
              }
              var t = Object(this);
              var len = t.length >>> 0;
              if (len === 0) {
                  return -1;
              }
              var n = len;
              if (arguments.length > 1) {
                  n = Number(arguments[1]);
                  if (n != n) {
                      n = 0;
                  } else if (n != 0 && n != (1 / 0) && n != -(1 / 0)) {
                      n = (n > 0 || -1) * Math.floor(Math.abs(n));
                  }
              }
              var k = n >= 0 ? Math.min(n, len - 1) : len - Math.abs(n);
              for (; k >= 0; k--) {
                  if (k in t && t[k] === searchElement) {
                      return k;
                  }
              }
              return -1;
          };
      }
      
      // Add string trim for IE8.
      if (typeof String.prototype.trim !== 'function') {
          String.prototype.trim = function() {
              return this.replace(/^\s+|\s+$/g, ''); 
          }
      }
  
      var $ = root.jQuery || root.Zepto
        , i18n = {}
        , resStore = {}
        , currentLng
        , replacementCounter = 0
        , languages = []
        , initialized = false
        , sync = {}
        , conflictReference = null;
  
  
  
      // Export the i18next object for **CommonJS**. 
      // If we're not in CommonJS, add `i18n` to the
      // global object or to jquery.
      if (typeof module !== 'undefined' && module.exports) {
          module.exports = i18n;
      } else {
          if ($) {
              $.i18n = $.i18n || i18n;
          }
          
          if (root.i18n) {
          	conflictReference = root.i18n;
          }
          root.i18n = i18n;
      }
      sync = {
      
          load: function(lngs, options, cb) {
              if (options.useLocalStorage) {
                  sync._loadLocal(lngs, options, function(err, store) {
                      var missingLngs = [];
                      for (var i = 0, len = lngs.length; i < len; i++) {
                          if (!store[lngs[i]]) missingLngs.push(lngs[i]);
                      }
      
                      if (missingLngs.length > 0) {
                          sync._fetch(missingLngs, options, function(err, fetched) {
                              f.extend(store, fetched);
                              sync._storeLocal(fetched);
      
                              cb(null, store);
                          });
                      } else {
                          cb(null, store);
                      }
                  });
              } else {
                  sync._fetch(lngs, options, function(err, store){
                      cb(null, store);
                  });
              }
          },
      
          _loadLocal: function(lngs, options, cb) {
              var store = {}
                , nowMS = new Date().getTime();
      
              if(window.localStorage) {
      
                  var todo = lngs.length;
      
                  f.each(lngs, function(key, lng) {
                      var local = f.localStorage.getItem('res_' + lng);
      
                      if (local) {
                          local = JSON.parse(local);
      
                          if (local.i18nStamp && local.i18nStamp + options.localStorageExpirationTime > nowMS) {
                              store[lng] = local;
                          }
                      }
      
                      todo--; // wait for all done befor callback
                      if (todo === 0) cb(null, store);
                  });
              }
          },
      
          _storeLocal: function(store) {
              if(window.localStorage) {
                  for (var m in store) {
                      store[m].i18nStamp = new Date().getTime();
                      f.localStorage.setItem('res_' + m, JSON.stringify(store[m]));
                  }
              }
              return;
          },
      
          _fetch: function(lngs, options, cb) {
              var ns = options.ns
                , store = {};
              
              if (!options.dynamicLoad) {
                  var todo = ns.namespaces.length * lngs.length
                    , errors;
      
                  // load each file individual
                  f.each(ns.namespaces, function(nsIndex, nsValue) {
                      f.each(lngs, function(lngIndex, lngValue) {
                          
                          // Call this once our translation has returned.
                          var loadComplete = function(err, data) {
                              if (err) {
                                  errors = errors || [];
                                  errors.push(err);
                              }
                              store[lngValue] = store[lngValue] || {};
                              store[lngValue][nsValue] = data;
      
                              todo--; // wait for all done befor callback
                              if (todo === 0) cb(errors, store);
                          };
                          
                          if(typeof options.customLoad == 'function'){
                              // Use the specified custom callback.
                              options.customLoad(lngValue, nsValue, options, loadComplete);
                          } else {
                              //~ // Use our inbuilt sync.
                              sync._fetchOne(lngValue, nsValue, options, loadComplete);
                          }
                      });
                  });
              } else {
                  // Call this once our translation has returned.
                  var loadComplete = function(err, data) {
                      cb(null, data);
                  };
      
                  if(typeof options.customLoad == 'function'){
                      // Use the specified custom callback.
                      options.customLoad(lngs, ns.namespaces, options, loadComplete);
                  } else {
                      var url = applyReplacement(options.resGetPath, { lng: lngs.join('+'), ns: ns.namespaces.join('+') });
                      // load all needed stuff once
                      f.ajax({
                          url: url,
                          cache: options.cache,
                          success: function(data, status, xhr) {
                              f.log('loaded: ' + url);
                              loadComplete(null, data);
                          },
                          error : function(xhr, status, error) {
                              f.log('failed loading: ' + url);
                              loadComplete('failed loading resource.json error: ' + error);
                          },
                          dataType: "json",
                          async : options.getAsync,
                          timeout: options.ajaxTimeout
                      });
                  }    
              }
          },
      
          _fetchOne: function(lng, ns, options, done) {
              var url = applyReplacement(options.resGetPath, { lng: lng, ns: ns });
              f.ajax({
                  url: url,
                  cache: options.cache,
                  success: function(data, status, xhr) {
                      f.log('loaded: ' + url);
                      done(null, data);
                  },
                  error : function(xhr, status, error) {
                      if ((status && status == 200) || (xhr && xhr.status && xhr.status == 200)) {
                          // file loaded but invalid json, stop waste time !
                          f.error('There is a typo in: ' + url);
                      } else if ((status && status == 404) || (xhr && xhr.status && xhr.status == 404)) {
                          f.log('Does not exist: ' + url);
                      } else {
                          var theStatus = status ? status : ((xhr && xhr.status) ? xhr.status : null);
                          f.log(theStatus + ' when loading ' + url);
                      }
                      
                      done(error, {});
                  },
                  dataType: "json",
                  async : options.getAsync,
                  timeout: options.ajaxTimeout
              });
          },
      
          postMissing: function(lng, ns, key, defaultValue, lngs) {
              var payload = {};
              payload[key] = defaultValue;
      
              var urls = [];
      
              if (o.sendMissingTo === 'fallback' && o.fallbackLng[0] !== false) {
                  for (var i = 0; i < o.fallbackLng.length; i++) {
                      urls.push({lng: o.fallbackLng[i], url: applyReplacement(o.resPostPath, { lng: o.fallbackLng[i], ns: ns })});
                  }
              } else if (o.sendMissingTo === 'current' || (o.sendMissingTo === 'fallback' && o.fallbackLng[0] === false) ) {
                  urls.push({lng: lng, url: applyReplacement(o.resPostPath, { lng: lng, ns: ns })});
              } else if (o.sendMissingTo === 'all') {
                  for (var i = 0, l = lngs.length; i < l; i++) {
                      urls.push({lng: lngs[i], url: applyReplacement(o.resPostPath, { lng: lngs[i], ns: ns })});
                  }
              }
      
              for (var y = 0, len = urls.length; y < len; y++) {
                  var item = urls[y];
                  f.ajax({
                      url: item.url,
                      type: o.sendType,
                      data: payload,
                      success: function(data, status, xhr) {
                          f.log('posted missing key \'' + key + '\' to: ' + item.url);
      
                          // add key to resStore
                          var keys = key.split('.');
                          var x = 0;
                          var value = resStore[item.lng][ns];
                          while (keys[x]) {
                              if (x === keys.length - 1) {
                                  value = value[keys[x]] = defaultValue;
                              } else {
                                  value = value[keys[x]] = value[keys[x]] || {};
                              }
                              x++;
                          }
                      },
                      error : function(xhr, status, error) {
                          f.log('failed posting missing key \'' + key + '\' to: ' + item.url);
                      },
                      dataType: "json",
                      async : o.postAsync,
                      timeout: o.ajaxTimeout
                  });
              }
          },
      
          reload: reload
      };
      // defaults
      var o = {
          lng: undefined,
          load: 'all',
          preload: [],
          lowerCaseLng: false,
          returnObjectTrees: false,
          fallbackLng: ['dev'],
          fallbackNS: [],
          detectLngQS: 'setLng',
          detectLngFromLocalStorage: false,
          ns: {
              namespaces: ['translation'],
              defaultNs: 'translation'
          },
          fallbackOnNull: true,
          fallbackOnEmpty: false,
          fallbackToDefaultNS: false,
          showKeyIfEmpty: false,
          nsseparator: ':',
          keyseparator: '.',
          selectorAttr: 'data-i18n',
          debug: false,
      
          resGetPath: 'locales/__lng__/__ns__.json',
          resPostPath: 'locales/add/__lng__/__ns__',
      
          getAsync: true,
          postAsync: true,
      
          resStore: undefined,
          useLocalStorage: false,
          localStorageExpirationTime: 7*24*60*60*1000,
      
          dynamicLoad: false,
          sendMissing: false,
          sendMissingTo: 'fallback', // current | all
          sendType: 'POST',
      
          interpolationPrefix: '__',
          interpolationSuffix: '__',
          defaultVariables: false,
          reusePrefix: '$t(',
          reuseSuffix: ')',
          pluralSuffix: '_plural',
          pluralNotFound: ['plural_not_found', Math.random()].join(''),
          contextNotFound: ['context_not_found', Math.random()].join(''),
          escapeInterpolation: false,
          indefiniteSuffix: '_indefinite',
          indefiniteNotFound: ['indefinite_not_found', Math.random()].join(''),
      
          setJqueryExt: true,
          defaultValueFromContent: true,
          useDataAttrOptions: false,
          cookieExpirationTime: undefined,
          useCookie: true,
          cookieName: 'i18next',
          cookieDomain: undefined,
      
          objectTreeKeyHandler: undefined,
          postProcess: undefined,
          parseMissingKey: undefined,
          missingKeyHandler: sync.postMissing,
          ajaxTimeout: 0,
      
          shortcutFunction: 'sprintf' // or: defaultValue
      };
      function _extend(target, source) {
          if (!source || typeof source === 'function') {
              return target;
          }
      
          for (var attr in source) { target[attr] = source[attr]; }
          return target;
      }
      
      function _deepExtend(target, source) {
          for (var prop in source)
              if (prop in target)
                  _deepExtend(target[prop], source[prop]);
              else
                  target[prop] = source[prop];
          return target;
      }
      
      function _each(object, callback, args) {
          var name, i = 0,
              length = object.length,
              isObj = length === undefined || Object.prototype.toString.apply(object) !== '[object Array]' || typeof object === "function";
      
          if (args) {
              if (isObj) {
                  for (name in object) {
                      if (callback.apply(object[name], args) === false) {
                          break;
                      }
                  }
              } else {
                  for ( ; i < length; ) {
                      if (callback.apply(object[i++], args) === false) {
                          break;
                      }
                  }
              }
      
          // A special, fast, case for the most common use of each
          } else {
              if (isObj) {
                  for (name in object) {
                      if (callback.call(object[name], name, object[name]) === false) {
                          break;
                      }
                  }
              } else {
                  for ( ; i < length; ) {
                      if (callback.call(object[i], i, object[i++]) === false) {
                          break;
                      }
                  }
              }
          }
      
          return object;
      }
      
      var _entityMap = {
          "&": "&amp;",
          "<": "&lt;",
          ">": "&gt;",
          '"': '&quot;',
          "'": '&#39;',
          "/": '&#x2F;'
      };
      
      function _escape(data) {
          if (typeof data === 'string') {
              return data.replace(/[&<>"'\/]/g, function (s) {
                  return _entityMap[s];
              });
          }else{
              return data;
          }
      }
      
      function _ajax(options) {
      
          // v0.5.0 of https://github.com/goloroden/http.js
          var getXhr = function (callback) {
              // Use the native XHR object if the browser supports it.
              if (window.XMLHttpRequest) {
                  return callback(null, new XMLHttpRequest());
              } else if (window.ActiveXObject) {
                  // In Internet Explorer check for ActiveX versions of the XHR object.
                  try {
                      return callback(null, new ActiveXObject("Msxml2.XMLHTTP"));
                  } catch (e) {
                      return callback(null, new ActiveXObject("Microsoft.XMLHTTP"));
                  }
              }
      
              // If no XHR support was found, throw an error.
              return callback(new Error());
          };
      
          var encodeUsingUrlEncoding = function (data) {
              if(typeof data === 'string') {
                  return data;
              }
      
              var result = [];
              for(var dataItem in data) {
                  if(data.hasOwnProperty(dataItem)) {
                      result.push(encodeURIComponent(dataItem) + '=' + encodeURIComponent(data[dataItem]));
                  }
              }
      
              return result.join('&');
          };
      
          var utf8 = function (text) {
              text = text.replace(/\r\n/g, '\n');
              var result = '';
      
              for(var i = 0; i < text.length; i++) {
                  var c = text.charCodeAt(i);
      
                  if(c < 128) {
                          result += String.fromCharCode(c);
                  } else if((c > 127) && (c < 2048)) {
                          result += String.fromCharCode((c >> 6) | 192);
                          result += String.fromCharCode((c & 63) | 128);
                  } else {
                          result += String.fromCharCode((c >> 12) | 224);
                          result += String.fromCharCode(((c >> 6) & 63) | 128);
                          result += String.fromCharCode((c & 63) | 128);
                  }
              }
      
              return result;
          };
      
          var base64 = function (text) {
              var keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
      
              text = utf8(text);
              var result = '',
                      chr1, chr2, chr3,
                      enc1, enc2, enc3, enc4,
                      i = 0;
      
              do {
                  chr1 = text.charCodeAt(i++);
                  chr2 = text.charCodeAt(i++);
                  chr3 = text.charCodeAt(i++);
      
                  enc1 = chr1 >> 2;
                  enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                  enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                  enc4 = chr3 & 63;
      
                  if(isNaN(chr2)) {
                      enc3 = enc4 = 64;
                  } else if(isNaN(chr3)) {
                      enc4 = 64;
                  }
      
                  result +=
                      keyStr.charAt(enc1) +
                      keyStr.charAt(enc2) +
                      keyStr.charAt(enc3) +
                      keyStr.charAt(enc4);
                  chr1 = chr2 = chr3 = '';
                  enc1 = enc2 = enc3 = enc4 = '';
              } while(i < text.length);
      
              return result;
          };
      
          var mergeHeaders = function () {
              // Use the first header object as base.
              var result = arguments[0];
      
              // Iterate through the remaining header objects and add them.
              for(var i = 1; i < arguments.length; i++) {
                  var currentHeaders = arguments[i];
                  for(var header in currentHeaders) {
                      if(currentHeaders.hasOwnProperty(header)) {
                          result[header] = currentHeaders[header];
                      }
                  }
              }
      
              // Return the merged headers.
              return result;
          };
      
          var ajax = function (method, url, options, callback) {
              // Adjust parameters.
              if(typeof options === 'function') {
                  callback = options;
                  options = {};
              }
      
              // Set default parameter values.
              options.cache = options.cache || false;
              options.data = options.data || {};
              options.headers = options.headers || {};
              options.jsonp = options.jsonp || false;
              options.async = options.async === undefined ? true : options.async;
      
              // Merge the various header objects.
              var headers = mergeHeaders({
                  'accept': '*/*',
                  'content-type': 'application/x-www-form-urlencoded;charset=UTF-8'
              }, ajax.headers, options.headers);
      
              // Encode the data according to the content-type.
              var payload;
              if (headers['content-type'] === 'application/json') {
                  payload = JSON.stringify(options.data);
              } else {
                  payload = encodeUsingUrlEncoding(options.data);
              }
      
              // Specially prepare GET requests: Setup the query string, handle caching and make a JSONP call
              // if neccessary.
              if(method === 'GET') {
                  // Setup the query string.
                  var queryString = [];
                  if(payload) {
                      queryString.push(payload);
                      payload = null;
                  }
      
                  // Handle caching.
                  if(!options.cache) {
                      queryString.push('_=' + (new Date()).getTime());
                  }
      
                  // If neccessary prepare the query string for a JSONP call.
                  if(options.jsonp) {
                      queryString.push('callback=' + options.jsonp);
                      queryString.push('jsonp=' + options.jsonp);
                  }
      
                  // Merge the query string and attach it to the url.
                  queryString = queryString.join('&');
                  if (queryString.length > 1) {
                      if (url.indexOf('?') > -1) {
                          url += '&' + queryString;
                      } else {
                          url += '?' + queryString;
                      }
                  }
      
                  // Make a JSONP call if neccessary.
                  if(options.jsonp) {
                      var head = document.getElementsByTagName('head')[0];
                      var script = document.createElement('script');
                      script.type = 'text/javascript';
                      script.src = url;
                      head.appendChild(script);
                      return;
                  }
              }
      
              // Since we got here, it is no JSONP request, so make a normal XHR request.
              getXhr(function (err, xhr) {
                  if(err) return callback(err);
      
                  // Open the request.
                  xhr.open(method, url, options.async);
      
                  // Set the request headers.
                  for(var header in headers) {
                      if(headers.hasOwnProperty(header)) {
                          xhr.setRequestHeader(header, headers[header]);
                      }
                  }
      
                  // Handle the request events.
                  xhr.onreadystatechange = function () {
                      if(xhr.readyState === 4) {
                          var data = xhr.responseText || '';
      
                          // If no callback is given, return.
                          if(!callback) {
                              return;
                          }
      
                          // Return an object that provides access to the data as text and JSON.
                          callback(xhr.status, {
                              text: function () {
                                  return data;
                              },
      
                              json: function () {
                                  try {
                                      return JSON.parse(data)
                                  } catch (e) {
                                      f.error('Can not parse JSON. URL: ' + url);
                                      return {};
                                  }
                              }
                          });
                      }
                  };
      
                  // Actually send the XHR request.
                  xhr.send(payload);
              });
          };
      
          // Define the external interface.
          var http = {
              authBasic: function (username, password) {
                  ajax.headers['Authorization'] = 'Basic ' + base64(username + ':' + password);
              },
      
              connect: function (url, options, callback) {
                  return ajax('CONNECT', url, options, callback);
              },
      
              del: function (url, options, callback) {
                  return ajax('DELETE', url, options, callback);
              },
      
              get: function (url, options, callback) {
                  return ajax('GET', url, options, callback);
              },
      
              head: function (url, options, callback) {
                  return ajax('HEAD', url, options, callback);
              },
      
              headers: function (headers) {
                  ajax.headers = headers || {};
              },
      
              isAllowed: function (url, verb, callback) {
                  this.options(url, function (status, data) {
                      callback(data.text().indexOf(verb) !== -1);
                  });
              },
      
              options: function (url, options, callback) {
                  return ajax('OPTIONS', url, options, callback);
              },
      
              patch: function (url, options, callback) {
                  return ajax('PATCH', url, options, callback);
              },
      
              post: function (url, options, callback) {
                  return ajax('POST', url, options, callback);
              },
      
              put: function (url, options, callback) {
                  return ajax('PUT', url, options, callback);
              },
      
              trace: function (url, options, callback) {
                  return ajax('TRACE', url, options, callback);
              }
          };
      
      
          var methode = options.type ? options.type.toLowerCase() : 'get';
      
          http[methode](options.url, options, function (status, data) {
              // file: protocol always gives status code 0, so check for data
              if (status === 200 || (status === 0 && data.text())) {
                  options.success(data.json(), status, null);
              } else {
                  options.error(data.text(), status, null);
              }
          });
      }
      
      var _cookie = {
          create: function(name,value,minutes,domain) {
              var expires;
              if (minutes) {
                  var date = new Date();
                  date.setTime(date.getTime()+(minutes*60*1000));
                  expires = "; expires="+date.toGMTString();
              }
              else expires = "";
              domain = (domain)? "domain="+domain+";" : "";
              document.cookie = name+"="+value+expires+";"+domain+"path=/";
          },
      
          read: function(name) {
              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 c.substring(nameEQ.length,c.length);
              }
              return null;
          },
      
          remove: function(name) {
              this.create(name,"",-1);
          }
      };
      
      var cookie_noop = {
          create: function(name,value,minutes,domain) {},
          read: function(name) { return null; },
          remove: function(name) {}
      };
      
      
      
      // move dependent functions to a container so that
      // they can be overriden easier in no jquery environment (node.js)
      var f = {
          extend: $ ? $.extend : _extend,
          deepExtend: _deepExtend,
          each: $ ? $.each : _each,
          ajax: $ ? $.ajax : (typeof document !== 'undefined' ? _ajax : function() {}),
          cookie: typeof document !== 'undefined' ? _cookie : cookie_noop,
          detectLanguage: detectLanguage,
          escape: _escape,
          log: function(str) {
              if (o.debug && typeof console !== "undefined") console.log(str);
          },
          error: function(str) {
              if (typeof console !== "undefined") console.error(str);
          },
          getCountyIndexOfLng: function(lng) {
              var lng_index = 0;
              if (lng === 'nb-NO' || lng === 'nn-NO' || lng === 'nb-no' || lng === 'nn-no') lng_index = 1;
              return lng_index;
          },
          toLanguages: function(lng) {
              var log = this.log;
      
              function applyCase(l) {
                  var ret = l;
      
                  if (typeof l === 'string' && l.indexOf('-') > -1) {
                      var parts = l.split('-');
      
                      ret = o.lowerCaseLng ?
                          parts[0].toLowerCase() +  '-' + parts[1].toLowerCase() :
                          parts[0].toLowerCase() +  '-' + parts[1].toUpperCase();
                  } else {
                      ret = o.lowerCaseLng ? l.toLowerCase() : l;
                  }
      
                  return ret;
              }
      
              var languages = [];
              var whitelist = o.lngWhitelist || false;
              var addLanguage = function(language){
                //reject langs not whitelisted
                if(!whitelist || whitelist.indexOf(language) > -1){
                  languages.push(language);
                }else{
                  log('rejecting non-whitelisted language: ' + language);
                }
              };
              if (typeof lng === 'string' && lng.indexOf('-') > -1) {
                  var parts = lng.split('-');
      
                  if (o.load !== 'unspecific') addLanguage(applyCase(lng));
                  if (o.load !== 'current') addLanguage(applyCase(parts[this.getCountyIndexOfLng(lng)]));
              } else {
                  addLanguage(applyCase(lng));
              }
      
              for (var i = 0; i < o.fallbackLng.length; i++) {
                  if (languages.indexOf(o.fallbackLng[i]) === -1 && o.fallbackLng[i]) languages.push(applyCase(o.fallbackLng[i]));
              }
              return languages;
          },
          regexEscape: function(str) {
              return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
          },
          regexReplacementEscape: function(strOrFn) {
              if (typeof strOrFn === 'string') {
                  return strOrFn.replace(/\$/g, "$$$$");
              } else {
                  return strOrFn;
              }
          },
          localStorage: {
              setItem: function(key, value) {
                  if (window.localStorage) {
                      try {
                          window.localStorage.setItem(key, value);
                      } catch (e) {
                          f.log('failed to set value for key "' + key + '" to localStorage.');
                      }
                  }
              },
              getItem: function(key, value) {
                  if (window.localStorage) {
                      try {
                          return window.localStorage.getItem(key, value);
                      } catch (e) {
                          f.log('failed to get value for key "' + key + '" from localStorage.');
                          return undefined;
                      }
                  }
              }
          }
      };
      function init(options, cb) {
      
          if (typeof options === 'function') {
              cb = options;
              options = {};
          }
          options = options || {};
      
          // override defaults with passed in options
          f.extend(o, options);
          delete o.fixLng; /* passed in each time */
      
          // override functions: .log(), .detectLanguage(), etc
          if (o.functions) {
              delete o.functions;
              f.extend(f, options.functions);
          }
      
          // create namespace object if namespace is passed in as string
          if (typeof o.ns == 'string') {
              o.ns = { namespaces: [o.ns], defaultNs: o.ns};
          }
      
          // fallback namespaces
          if (typeof o.fallbackNS == 'string') {
              o.fallbackNS = [o.fallbackNS];
          }
      
          // fallback languages
          if (typeof o.fallbackLng == 'string' || typeof o.fallbackLng == 'boolean') {
              o.fallbackLng = [o.fallbackLng];
          }
      
          // escape prefix/suffix
          o.interpolationPrefixEscaped = f.regexEscape(o.interpolationPrefix);
          o.interpolationSuffixEscaped = f.regexEscape(o.interpolationSuffix);
      
          if (!o.lng) o.lng = f.detectLanguage();
      
          languages = f.toLanguages(o.lng);
          currentLng = languages[0];
          f.log('currentLng set to: ' + currentLng);
      
          if (o.useCookie && f.cookie.read(o.cookieName) !== currentLng){ //cookie is unset or invalid
              f.cookie.create(o.cookieName, currentLng, o.cookieExpirationTime, o.cookieDomain);
          }
          if (o.detectLngFromLocalStorage && typeof document !== 'undefined' && window.localStorage) {
              f.localStorage.setItem('i18next_lng', currentLng);
          }
      
          var lngTranslate = translate;
          if (options.fixLng) {
              lngTranslate = function(key, options) {
                  options = options || {};
                  options.lng = options.lng || lngTranslate.lng;
                  return translate(key, options);
              };
              lngTranslate.lng = currentLng;
          }
      
          pluralExtensions.setCurrentLng(currentLng);
      
          // add JQuery extensions
          if ($ && o.setJqueryExt) addJqueryFunct();
      
          // jQuery deferred
          var deferred;
          if ($ && $.Deferred) {
              deferred = $.Deferred();
          }
      
          // return immidiatly if res are passed in
          if (o.resStore) {
              resStore = o.resStore;
              initialized = true;
              if (cb) cb(lngTranslate);
              if (deferred) deferred.resolve(lngTranslate);
              if (deferred) return deferred.promise();
              return;
          }
      
          // languages to load
          var lngsToLoad = f.toLanguages(o.lng);
          if (typeof o.preload === 'string') o.preload = [o.preload];
          for (var i = 0, l = o.preload.length; i < l; i++) {
              var pres = f.toLanguages(o.preload[i]);
              for (var y = 0, len = pres.length; y < len; y++) {
                  if (lngsToLoad.indexOf(pres[y]) < 0) {
                      lngsToLoad.push(pres[y]);
                  }
              }
          }
      
          // else load them
          i18n.sync.load(lngsToLoad, o, function(err, store) {
              resStore = store;
              initialized = true;
      
              if (cb) cb(lngTranslate);
              if (deferred) deferred.resolve(lngTranslate);
          });
      
          if (deferred) return deferred.promise();
      }
      
      function isInitialized() {
          return initialized;
      }
      function preload(lngs, cb) {
          if (typeof lngs === 'string') lngs = [lngs];
          for (var i = 0, l = lngs.length; i < l; i++) {
              if (o.preload.indexOf(lngs[i]) < 0) {
                  o.preload.push(lngs[i]);
              }
          }
          return init(cb);
      }
      
      function addResourceBundle(lng, ns, resources, deep) {
          if (typeof ns !== 'string') {
              resources = ns;
              ns = o.ns.defaultNs;
          } else if (o.ns.namespaces.indexOf(ns) < 0) {
              o.ns.namespaces.push(ns);
          }
      
          resStore[lng] = resStore[lng] || {};
          resStore[lng][ns] = resStore[lng][ns] || {};
      
          if (deep) {
              f.deepExtend(resStore[lng][ns], resources);
          } else {
              f.extend(resStore[lng][ns], resources);
          }
          if (o.useLocalStorage) {
              sync._storeLocal(resStore);
          }
      }
      
      function hasResourceBundle(lng, ns) {
          if (typeof ns !== 'string') {
              ns = o.ns.defaultNs;
          }
      
          resStore[lng] = resStore[lng] || {};
          var res = resStore[lng][ns] || {};
      
          var hasValues = false;
          for(var prop in res) {
              if (res.hasOwnProperty(prop)) {
                  hasValues = true;
              }
          }
      
          return hasValues;
      }
      
      function getResourceBundle(lng, ns) {
          if (typeof ns !== 'string') {
              ns = o.ns.defaultNs;
          }
      
          resStore[lng] = resStore[lng] || {};
          return f.extend({}, resStore[lng][ns]);
      }
      
      function removeResourceBundle(lng, ns) {
          if (typeof ns !== 'string') {
              ns = o.ns.defaultNs;
          }
      
          resStore[lng] = resStore[lng] || {};
          resStore[lng][ns] = {};
          if (o.useLocalStorage) {
              sync._storeLocal(resStore);
          }
      }
      
      function addResource(lng, ns, key, value) {
          if (typeof ns !== 'string') {
              resource = ns;
              ns = o.ns.defaultNs;
          } else if (o.ns.namespaces.indexOf(ns) < 0) {
              o.ns.namespaces.push(ns);
          }
      
          resStore[lng] = resStore[lng] || {};
          resStore[lng][ns] = resStore[lng][ns] || {};
      
          var keys = key.split(o.keyseparator);
          var x = 0;
          var node = resStore[lng][ns];
          var origRef = node;
      
          while (keys[x]) {
              if (x == keys.length - 1)
                  node[keys[x]] = value;
              else {
                  if (node[keys[x]] == null)
                      node[keys[x]] = {};
      
                  node = node[keys[x]];
              }
              x++;
          }
          if (o.useLocalStorage) {
              sync._storeLocal(resStore);
          }
      }
      
      function addResources(lng, ns, resources) {
          if (typeof ns !== 'string') {
              resource = ns;
              ns = o.ns.defaultNs;
          } else if (o.ns.namespaces.indexOf(ns) < 0) {
              o.ns.namespaces.push(ns);
          }
      
          for (var m in resources) {
              if (typeof resources[m] === 'string') addResource(lng, ns, m, resources[m]);
          }
      }
      
      function setDefaultNamespace(ns) {
          o.ns.defaultNs = ns;
      }
      
      function loadNamespace(namespace, cb) {
          loadNamespaces([namespace], cb);
      }
      
      function loadNamespaces(namespaces, cb) {
          var opts = {
              dynamicLoad: o.dynamicLoad,
              resGetPath: o.resGetPath,
              getAsync: o.getAsync,
              customLoad: o.customLoad,
              ns: { namespaces: namespaces, defaultNs: ''} /* new namespaces to load */
          };
      
          // languages to load
          var lngsToLoad = f.toLanguages(o.lng);
          if (typeof o.preload === 'string') o.preload = [o.preload];
          for (var i = 0, l = o.preload.length; i < l; i++) {
              var pres = f.toLanguages(o.preload[i]);
              for (var y = 0, len = pres.length; y < len; y++) {
                  if (lngsToLoad.indexOf(pres[y]) < 0) {
                      lngsToLoad.push(pres[y]);
                  }
              }
          }
      
          // check if we have to load
          var lngNeedLoad = [];
          for (var a = 0, lenA = lngsToLoad.length; a < lenA; a++) {
              var needLoad = false;
              var resSet = resStore[lngsToLoad[a]];
              if (resSet) {
                  for (var b = 0, lenB = namespaces.length; b < lenB; b++) {
                      if (!resSet[namespaces[b]]) needLoad = true;
                  }
              } else {
                  needLoad = true;
              }
      
              if (needLoad) lngNeedLoad.push(lngsToLoad[a]);
          }
      
          if (lngNeedLoad.length) {
              i18n.sync._fetch(lngNeedLoad, opts, function(err, store) {
                  var todo = namespaces.length * lngNeedLoad.length;
      
                  // load each file individual
                  f.each(namespaces, function(nsIndex, nsValue) {
      
                      // append namespace to namespace array
                      if (o.ns.namespaces.indexOf(nsValue) < 0) {
                          o.ns.namespaces.push(nsValue);
                      }
      
                      f.each(lngNeedLoad, function(lngIndex, lngValue) {
                          resStore[lngValue] = resStore[lngValue] || {};
                          resStore[lngValue][nsValue] = store[lngValue][nsValue];
      
                          todo--; // wait for all done befor callback
                          if (todo === 0 && cb) {
                              if (o.useLocalStorage) i18n.sync._storeLocal(resStore);
                              cb();
                          }
                      });
                  });
              });
          } else {
              if (cb) cb();
          }
      }
      
      function setLng(lng, options, cb) {
          if (typeof options === 'function') {
              cb = options;
              options = {};
          } else if (!options) {
              options = {};
          }
      
          options.lng = lng;
          return init(options, cb);
      }
      
      function lng() {
          return currentLng;
      }
      
      function reload(cb) {
          resStore = {};
          setLng(currentLng, cb);
      }
      
      function noConflict() {
          
          window.i18next = window.i18n;
      
          if (conflictReference) {
              window.i18n = conflictReference;
          } else {
              delete window.i18n;
          }
      }
      function addJqueryFunct() {
          // $.t shortcut
          $.t = $.t || translate;
      
          function parse(ele, key, options) {
              if (key.length === 0) return;
      
              var attr = 'text';
      
              if (key.indexOf('[') === 0) {
                  var parts = key.split(']');
                  key = parts[1];
                  attr = parts[0].substr(1, parts[0].length-1);
              }
      
              if (key.indexOf(';') === key.length-1) {
                  key = key.substr(0, key.length-2);
              }
      
              var optionsToUse;
              if (attr === 'html') {
                  optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options;
                  ele.html($.t(key, optionsToUse));
              } else if (attr === 'text') {
                  optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.text() }, options) : options;
                  ele.text($.t(key, optionsToUse));
              } else if (attr === 'prepend') {
                  optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options;
                  ele.prepend($.t(key, optionsToUse));
              } else if (attr === 'append') {
                  optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options;
                  ele.append($.t(key, optionsToUse));
              } else if (attr.indexOf("data-") === 0) {
                  var dataAttr = attr.substr(("data-").length);
                  optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.data(dataAttr) }, options) : options;
                  var translated = $.t(key, optionsToUse);
                  //we change into the data cache
                  ele.data(dataAttr, translated);
                  //we change into the dom
                  ele.attr(attr, translated);
              } else {
                  optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.attr(attr) }, options) : options;
                  ele.attr(attr, $.t(key, optionsToUse));
              }
          }
      
          function localize(ele, options) {
              var key = ele.attr(o.selectorAttr);
              if (!key && typeof key !== 'undefined' && key !== false) key = ele.text() || ele.val();
              if (!key) return;
      
              var target = ele
                , targetSelector = ele.data("i18n-target");
              if (targetSelector) {
                  target = ele.find(targetSelector) || ele;
              }
      
              if (!options && o.useDataAttrOptions === true) {
                  options = ele.data("i18n-options");
              }
              options = options || {};
      
              if (key.indexOf(';') >= 0) {
                  var keys = key.split(';');
      
                  $.each(keys, function(m, k) {
                      if (k !== '') parse(target, k, options);
                  });
      
              } else {
                  parse(target, key, options);
              }
      
              if (o.useDataAttrOptions === true) ele.data("i18n-options", options);
          }
      
          // fn
          $.fn.i18n = function (options) {
              return this.each(function() {
                  // localize element itself
                  localize($(this), options);
      
                  // localize childs
                  var elements =  $(this).find('[' + o.selectorAttr + ']');
                  elements.each(function() { 
                      localize($(this), options);
                  });
              });
          };
      }
      function applyReplacement(str, replacementHash, nestedKey, options) {
          if (!str) return str;
      
          options = options || replacementHash; // first call uses replacement hash combined with options
          if (str.indexOf(options.interpolationPrefix || o.interpolationPrefix) < 0) return str;
      
          var prefix = options.interpolationPrefix ? f.regexEscape(options.interpolationPrefix) : o.interpolationPrefixEscaped
            , suffix = options.interpolationSuffix ? f.regexEscape(options.interpolationSuffix) : o.interpolationSuffixEscaped
            , unEscapingSuffix = 'HTML'+suffix;
      
          var hash = replacementHash.replace && typeof replacementHash.replace === 'object' ? replacementHash.replace : replacementHash;
          f.each(hash, function(key, value) {
              var nextKey = nestedKey ? nestedKey + o.keyseparator + key : key;
              if (typeof value === 'object' && value !== null) {
                  str = applyReplacement(str, value, nextKey, options);
              } else {
                  if (options.escapeInterpolation || o.escapeInterpolation) {
                      str = str.replace(new RegExp([prefix, nextKey, unEscapingSuffix].join(''), 'g'), f.regexReplacementEscape(value));
                      str = str.replace(new RegExp([prefix, nextKey, suffix].join(''), 'g'), f.regexReplacementEscape(f.escape(value)));
                  } else {
                      str = str.replace(new RegExp([prefix, nextKey, suffix].join(''), 'g'), f.regexReplacementEscape(value));
                  }
                  // str = options.escapeInterpolation;
              }
          });
          return str;
      }
      
      // append it to functions
      f.applyReplacement = applyReplacement;
      
      function applyReuse(translated, options) {
          var comma = ',';
          var options_open = '{';
          var options_close = '}';
      
          var opts = f.extend({}, options);
          delete opts.postProcess;
      
          while (translated.indexOf(o.reusePrefix) != -1) {
              replacementCounter++;
              if (replacementCounter > o.maxRecursion) { break; } // safety net for too much recursion
              var index_of_opening = translated.lastIndexOf(o.reusePrefix);
              var index_of_end_of_closing = translated.indexOf(o.reuseSuffix, index_of_opening) + o.reuseSuffix.length;
              var token = translated.substring(index_of_opening, index_of_end_of_closing);
              var token_without_symbols = token.replace(o.reusePrefix, '').replace(o.reuseSuffix, '');
      
              if (index_of_end_of_closing <= index_of_opening) {
                  f.error('there is an missing closing in following translation value', translated);
                  return '';
              }
      
              if (token_without_symbols.indexOf(comma) != -1) {
                  var index_of_token_end_of_closing = token_without_symbols.indexOf(comma);
                  if (token_without_symbols.indexOf(options_open, index_of_token_end_of_closing) != -1 && token_without_symbols.indexOf(options_close, index_of_token_end_of_closing) != -1) {
                      var index_of_opts_opening = token_without_symbols.indexOf(options_open, index_of_token_end_of_closing);
                      var index_of_opts_end_of_closing = token_without_symbols.indexOf(options_close, index_of_opts_opening) + options_close.length;
                      try {
                          opts = f.extend(opts, JSON.parse(token_without_symbols.substring(index_of_opts_opening, index_of_opts_end_of_closing)));
                          token_without_symbols = token_without_symbols.substring(0, index_of_token_end_of_closing);
                      } catch (e) {
                      }
                  }
              }
      
              var translated_token = _translate(token_without_symbols, opts);
              translated = translated.replace(token, f.regexReplacementEscape(translated_token));
          }
          return translated;
      }
      
      function hasContext(options) {
          return (options.context && (typeof options.context == 'string' || typeof options.context == 'number'));
      }
      
      function needsPlural(options, lng) {
          return (options.count !== undefined && typeof options.count != 'string'/* && pluralExtensions.needsPlural(lng, options.count)*/);
      }
      
      function needsIndefiniteArticle(options) {
          return (options.indefinite_article !== undefined && typeof options.indefinite_article != 'string' && options.indefinite_article);
      }
      
      function exists(key, options) {
          options = options || {};
      
          var notFound = _getDefaultValue(key, options)
              , found = _find(key, options);
      
          return found !== undefined || found === notFound;
      }
      
      function translate(key, options) {
          options = options || {};
      
          if (!initialized) {
              f.log('i18next not finished initialization. you might have called t function before loading resources finished.')
              return options.defaultValue || '';
          };
          replacementCounter = 0;
          return _translate.apply(null, arguments);
      }
      
      function _getDefaultValue(key, options) {
          return (options.defaultValue !== undefined) ? options.defaultValue : key;
      }
      
      function _injectSprintfProcessor() {
      
          var values = [];
      
          // mh: build array from second argument onwards
          for (var i = 1; i < arguments.length; i++) {
              values.push(arguments[i]);
          }
      
          return {
              postProcess: 'sprintf',
              sprintf:     values
          };
      }
      
      function _translate(potentialKeys, options) {
          if (options && typeof options !== 'object') {
              if (o.shortcutFunction === 'sprintf') {
                  // mh: gettext like sprintf syntax found, automatically create sprintf processor
                  options = _injectSprintfProcessor.apply(null, arguments);
              } else if (o.shortcutFunction === 'defaultValue') {
                  options = {
                      defaultValue: options
                  }
              }
          } else {
              options = options || {};
          }
      
          if (typeof o.defaultVariables === 'object') {
              options = f.extend({}, o.defaultVariables, options);
          }
      
          if (potentialKeys === undefined || potentialKeys === null || potentialKeys === '') return '';
      
          if (typeof potentialKeys === 'number') {
              potentialKeys = String(potentialKeys);
          }
      
          if (typeof potentialKeys === 'string') {
              potentialKeys = [potentialKeys];
          }
      
          var key = potentialKeys[0];
      
          if (potentialKeys.length > 1) {
              for (var i = 0; i < potentialKeys.length; i++) {
                  key = potentialKeys[i];
                  if (exists(key, options)) {
                      break;
                  }
              }
          }
      
          var notFound = _getDefaultValue(key, options)
              , found = _find(key, options)
              , lngs = options.lng ? f.toLanguages(options.lng, options.fallbackLng) : languages
              , ns = options.ns || o.ns.defaultNs
              , parts;
      
          // split ns and key
          if (key.indexOf(o.nsseparator) > -1) {
              parts = key.split(o.nsseparator);
              ns = parts[0];
              key = parts[1];
          }
      
          if (found === undefined && o.sendMissing && typeof o.missingKeyHandler === 'function') {
              if (options.lng) {
                  o.missingKeyHandler(lngs[0], ns, key, notFound, lngs);
              } else {
                  o.missingKeyHandler(o.lng, ns, key, notFound, lngs);
              }
          }
      
          var postProcessorsToApply;
          if (typeof o.postProcess === 'string' && o.postProcess !== '') {
              postProcessorsToApply = [o.postProcess];
          } else if (typeof o.postProcess === 'array' || typeof o.postProcess === 'object') {
              postProcessorsToApply = o.postProcess;
          } else {
              postProcessorsToApply = [];
          }
      
          if (typeof options.postProcess === 'string' && options.postProcess !== '') {
              postProcessorsToApply = postProcessorsToApply.concat([options.postProcess]);
          } else if (typeof options.postProcess === 'array' || typeof options.postProcess === 'object') {
              postProcessorsToApply = postProcessorsToApply.concat(options.postProcess);
          }
      
          if (found !== undefined && postProcessorsToApply.length) {
              postProcessorsToApply.forEach(function(postProcessor) {
                  if (postProcessors[postProcessor]) {
                      found = postProcessors[postProcessor](found, key, options);
                  }
              });
          }
      
          // process notFound if function exists
          var splitNotFound = notFound;
          if (notFound.indexOf(o.nsseparator) > -1) {
              parts = notFound.split(o.nsseparator);
              splitNotFound = parts[1];
          }
          if (splitNotFound === key && o.parseMissingKey) {
              notFound = o.parseMissingKey(notFound);
          }
      
          if (found === undefined) {
              notFound = applyReplacement(notFound, options);
              notFound = applyReuse(notFound, options);
      
              if (postProcessorsToApply.length) {
                  var val = _getDefaultValue(key, options);
                  postProcessorsToApply.forEach(function(postProcessor) {
                      if (postProcessors[postProcessor]) {
                          found = postProcessors[postProcessor](val, key, options);
                      }
                  });
              }
          }
      
          return (found !== undefined) ? found : notFound;
      }
      
      function _find(key, options) {
          options = options || {};
      
          var optionWithoutCount, translated
              , notFound = _getDefaultValue(key, options)
              , lngs = languages;
      
          if (!resStore) { return notFound; } // no resStore to translate from
      
          // CI mode
          if (lngs[0].toLowerCase() === 'cimode') return notFound;
      
          // passed in lng
          if (options.lngs) lngs = options.lngs;
          if (options.lng) {
              lngs = f.toLanguages(options.lng, options.fallbackLng);
      
              if (!resStore[lngs[0]]) {
                  var oldAsync = o.getAsync;
                  o.getAsync = false;
      
                  i18n.sync.load(lngs, o, function(err, store) {
                      f.extend(resStore, store);
                      o.getAsync = oldAsync;
                  });
              }
          }
      
          var ns = options.ns || o.ns.defaultNs;
          if (key.indexOf(o.nsseparator) > -1) {
              var parts = key.split(o.nsseparator);
              ns = parts[0];
              key = parts[1];
          }
      
          if (hasContext(options)) {
              optionWithoutCount = f.extend({}, options);
              delete optionWithoutCount.context;
              optionWithoutCount.defaultValue = o.contextNotFound;
      
              var contextKey = ns + o.nsseparator + key + '_' + options.context;
      
              translated = translate(contextKey, optionWithoutCount);
              if (translated != o.contextNotFound) {
                  return applyReplacement(translated, { context: options.context }); // apply replacement for context only
              } // else continue translation with original/nonContext key
          }
      
          if (needsPlural(options, lngs[0])) {
              optionWithoutCount = f.extend({ lngs: [lngs[0]]}, options);
              delete optionWithoutCount.count;
              optionWithoutCount._origLng = optionWithoutCount._origLng || optionWithoutCount.lng || lngs[0];
              delete optionWithoutCount.lng;
              optionWithoutCount.defaultValue = o.pluralNotFound;
      
              var pluralKey;
              if (!pluralExtensions.needsPlural(lngs[0], options.count)) {
                  pluralKey = ns + o.nsseparator + key;
              } else {
                  pluralKey = ns + o.nsseparator + key + o.pluralSuffix;
                  var pluralExtension = pluralExtensions.get(lngs[0], options.count);
                  if (pluralExtension >= 0) {
                      pluralKey = pluralKey + '_' + pluralExtension;
                  } else if (pluralExtension === 1) {
                      pluralKey = ns + o.nsseparator + key; // singular
                  }
              }
      
              translated = translate(pluralKey, optionWithoutCount);
      
              if (translated != o.pluralNotFound) {
                  return applyReplacement(translated, {
                      count: options.count,
                      interpolationPrefix: options.interpolationPrefix,
                      interpolationSuffix: options.interpolationSuffix
                  }); // apply replacement for count only
              } else if (lngs.length > 1) {
                  // remove failed lng
                  var clone = lngs.slice();
                  clone.shift();
                  options = f.extend(options, { lngs: clone });
                  options._origLng = optionWithoutCount._origLng;
                  delete options.lng;
                  // retry with fallbacks
                  translated = translate(ns + o.nsseparator + key, options);
                  if (translated != o.pluralNotFound) return translated;
              } else {
                  optionWithoutCount.lng = optionWithoutCount._origLng;
                  delete optionWithoutCount._origLng;
                  translated = translate(ns + o.nsseparator + key, optionWithoutCount);
      
                  return applyReplacement(translated, {
                      count: options.count,
                      interpolationPrefix: options.interpolationPrefix,
                      interpolationSuffix: options.interpolationSuffix
                  });
              }
          }
      
          if (needsIndefiniteArticle(options)) {
              var optionsWithoutIndef = f.extend({}, options);
              delete optionsWithoutIndef.indefinite_article;
              optionsWithoutIndef.defaultValue = o.indefiniteNotFound;
              // If we don't have a count, we want the indefinite, if we do have a count, and needsPlural is false
              var indefiniteKey = ns + o.nsseparator + key + (((options.count && !needsPlural(options, lngs[0])) || !options.count) ? o.indefiniteSuffix : "");
              translated = translate(indefiniteKey, optionsWithoutIndef);
              if (translated != o.indefiniteNotFound) {
                  return translated;
              }
          }
      
          var found;
          var keys = key.split(o.keyseparator);
          for (var i = 0, len = lngs.length; i < len; i++ ) {
              if (found !== undefined) break;
      
              var l = lngs[i];
      
              var x = 0;
              var value = resStore[l] && resStore[l][ns];
              while (keys[x]) {
                  value = value && value[keys[x]];
                  x++;
              }
              if (value !== undefined && (!o.showKeyIfEmpty || value !== '')) {
                  var valueType = Object.prototype.toString.apply(value);
                  if (typeof value === 'string') {
                      value = applyReplacement(value, options);
                      value = applyReuse(value, options);
                  } else if (valueType === '[object Array]' && !o.returnObjectTrees && !options.returnObjectTrees) {
                      value = value.join('\n');
                      value = applyReplacement(value, options);
                      value = applyReuse(value, options);
                  } else if (value === null && o.fallbackOnNull === true) {
                      value = undefined;
                  } else if (value !== null) {
                      if (!o.returnObjectTrees && !options.returnObjectTrees) {
                          if (o.objectTreeKeyHandler && typeof o.objectTreeKeyHandler == 'function') {
                              value = o.objectTreeKeyHandler(key, value, l, ns, options);
                          } else {
                              value = 'key \'' + ns + ':' + key + ' (' + l + ')\' ' +
                                  'returned an object instead of string.';
                              f.log(value);
                          }
                      } else if (valueType !== '[object Number]' && valueType !== '[object Function]' && valueType !== '[object RegExp]') {
                          var copy = (valueType === '[object Array]') ? [] : {}; // apply child translation on a copy
                          f.each(value, function(m) {
                              copy[m] = _translate(ns + o.nsseparator + key + o.keyseparator + m, options);
                          });
                          value = copy;
                      }
                  }
      
                  if (typeof value === 'string' && value.trim() === '' && o.fallbackOnEmpty === true)
                      value = undefined;
      
                  found = value;
              }
          }
      
          if (found === undefined && !options.isFallbackLookup && (o.fallbackToDefaultNS === true || (o.fallbackNS && o.fallbackNS.length > 0))) {
              // set flag for fallback lookup - avoid recursion
              options.isFallbackLookup = true;
      
              if (o.fallbackNS.length) {
      
                  for (var y = 0, lenY = o.fallbackNS.length; y < lenY; y++) {
                      found = _find(o.fallbackNS[y] + o.nsseparator + key, options);
      
                      if (found || (found==="" && o.fallbackOnEmpty === false)) {
                          /* compare value without namespace */
                          var foundValue = found.indexOf(o.nsseparator) > -1 ? found.split(o.nsseparator)[1] : found
                            , notFoundValue = notFound.indexOf(o.nsseparator) > -1 ? notFound.split(o.nsseparator)[1] : notFound;
      
                          if (foundValue !== notFoundValue) break;
                      }
                  }
              } else {
                  options.ns = o.ns.defaultNs;
                  found = _find(key, options); // fallback to default NS
              }
              options.isFallbackLookup = false;
          }
      
          return found;
      }
      function detectLanguage() {
          var detectedLng;
          var whitelist = o.lngWhitelist || [];
          var userLngChoices = [];
      
          // get from qs
          var qsParm = [];
          if (typeof window !== 'undefined') {
              (function() {
                  var query = window.location.search.substring(1);
                  var params = query.split('&');
                  for (var i=0; i<params.length; i++) {
                      var pos = params[i].indexOf('=');
                      if (pos > 0) {
                          var key = params[i].substring(0,pos);
                          if (key == o.detectLngQS) {
                              userLngChoices.push(params[i].substring(pos+1));
                          }
                      }
                  }
              })();
          }
      
          // get from cookie
          if (o.useCookie && typeof document !== 'undefined') {
              var c = f.cookie.read(o.cookieName);
              if (c) userLngChoices.push(c);
          }
      
          // get from localStorage
          if (o.detectLngFromLocalStorage && typeof window !== 'undefined' && window.localStorage) {
              var lang = f.localStorage.getItem('i18next_lng');
              if (lang) {
                  userLngChoices.push(lang);
              }
          }
      
          // get from navigator
          if (typeof navigator !== 'undefined') {
              if (navigator.languages) { // chrome only; not an array, so can't use .push.apply instead of iterating
                  for (var i=0;i<navigator.languages.length;i++) {
                      userLngChoices.push(navigator.languages[i]);
                  }
              }
              if (navigator.userLanguage) {
                  userLngChoices.push(navigator.userLanguage);
              }
              if (navigator.language) {
                  userLngChoices.push(navigator.language);
              }
          }
      
          (function() {
              for (var i=0;i<userLngChoices.length;i++) {
                  var lng = userLngChoices[i];
      
                  if (lng.indexOf('-') > -1) {
                      var parts = lng.split('-');
                      lng = o.lowerCaseLng ?
                          parts[0].toLowerCase() +  '-' + parts[1].toLowerCase() :
                          parts[0].toLowerCase() +  '-' + parts[1].toUpperCase();
                  }
      
                  if (whitelist.length === 0 || whitelist.indexOf(lng) > -1) {
                      detectedLng = lng;
                      break;
                  }
              }
          })();
      
          //fallback
          if (!detectedLng){
            detectedLng = o.fallbackLng[0];
          }
          
          return detectedLng;
      }
      // definition http://translate.sourceforge.net/wiki/l10n/pluralforms
      
      /* [code, name, numbers, pluralsType] */
      var _rules = [
          ["ach", "Acholi", [1,2], 1],
          ["af", "Afrikaans",[1,2], 2],
          ["ak", "Akan", [1,2], 1],
          ["am", "Amharic", [1,2], 1],
          ["an", "Aragonese",[1,2], 2],
          ["ar", "Arabic", [0,1,2,3,11,100],5],
          ["arn", "Mapudungun",[1,2], 1],
          ["ast", "Asturian", [1,2], 2],
          ["ay", "Aymará", [1], 3],
          ["az", "Azerbaijani",[1,2],2],
          ["be", "Belarusian",[1,2,5],4],
          ["bg", "Bulgarian",[1,2], 2],
          ["bn", "Bengali", [1,2], 2],
          ["bo", "Tibetan", [1], 3],
          ["br", "Breton", [1,2], 1],
          ["bs", "Bosnian", [1,2,5],4],
          ["ca", "Catalan", [1,2], 2],
          ["cgg", "Chiga", [1], 3],
          ["cs", "Czech", [1,2,5],6],
          ["csb", "Kashubian",[1,2,5],7],
          ["cy", "Welsh", [1,2,3,8],8],
          ["da", "Danish", [1,2], 2],
          ["de", "German", [1,2], 2],
          ["dev", "Development Fallback", [1,2], 2],
          ["dz", "Dzongkha", [1], 3],
          ["el", "Greek", [1,2], 2],
          ["en", "English", [1,2], 2],
          ["eo", "Esperanto",[1,2], 2],
          ["es", "Spanish", [1,2], 2],
          ["es_ar","Argentinean Spanish", [1,2], 2],
          ["et", "Estonian", [1,2], 2],
          ["eu", "Basque", [1,2], 2],
          ["fa", "Persian", [1], 3],
          ["fi", "Finnish", [1,2], 2],
          ["fil", "Filipino", [1,2], 1],
          ["fo", "Faroese", [1,2], 2],
          ["fr", "French", [1,2], 9],
          ["fur", "Friulian", [1,2], 2],
          ["fy", "Frisian", [1,2], 2],
          ["ga", "Irish", [1,2,3,7,11],10],
          ["gd", "Scottish Gaelic",[1,2,3,20],11],
          ["gl", "Galician", [1,2], 2],
          ["gu", "Gujarati", [1,2], 2],
          ["gun", "Gun", [1,2], 1],
          ["ha", "Hausa", [1,2], 2],
          ["he", "Hebrew", [1,2], 2],
          ["hi", "Hindi", [1,2], 2],
          ["hr", "Croatian", [1,2,5],4],
          ["hu", "Hungarian",[1,2], 2],
          ["hy", "Armenian", [1,2], 2],
          ["ia", "Interlingua",[1,2],2],
          ["id", "Indonesian",[1], 3],
          ["is", "Icelandic",[1,2], 12],
          ["it", "Italian", [1,2], 2],
          ["ja", "Japanese", [1], 3],
          ["jbo", "Lojban", [1], 3],
          ["jv", "Javanese", [0,1], 13],
          ["ka", "Georgian", [1], 3],
          ["kk", "Kazakh", [1], 3],
          ["km", "Khmer", [1], 3],
          ["kn", "Kannada", [1,2], 2],
          ["ko", "Korean", [1], 3],
          ["ku", "Kurdish", [1,2], 2],
          ["kw", "Cornish", [1,2,3,4],14],
          ["ky", "Kyrgyz", [1], 3],
          ["lb", "Letzeburgesch",[1,2],2],
          ["ln", "Lingala", [1,2], 1],
          ["lo", "Lao", [1], 3],
          ["lt", "Lithuanian",[1,2,10],15],
          ["lv", "Latvian", [1,2,0],16],
          ["mai", "Maithili", [1,2], 2],
          ["mfe", "Mauritian Creole",[1,2],1],
          ["mg", "Malagasy", [1,2], 1],
          ["mi", "Maori", [1,2], 1],
          ["mk", "Macedonian",[1,2],17],
          ["ml", "Malayalam",[1,2], 2],
          ["mn", "Mongolian",[1,2], 2],
          ["mnk", "Mandinka", [0,1,2],18],
          ["mr", "Marathi", [1,2], 2],
          ["ms", "Malay", [1], 3],
          ["mt", "Maltese", [1,2,11,20],19],
          ["nah", "Nahuatl", [1,2], 2],
          ["nap", "Neapolitan",[1,2], 2],
          ["nb", "Norwegian Bokmal",[1,2],2],
          ["ne", "Nepali", [1,2], 2],
          ["nl", "Dutch", [1,2], 2],
          ["nn", "Norwegian Nynorsk",[1,2],2],
          ["no", "Norwegian",[1,2], 2],
          ["nso", "Northern Sotho",[1,2],2],
          ["oc", "Occitan", [1,2], 1],
          ["or", "Oriya", [2,1], 2],
          ["pa", "Punjabi", [1,2], 2],
          ["pap", "Papiamento",[1,2], 2],
          ["pl", "Polish", [1,2,5],7],
          ["pms", "Piemontese",[1,2], 2],
          ["ps", "Pashto", [1,2], 2],
          ["pt", "Portuguese",[1,2], 2],
          ["pt_br","Brazilian Portuguese",[1,2], 2],
          ["rm", "Romansh", [1,2], 2],
          ["ro", "Romanian", [1,2,20],20],
          ["ru", "Russian", [1,2,5],4],
          ["sah", "Yakut", [1], 3],
          ["sco", "Scots", [1,2], 2],
          ["se", "Northern Sami",[1,2], 2],
          ["si", "Sinhala", [1,2], 2],
          ["sk", "Slovak", [1,2,5],6],
          ["sl", "Slovenian",[5,1,2,3],21],
          ["so", "Somali", [1,2], 2],
          ["son", "Songhay", [1,2], 2],
          ["sq", "Albanian", [1,2], 2],
          ["sr", "Serbian", [1,2,5],4],
          ["su", "Sundanese",[1], 3],
          ["sv", "Swedish", [1,2], 2],
          ["sw", "Swahili", [1,2], 2],
          ["ta", "Tamil", [1,2], 2],
          ["te", "Telugu", [1,2], 2],
          ["tg", "Tajik", [1,2], 1],
          ["th", "Thai", [1], 3],
          ["ti", "Tigrinya", [1,2], 1],
          ["tk", "Turkmen", [1,2], 2],
          ["tr", "Turkish", [1,2], 1],
          ["tt", "Tatar", [1], 3],
          ["ug", "Uyghur", [1], 3],
          ["uk", "Ukrainian",[1,2,5],4],
          ["ur", "Urdu", [1,2], 2],
          ["uz", "Uzbek", [1,2], 1],
          ["vi", "Vietnamese",[1], 3],
          ["wa", "Walloon", [1,2], 1],
          ["wo", "Wolof", [1], 3],
          ["yo", "Yoruba", [1,2], 2],
          ["zh", "Chinese", [1], 3]
      ];
      
      var _rulesPluralsTypes = {
          1: function(n) {return Number(n > 1);},
          2: function(n) {return Number(n != 1);},
          3: function(n) {return 0;},
          4: function(n) {return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);},
          5: function(n) {return Number(n===0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5);},
          6: function(n) {return Number((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2);},
          7: function(n) {return Number(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);},
          8: function(n) {return Number((n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3);},
          9: function(n) {return Number(n >= 2);},
          10: function(n) {return Number(n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4) ;},
          11: function(n) {return Number((n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : (n > 2 && n < 20) ? 2 : 3);},
          12: function(n) {return Number(n%10!=1 || n%100==11);},
          13: function(n) {return Number(n !== 0);},
          14: function(n) {return Number((n==1) ? 0 : (n==2) ? 1 : (n == 3) ? 2 : 3);},
          15: function(n) {return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);},
          16: function(n) {return Number(n%10==1 && n%100!=11 ? 0 : n !== 0 ? 1 : 2);},
          17: function(n) {return Number(n==1 || n%10==1 ? 0 : 1);},
          18: function(n) {return Number(0 ? 0 : n==1 ? 1 : 2);},
          19: function(n) {return Number(n==1 ? 0 : n===0 || ( n%100>1 && n%100<11) ? 1 : (n%100>10 && n%100<20 ) ? 2 : 3);},
          20: function(n) {return Number(n==1 ? 0 : (n===0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2);},
          21: function(n) {return Number(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? 3 : 0); }
      };
      
      var pluralExtensions = {
      
          rules: (function () {
              var l, rules = {};
              for (l=_rules.length; l-- ;) {
                  rules[_rules[l][0]] = {
                      name: _rules[l][1],
                      numbers: _rules[l][2],
                      plurals: _rulesPluralsTypes[_rules[l][3]]
                  }
              }
              return rules;
          }()),
      
          // you can add your own pluralExtensions
          addRule: function(lng, obj) {
              pluralExtensions.rules[lng] = obj;
          },
      
          setCurrentLng: function(lng) {
              if (!pluralExtensions.currentRule || pluralExtensions.currentRule.lng !== lng) {
                  var parts = lng.split('-');
      
                  pluralExtensions.currentRule = {
                      lng: lng,
                      rule: pluralExtensions.rules[parts[0]]
                  };
              }
          },
      
          needsPlural: function(lng, count) {
              var parts = lng.split('-');
      
              var ext;
              if (pluralExtensions.currentRule && pluralExtensions.currentRule.lng === lng) {
                  ext = pluralExtensions.currentRule.rule; 
              } else {
                  ext = pluralExtensions.rules[parts[f.getCountyIndexOfLng(lng)]];
              }
      
              if (ext && ext.numbers.length <= 1) {
                  return false;
              } else {
                  return this.get(lng, count) !== 1;
              }
          },
      
          get: function(lng, count) {
              var parts = lng.split('-');
      
              function getResult(l, c) {
                  var ext;
                  if (pluralExtensions.currentRule && pluralExtensions.currentRule.lng === lng) {
                      ext = pluralExtensions.currentRule.rule; 
                  } else {
                      ext = pluralExtensions.rules[l];
                  }
                  if (ext) {
                      var i;
                      if (ext.noAbs) {
                          i = ext.plurals(c);
                      } else {
                          i = ext.plurals(Math.abs(c));
                      }
                      
                      var number = ext.numbers[i];
                      if (ext.numbers.length === 2 && ext.numbers[0] === 1) {
                          if (number === 2) { 
                              number = -1; // regular plural
                          } else if (number === 1) {
                              number = 1; // singular
                          }
                      }//console.log(count + '-' + number);
                      return number;
                  } else {
                      return c === 1 ? '1' : '-1';
                  }
              }
                          
              return getResult(parts[f.getCountyIndexOfLng(lng)], count);
          }
      
      };
      var postProcessors = {};
      var addPostProcessor = function(name, fc) {
          postProcessors[name] = fc;
      };
      // sprintf support
      var sprintf = (function() {
          function get_type(variable) {
              return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
          }
          function str_repeat(input, multiplier) {
              for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}
              return output.join('');
          }
      
          var str_format = function() {
              if (!str_format.cache.hasOwnProperty(arguments[0])) {
                  str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
              }
              return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
          };
      
          str_format.format = function(parse_tree, argv) {
              var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
              for (i = 0; i < tree_length; i++) {
                  node_type = get_type(parse_tree[i]);
                  if (node_type === 'string') {
                      output.push(parse_tree[i]);
                  }
                  else if (node_type === 'array') {
                      match = parse_tree[i]; // convenience purposes only
                      if (match[2]) { // keyword argument
                          arg = argv[cursor];
                          for (k = 0; k < match[2].length; k++) {
                              if (!arg.hasOwnProperty(match[2][k])) {
                                  throw(sprintf('[sprintf] property "%s" does not exist', match[2][k]));
                              }
                              arg = arg[match[2][k]];
                          }
                      }
                      else if (match[1]) { // positional argument (explicit)
                          arg = argv[match[1]];
                      }
                      else { // positional argument (implicit)
                          arg = argv[cursor++];
                      }
      
                      if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
                          throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));
                      }
                      switch (match[8]) {
                          case 'b': arg = arg.toString(2); break;
                          case 'c': arg = String.fromCharCode(arg); break;
                          case 'd': arg = parseInt(arg, 10); break;
                          case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
                          case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
                          case 'o': arg = arg.toString(8); break;
                          case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
                          case 'u': arg = Math.abs(arg); break;
                          case 'x': arg = arg.toString(16); break;
                          case 'X': arg = arg.toString(16).toUpperCase(); break;
                      }
                      arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
                      pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
                      pad_length = match[6] - String(arg).length;
                      pad = match[6] ? str_repeat(pad_character, pad_length) : '';
                      output.push(match[5] ? arg + pad : pad + arg);
                  }
              }
              return output.join('');
          };
      
          str_format.cache = {};
      
          str_format.parse = function(fmt) {
              var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
              while (_fmt) {
                  if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
                      parse_tree.push(match[0]);
                  }
                  else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
                      parse_tree.push('%');
                  }
                  else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
                      if (match[2]) {
                          arg_names |= 1;
                          var field_list = [], replacement_field = match[2], field_match = [];
                          if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
                              field_list.push(field_match[1]);
                              while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
                                  if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
                                      field_list.push(field_match[1]);
                                  }
                                  else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
                                      field_list.push(field_match[1]);
                                  }
                                  else {
                                      throw('[sprintf] huh?');
                                  }
                              }
                          }
                          else {
                              throw('[sprintf] huh?');
                          }
                          match[2] = field_list;
                      }
                      else {
                          arg_names |= 2;
                      }
                      if (arg_names === 3) {
                          throw('[sprintf] mixing positional and named placeholders is not (yet) supported');
                      }
                      parse_tree.push(match);
                  }
                  else {
                      throw('[sprintf] huh?');
                  }
                  _fmt = _fmt.substring(match[0].length);
              }
              return parse_tree;
          };
      
          return str_format;
      })();
      
      var vsprintf = function(fmt, argv) {
          argv.unshift(fmt);
          return sprintf.apply(null, argv);
      };
      
      addPostProcessor("sprintf", function(val, key, opts) {
          if (!opts.sprintf) return val;
      
          if (Object.prototype.toString.apply(opts.sprintf) === '[object Array]') {
              return vsprintf(val, opts.sprintf);
          } else if (typeof opts.sprintf === 'object') {
              return sprintf(val, opts.sprintf);
          }
      
          return val;
      });
      // public api interface
      i18n.init = init;
      i18n.isInitialized = isInitialized;
      i18n.setLng = setLng;
      i18n.preload = preload;
      i18n.addResourceBundle = addResourceBundle;
      i18n.hasResourceBundle = hasResourceBundle;
      i18n.getResourceBundle = getResourceBundle;
      i18n.addResource = addResource;
      i18n.addResources = addResources;
      i18n.removeResourceBundle = removeResourceBundle;
      i18n.loadNamespace = loadNamespace;
      i18n.loadNamespaces = loadNamespaces;
      i18n.setDefaultNamespace = setDefaultNamespace;
      i18n.t = translate;
      i18n.translate = translate;
      i18n.exists = exists;
      i18n.detectLanguage = f.detectLanguage;
      i18n.pluralExtensions = pluralExtensions;
      i18n.sync = sync;
      i18n.functions = f;
      i18n.lng = lng;
      i18n.addPostProcessor = addPostProcessor;
      i18n.applyReplacement = f.applyReplacement;
      i18n.options = o;
      i18n.noConflict = noConflict;
  
  })(typeof exports === 'undefined' ? window : exports);