express_translate 1.0.7 → 1.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2734 @@
1
+ // i18next, v1.7.3
2
+ // Copyright (c)2014 Jan Mühlemann (jamuhl).
3
+ // Distributed under MIT license
4
+ // http://i18next.com
5
+
6
+ (function() {
7
+
8
+ // add indexOf to non ECMA-262 standard compliant browsers
9
+ if (!Array.prototype.indexOf) {
10
+ Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
11
+ "use strict";
12
+ if (this == null) {
13
+ throw new TypeError();
14
+ }
15
+ var t = Object(this);
16
+ var len = t.length >>> 0;
17
+ if (len === 0) {
18
+ return -1;
19
+ }
20
+ var n = 0;
21
+ if (arguments.length > 0) {
22
+ n = Number(arguments[1]);
23
+ if (n != n) { // shortcut for verifying if it's NaN
24
+ n = 0;
25
+ } else if (n != 0 && n != Infinity && n != -Infinity) {
26
+ n = (n > 0 || -1) * Math.floor(Math.abs(n));
27
+ }
28
+ }
29
+ if (n >= len) {
30
+ return -1;
31
+ }
32
+ var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
33
+ for (; k < len; k++) {
34
+ if (k in t && t[k] === searchElement) {
35
+ return k;
36
+ }
37
+ }
38
+ return -1;
39
+ }
40
+ }
41
+
42
+ // add lastIndexOf to non ECMA-262 standard compliant browsers
43
+ if (!Array.prototype.lastIndexOf) {
44
+ Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/) {
45
+ "use strict";
46
+ if (this == null) {
47
+ throw new TypeError();
48
+ }
49
+ var t = Object(this);
50
+ var len = t.length >>> 0;
51
+ if (len === 0) {
52
+ return -1;
53
+ }
54
+ var n = len;
55
+ if (arguments.length > 1) {
56
+ n = Number(arguments[1]);
57
+ if (n != n) {
58
+ n = 0;
59
+ } else if (n != 0 && n != (1 / 0) && n != -(1 / 0)) {
60
+ n = (n > 0 || -1) * Math.floor(Math.abs(n));
61
+ }
62
+ }
63
+ var k = n >= 0 ? Math.min(n, len - 1) : len - Math.abs(n);
64
+ for (; k >= 0; k--) {
65
+ if (k in t && t[k] === searchElement) {
66
+ return k;
67
+ }
68
+ }
69
+ return -1;
70
+ };
71
+ }
72
+
73
+ // Add string trim for IE8.
74
+ if (typeof String.prototype.trim !== 'function') {
75
+ String.prototype.trim = function() {
76
+ return this.replace(/^\s+|\s+$/g, '');
77
+ }
78
+ }
79
+
80
+ var root = this
81
+ , $ = root.jQuery || root.Zepto
82
+ , i18n = {}
83
+ , resStore = {}
84
+ , currentLng
85
+ , replacementCounter = 0
86
+ , languages = []
87
+ , initialized = false;
88
+
89
+
90
+ // Export the i18next object for **CommonJS**.
91
+ // If we're not in CommonJS, add `i18n` to the
92
+ // global object or to jquery.
93
+ if (typeof module !== 'undefined' && module.exports) {
94
+ module.exports = i18n;
95
+ } else {
96
+ if ($) {
97
+ $.i18n = $.i18n || i18n;
98
+ }
99
+
100
+ root.i18n = root.i18n || i18n;
101
+ }
102
+ // defaults
103
+ var o = {
104
+ lng: undefined,
105
+ load: 'all',
106
+ preload: [],
107
+ lowerCaseLng: false,
108
+ returnObjectTrees: false,
109
+ fallbackLng: ['dev'],
110
+ fallbackNS: [],
111
+ detectLngQS: 'setLng',
112
+ ns: 'translation',
113
+ fallbackOnNull: true,
114
+ fallbackOnEmpty: false,
115
+ fallbackToDefaultNS: false,
116
+ nsseparator: ':',
117
+ keyseparator: '.',
118
+ selectorAttr: 'data-i18n',
119
+ debug: false,
120
+
121
+ resGetPath: 'locales/__lng__/__ns__.json',
122
+ resPostPath: 'locales/add/__lng__/__ns__',
123
+
124
+ getAsync: true,
125
+ postAsync: true,
126
+
127
+ resStore: undefined,
128
+ useLocalStorage: false,
129
+ localStorageExpirationTime: 7*24*60*60*1000,
130
+
131
+ dynamicLoad: false,
132
+ sendMissing: false,
133
+ sendMissingTo: 'fallback', // current | all
134
+ sendType: 'POST',
135
+
136
+ interpolationPrefix: '__',
137
+ interpolationSuffix: '__',
138
+ reusePrefix: '$t(',
139
+ reuseSuffix: ')',
140
+ pluralSuffix: '_plural',
141
+ pluralNotFound: ['plural_not_found', Math.random()].join(''),
142
+ contextNotFound: ['context_not_found', Math.random()].join(''),
143
+ escapeInterpolation: false,
144
+
145
+ setJqueryExt: true,
146
+ defaultValueFromContent: true,
147
+ useDataAttrOptions: false,
148
+ cookieExpirationTime: undefined,
149
+ useCookie: true,
150
+ cookieName: 'i18next',
151
+ cookieDomain: undefined,
152
+
153
+ objectTreeKeyHandler: undefined,
154
+ postProcess: undefined,
155
+ parseMissingKey: undefined,
156
+
157
+ shortcutFunction: 'sprintf' // or: defaultValue
158
+ };
159
+ function _extend(target, source) {
160
+ if (!source || typeof source === 'function') {
161
+ return target;
162
+ }
163
+
164
+ for (var attr in source) { target[attr] = source[attr]; }
165
+ return target;
166
+ }
167
+
168
+ function _each(object, callback, args) {
169
+ var name, i = 0,
170
+ length = object.length,
171
+ isObj = length === undefined || Object.prototype.toString.apply(object) !== '[object Array]' || typeof object === "function";
172
+
173
+ if (args) {
174
+ if (isObj) {
175
+ for (name in object) {
176
+ if (callback.apply(object[name], args) === false) {
177
+ break;
178
+ }
179
+ }
180
+ } else {
181
+ for ( ; i < length; ) {
182
+ if (callback.apply(object[i++], args) === false) {
183
+ break;
184
+ }
185
+ }
186
+ }
187
+
188
+ // A special, fast, case for the most common use of each
189
+ } else {
190
+ if (isObj) {
191
+ for (name in object) {
192
+ if (callback.call(object[name], name, object[name]) === false) {
193
+ break;
194
+ }
195
+ }
196
+ } else {
197
+ for ( ; i < length; ) {
198
+ if (callback.call(object[i], i, object[i++]) === false) {
199
+ break;
200
+ }
201
+ }
202
+ }
203
+ }
204
+
205
+ return object;
206
+ }
207
+
208
+ var _entityMap = {
209
+ "&": "&amp;",
210
+ "<": "&lt;",
211
+ ">": "&gt;",
212
+ '"': '&quot;',
213
+ "'": '&#39;',
214
+ "/": '&#x2F;'
215
+ };
216
+
217
+ function _escape(data) {
218
+ if (typeof data === 'string') {
219
+ return data.replace(/[&<>"'\/]/g, function (s) {
220
+ return _entityMap[s];
221
+ });
222
+ }else{
223
+ return data;
224
+ }
225
+ }
226
+
227
+ function _ajax(options) {
228
+
229
+ // v0.5.0 of https://github.com/goloroden/http.js
230
+ var getXhr = function (callback) {
231
+ // Use the native XHR object if the browser supports it.
232
+ if (window.XMLHttpRequest) {
233
+ return callback(null, new XMLHttpRequest());
234
+ } else if (window.ActiveXObject) {
235
+ // In Internet Explorer check for ActiveX versions of the XHR object.
236
+ try {
237
+ return callback(null, new ActiveXObject("Msxml2.XMLHTTP"));
238
+ } catch (e) {
239
+ return callback(null, new ActiveXObject("Microsoft.XMLHTTP"));
240
+ }
241
+ }
242
+
243
+ // If no XHR support was found, throw an error.
244
+ return callback(new Error());
245
+ };
246
+
247
+ var encodeUsingUrlEncoding = function (data) {
248
+ if(typeof data === 'string') {
249
+ return data;
250
+ }
251
+
252
+ var result = [];
253
+ for(var dataItem in data) {
254
+ if(data.hasOwnProperty(dataItem)) {
255
+ result.push(encodeURIComponent(dataItem) + '=' + encodeURIComponent(data[dataItem]));
256
+ }
257
+ }
258
+
259
+ return result.join('&');
260
+ };
261
+
262
+ var utf8 = function (text) {
263
+ text = text.replace(/\r\n/g, '\n');
264
+ var result = '';
265
+
266
+ for(var i = 0; i < text.length; i++) {
267
+ var c = text.charCodeAt(i);
268
+
269
+ if(c < 128) {
270
+ result += String.fromCharCode(c);
271
+ } else if((c > 127) && (c < 2048)) {
272
+ result += String.fromCharCode((c >> 6) | 192);
273
+ result += String.fromCharCode((c & 63) | 128);
274
+ } else {
275
+ result += String.fromCharCode((c >> 12) | 224);
276
+ result += String.fromCharCode(((c >> 6) & 63) | 128);
277
+ result += String.fromCharCode((c & 63) | 128);
278
+ }
279
+ }
280
+
281
+ return result;
282
+ };
283
+
284
+ var base64 = function (text) {
285
+ var keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
286
+
287
+ text = utf8(text);
288
+ var result = '',
289
+ chr1, chr2, chr3,
290
+ enc1, enc2, enc3, enc4,
291
+ i = 0;
292
+
293
+ do {
294
+ chr1 = text.charCodeAt(i++);
295
+ chr2 = text.charCodeAt(i++);
296
+ chr3 = text.charCodeAt(i++);
297
+
298
+ enc1 = chr1 >> 2;
299
+ enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
300
+ enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
301
+ enc4 = chr3 & 63;
302
+
303
+ if(isNaN(chr2)) {
304
+ enc3 = enc4 = 64;
305
+ } else if(isNaN(chr3)) {
306
+ enc4 = 64;
307
+ }
308
+
309
+ result +=
310
+ keyStr.charAt(enc1) +
311
+ keyStr.charAt(enc2) +
312
+ keyStr.charAt(enc3) +
313
+ keyStr.charAt(enc4);
314
+ chr1 = chr2 = chr3 = '';
315
+ enc1 = enc2 = enc3 = enc4 = '';
316
+ } while(i < text.length);
317
+
318
+ return result;
319
+ };
320
+
321
+ var mergeHeaders = function () {
322
+ // Use the first header object as base.
323
+ var result = arguments[0];
324
+
325
+ // Iterate through the remaining header objects and add them.
326
+ for(var i = 1; i < arguments.length; i++) {
327
+ var currentHeaders = arguments[i];
328
+ for(var header in currentHeaders) {
329
+ if(currentHeaders.hasOwnProperty(header)) {
330
+ result[header] = currentHeaders[header];
331
+ }
332
+ }
333
+ }
334
+
335
+ // Return the merged headers.
336
+ return result;
337
+ };
338
+
339
+ var ajax = function (method, url, options, callback) {
340
+ // Adjust parameters.
341
+ if(typeof options === 'function') {
342
+ callback = options;
343
+ options = {};
344
+ }
345
+
346
+ // Set default parameter values.
347
+ options.cache = options.cache || false;
348
+ options.data = options.data || {};
349
+ options.headers = options.headers || {};
350
+ options.jsonp = options.jsonp || false;
351
+ options.async = options.async === undefined ? true : options.async;
352
+
353
+ // Merge the various header objects.
354
+ var headers = mergeHeaders({
355
+ 'accept': '*/*',
356
+ 'content-type': 'application/x-www-form-urlencoded;charset=UTF-8'
357
+ }, ajax.headers, options.headers);
358
+
359
+ // Encode the data according to the content-type.
360
+ var payload;
361
+ if (headers['content-type'] === 'application/json') {
362
+ payload = JSON.stringify(options.data);
363
+ } else {
364
+ payload = encodeUsingUrlEncoding(options.data);
365
+ }
366
+
367
+ // Specially prepare GET requests: Setup the query string, handle caching and make a JSONP call
368
+ // if neccessary.
369
+ if(method === 'GET') {
370
+ // Setup the query string.
371
+ var queryString = [];
372
+ if(payload) {
373
+ queryString.push(payload);
374
+ payload = null;
375
+ }
376
+
377
+ // Handle caching.
378
+ if(!options.cache) {
379
+ queryString.push('_=' + (new Date()).getTime());
380
+ }
381
+
382
+ // If neccessary prepare the query string for a JSONP call.
383
+ if(options.jsonp) {
384
+ queryString.push('callback=' + options.jsonp);
385
+ queryString.push('jsonp=' + options.jsonp);
386
+ }
387
+
388
+ // Merge the query string and attach it to the url.
389
+ queryString = queryString.join('&');
390
+ if (queryString.length > 1) {
391
+ if (url.indexOf('?') > -1) {
392
+ url += '&' + queryString;
393
+ } else {
394
+ url += '?' + queryString;
395
+ }
396
+ }
397
+
398
+ // Make a JSONP call if neccessary.
399
+ if(options.jsonp) {
400
+ var head = document.getElementsByTagName('head')[0];
401
+ var script = document.createElement('script');
402
+ script.type = 'text/javascript';
403
+ script.src = url;
404
+ head.appendChild(script);
405
+ return;
406
+ }
407
+ }
408
+
409
+ // Since we got here, it is no JSONP request, so make a normal XHR request.
410
+ getXhr(function (err, xhr) {
411
+ if(err) return callback(err);
412
+
413
+ // Open the request.
414
+ xhr.open(method, url, options.async);
415
+
416
+ // Set the request headers.
417
+ for(var header in headers) {
418
+ if(headers.hasOwnProperty(header)) {
419
+ xhr.setRequestHeader(header, headers[header]);
420
+ }
421
+ }
422
+
423
+ // Handle the request events.
424
+ xhr.onreadystatechange = function () {
425
+ if(xhr.readyState === 4) {
426
+ var data = xhr.responseText || '';
427
+
428
+ // If no callback is given, return.
429
+ if(!callback) {
430
+ return;
431
+ }
432
+
433
+ // Return an object that provides access to the data as text and JSON.
434
+ callback(xhr.status, {
435
+ text: function () {
436
+ return data;
437
+ },
438
+
439
+ json: function () {
440
+ return JSON.parse(data);
441
+ }
442
+ });
443
+ }
444
+ };
445
+
446
+ // Actually send the XHR request.
447
+ xhr.send(payload);
448
+ });
449
+ };
450
+
451
+ // Define the external interface.
452
+ var http = {
453
+ authBasic: function (username, password) {
454
+ ajax.headers['Authorization'] = 'Basic ' + base64(username + ':' + password);
455
+ },
456
+
457
+ connect: function (url, options, callback) {
458
+ return ajax('CONNECT', url, options, callback);
459
+ },
460
+
461
+ del: function (url, options, callback) {
462
+ return ajax('DELETE', url, options, callback);
463
+ },
464
+
465
+ get: function (url, options, callback) {
466
+ return ajax('GET', url, options, callback);
467
+ },
468
+
469
+ head: function (url, options, callback) {
470
+ return ajax('HEAD', url, options, callback);
471
+ },
472
+
473
+ headers: function (headers) {
474
+ ajax.headers = headers || {};
475
+ },
476
+
477
+ isAllowed: function (url, verb, callback) {
478
+ this.options(url, function (status, data) {
479
+ callback(data.text().indexOf(verb) !== -1);
480
+ });
481
+ },
482
+
483
+ options: function (url, options, callback) {
484
+ return ajax('OPTIONS', url, options, callback);
485
+ },
486
+
487
+ patch: function (url, options, callback) {
488
+ return ajax('PATCH', url, options, callback);
489
+ },
490
+
491
+ post: function (url, options, callback) {
492
+ return ajax('POST', url, options, callback);
493
+ },
494
+
495
+ put: function (url, options, callback) {
496
+ return ajax('PUT', url, options, callback);
497
+ },
498
+
499
+ trace: function (url, options, callback) {
500
+ return ajax('TRACE', url, options, callback);
501
+ }
502
+ };
503
+
504
+
505
+ var methode = options.type ? options.type.toLowerCase() : 'get';
506
+
507
+ http[methode](options.url, options, function (status, data) {
508
+ if (status === 200) {
509
+ options.success(data.json(), status, null);
510
+ } else {
511
+ options.error(data.text(), status, null);
512
+ }
513
+ });
514
+ }
515
+
516
+ var _cookie = {
517
+ create: function(name,value,minutes,domain) {
518
+ var expires;
519
+ if (minutes) {
520
+ var date = new Date();
521
+ date.setTime(date.getTime()+(minutes*60*1000));
522
+ expires = "; expires="+date.toGMTString();
523
+ }
524
+ else expires = "";
525
+ domain = (domain)? "domain="+domain+";" : "";
526
+ document.cookie = name+"="+value+expires+";"+domain+"path=/";
527
+ },
528
+
529
+ read: function(name) {
530
+ var nameEQ = name + "=";
531
+ var ca = document.cookie.split(';');
532
+ for(var i=0;i < ca.length;i++) {
533
+ var c = ca[i];
534
+ while (c.charAt(0)==' ') c = c.substring(1,c.length);
535
+ if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length,c.length);
536
+ }
537
+ return null;
538
+ },
539
+
540
+ remove: function(name) {
541
+ this.create(name,"",-1);
542
+ }
543
+ };
544
+
545
+ var cookie_noop = {
546
+ create: function(name,value,minutes,domain) {},
547
+ read: function(name) { return null; },
548
+ remove: function(name) {}
549
+ };
550
+
551
+
552
+
553
+ // move dependent functions to a container so that
554
+ // they can be overriden easier in no jquery environment (node.js)
555
+ var f = {
556
+ extend: $ ? $.extend : _extend,
557
+ each: $ ? $.each : _each,
558
+ ajax: $ ? $.ajax : (typeof document !== 'undefined' ? _ajax : function() {}),
559
+ cookie: typeof document !== 'undefined' ? _cookie : cookie_noop,
560
+ detectLanguage: detectLanguage,
561
+ escape: _escape,
562
+ log: function(str) {
563
+ if (o.debug && typeof console !== "undefined") console.log(str);
564
+ },
565
+ toLanguages: function(lng) {
566
+ var languages = [];
567
+ if (typeof lng === 'string' && lng.indexOf('-') > -1) {
568
+ var parts = lng.split('-');
569
+
570
+ lng = o.lowerCaseLng ?
571
+ parts[0].toLowerCase() + '-' + parts[1].toLowerCase() :
572
+ parts[0].toLowerCase() + '-' + parts[1].toUpperCase();
573
+
574
+ if (o.load !== 'unspecific') languages.push(lng);
575
+ if (o.load !== 'current') languages.push(parts[0]);
576
+ } else {
577
+ languages.push(lng);
578
+ }
579
+
580
+ for (var i = 0; i < o.fallbackLng.length; i++) {
581
+ if (languages.indexOf(o.fallbackLng[i]) === -1 && o.fallbackLng[i]) languages.push(o.fallbackLng[i]);
582
+ }
583
+
584
+ return languages;
585
+ },
586
+ regexEscape: function(str) {
587
+ return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
588
+ }
589
+ };
590
+ function init(options, cb) {
591
+
592
+ if (typeof options === 'function') {
593
+ cb = options;
594
+ options = {};
595
+ }
596
+ options = options || {};
597
+
598
+ // override defaults with passed in options
599
+ f.extend(o, options);
600
+ delete o.fixLng; /* passed in each time */
601
+
602
+ // create namespace object if namespace is passed in as string
603
+ if (typeof o.ns == 'string') {
604
+ o.ns = { namespaces: [o.ns], defaultNs: o.ns};
605
+ }
606
+
607
+ // fallback namespaces
608
+ if (typeof o.fallbackNS == 'string') {
609
+ o.fallbackNS = [o.fallbackNS];
610
+ }
611
+
612
+ // fallback languages
613
+ if (typeof o.fallbackLng == 'string' || typeof o.fallbackLng == 'boolean') {
614
+ o.fallbackLng = [o.fallbackLng];
615
+ }
616
+
617
+ // escape prefix/suffix
618
+ o.interpolationPrefixEscaped = f.regexEscape(o.interpolationPrefix);
619
+ o.interpolationSuffixEscaped = f.regexEscape(o.interpolationSuffix);
620
+
621
+ if (!o.lng) o.lng = f.detectLanguage();
622
+ if (o.lng) {
623
+ // set cookie with lng set (as detectLanguage will set cookie on need)
624
+ if (o.useCookie) f.cookie.create(o.cookieName, o.lng, o.cookieExpirationTime, o.cookieDomain);
625
+ } else {
626
+ o.lng = o.fallbackLng[0];
627
+ if (o.useCookie) f.cookie.remove(o.cookieName);
628
+ }
629
+
630
+ languages = f.toLanguages(o.lng);
631
+ currentLng = languages[0];
632
+ f.log('currentLng set to: ' + currentLng);
633
+
634
+ var lngTranslate = translate;
635
+ if (options.fixLng) {
636
+ lngTranslate = function(key, options) {
637
+ options = options || {};
638
+ options.lng = options.lng || lngTranslate.lng;
639
+ return translate(key, options);
640
+ };
641
+ lngTranslate.lng = currentLng;
642
+ }
643
+
644
+ pluralExtensions.setCurrentLng(currentLng);
645
+
646
+ // add JQuery extensions
647
+ if ($ && o.setJqueryExt) addJqueryFunct();
648
+
649
+ // jQuery deferred
650
+ var deferred;
651
+ if ($ && $.Deferred) {
652
+ deferred = $.Deferred();
653
+ }
654
+
655
+ // return immidiatly if res are passed in
656
+ if (o.resStore) {
657
+ resStore = o.resStore;
658
+ initialized = true;
659
+ if (cb) cb(lngTranslate);
660
+ if (deferred) deferred.resolve(lngTranslate);
661
+ if (deferred) return deferred.promise();
662
+ return;
663
+ }
664
+
665
+ // languages to load
666
+ var lngsToLoad = f.toLanguages(o.lng);
667
+ if (typeof o.preload === 'string') o.preload = [o.preload];
668
+ for (var i = 0, l = o.preload.length; i < l; i++) {
669
+ var pres = f.toLanguages(o.preload[i]);
670
+ for (var y = 0, len = pres.length; y < len; y++) {
671
+ if (lngsToLoad.indexOf(pres[y]) < 0) {
672
+ lngsToLoad.push(pres[y]);
673
+ }
674
+ }
675
+ }
676
+
677
+ // else load them
678
+ i18n.sync.load(lngsToLoad, o, function(err, store) {
679
+ resStore = store;
680
+ initialized = true;
681
+
682
+ if (cb) cb(lngTranslate);
683
+ if (deferred) deferred.resolve(lngTranslate);
684
+ });
685
+
686
+ if (deferred) return deferred.promise();
687
+ }
688
+ function preload(lngs, cb) {
689
+ if (typeof lngs === 'string') lngs = [lngs];
690
+ for (var i = 0, l = lngs.length; i < l; i++) {
691
+ if (o.preload.indexOf(lngs[i]) < 0) {
692
+ o.preload.push(lngs[i]);
693
+ }
694
+ }
695
+ return init(cb);
696
+ }
697
+
698
+ function addResourceBundle(lng, ns, resources) {
699
+ if (typeof ns !== 'string') {
700
+ resources = ns;
701
+ ns = o.ns.defaultNs;
702
+ } else if (o.ns.namespaces.indexOf(ns) < 0) {
703
+ o.ns.namespaces.push(ns);
704
+ }
705
+
706
+ resStore[lng] = resStore[lng] || {};
707
+ resStore[lng][ns] = resStore[lng][ns] || {};
708
+
709
+ f.extend(resStore[lng][ns], resources);
710
+ }
711
+
712
+ function removeResourceBundle(lng, ns) {
713
+ if (typeof ns !== 'string') {
714
+ ns = o.ns.defaultNs;
715
+ }
716
+
717
+ resStore[lng] = resStore[lng] || {};
718
+ resStore[lng][ns] = {};
719
+ }
720
+
721
+ function setDefaultNamespace(ns) {
722
+ o.ns.defaultNs = ns;
723
+ }
724
+
725
+ function loadNamespace(namespace, cb) {
726
+ loadNamespaces([namespace], cb);
727
+ }
728
+
729
+ function loadNamespaces(namespaces, cb) {
730
+ var opts = {
731
+ dynamicLoad: o.dynamicLoad,
732
+ resGetPath: o.resGetPath,
733
+ getAsync: o.getAsync,
734
+ customLoad: o.customLoad,
735
+ ns: { namespaces: namespaces, defaultNs: ''} /* new namespaces to load */
736
+ };
737
+
738
+ // languages to load
739
+ var lngsToLoad = f.toLanguages(o.lng);
740
+ if (typeof o.preload === 'string') o.preload = [o.preload];
741
+ for (var i = 0, l = o.preload.length; i < l; i++) {
742
+ var pres = f.toLanguages(o.preload[i]);
743
+ for (var y = 0, len = pres.length; y < len; y++) {
744
+ if (lngsToLoad.indexOf(pres[y]) < 0) {
745
+ lngsToLoad.push(pres[y]);
746
+ }
747
+ }
748
+ }
749
+
750
+ // check if we have to load
751
+ var lngNeedLoad = [];
752
+ for (var a = 0, lenA = lngsToLoad.length; a < lenA; a++) {
753
+ var needLoad = false;
754
+ var resSet = resStore[lngsToLoad[a]];
755
+ if (resSet) {
756
+ for (var b = 0, lenB = namespaces.length; b < lenB; b++) {
757
+ if (!resSet[namespaces[b]]) needLoad = true;
758
+ }
759
+ } else {
760
+ needLoad = true;
761
+ }
762
+
763
+ if (needLoad) lngNeedLoad.push(lngsToLoad[a]);
764
+ }
765
+
766
+ if (lngNeedLoad.length) {
767
+ i18n.sync._fetch(lngNeedLoad, opts, function(err, store) {
768
+ var todo = namespaces.length * lngNeedLoad.length;
769
+
770
+ // load each file individual
771
+ f.each(namespaces, function(nsIndex, nsValue) {
772
+
773
+ // append namespace to namespace array
774
+ if (o.ns.namespaces.indexOf(nsValue) < 0) {
775
+ o.ns.namespaces.push(nsValue);
776
+ }
777
+
778
+ f.each(lngNeedLoad, function(lngIndex, lngValue) {
779
+ resStore[lngValue] = resStore[lngValue] || {};
780
+ resStore[lngValue][nsValue] = store[lngValue][nsValue];
781
+
782
+ todo--; // wait for all done befor callback
783
+ if (todo === 0 && cb) {
784
+ if (o.useLocalStorage) i18n.sync._storeLocal(resStore);
785
+ cb();
786
+ }
787
+ });
788
+ });
789
+ });
790
+ } else {
791
+ if (cb) cb();
792
+ }
793
+ }
794
+
795
+ function setLng(lng, options, cb) {
796
+ if (typeof options === 'function') {
797
+ cb = options;
798
+ options = {};
799
+ } else if (!options) {
800
+ options = {};
801
+ }
802
+
803
+ options.lng = lng;
804
+ return init(options, cb);
805
+ }
806
+
807
+ function lng() {
808
+ return currentLng;
809
+ }
810
+ function addJqueryFunct() {
811
+ // $.t shortcut
812
+ $.t = $.t || translate;
813
+
814
+ function parse(ele, key, options) {
815
+ if (key.length === 0) return;
816
+
817
+ var attr = 'text';
818
+
819
+ if (key.indexOf('[') === 0) {
820
+ var parts = key.split(']');
821
+ key = parts[1];
822
+ attr = parts[0].substr(1, parts[0].length-1);
823
+ }
824
+
825
+ if (key.indexOf(';') === key.length-1) {
826
+ key = key.substr(0, key.length-2);
827
+ }
828
+
829
+ var optionsToUse;
830
+ if (attr === 'html') {
831
+ optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options;
832
+ ele.html($.t(key, optionsToUse));
833
+ } else if (attr === 'text') {
834
+ optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.text() }, options) : options;
835
+ ele.text($.t(key, optionsToUse));
836
+ } else if (attr === 'prepend') {
837
+ optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options;
838
+ ele.prepend($.t(key, optionsToUse));
839
+ } else if (attr === 'append') {
840
+ optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options;
841
+ ele.append($.t(key, optionsToUse));
842
+ } else if (attr.indexOf("data-") === 0) {
843
+ var dataAttr = attr.substr(("data-").length);
844
+ optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.data(dataAttr) }, options) : options;
845
+ var translated = $.t(key, optionsToUse);
846
+ //we change into the data cache
847
+ ele.data(dataAttr, translated);
848
+ //we change into the dom
849
+ ele.attr(attr, translated);
850
+ } else {
851
+ optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.attr(attr) }, options) : options;
852
+ ele.attr(attr, $.t(key, optionsToUse));
853
+ }
854
+ }
855
+
856
+ function localize(ele, options) {
857
+ var key = ele.attr(o.selectorAttr);
858
+ if (!key && typeof key !== 'undefined' && key !== false) key = ele.text() || ele.val();
859
+ if (!key) return;
860
+
861
+ var target = ele
862
+ , targetSelector = ele.data("i18n-target");
863
+ if (targetSelector) {
864
+ target = ele.find(targetSelector) || ele;
865
+ }
866
+
867
+ if (!options && o.useDataAttrOptions === true) {
868
+ options = ele.data("i18n-options");
869
+ }
870
+ options = options || {};
871
+
872
+ if (key.indexOf(';') >= 0) {
873
+ var keys = key.split(';');
874
+
875
+ $.each(keys, function(m, k) {
876
+ if (k !== '') parse(target, k, options);
877
+ });
878
+
879
+ } else {
880
+ parse(target, key, options);
881
+ }
882
+
883
+ if (o.useDataAttrOptions === true) ele.data("i18n-options", options);
884
+ }
885
+
886
+ // fn
887
+ $.fn.i18n = function (options) {
888
+ return this.each(function() {
889
+ // localize element itself
890
+ localize($(this), options);
891
+
892
+ // localize childs
893
+ var elements = $(this).find('[' + o.selectorAttr + ']');
894
+ elements.each(function() {
895
+ localize($(this), options);
896
+ });
897
+ });
898
+ };
899
+ }
900
+ function applyReplacement(str, replacementHash, nestedKey, options) {
901
+ if (!str) return str;
902
+
903
+ options = options || replacementHash; // first call uses replacement hash combined with options
904
+ if (str.indexOf(options.interpolationPrefix || o.interpolationPrefix) < 0) return str;
905
+
906
+ var prefix = options.interpolationPrefix ? f.regexEscape(options.interpolationPrefix) : o.interpolationPrefixEscaped
907
+ , suffix = options.interpolationSuffix ? f.regexEscape(options.interpolationSuffix) : o.interpolationSuffixEscaped
908
+ , unEscapingSuffix = 'HTML'+suffix;
909
+
910
+ f.each(replacementHash, function(key, value) {
911
+ var nextKey = nestedKey ? nestedKey + o.keyseparator + key : key;
912
+ if (typeof value === 'object' && value !== null) {
913
+ str = applyReplacement(str, value, nextKey, options);
914
+ } else {
915
+ if (options.escapeInterpolation || o.escapeInterpolation) {
916
+ str = str.replace(new RegExp([prefix, nextKey, unEscapingSuffix].join(''), 'g'), value);
917
+ str = str.replace(new RegExp([prefix, nextKey, suffix].join(''), 'g'), f.escape(value));
918
+ } else {
919
+ str = str.replace(new RegExp([prefix, nextKey, suffix].join(''), 'g'), value);
920
+ }
921
+ // str = options.escapeInterpolation;
922
+ }
923
+ });
924
+ return str;
925
+ }
926
+
927
+ // append it to functions
928
+ f.applyReplacement = applyReplacement;
929
+
930
+ function applyReuse(translated, options) {
931
+ var comma = ',';
932
+ var options_open = '{';
933
+ var options_close = '}';
934
+
935
+ var opts = f.extend({}, options);
936
+ delete opts.postProcess;
937
+
938
+ while (translated.indexOf(o.reusePrefix) != -1) {
939
+ replacementCounter++;
940
+ if (replacementCounter > o.maxRecursion) { break; } // safety net for too much recursion
941
+ var index_of_opening = translated.lastIndexOf(o.reusePrefix);
942
+ var index_of_end_of_closing = translated.indexOf(o.reuseSuffix, index_of_opening) + o.reuseSuffix.length;
943
+ var token = translated.substring(index_of_opening, index_of_end_of_closing);
944
+ var token_without_symbols = token.replace(o.reusePrefix, '').replace(o.reuseSuffix, '');
945
+
946
+
947
+ if (token_without_symbols.indexOf(comma) != -1) {
948
+ var index_of_token_end_of_closing = token_without_symbols.indexOf(comma);
949
+ 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) {
950
+ var index_of_opts_opening = token_without_symbols.indexOf(options_open, index_of_token_end_of_closing);
951
+ var index_of_opts_end_of_closing = token_without_symbols.indexOf(options_close, index_of_opts_opening) + options_close.length;
952
+ try {
953
+ opts = f.extend(opts, JSON.parse(token_without_symbols.substring(index_of_opts_opening, index_of_opts_end_of_closing)));
954
+ token_without_symbols = token_without_symbols.substring(0, index_of_token_end_of_closing);
955
+ } catch (e) {
956
+ }
957
+ }
958
+ }
959
+
960
+ var translated_token = _translate(token_without_symbols, opts);
961
+ translated = translated.replace(token, translated_token);
962
+ }
963
+ return translated;
964
+ }
965
+
966
+ function hasContext(options) {
967
+ return (options.context && (typeof options.context == 'string' || typeof options.context == 'number'));
968
+ }
969
+
970
+ function needsPlural(options) {
971
+ return (options.count !== undefined && typeof options.count != 'string' && options.count !== 1);
972
+ }
973
+
974
+ function exists(key, options) {
975
+ options = options || {};
976
+
977
+ var notFound = _getDefaultValue(key, options)
978
+ , found = _find(key, options);
979
+
980
+ return found !== undefined || found === notFound;
981
+ }
982
+
983
+ function translate(key, options) {
984
+ options = options || {};
985
+
986
+ if (!initialized) {
987
+ f.log('i18next not finished initialization. you might have called t function before loading resources finished.')
988
+ return options.defaultValue || '';
989
+ };
990
+ replacementCounter = 0;
991
+ return _translate.apply(null, arguments);
992
+ }
993
+
994
+ function _getDefaultValue(key, options) {
995
+ return (options.defaultValue !== undefined) ? options.defaultValue : key;
996
+ }
997
+
998
+ function _injectSprintfProcessor() {
999
+
1000
+ var values = [];
1001
+
1002
+ // mh: build array from second argument onwards
1003
+ for (var i = 1; i < arguments.length; i++) {
1004
+ values.push(arguments[i]);
1005
+ }
1006
+
1007
+ return {
1008
+ postProcess: 'sprintf',
1009
+ sprintf: values
1010
+ };
1011
+ }
1012
+
1013
+ function _translate(potentialKeys, options) {
1014
+ if (options && typeof options !== 'object') {
1015
+ if (o.shortcutFunction === 'sprintf') {
1016
+ // mh: gettext like sprintf syntax found, automatically create sprintf processor
1017
+ options = _injectSprintfProcessor.apply(null, arguments);
1018
+ } else if (o.shortcutFunction === 'defaultValue') {
1019
+ options = {
1020
+ defaultValue: options
1021
+ }
1022
+ }
1023
+ } else {
1024
+ options = options || {};
1025
+ }
1026
+
1027
+ if (potentialKeys === undefined || potentialKeys === null) return '';
1028
+
1029
+ if (typeof potentialKeys == 'string') {
1030
+ potentialKeys = [potentialKeys];
1031
+ }
1032
+
1033
+ var key = potentialKeys[0];
1034
+
1035
+ if (potentialKeys.length > 1) {
1036
+ for (var i = 0; i < potentialKeys.length; i++) {
1037
+ key = potentialKeys[i];
1038
+ if (exists(key, options)) {
1039
+ break;
1040
+ }
1041
+ }
1042
+ }
1043
+
1044
+ var notFound = _getDefaultValue(key, options)
1045
+ , found = _find(key, options)
1046
+ , lngs = options.lng ? f.toLanguages(options.lng) : languages
1047
+ , ns = options.ns || o.ns.defaultNs
1048
+ , parts;
1049
+
1050
+ // split ns and key
1051
+ if (key.indexOf(o.nsseparator) > -1) {
1052
+ parts = key.split(o.nsseparator);
1053
+ ns = parts[0];
1054
+ key = parts[1];
1055
+ }
1056
+
1057
+ if (found === undefined && o.sendMissing) {
1058
+ if (options.lng) {
1059
+ sync.postMissing(lngs[0], ns, key, notFound, lngs);
1060
+ } else {
1061
+ sync.postMissing(o.lng, ns, key, notFound, lngs);
1062
+ }
1063
+ }
1064
+
1065
+ var postProcessor = options.postProcess || o.postProcess;
1066
+ if (found !== undefined && postProcessor) {
1067
+ if (postProcessors[postProcessor]) {
1068
+ found = postProcessors[postProcessor](found, key, options);
1069
+ }
1070
+ }
1071
+
1072
+ // process notFound if function exists
1073
+ var splitNotFound = notFound;
1074
+ if (notFound.indexOf(o.nsseparator) > -1) {
1075
+ parts = notFound.split(o.nsseparator);
1076
+ splitNotFound = parts[1];
1077
+ }
1078
+ if (splitNotFound === key && o.parseMissingKey) {
1079
+ notFound = o.parseMissingKey(notFound);
1080
+ }
1081
+
1082
+ if (found === undefined) {
1083
+ notFound = applyReplacement(notFound, options);
1084
+ notFound = applyReuse(notFound, options);
1085
+
1086
+ if (postProcessor && postProcessors[postProcessor]) {
1087
+ var val = _getDefaultValue(key, options);
1088
+ found = postProcessors[postProcessor](val, key, options);
1089
+ }
1090
+ }
1091
+
1092
+ return (found !== undefined) ? found : notFound;
1093
+ }
1094
+
1095
+ function _find(key, options) {
1096
+ options = options || {};
1097
+
1098
+ var optionWithoutCount, translated
1099
+ , notFound = _getDefaultValue(key, options)
1100
+ , lngs = languages;
1101
+
1102
+ if (!resStore) { return notFound; } // no resStore to translate from
1103
+
1104
+ // CI mode
1105
+ if (lngs[0].toLowerCase() === 'cimode') return notFound;
1106
+
1107
+ // passed in lng
1108
+ if (options.lng) {
1109
+ lngs = f.toLanguages(options.lng);
1110
+
1111
+ if (!resStore[lngs[0]]) {
1112
+ var oldAsync = o.getAsync;
1113
+ o.getAsync = false;
1114
+
1115
+ i18n.sync.load(lngs, o, function(err, store) {
1116
+ f.extend(resStore, store);
1117
+ o.getAsync = oldAsync;
1118
+ });
1119
+ }
1120
+ }
1121
+
1122
+ var ns = options.ns || o.ns.defaultNs;
1123
+ if (key.indexOf(o.nsseparator) > -1) {
1124
+ var parts = key.split(o.nsseparator);
1125
+ ns = parts[0];
1126
+ key = parts[1];
1127
+ }
1128
+
1129
+ if (hasContext(options)) {
1130
+ optionWithoutCount = f.extend({}, options);
1131
+ delete optionWithoutCount.context;
1132
+ optionWithoutCount.defaultValue = o.contextNotFound;
1133
+
1134
+ var contextKey = ns + o.nsseparator + key + '_' + options.context;
1135
+
1136
+ translated = translate(contextKey, optionWithoutCount);
1137
+ if (translated != o.contextNotFound) {
1138
+ return applyReplacement(translated, { context: options.context }); // apply replacement for context only
1139
+ } // else continue translation with original/nonContext key
1140
+ }
1141
+
1142
+ if (needsPlural(options)) {
1143
+ optionWithoutCount = f.extend({}, options);
1144
+ delete optionWithoutCount.count;
1145
+ optionWithoutCount.defaultValue = o.pluralNotFound;
1146
+
1147
+ var pluralKey = ns + o.nsseparator + key + o.pluralSuffix;
1148
+ var pluralExtension = pluralExtensions.get(lngs[0], options.count);
1149
+ if (pluralExtension >= 0) {
1150
+ pluralKey = pluralKey + '_' + pluralExtension;
1151
+ } else if (pluralExtension === 1) {
1152
+ pluralKey = ns + o.nsseparator + key; // singular
1153
+ }
1154
+
1155
+ translated = translate(pluralKey, optionWithoutCount);
1156
+ if (translated != o.pluralNotFound) {
1157
+ return applyReplacement(translated, {
1158
+ count: options.count,
1159
+ interpolationPrefix: options.interpolationPrefix,
1160
+ interpolationSuffix: options.interpolationSuffix
1161
+ }); // apply replacement for count only
1162
+ } // else continue translation with original/singular key
1163
+ }
1164
+
1165
+ var found;
1166
+ var keys = key.split(o.keyseparator);
1167
+ for (var i = 0, len = lngs.length; i < len; i++ ) {
1168
+ if (found !== undefined) break;
1169
+
1170
+ var l = lngs[i];
1171
+
1172
+ var x = 0;
1173
+ var value = resStore[l] && resStore[l][ns];
1174
+ while (keys[x]) {
1175
+ value = value && value[keys[x]];
1176
+ x++;
1177
+ }
1178
+ if (value !== undefined) {
1179
+ var valueType = Object.prototype.toString.apply(value);
1180
+ if (typeof value === 'string') {
1181
+ value = applyReplacement(value, options);
1182
+ value = applyReuse(value, options);
1183
+ } else if (valueType === '[object Array]' && !o.returnObjectTrees && !options.returnObjectTrees) {
1184
+ value = value.join('\n');
1185
+ value = applyReplacement(value, options);
1186
+ value = applyReuse(value, options);
1187
+ } else if (value === null && o.fallbackOnNull === true) {
1188
+ value = undefined;
1189
+ } else if (value !== null) {
1190
+ if (!o.returnObjectTrees && !options.returnObjectTrees) {
1191
+ if (o.objectTreeKeyHandler && typeof o.objectTreeKeyHandler == 'function') {
1192
+ value = o.objectTreeKeyHandler(key, value, l, ns, options);
1193
+ } else {
1194
+ value = 'key \'' + ns + ':' + key + ' (' + l + ')\' ' +
1195
+ 'returned an object instead of string.';
1196
+ f.log(value);
1197
+ }
1198
+ } else if (valueType !== '[object Number]' && valueType !== '[object Function]' && valueType !== '[object RegExp]') {
1199
+ var copy = (valueType === '[object Array]') ? [] : {}; // apply child translation on a copy
1200
+ f.each(value, function(m) {
1201
+ copy[m] = _translate(ns + o.nsseparator + key + o.keyseparator + m, options);
1202
+ });
1203
+ value = copy;
1204
+ }
1205
+ }
1206
+
1207
+ if (typeof value === 'string' && value.trim() === '' && o.fallbackOnEmpty === true)
1208
+ value = undefined;
1209
+
1210
+ found = value;
1211
+ }
1212
+ }
1213
+
1214
+ if (found === undefined && !options.isFallbackLookup && (o.fallbackToDefaultNS === true || (o.fallbackNS && o.fallbackNS.length > 0))) {
1215
+ // set flag for fallback lookup - avoid recursion
1216
+ options.isFallbackLookup = true;
1217
+
1218
+ if (o.fallbackNS.length) {
1219
+
1220
+ for (var y = 0, lenY = o.fallbackNS.length; y < lenY; y++) {
1221
+ found = _find(o.fallbackNS[y] + o.nsseparator + key, options);
1222
+
1223
+ if (found) {
1224
+ /* compare value without namespace */
1225
+ var foundValue = found.indexOf(o.nsseparator) > -1 ? found.split(o.nsseparator)[1] : found
1226
+ , notFoundValue = notFound.indexOf(o.nsseparator) > -1 ? notFound.split(o.nsseparator)[1] : notFound;
1227
+
1228
+ if (foundValue !== notFoundValue) break;
1229
+ }
1230
+ }
1231
+ } else {
1232
+ found = _find(key, options); // fallback to default NS
1233
+ }
1234
+ }
1235
+
1236
+ return found;
1237
+ }
1238
+ function detectLanguage() {
1239
+ var detectedLng;
1240
+
1241
+ // get from qs
1242
+ var qsParm = [];
1243
+ if (typeof window !== 'undefined') {
1244
+ (function() {
1245
+ var query = window.location.search.substring(1);
1246
+ var parms = query.split('&');
1247
+ for (var i=0; i<parms.length; i++) {
1248
+ var pos = parms[i].indexOf('=');
1249
+ if (pos > 0) {
1250
+ var key = parms[i].substring(0,pos);
1251
+ var val = parms[i].substring(pos+1);
1252
+ qsParm[key] = val;
1253
+ }
1254
+ }
1255
+ })();
1256
+ if (qsParm[o.detectLngQS]) {
1257
+ detectedLng = qsParm[o.detectLngQS];
1258
+ }
1259
+ }
1260
+
1261
+ // get from cookie
1262
+ if (!detectedLng && typeof document !== 'undefined' && o.useCookie ) {
1263
+ var c = f.cookie.read(o.cookieName);
1264
+ if (c) detectedLng = c;
1265
+ }
1266
+
1267
+ // get from navigator
1268
+ if (!detectedLng && typeof navigator !== 'undefined') {
1269
+ detectedLng = (navigator.language) ? navigator.language : navigator.userLanguage;
1270
+ }
1271
+
1272
+ return detectedLng;
1273
+ }
1274
+ var sync = {
1275
+
1276
+ load: function(lngs, options, cb) {
1277
+ if (options.useLocalStorage) {
1278
+ sync._loadLocal(lngs, options, function(err, store) {
1279
+ var missingLngs = [];
1280
+ for (var i = 0, len = lngs.length; i < len; i++) {
1281
+ if (!store[lngs[i]]) missingLngs.push(lngs[i]);
1282
+ }
1283
+
1284
+ if (missingLngs.length > 0) {
1285
+ sync._fetch(missingLngs, options, function(err, fetched) {
1286
+ f.extend(store, fetched);
1287
+ sync._storeLocal(fetched);
1288
+
1289
+ cb(null, store);
1290
+ });
1291
+ } else {
1292
+ cb(null, store);
1293
+ }
1294
+ });
1295
+ } else {
1296
+ sync._fetch(lngs, options, function(err, store){
1297
+ cb(null, store);
1298
+ });
1299
+ }
1300
+ },
1301
+
1302
+ _loadLocal: function(lngs, options, cb) {
1303
+ var store = {}
1304
+ , nowMS = new Date().getTime();
1305
+
1306
+ if(window.localStorage) {
1307
+
1308
+ var todo = lngs.length;
1309
+
1310
+ f.each(lngs, function(key, lng) {
1311
+ var local = window.localStorage.getItem('res_' + lng);
1312
+
1313
+ if (local) {
1314
+ local = JSON.parse(local);
1315
+
1316
+ if (local.i18nStamp && local.i18nStamp + options.localStorageExpirationTime > nowMS) {
1317
+ store[lng] = local;
1318
+ }
1319
+ }
1320
+
1321
+ todo--; // wait for all done befor callback
1322
+ if (todo === 0) cb(null, store);
1323
+ });
1324
+ }
1325
+ },
1326
+
1327
+ _storeLocal: function(store) {
1328
+ if(window.localStorage) {
1329
+ for (var m in store) {
1330
+ store[m].i18nStamp = new Date().getTime();
1331
+ window.localStorage.setItem('res_' + m, JSON.stringify(store[m]));
1332
+ }
1333
+ }
1334
+ return;
1335
+ },
1336
+
1337
+ _fetch: function(lngs, options, cb) {
1338
+ var ns = options.ns
1339
+ , store = {};
1340
+
1341
+ if (!options.dynamicLoad) {
1342
+ var todo = ns.namespaces.length * lngs.length
1343
+ , errors;
1344
+
1345
+ // load each file individual
1346
+ f.each(ns.namespaces, function(nsIndex, nsValue) {
1347
+ f.each(lngs, function(lngIndex, lngValue) {
1348
+
1349
+ // Call this once our translation has returned.
1350
+ var loadComplete = function(err, data) {
1351
+ if (err) {
1352
+ errors = errors || [];
1353
+ errors.push(err);
1354
+ }
1355
+ store[lngValue] = store[lngValue] || {};
1356
+ store[lngValue][nsValue] = data;
1357
+
1358
+ todo--; // wait for all done befor callback
1359
+ if (todo === 0) cb(errors, store);
1360
+ };
1361
+
1362
+ if(typeof options.customLoad == 'function'){
1363
+ // Use the specified custom callback.
1364
+ options.customLoad(lngValue, nsValue, options, loadComplete);
1365
+ } else {
1366
+ //~ // Use our inbuilt sync.
1367
+ sync._fetchOne(lngValue, nsValue, options, loadComplete);
1368
+ }
1369
+ });
1370
+ });
1371
+ } else {
1372
+ // Call this once our translation has returned.
1373
+ var loadComplete = function(err, data) {
1374
+ cb(null, data);
1375
+ };
1376
+
1377
+ if(typeof options.customLoad == 'function'){
1378
+ // Use the specified custom callback.
1379
+ options.customLoad(lngs, ns.namespaces, options, loadComplete);
1380
+ } else {
1381
+ var url = applyReplacement(options.resGetPath, { lng: lngs.join('+'), ns: ns.namespaces.join('+') });
1382
+ // load all needed stuff once
1383
+ f.ajax({
1384
+ url: url,
1385
+ success: function(data, status, xhr) {
1386
+ f.log('loaded: ' + url);
1387
+ loadComplete(null, data);
1388
+ },
1389
+ error : function(xhr, status, error) {
1390
+ f.log('failed loading: ' + url);
1391
+ loadComplete('failed loading resource.json error: ' + error);
1392
+ },
1393
+ dataType: "json",
1394
+ async : options.getAsync
1395
+ });
1396
+ }
1397
+ }
1398
+ },
1399
+
1400
+ _fetchOne: function(lng, ns, options, done) {
1401
+ var url = applyReplacement(options.resGetPath, { lng: lng, ns: ns });
1402
+ f.ajax({
1403
+ url: url,
1404
+ success: function(data, status, xhr) {
1405
+ f.log('loaded: ' + url);
1406
+ done(null, data);
1407
+ },
1408
+ error : function(xhr, status, error) {
1409
+ if ((status && status == 200) || (xhr && xhr.status && xhr.status == 200)) {
1410
+ // file loaded but invalid json, stop waste time !
1411
+ f.log('There is a typo in: ' + url);
1412
+ } else if ((status && status == 404) || (xhr && xhr.status && xhr.status == 404)) {
1413
+ f.log('Does not exist: ' + url);
1414
+ } else {
1415
+ var theStatus = status ? status : ((xhr && xhr.status) ? xhr.status : null);
1416
+ f.log(theStatus + ' when loading ' + url);
1417
+ }
1418
+
1419
+ done(error, {});
1420
+ },
1421
+ dataType: "json",
1422
+ async : options.getAsync
1423
+ });
1424
+ },
1425
+
1426
+ postMissing: function(lng, ns, key, defaultValue, lngs) {
1427
+ var payload = {};
1428
+ payload[key] = defaultValue;
1429
+
1430
+ var urls = [];
1431
+
1432
+ if (o.sendMissingTo === 'fallback' && o.fallbackLng[0] !== false) {
1433
+ for (var i = 0; i < o.fallbackLng.length; i++) {
1434
+ urls.push({lng: o.fallbackLng[i], url: applyReplacement(o.resPostPath, { lng: o.fallbackLng[i], ns: ns })});
1435
+ }
1436
+ } else if (o.sendMissingTo === 'current' || (o.sendMissingTo === 'fallback' && o.fallbackLng[0] === false) ) {
1437
+ urls.push({lng: lng, url: applyReplacement(o.resPostPath, { lng: lng, ns: ns })});
1438
+ } else if (o.sendMissingTo === 'all') {
1439
+ for (var i = 0, l = lngs.length; i < l; i++) {
1440
+ urls.push({lng: lngs[i], url: applyReplacement(o.resPostPath, { lng: lngs[i], ns: ns })});
1441
+ }
1442
+ }
1443
+
1444
+ for (var y = 0, len = urls.length; y < len; y++) {
1445
+ var item = urls[y];
1446
+ f.ajax({
1447
+ url: item.url,
1448
+ type: o.sendType,
1449
+ data: payload,
1450
+ success: function(data, status, xhr) {
1451
+ f.log('posted missing key \'' + key + '\' to: ' + item.url);
1452
+
1453
+ // add key to resStore
1454
+ var keys = key.split('.');
1455
+ var x = 0;
1456
+ var value = resStore[item.lng][ns];
1457
+ while (keys[x]) {
1458
+ if (x === keys.length - 1) {
1459
+ value = value[keys[x]] = defaultValue;
1460
+ } else {
1461
+ value = value[keys[x]] = value[keys[x]] || {};
1462
+ }
1463
+ x++;
1464
+ }
1465
+ },
1466
+ error : function(xhr, status, error) {
1467
+ f.log('failed posting missing key \'' + key + '\' to: ' + item.url);
1468
+ },
1469
+ dataType: "json",
1470
+ async : o.postAsync
1471
+ });
1472
+ }
1473
+ }
1474
+ };
1475
+ // definition http://translate.sourceforge.net/wiki/l10n/pluralforms
1476
+ var pluralExtensions = {
1477
+
1478
+ rules: {
1479
+ "ach": {
1480
+ "name": "Acholi",
1481
+ "numbers": [
1482
+ 1,
1483
+ 2
1484
+ ],
1485
+ "plurals": function(n) { return Number(n > 1); }
1486
+ },
1487
+ "af": {
1488
+ "name": "Afrikaans",
1489
+ "numbers": [
1490
+ 1,
1491
+ 2
1492
+ ],
1493
+ "plurals": function(n) { return Number(n != 1); }
1494
+ },
1495
+ "ak": {
1496
+ "name": "Akan",
1497
+ "numbers": [
1498
+ 1,
1499
+ 2
1500
+ ],
1501
+ "plurals": function(n) { return Number(n > 1); }
1502
+ },
1503
+ "am": {
1504
+ "name": "Amharic",
1505
+ "numbers": [
1506
+ 1,
1507
+ 2
1508
+ ],
1509
+ "plurals": function(n) { return Number(n > 1); }
1510
+ },
1511
+ "an": {
1512
+ "name": "Aragonese",
1513
+ "numbers": [
1514
+ 1,
1515
+ 2
1516
+ ],
1517
+ "plurals": function(n) { return Number(n != 1); }
1518
+ },
1519
+ "ar": {
1520
+ "name": "Arabic",
1521
+ "numbers": [
1522
+ 0,
1523
+ 1,
1524
+ 2,
1525
+ 3,
1526
+ 11,
1527
+ 100
1528
+ ],
1529
+ "plurals": 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); }
1530
+ },
1531
+ "arn": {
1532
+ "name": "Mapudungun",
1533
+ "numbers": [
1534
+ 1,
1535
+ 2
1536
+ ],
1537
+ "plurals": function(n) { return Number(n > 1); }
1538
+ },
1539
+ "ast": {
1540
+ "name": "Asturian",
1541
+ "numbers": [
1542
+ 1,
1543
+ 2
1544
+ ],
1545
+ "plurals": function(n) { return Number(n != 1); }
1546
+ },
1547
+ "ay": {
1548
+ "name": "Aymar\u00e1",
1549
+ "numbers": [
1550
+ 1
1551
+ ],
1552
+ "plurals": function(n) { return 0; }
1553
+ },
1554
+ "az": {
1555
+ "name": "Azerbaijani",
1556
+ "numbers": [
1557
+ 1,
1558
+ 2
1559
+ ],
1560
+ "plurals": function(n) { return Number(n != 1); }
1561
+ },
1562
+ "be": {
1563
+ "name": "Belarusian",
1564
+ "numbers": [
1565
+ 1,
1566
+ 2,
1567
+ 5
1568
+ ],
1569
+ "plurals": 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); }
1570
+ },
1571
+ "bg": {
1572
+ "name": "Bulgarian",
1573
+ "numbers": [
1574
+ 1,
1575
+ 2
1576
+ ],
1577
+ "plurals": function(n) { return Number(n != 1); }
1578
+ },
1579
+ "bn": {
1580
+ "name": "Bengali",
1581
+ "numbers": [
1582
+ 1,
1583
+ 2
1584
+ ],
1585
+ "plurals": function(n) { return Number(n != 1); }
1586
+ },
1587
+ "bo": {
1588
+ "name": "Tibetan",
1589
+ "numbers": [
1590
+ 1
1591
+ ],
1592
+ "plurals": function(n) { return 0; }
1593
+ },
1594
+ "br": {
1595
+ "name": "Breton",
1596
+ "numbers": [
1597
+ 1,
1598
+ 2
1599
+ ],
1600
+ "plurals": function(n) { return Number(n > 1); }
1601
+ },
1602
+ "bs": {
1603
+ "name": "Bosnian",
1604
+ "numbers": [
1605
+ 1,
1606
+ 2,
1607
+ 5
1608
+ ],
1609
+ "plurals": 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); }
1610
+ },
1611
+ "ca": {
1612
+ "name": "Catalan",
1613
+ "numbers": [
1614
+ 1,
1615
+ 2
1616
+ ],
1617
+ "plurals": function(n) { return Number(n != 1); }
1618
+ },
1619
+ "cgg": {
1620
+ "name": "Chiga",
1621
+ "numbers": [
1622
+ 1
1623
+ ],
1624
+ "plurals": function(n) { return 0; }
1625
+ },
1626
+ "cs": {
1627
+ "name": "Czech",
1628
+ "numbers": [
1629
+ 1,
1630
+ 2,
1631
+ 5
1632
+ ],
1633
+ "plurals": function(n) { return Number((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2); }
1634
+ },
1635
+ "csb": {
1636
+ "name": "Kashubian",
1637
+ "numbers": [
1638
+ 1,
1639
+ 2,
1640
+ 5
1641
+ ],
1642
+ "plurals": function(n) { return Number(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); }
1643
+ },
1644
+ "cy": {
1645
+ "name": "Welsh",
1646
+ "numbers": [
1647
+ 1,
1648
+ 2,
1649
+ 3,
1650
+ 8
1651
+ ],
1652
+ "plurals": function(n) { return Number((n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3); }
1653
+ },
1654
+ "da": {
1655
+ "name": "Danish",
1656
+ "numbers": [
1657
+ 1,
1658
+ 2
1659
+ ],
1660
+ "plurals": function(n) { return Number(n != 1); }
1661
+ },
1662
+ "de": {
1663
+ "name": "German",
1664
+ "numbers": [
1665
+ 1,
1666
+ 2
1667
+ ],
1668
+ "plurals": function(n) { return Number(n != 1); }
1669
+ },
1670
+ "dz": {
1671
+ "name": "Dzongkha",
1672
+ "numbers": [
1673
+ 1
1674
+ ],
1675
+ "plurals": function(n) { return 0; }
1676
+ },
1677
+ "el": {
1678
+ "name": "Greek",
1679
+ "numbers": [
1680
+ 1,
1681
+ 2
1682
+ ],
1683
+ "plurals": function(n) { return Number(n != 1); }
1684
+ },
1685
+ "en": {
1686
+ "name": "English",
1687
+ "numbers": [
1688
+ 1,
1689
+ 2
1690
+ ],
1691
+ "plurals": function(n) { return Number(n != 1); }
1692
+ },
1693
+ "eo": {
1694
+ "name": "Esperanto",
1695
+ "numbers": [
1696
+ 1,
1697
+ 2
1698
+ ],
1699
+ "plurals": function(n) { return Number(n != 1); }
1700
+ },
1701
+ "es": {
1702
+ "name": "Spanish",
1703
+ "numbers": [
1704
+ 1,
1705
+ 2
1706
+ ],
1707
+ "plurals": function(n) { return Number(n != 1); }
1708
+ },
1709
+ "es_ar": {
1710
+ "name": "Argentinean Spanish",
1711
+ "numbers": [
1712
+ 1,
1713
+ 2
1714
+ ],
1715
+ "plurals": function(n) { return Number(n != 1); }
1716
+ },
1717
+ "et": {
1718
+ "name": "Estonian",
1719
+ "numbers": [
1720
+ 1,
1721
+ 2
1722
+ ],
1723
+ "plurals": function(n) { return Number(n != 1); }
1724
+ },
1725
+ "eu": {
1726
+ "name": "Basque",
1727
+ "numbers": [
1728
+ 1,
1729
+ 2
1730
+ ],
1731
+ "plurals": function(n) { return Number(n != 1); }
1732
+ },
1733
+ "fa": {
1734
+ "name": "Persian",
1735
+ "numbers": [
1736
+ 1
1737
+ ],
1738
+ "plurals": function(n) { return 0; }
1739
+ },
1740
+ "fi": {
1741
+ "name": "Finnish",
1742
+ "numbers": [
1743
+ 1,
1744
+ 2
1745
+ ],
1746
+ "plurals": function(n) { return Number(n != 1); }
1747
+ },
1748
+ "fil": {
1749
+ "name": "Filipino",
1750
+ "numbers": [
1751
+ 1,
1752
+ 2
1753
+ ],
1754
+ "plurals": function(n) { return Number(n > 1); }
1755
+ },
1756
+ "fo": {
1757
+ "name": "Faroese",
1758
+ "numbers": [
1759
+ 1,
1760
+ 2
1761
+ ],
1762
+ "plurals": function(n) { return Number(n != 1); }
1763
+ },
1764
+ "fr": {
1765
+ "name": "French",
1766
+ "numbers": [
1767
+ 1,
1768
+ 2
1769
+ ],
1770
+ "plurals": function(n) { return Number(n > 1); }
1771
+ },
1772
+ "fur": {
1773
+ "name": "Friulian",
1774
+ "numbers": [
1775
+ 1,
1776
+ 2
1777
+ ],
1778
+ "plurals": function(n) { return Number(n != 1); }
1779
+ },
1780
+ "fy": {
1781
+ "name": "Frisian",
1782
+ "numbers": [
1783
+ 1,
1784
+ 2
1785
+ ],
1786
+ "plurals": function(n) { return Number(n != 1); }
1787
+ },
1788
+ "ga": {
1789
+ "name": "Irish",
1790
+ "numbers": [
1791
+ 1,
1792
+ 2,
1793
+ 3,
1794
+ 7,
1795
+ 11
1796
+ ],
1797
+ "plurals": function(n) { return Number(n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4) ;}
1798
+ },
1799
+ "gd": {
1800
+ "name": "Scottish Gaelic",
1801
+ "numbers": [
1802
+ 1,
1803
+ 2,
1804
+ 3,
1805
+ 20
1806
+ ],
1807
+ "plurals": function(n) { return Number((n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : (n > 2 && n < 20) ? 2 : 3); }
1808
+ },
1809
+ "gl": {
1810
+ "name": "Galician",
1811
+ "numbers": [
1812
+ 1,
1813
+ 2
1814
+ ],
1815
+ "plurals": function(n) { return Number(n != 1); }
1816
+ },
1817
+ "gu": {
1818
+ "name": "Gujarati",
1819
+ "numbers": [
1820
+ 1,
1821
+ 2
1822
+ ],
1823
+ "plurals": function(n) { return Number(n != 1); }
1824
+ },
1825
+ "gun": {
1826
+ "name": "Gun",
1827
+ "numbers": [
1828
+ 1,
1829
+ 2
1830
+ ],
1831
+ "plurals": function(n) { return Number(n > 1); }
1832
+ },
1833
+ "ha": {
1834
+ "name": "Hausa",
1835
+ "numbers": [
1836
+ 1,
1837
+ 2
1838
+ ],
1839
+ "plurals": function(n) { return Number(n != 1); }
1840
+ },
1841
+ "he": {
1842
+ "name": "Hebrew",
1843
+ "numbers": [
1844
+ 1,
1845
+ 2
1846
+ ],
1847
+ "plurals": function(n) { return Number(n != 1); }
1848
+ },
1849
+ "hi": {
1850
+ "name": "Hindi",
1851
+ "numbers": [
1852
+ 1,
1853
+ 2
1854
+ ],
1855
+ "plurals": function(n) { return Number(n != 1); }
1856
+ },
1857
+ "hr": {
1858
+ "name": "Croatian",
1859
+ "numbers": [
1860
+ 1,
1861
+ 2,
1862
+ 5
1863
+ ],
1864
+ "plurals": 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); }
1865
+ },
1866
+ "hu": {
1867
+ "name": "Hungarian",
1868
+ "numbers": [
1869
+ 1,
1870
+ 2
1871
+ ],
1872
+ "plurals": function(n) { return Number(n != 1); }
1873
+ },
1874
+ "hy": {
1875
+ "name": "Armenian",
1876
+ "numbers": [
1877
+ 1,
1878
+ 2
1879
+ ],
1880
+ "plurals": function(n) { return Number(n != 1); }
1881
+ },
1882
+ "ia": {
1883
+ "name": "Interlingua",
1884
+ "numbers": [
1885
+ 1,
1886
+ 2
1887
+ ],
1888
+ "plurals": function(n) { return Number(n != 1); }
1889
+ },
1890
+ "id": {
1891
+ "name": "Indonesian",
1892
+ "numbers": [
1893
+ 1
1894
+ ],
1895
+ "plurals": function(n) { return 0; }
1896
+ },
1897
+ "is": {
1898
+ "name": "Icelandic",
1899
+ "numbers": [
1900
+ 1,
1901
+ 2
1902
+ ],
1903
+ "plurals": function(n) { return Number(n%10!=1 || n%100==11); }
1904
+ },
1905
+ "it": {
1906
+ "name": "Italian",
1907
+ "numbers": [
1908
+ 1,
1909
+ 2
1910
+ ],
1911
+ "plurals": function(n) { return Number(n != 1); }
1912
+ },
1913
+ "ja": {
1914
+ "name": "Japanese",
1915
+ "numbers": [
1916
+ 1
1917
+ ],
1918
+ "plurals": function(n) { return 0; }
1919
+ },
1920
+ "jbo": {
1921
+ "name": "Lojban",
1922
+ "numbers": [
1923
+ 1
1924
+ ],
1925
+ "plurals": function(n) { return 0; }
1926
+ },
1927
+ "jv": {
1928
+ "name": "Javanese",
1929
+ "numbers": [
1930
+ 0,
1931
+ 1
1932
+ ],
1933
+ "plurals": function(n) { return Number(n !== 0); }
1934
+ },
1935
+ "ka": {
1936
+ "name": "Georgian",
1937
+ "numbers": [
1938
+ 1
1939
+ ],
1940
+ "plurals": function(n) { return 0; }
1941
+ },
1942
+ "kk": {
1943
+ "name": "Kazakh",
1944
+ "numbers": [
1945
+ 1
1946
+ ],
1947
+ "plurals": function(n) { return 0; }
1948
+ },
1949
+ "km": {
1950
+ "name": "Khmer",
1951
+ "numbers": [
1952
+ 1
1953
+ ],
1954
+ "plurals": function(n) { return 0; }
1955
+ },
1956
+ "kn": {
1957
+ "name": "Kannada",
1958
+ "numbers": [
1959
+ 1,
1960
+ 2
1961
+ ],
1962
+ "plurals": function(n) { return Number(n != 1); }
1963
+ },
1964
+ "ko": {
1965
+ "name": "Korean",
1966
+ "numbers": [
1967
+ 1
1968
+ ],
1969
+ "plurals": function(n) { return 0; }
1970
+ },
1971
+ "ku": {
1972
+ "name": "Kurdish",
1973
+ "numbers": [
1974
+ 1,
1975
+ 2
1976
+ ],
1977
+ "plurals": function(n) { return Number(n != 1); }
1978
+ },
1979
+ "kw": {
1980
+ "name": "Cornish",
1981
+ "numbers": [
1982
+ 1,
1983
+ 2,
1984
+ 3,
1985
+ 4
1986
+ ],
1987
+ "plurals": function(n) { return Number((n==1) ? 0 : (n==2) ? 1 : (n == 3) ? 2 : 3); }
1988
+ },
1989
+ "ky": {
1990
+ "name": "Kyrgyz",
1991
+ "numbers": [
1992
+ 1
1993
+ ],
1994
+ "plurals": function(n) { return 0; }
1995
+ },
1996
+ "lb": {
1997
+ "name": "Letzeburgesch",
1998
+ "numbers": [
1999
+ 1,
2000
+ 2
2001
+ ],
2002
+ "plurals": function(n) { return Number(n != 1); }
2003
+ },
2004
+ "ln": {
2005
+ "name": "Lingala",
2006
+ "numbers": [
2007
+ 1,
2008
+ 2
2009
+ ],
2010
+ "plurals": function(n) { return Number(n > 1); }
2011
+ },
2012
+ "lo": {
2013
+ "name": "Lao",
2014
+ "numbers": [
2015
+ 1
2016
+ ],
2017
+ "plurals": function(n) { return 0; }
2018
+ },
2019
+ "lt": {
2020
+ "name": "Lithuanian",
2021
+ "numbers": [
2022
+ 1,
2023
+ 2,
2024
+ 10
2025
+ ],
2026
+ "plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2); }
2027
+ },
2028
+ "lv": {
2029
+ "name": "Latvian",
2030
+ "numbers": [
2031
+ 1,
2032
+ 2,
2033
+ 0
2034
+ ],
2035
+ "plurals": function(n) { return Number(n%10==1 && n%100!=11 ? 0 : n !== 0 ? 1 : 2); }
2036
+ },
2037
+ "mai": {
2038
+ "name": "Maithili",
2039
+ "numbers": [
2040
+ 1,
2041
+ 2
2042
+ ],
2043
+ "plurals": function(n) { return Number(n != 1); }
2044
+ },
2045
+ "mfe": {
2046
+ "name": "Mauritian Creole",
2047
+ "numbers": [
2048
+ 1,
2049
+ 2
2050
+ ],
2051
+ "plurals": function(n) { return Number(n > 1); }
2052
+ },
2053
+ "mg": {
2054
+ "name": "Malagasy",
2055
+ "numbers": [
2056
+ 1,
2057
+ 2
2058
+ ],
2059
+ "plurals": function(n) { return Number(n > 1); }
2060
+ },
2061
+ "mi": {
2062
+ "name": "Maori",
2063
+ "numbers": [
2064
+ 1,
2065
+ 2
2066
+ ],
2067
+ "plurals": function(n) { return Number(n > 1); }
2068
+ },
2069
+ "mk": {
2070
+ "name": "Macedonian",
2071
+ "numbers": [
2072
+ 1,
2073
+ 2
2074
+ ],
2075
+ "plurals": function(n) { return Number(n==1 || n%10==1 ? 0 : 1); }
2076
+ },
2077
+ "ml": {
2078
+ "name": "Malayalam",
2079
+ "numbers": [
2080
+ 1,
2081
+ 2
2082
+ ],
2083
+ "plurals": function(n) { return Number(n != 1); }
2084
+ },
2085
+ "mn": {
2086
+ "name": "Mongolian",
2087
+ "numbers": [
2088
+ 1,
2089
+ 2
2090
+ ],
2091
+ "plurals": function(n) { return Number(n != 1); }
2092
+ },
2093
+ "mnk": {
2094
+ "name": "Mandinka",
2095
+ "numbers": [
2096
+ 0,
2097
+ 1,
2098
+ 2
2099
+ ],
2100
+ "plurals": function(n) { return Number(0 ? 0 : n==1 ? 1 : 2); }
2101
+ },
2102
+ "mr": {
2103
+ "name": "Marathi",
2104
+ "numbers": [
2105
+ 1,
2106
+ 2
2107
+ ],
2108
+ "plurals": function(n) { return Number(n != 1); }
2109
+ },
2110
+ "ms": {
2111
+ "name": "Malay",
2112
+ "numbers": [
2113
+ 1
2114
+ ],
2115
+ "plurals": function(n) { return 0; }
2116
+ },
2117
+ "mt": {
2118
+ "name": "Maltese",
2119
+ "numbers": [
2120
+ 1,
2121
+ 2,
2122
+ 11,
2123
+ 20
2124
+ ],
2125
+ "plurals": function(n) { return Number(n==1 ? 0 : n===0 || ( n%100>1 && n%100<11) ? 1 : (n%100>10 && n%100<20 ) ? 2 : 3); }
2126
+ },
2127
+ "nah": {
2128
+ "name": "Nahuatl",
2129
+ "numbers": [
2130
+ 1,
2131
+ 2
2132
+ ],
2133
+ "plurals": function(n) { return Number(n != 1); }
2134
+ },
2135
+ "nap": {
2136
+ "name": "Neapolitan",
2137
+ "numbers": [
2138
+ 1,
2139
+ 2
2140
+ ],
2141
+ "plurals": function(n) { return Number(n != 1); }
2142
+ },
2143
+ "nb": {
2144
+ "name": "Norwegian Bokmal",
2145
+ "numbers": [
2146
+ 1,
2147
+ 2
2148
+ ],
2149
+ "plurals": function(n) { return Number(n != 1); }
2150
+ },
2151
+ "ne": {
2152
+ "name": "Nepali",
2153
+ "numbers": [
2154
+ 1,
2155
+ 2
2156
+ ],
2157
+ "plurals": function(n) { return Number(n != 1); }
2158
+ },
2159
+ "nl": {
2160
+ "name": "Dutch",
2161
+ "numbers": [
2162
+ 1,
2163
+ 2
2164
+ ],
2165
+ "plurals": function(n) { return Number(n != 1); }
2166
+ },
2167
+ "nn": {
2168
+ "name": "Norwegian Nynorsk",
2169
+ "numbers": [
2170
+ 1,
2171
+ 2
2172
+ ],
2173
+ "plurals": function(n) { return Number(n != 1); }
2174
+ },
2175
+ "no": {
2176
+ "name": "Norwegian",
2177
+ "numbers": [
2178
+ 1,
2179
+ 2
2180
+ ],
2181
+ "plurals": function(n) { return Number(n != 1); }
2182
+ },
2183
+ "nso": {
2184
+ "name": "Northern Sotho",
2185
+ "numbers": [
2186
+ 1,
2187
+ 2
2188
+ ],
2189
+ "plurals": function(n) { return Number(n != 1); }
2190
+ },
2191
+ "oc": {
2192
+ "name": "Occitan",
2193
+ "numbers": [
2194
+ 1,
2195
+ 2
2196
+ ],
2197
+ "plurals": function(n) { return Number(n > 1); }
2198
+ },
2199
+ "or": {
2200
+ "name": "Oriya",
2201
+ "numbers": [
2202
+ 2,
2203
+ 1
2204
+ ],
2205
+ "plurals": function(n) { return Number(n != 1); }
2206
+ },
2207
+ "pa": {
2208
+ "name": "Punjabi",
2209
+ "numbers": [
2210
+ 1,
2211
+ 2
2212
+ ],
2213
+ "plurals": function(n) { return Number(n != 1); }
2214
+ },
2215
+ "pap": {
2216
+ "name": "Papiamento",
2217
+ "numbers": [
2218
+ 1,
2219
+ 2
2220
+ ],
2221
+ "plurals": function(n) { return Number(n != 1); }
2222
+ },
2223
+ "pl": {
2224
+ "name": "Polish",
2225
+ "numbers": [
2226
+ 1,
2227
+ 2,
2228
+ 5
2229
+ ],
2230
+ "plurals": function(n) { return Number(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); }
2231
+ },
2232
+ "pms": {
2233
+ "name": "Piemontese",
2234
+ "numbers": [
2235
+ 1,
2236
+ 2
2237
+ ],
2238
+ "plurals": function(n) { return Number(n != 1); }
2239
+ },
2240
+ "ps": {
2241
+ "name": "Pashto",
2242
+ "numbers": [
2243
+ 1,
2244
+ 2
2245
+ ],
2246
+ "plurals": function(n) { return Number(n != 1); }
2247
+ },
2248
+ "pt": {
2249
+ "name": "Portuguese",
2250
+ "numbers": [
2251
+ 1,
2252
+ 2
2253
+ ],
2254
+ "plurals": function(n) { return Number(n != 1); }
2255
+ },
2256
+ "pt_br": {
2257
+ "name": "Brazilian Portuguese",
2258
+ "numbers": [
2259
+ 1,
2260
+ 2
2261
+ ],
2262
+ "plurals": function(n) { return Number(n != 1); }
2263
+ },
2264
+ "rm": {
2265
+ "name": "Romansh",
2266
+ "numbers": [
2267
+ 1,
2268
+ 2
2269
+ ],
2270
+ "plurals": function(n) { return Number(n != 1); }
2271
+ },
2272
+ "ro": {
2273
+ "name": "Romanian",
2274
+ "numbers": [
2275
+ 1,
2276
+ 2,
2277
+ 20
2278
+ ],
2279
+ "plurals": function(n) { return Number(n==1 ? 0 : (n===0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2); }
2280
+ },
2281
+ "ru": {
2282
+ "name": "Russian",
2283
+ "numbers": [
2284
+ 1,
2285
+ 2,
2286
+ 5
2287
+ ],
2288
+ "plurals": 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); }
2289
+ },
2290
+ "sah": {
2291
+ "name": "Yakut",
2292
+ "numbers": [
2293
+ 1
2294
+ ],
2295
+ "plurals": function(n) { return 0; }
2296
+ },
2297
+ "sco": {
2298
+ "name": "Scots",
2299
+ "numbers": [
2300
+ 1,
2301
+ 2
2302
+ ],
2303
+ "plurals": function(n) { return Number(n != 1); }
2304
+ },
2305
+ "se": {
2306
+ "name": "Northern Sami",
2307
+ "numbers": [
2308
+ 1,
2309
+ 2
2310
+ ],
2311
+ "plurals": function(n) { return Number(n != 1); }
2312
+ },
2313
+ "si": {
2314
+ "name": "Sinhala",
2315
+ "numbers": [
2316
+ 1,
2317
+ 2
2318
+ ],
2319
+ "plurals": function(n) { return Number(n != 1); }
2320
+ },
2321
+ "sk": {
2322
+ "name": "Slovak",
2323
+ "numbers": [
2324
+ 1,
2325
+ 2,
2326
+ 5
2327
+ ],
2328
+ "plurals": function(n) { return Number((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2); }
2329
+ },
2330
+ "sl": {
2331
+ "name": "Slovenian",
2332
+ "numbers": [
2333
+ 5,
2334
+ 1,
2335
+ 2,
2336
+ 3
2337
+ ],
2338
+ "plurals": function(n) { return Number(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? 3 : 0); }
2339
+ },
2340
+ "so": {
2341
+ "name": "Somali",
2342
+ "numbers": [
2343
+ 1,
2344
+ 2
2345
+ ],
2346
+ "plurals": function(n) { return Number(n != 1); }
2347
+ },
2348
+ "son": {
2349
+ "name": "Songhay",
2350
+ "numbers": [
2351
+ 1,
2352
+ 2
2353
+ ],
2354
+ "plurals": function(n) { return Number(n != 1); }
2355
+ },
2356
+ "sq": {
2357
+ "name": "Albanian",
2358
+ "numbers": [
2359
+ 1,
2360
+ 2
2361
+ ],
2362
+ "plurals": function(n) { return Number(n != 1); }
2363
+ },
2364
+ "sr": {
2365
+ "name": "Serbian",
2366
+ "numbers": [
2367
+ 1,
2368
+ 2,
2369
+ 5
2370
+ ],
2371
+ "plurals": 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); }
2372
+ },
2373
+ "su": {
2374
+ "name": "Sundanese",
2375
+ "numbers": [
2376
+ 1
2377
+ ],
2378
+ "plurals": function(n) { return 0; }
2379
+ },
2380
+ "sv": {
2381
+ "name": "Swedish",
2382
+ "numbers": [
2383
+ 1,
2384
+ 2
2385
+ ],
2386
+ "plurals": function(n) { return Number(n != 1); }
2387
+ },
2388
+ "sw": {
2389
+ "name": "Swahili",
2390
+ "numbers": [
2391
+ 1,
2392
+ 2
2393
+ ],
2394
+ "plurals": function(n) { return Number(n != 1); }
2395
+ },
2396
+ "ta": {
2397
+ "name": "Tamil",
2398
+ "numbers": [
2399
+ 1,
2400
+ 2
2401
+ ],
2402
+ "plurals": function(n) { return Number(n != 1); }
2403
+ },
2404
+ "te": {
2405
+ "name": "Telugu",
2406
+ "numbers": [
2407
+ 1,
2408
+ 2
2409
+ ],
2410
+ "plurals": function(n) { return Number(n != 1); }
2411
+ },
2412
+ "tg": {
2413
+ "name": "Tajik",
2414
+ "numbers": [
2415
+ 1,
2416
+ 2
2417
+ ],
2418
+ "plurals": function(n) { return Number(n > 1); }
2419
+ },
2420
+ "th": {
2421
+ "name": "Thai",
2422
+ "numbers": [
2423
+ 1
2424
+ ],
2425
+ "plurals": function(n) { return 0; }
2426
+ },
2427
+ "ti": {
2428
+ "name": "Tigrinya",
2429
+ "numbers": [
2430
+ 1,
2431
+ 2
2432
+ ],
2433
+ "plurals": function(n) { return Number(n > 1); }
2434
+ },
2435
+ "tk": {
2436
+ "name": "Turkmen",
2437
+ "numbers": [
2438
+ 1,
2439
+ 2
2440
+ ],
2441
+ "plurals": function(n) { return Number(n != 1); }
2442
+ },
2443
+ "tr": {
2444
+ "name": "Turkish",
2445
+ "numbers": [
2446
+ 1,
2447
+ 2
2448
+ ],
2449
+ "plurals": function(n) { return Number(n > 1); }
2450
+ },
2451
+ "tt": {
2452
+ "name": "Tatar",
2453
+ "numbers": [
2454
+ 1
2455
+ ],
2456
+ "plurals": function(n) { return 0; }
2457
+ },
2458
+ "ug": {
2459
+ "name": "Uyghur",
2460
+ "numbers": [
2461
+ 1
2462
+ ],
2463
+ "plurals": function(n) { return 0; }
2464
+ },
2465
+ "uk": {
2466
+ "name": "Ukrainian",
2467
+ "numbers": [
2468
+ 1,
2469
+ 2,
2470
+ 5
2471
+ ],
2472
+ "plurals": 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); }
2473
+ },
2474
+ "ur": {
2475
+ "name": "Urdu",
2476
+ "numbers": [
2477
+ 1,
2478
+ 2
2479
+ ],
2480
+ "plurals": function(n) { return Number(n != 1); }
2481
+ },
2482
+ "uz": {
2483
+ "name": "Uzbek",
2484
+ "numbers": [
2485
+ 1,
2486
+ 2
2487
+ ],
2488
+ "plurals": function(n) { return Number(n > 1); }
2489
+ },
2490
+ "vi": {
2491
+ "name": "Vietnamese",
2492
+ "numbers": [
2493
+ 1
2494
+ ],
2495
+ "plurals": function(n) { return 0; }
2496
+ },
2497
+ "wa": {
2498
+ "name": "Walloon",
2499
+ "numbers": [
2500
+ 1,
2501
+ 2
2502
+ ],
2503
+ "plurals": function(n) { return Number(n > 1); }
2504
+ },
2505
+ "wo": {
2506
+ "name": "Wolof",
2507
+ "numbers": [
2508
+ 1
2509
+ ],
2510
+ "plurals": function(n) { return 0; }
2511
+ },
2512
+ "yo": {
2513
+ "name": "Yoruba",
2514
+ "numbers": [
2515
+ 1,
2516
+ 2
2517
+ ],
2518
+ "plurals": function(n) { return Number(n != 1); }
2519
+ },
2520
+ "zh": {
2521
+ "name": "Chinese",
2522
+ "numbers": [
2523
+ 1
2524
+ ],
2525
+ "plurals": function(n) { return 0; }
2526
+ }
2527
+ },
2528
+
2529
+ // for demonstration only sl and ar is added but you can add your own pluralExtensions
2530
+ addRule: function(lng, obj) {
2531
+ pluralExtensions.rules[lng] = obj;
2532
+ },
2533
+
2534
+ setCurrentLng: function(lng) {
2535
+ if (!pluralExtensions.currentRule || pluralExtensions.currentRule.lng !== lng) {
2536
+ var parts = lng.split('-');
2537
+
2538
+ pluralExtensions.currentRule = {
2539
+ lng: lng,
2540
+ rule: pluralExtensions.rules[parts[0]]
2541
+ };
2542
+ }
2543
+ },
2544
+
2545
+ get: function(lng, count) {
2546
+ var parts = lng.split('-');
2547
+
2548
+ function getResult(l, c) {
2549
+ var ext;
2550
+ if (pluralExtensions.currentRule && pluralExtensions.currentRule.lng === lng) {
2551
+ ext = pluralExtensions.currentRule.rule;
2552
+ } else {
2553
+ ext = pluralExtensions.rules[l];
2554
+ }
2555
+ if (ext) {
2556
+ var i = ext.plurals(c);
2557
+ var number = ext.numbers[i];
2558
+ if (ext.numbers.length === 2 && ext.numbers[0] === 1) {
2559
+ if (number === 2) {
2560
+ number = -1; // regular plural
2561
+ } else if (number === 1) {
2562
+ number = 1; // singular
2563
+ }
2564
+ }//console.log(count + '-' + number);
2565
+ return number;
2566
+ } else {
2567
+ return c === 1 ? '1' : '-1';
2568
+ }
2569
+ }
2570
+
2571
+ return getResult(parts[0], count);
2572
+ }
2573
+
2574
+ };
2575
+ var postProcessors = {};
2576
+ var addPostProcessor = function(name, fc) {
2577
+ postProcessors[name] = fc;
2578
+ };
2579
+ // sprintf support
2580
+ var sprintf = (function() {
2581
+ function get_type(variable) {
2582
+ return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
2583
+ }
2584
+ function str_repeat(input, multiplier) {
2585
+ for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}
2586
+ return output.join('');
2587
+ }
2588
+
2589
+ var str_format = function() {
2590
+ if (!str_format.cache.hasOwnProperty(arguments[0])) {
2591
+ str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
2592
+ }
2593
+ return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
2594
+ };
2595
+
2596
+ str_format.format = function(parse_tree, argv) {
2597
+ var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
2598
+ for (i = 0; i < tree_length; i++) {
2599
+ node_type = get_type(parse_tree[i]);
2600
+ if (node_type === 'string') {
2601
+ output.push(parse_tree[i]);
2602
+ }
2603
+ else if (node_type === 'array') {
2604
+ match = parse_tree[i]; // convenience purposes only
2605
+ if (match[2]) { // keyword argument
2606
+ arg = argv[cursor];
2607
+ for (k = 0; k < match[2].length; k++) {
2608
+ if (!arg.hasOwnProperty(match[2][k])) {
2609
+ throw(sprintf('[sprintf] property "%s" does not exist', match[2][k]));
2610
+ }
2611
+ arg = arg[match[2][k]];
2612
+ }
2613
+ }
2614
+ else if (match[1]) { // positional argument (explicit)
2615
+ arg = argv[match[1]];
2616
+ }
2617
+ else { // positional argument (implicit)
2618
+ arg = argv[cursor++];
2619
+ }
2620
+
2621
+ if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
2622
+ throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));
2623
+ }
2624
+ switch (match[8]) {
2625
+ case 'b': arg = arg.toString(2); break;
2626
+ case 'c': arg = String.fromCharCode(arg); break;
2627
+ case 'd': arg = parseInt(arg, 10); break;
2628
+ case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
2629
+ case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
2630
+ case 'o': arg = arg.toString(8); break;
2631
+ case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
2632
+ case 'u': arg = Math.abs(arg); break;
2633
+ case 'x': arg = arg.toString(16); break;
2634
+ case 'X': arg = arg.toString(16).toUpperCase(); break;
2635
+ }
2636
+ arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
2637
+ pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
2638
+ pad_length = match[6] - String(arg).length;
2639
+ pad = match[6] ? str_repeat(pad_character, pad_length) : '';
2640
+ output.push(match[5] ? arg + pad : pad + arg);
2641
+ }
2642
+ }
2643
+ return output.join('');
2644
+ };
2645
+
2646
+ str_format.cache = {};
2647
+
2648
+ str_format.parse = function(fmt) {
2649
+ var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
2650
+ while (_fmt) {
2651
+ if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
2652
+ parse_tree.push(match[0]);
2653
+ }
2654
+ else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
2655
+ parse_tree.push('%');
2656
+ }
2657
+ else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
2658
+ if (match[2]) {
2659
+ arg_names |= 1;
2660
+ var field_list = [], replacement_field = match[2], field_match = [];
2661
+ if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
2662
+ field_list.push(field_match[1]);
2663
+ while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
2664
+ if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
2665
+ field_list.push(field_match[1]);
2666
+ }
2667
+ else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
2668
+ field_list.push(field_match[1]);
2669
+ }
2670
+ else {
2671
+ throw('[sprintf] huh?');
2672
+ }
2673
+ }
2674
+ }
2675
+ else {
2676
+ throw('[sprintf] huh?');
2677
+ }
2678
+ match[2] = field_list;
2679
+ }
2680
+ else {
2681
+ arg_names |= 2;
2682
+ }
2683
+ if (arg_names === 3) {
2684
+ throw('[sprintf] mixing positional and named placeholders is not (yet) supported');
2685
+ }
2686
+ parse_tree.push(match);
2687
+ }
2688
+ else {
2689
+ throw('[sprintf] huh?');
2690
+ }
2691
+ _fmt = _fmt.substring(match[0].length);
2692
+ }
2693
+ return parse_tree;
2694
+ };
2695
+
2696
+ return str_format;
2697
+ })();
2698
+
2699
+ var vsprintf = function(fmt, argv) {
2700
+ argv.unshift(fmt);
2701
+ return sprintf.apply(null, argv);
2702
+ };
2703
+
2704
+ addPostProcessor("sprintf", function(val, key, opts) {
2705
+ if (!opts.sprintf) return val;
2706
+
2707
+ if (Object.prototype.toString.apply(opts.sprintf) === '[object Array]') {
2708
+ return vsprintf(val, opts.sprintf);
2709
+ } else if (typeof opts.sprintf === 'object') {
2710
+ return sprintf(val, opts.sprintf);
2711
+ }
2712
+
2713
+ return val;
2714
+ });
2715
+ // public api interface
2716
+ i18n.init = init;
2717
+ i18n.setLng = setLng;
2718
+ i18n.preload = preload;
2719
+ i18n.addResourceBundle = addResourceBundle;
2720
+ i18n.removeResourceBundle = removeResourceBundle;
2721
+ i18n.loadNamespace = loadNamespace;
2722
+ i18n.loadNamespaces = loadNamespaces;
2723
+ i18n.setDefaultNamespace = setDefaultNamespace;
2724
+ i18n.t = translate;
2725
+ i18n.translate = translate;
2726
+ i18n.exists = exists;
2727
+ i18n.detectLanguage = f.detectLanguage;
2728
+ i18n.pluralExtensions = pluralExtensions;
2729
+ i18n.sync = sync;
2730
+ i18n.functions = f;
2731
+ i18n.lng = lng;
2732
+ i18n.addPostProcessor = addPostProcessor;
2733
+ i18n.options = o;
2734
+ })();