i18n.js 86 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332
  1. // i18next, v1.11.2
  2. // Copyright (c)2015 Jan Mühlemann (jamuhl).
  3. // Distributed under MIT license
  4. // http://i18next.com
  5. (function(root) {
  6. // add indexOf to non ECMA-262 standard compliant browsers
  7. if (!Array.prototype.indexOf) {
  8. Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
  9. "use strict";
  10. if (this == null) {
  11. throw new TypeError();
  12. }
  13. var t = Object(this);
  14. var len = t.length >>> 0;
  15. if (len === 0) {
  16. return -1;
  17. }
  18. var n = 0;
  19. if (arguments.length > 0) {
  20. n = Number(arguments[1]);
  21. if (n != n) { // shortcut for verifying if it's NaN
  22. n = 0;
  23. } else if (n != 0 && n != Infinity && n != -Infinity) {
  24. n = (n > 0 || -1) * Math.floor(Math.abs(n));
  25. }
  26. }
  27. if (n >= len) {
  28. return -1;
  29. }
  30. var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
  31. for (; k < len; k++) {
  32. if (k in t && t[k] === searchElement) {
  33. return k;
  34. }
  35. }
  36. return -1;
  37. }
  38. }
  39. // add lastIndexOf to non ECMA-262 standard compliant browsers
  40. if (!Array.prototype.lastIndexOf) {
  41. Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/) {
  42. "use strict";
  43. if (this == null) {
  44. throw new TypeError();
  45. }
  46. var t = Object(this);
  47. var len = t.length >>> 0;
  48. if (len === 0) {
  49. return -1;
  50. }
  51. var n = len;
  52. if (arguments.length > 1) {
  53. n = Number(arguments[1]);
  54. if (n != n) {
  55. n = 0;
  56. } else if (n != 0 && n != (1 / 0) && n != -(1 / 0)) {
  57. n = (n > 0 || -1) * Math.floor(Math.abs(n));
  58. }
  59. }
  60. var k = n >= 0 ? Math.min(n, len - 1) : len - Math.abs(n);
  61. for (; k >= 0; k--) {
  62. if (k in t && t[k] === searchElement) {
  63. return k;
  64. }
  65. }
  66. return -1;
  67. };
  68. }
  69. // Add string trim for IE8.
  70. if (typeof String.prototype.trim !== 'function') {
  71. String.prototype.trim = function() {
  72. return this.replace(/^\s+|\s+$/g, '');
  73. }
  74. }
  75. var $ = root.jQuery || root.Zepto
  76. , i18n = {}
  77. , resStore = {}
  78. , currentLng
  79. , replacementCounter = 0
  80. , languages = []
  81. , initialized = false
  82. , sync = {}
  83. , conflictReference = null;
  84. // Export the i18next object for **CommonJS**.
  85. // If we're not in CommonJS, add `i18n` to the
  86. // global object or to jquery.
  87. if (typeof module !== 'undefined' && module.exports) {
  88. module.exports = i18n;
  89. } else {
  90. if ($) {
  91. $.i18n = $.i18n || i18n;
  92. }
  93. if (root.i18n) {
  94. conflictReference = root.i18n;
  95. }
  96. root.i18n = i18n;
  97. }
  98. sync = {
  99. load: function(lngs, options, cb) {
  100. if (options.useLocalStorage) {
  101. sync._loadLocal(lngs, options, function(err, store) {
  102. var missingLngs = [];
  103. for (var i = 0, len = lngs.length; i < len; i++) {
  104. if (!store[lngs[i]]) missingLngs.push(lngs[i]);
  105. }
  106. if (missingLngs.length > 0) {
  107. sync._fetch(missingLngs, options, function(err, fetched) {
  108. f.extend(store, fetched);
  109. sync._storeLocal(fetched);
  110. cb(err, store);
  111. });
  112. } else {
  113. cb(err, store);
  114. }
  115. });
  116. } else {
  117. sync._fetch(lngs, options, function(err, store){
  118. cb(err, store);
  119. });
  120. }
  121. },
  122. _loadLocal: function(lngs, options, cb) {
  123. var store = {}
  124. , nowMS = new Date().getTime();
  125. if(window.localStorage) {
  126. var todo = lngs.length;
  127. f.each(lngs, function(key, lng) {
  128. var local = f.localStorage.getItem('res_' + lng);
  129. if (local) {
  130. local = JSON.parse(local);
  131. if (local.i18nStamp && local.i18nStamp + options.localStorageExpirationTime > nowMS) {
  132. store[lng] = local;
  133. }
  134. }
  135. todo--; // wait for all done befor callback
  136. if (todo === 0) cb(null, store);
  137. });
  138. }
  139. },
  140. _storeLocal: function(store) {
  141. if(window.localStorage) {
  142. for (var m in store) {
  143. store[m].i18nStamp = new Date().getTime();
  144. f.localStorage.setItem('res_' + m, JSON.stringify(store[m]));
  145. }
  146. }
  147. return;
  148. },
  149. _fetch: function(lngs, options, cb) {
  150. var ns = options.ns
  151. , store = {};
  152. if (!options.dynamicLoad) {
  153. var todo = ns.namespaces.length * lngs.length
  154. , errors;
  155. // load each file individual
  156. f.each(ns.namespaces, function(nsIndex, nsValue) {
  157. f.each(lngs, function(lngIndex, lngValue) {
  158. // Call this once our translation has returned.
  159. var loadComplete = function(err, data) {
  160. if (err) {
  161. errors = errors || [];
  162. errors.push(err);
  163. }
  164. store[lngValue] = store[lngValue] || {};
  165. store[lngValue][nsValue] = data;
  166. todo--; // wait for all done befor callback
  167. if (todo === 0) cb(errors, store);
  168. };
  169. if(typeof options.customLoad == 'function'){
  170. // Use the specified custom callback.
  171. options.customLoad(lngValue, nsValue, options, loadComplete);
  172. } else {
  173. //~ // Use our inbuilt sync.
  174. sync._fetchOne(lngValue, nsValue, options, loadComplete);
  175. }
  176. });
  177. });
  178. } else {
  179. // Call this once our translation has returned.
  180. var loadComplete = function(err, data) {
  181. cb(err, data);
  182. };
  183. if(typeof options.customLoad == 'function'){
  184. // Use the specified custom callback.
  185. options.customLoad(lngs, ns.namespaces, options, loadComplete);
  186. } else {
  187. var url = applyReplacement(options.resGetPath, { lng: lngs.join('+'), ns: ns.namespaces.join('+') });
  188. // load all needed stuff once
  189. f.ajax({
  190. url: url,
  191. cache: options.cache,
  192. success: function(data, status, xhr) {
  193. f.log('loaded: ' + url);
  194. loadComplete(null, data);
  195. },
  196. error : function(xhr, status, error) {
  197. f.log('failed loading: ' + url);
  198. loadComplete('failed loading resource.json error: ' + error);
  199. },
  200. dataType: "json",
  201. async : options.getAsync,
  202. timeout: options.ajaxTimeout
  203. });
  204. }
  205. }
  206. },
  207. _fetchOne: function(lng, ns, options, done) {
  208. var url = applyReplacement(options.resGetPath, { lng: lng, ns: ns });
  209. f.ajax({
  210. url: url,
  211. cache: options.cache,
  212. success: function(data, status, xhr) {
  213. f.log('loaded: ' + url);
  214. done(null, data);
  215. },
  216. error : function(xhr, status, error) {
  217. if ((status && status == 200) || (xhr && xhr.status && xhr.status == 200)) {
  218. // file loaded but invalid json, stop waste time !
  219. f.error('There is a typo in: ' + url);
  220. } else if ((status && status == 404) || (xhr && xhr.status && xhr.status == 404)) {
  221. f.log('Does not exist: ' + url);
  222. } else {
  223. var theStatus = status ? status : ((xhr && xhr.status) ? xhr.status : null);
  224. f.log(theStatus + ' when loading ' + url);
  225. }
  226. done(error, {});
  227. },
  228. dataType: "json",
  229. async : options.getAsync,
  230. timeout: options.ajaxTimeout,
  231. headers: options.headers
  232. });
  233. },
  234. postMissing: function(lng, ns, key, defaultValue, lngs) {
  235. var payload = {};
  236. payload[key] = defaultValue;
  237. var urls = [];
  238. if (o.sendMissingTo === 'fallback' && o.fallbackLng[0] !== false) {
  239. for (var i = 0; i < o.fallbackLng.length; i++) {
  240. urls.push({lng: o.fallbackLng[i], url: applyReplacement(o.resPostPath, { lng: o.fallbackLng[i], ns: ns })});
  241. }
  242. } else if (o.sendMissingTo === 'current' || (o.sendMissingTo === 'fallback' && o.fallbackLng[0] === false) ) {
  243. urls.push({lng: lng, url: applyReplacement(o.resPostPath, { lng: lng, ns: ns })});
  244. } else if (o.sendMissingTo === 'all') {
  245. for (var i = 0, l = lngs.length; i < l; i++) {
  246. urls.push({lng: lngs[i], url: applyReplacement(o.resPostPath, { lng: lngs[i], ns: ns })});
  247. }
  248. }
  249. for (var y = 0, len = urls.length; y < len; y++) {
  250. var item = urls[y];
  251. f.ajax({
  252. url: item.url,
  253. type: o.sendType,
  254. data: payload,
  255. success: function(data, status, xhr) {
  256. f.log('posted missing key \'' + key + '\' to: ' + item.url);
  257. // add key to resStore
  258. var keys = key.split('.');
  259. var x = 0;
  260. var value = resStore[item.lng][ns];
  261. while (keys[x]) {
  262. if (x === keys.length - 1) {
  263. value = value[keys[x]] = defaultValue;
  264. } else {
  265. value = value[keys[x]] = value[keys[x]] || {};
  266. }
  267. x++;
  268. }
  269. },
  270. error : function(xhr, status, error) {
  271. f.log('failed posting missing key \'' + key + '\' to: ' + item.url);
  272. },
  273. dataType: "json",
  274. async : o.postAsync,
  275. timeout: o.ajaxTimeout
  276. });
  277. }
  278. },
  279. reload: reload
  280. };
  281. // defaults
  282. var o = {
  283. lng: undefined,
  284. load: 'all',
  285. preload: [],
  286. lowerCaseLng: false,
  287. returnObjectTrees: false,
  288. fallbackLng: ['dev'],
  289. fallbackNS: [],
  290. detectLngQS: 'setLng',
  291. detectLngFromLocalStorage: false,
  292. ns: {
  293. namespaces: ['translation'],
  294. defaultNs: 'translation'
  295. },
  296. fallbackOnNull: true,
  297. fallbackOnEmpty: false,
  298. fallbackToDefaultNS: false,
  299. showKeyIfEmpty: false,
  300. nsseparator: ':',
  301. keyseparator: '.',
  302. selectorAttr: 'data-i18n',
  303. debug: false,
  304. resGetPath: 'locales/__lng__/__ns__.json',
  305. resPostPath: 'locales/add/__lng__/__ns__',
  306. getAsync: true,
  307. postAsync: true,
  308. resStore: undefined,
  309. useLocalStorage: false,
  310. localStorageExpirationTime: 7*24*60*60*1000,
  311. dynamicLoad: false,
  312. sendMissing: false,
  313. sendMissingTo: 'fallback', // current | all
  314. sendType: 'POST',
  315. interpolationPrefix: '__',
  316. interpolationSuffix: '__',
  317. defaultVariables: false,
  318. reusePrefix: '$t(',
  319. reuseSuffix: ')',
  320. pluralSuffix: '_plural',
  321. pluralNotFound: ['plural_not_found', Math.random()].join(''),
  322. contextNotFound: ['context_not_found', Math.random()].join(''),
  323. escapeInterpolation: false,
  324. indefiniteSuffix: '_indefinite',
  325. indefiniteNotFound: ['indefinite_not_found', Math.random()].join(''),
  326. setJqueryExt: true,
  327. defaultValueFromContent: true,
  328. useDataAttrOptions: false,
  329. cookieExpirationTime: undefined,
  330. useCookie: true,
  331. cookieName: 'i18next',
  332. cookieDomain: undefined,
  333. objectTreeKeyHandler: undefined,
  334. postProcess: undefined,
  335. parseMissingKey: undefined,
  336. missingKeyHandler: sync.postMissing,
  337. ajaxTimeout: 0,
  338. shortcutFunction: 'sprintf' // or: defaultValue
  339. };
  340. function _extend(target, source) {
  341. if (!source || typeof source === 'function') {
  342. return target;
  343. }
  344. for (var attr in source) { target[attr] = source[attr]; }
  345. return target;
  346. }
  347. function _deepExtend(target, source, overwrite) {
  348. for (var prop in source)
  349. if (prop in target) {
  350. // If we reached a leaf string in target or source then replace with source or skip depending on the 'overwrite' switch
  351. if (typeof target[prop] === 'string' || target[prop] instanceof String || typeof source[prop] === 'string' || source[prop] instanceof String) {
  352. if (overwrite) {
  353. target[prop] = source[prop];
  354. }
  355. } else {
  356. _deepExtend(target[prop], source[prop], overwrite);
  357. }
  358. } else {
  359. target[prop] = source[prop];
  360. }
  361. return target;
  362. }
  363. function _each(object, callback, args) {
  364. var name, i = 0,
  365. length = object.length,
  366. isObj = length === undefined || Object.prototype.toString.apply(object) !== '[object Array]' || typeof object === "function";
  367. if (args) {
  368. if (isObj) {
  369. for (name in object) {
  370. if (callback.apply(object[name], args) === false) {
  371. break;
  372. }
  373. }
  374. } else {
  375. for ( ; i < length; ) {
  376. if (callback.apply(object[i++], args) === false) {
  377. break;
  378. }
  379. }
  380. }
  381. // A special, fast, case for the most common use of each
  382. } else {
  383. if (isObj) {
  384. for (name in object) {
  385. if (callback.call(object[name], name, object[name]) === false) {
  386. break;
  387. }
  388. }
  389. } else {
  390. for ( ; i < length; ) {
  391. if (callback.call(object[i], i, object[i++]) === false) {
  392. break;
  393. }
  394. }
  395. }
  396. }
  397. return object;
  398. }
  399. var _entityMap = {
  400. "&": "&amp;",
  401. "<": "&lt;",
  402. ">": "&gt;",
  403. '"': '&quot;',
  404. "'": '&#39;',
  405. "/": '&#x2F;'
  406. };
  407. function _escape(data) {
  408. if (typeof data === 'string') {
  409. return data.replace(/[&<>"'\/]/g, function (s) {
  410. return _entityMap[s];
  411. });
  412. }else{
  413. return data;
  414. }
  415. }
  416. function _ajax(options) {
  417. // v0.5.0 of https://github.com/goloroden/http.js
  418. var getXhr = function (callback) {
  419. // Use the native XHR object if the browser supports it.
  420. if (window.XMLHttpRequest) {
  421. return callback(null, new XMLHttpRequest());
  422. } else if (window.ActiveXObject) {
  423. // In Internet Explorer check for ActiveX versions of the XHR object.
  424. try {
  425. return callback(null, new ActiveXObject("Msxml2.XMLHTTP"));
  426. } catch (e) {
  427. return callback(null, new ActiveXObject("Microsoft.XMLHTTP"));
  428. }
  429. }
  430. // If no XHR support was found, throw an error.
  431. return callback(new Error());
  432. };
  433. var encodeUsingUrlEncoding = function (data) {
  434. if(typeof data === 'string') {
  435. return data;
  436. }
  437. var result = [];
  438. for(var dataItem in data) {
  439. if(data.hasOwnProperty(dataItem)) {
  440. result.push(encodeURIComponent(dataItem) + '=' + encodeURIComponent(data[dataItem]));
  441. }
  442. }
  443. return result.join('&');
  444. };
  445. var utf8 = function (text) {
  446. text = text.replace(/\r\n/g, '\n');
  447. var result = '';
  448. for(var i = 0; i < text.length; i++) {
  449. var c = text.charCodeAt(i);
  450. if(c < 128) {
  451. result += String.fromCharCode(c);
  452. } else if((c > 127) && (c < 2048)) {
  453. result += String.fromCharCode((c >> 6) | 192);
  454. result += String.fromCharCode((c & 63) | 128);
  455. } else {
  456. result += String.fromCharCode((c >> 12) | 224);
  457. result += String.fromCharCode(((c >> 6) & 63) | 128);
  458. result += String.fromCharCode((c & 63) | 128);
  459. }
  460. }
  461. return result;
  462. };
  463. var base64 = function (text) {
  464. var keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
  465. text = utf8(text);
  466. var result = '',
  467. chr1, chr2, chr3,
  468. enc1, enc2, enc3, enc4,
  469. i = 0;
  470. do {
  471. chr1 = text.charCodeAt(i++);
  472. chr2 = text.charCodeAt(i++);
  473. chr3 = text.charCodeAt(i++);
  474. enc1 = chr1 >> 2;
  475. enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
  476. enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
  477. enc4 = chr3 & 63;
  478. if(isNaN(chr2)) {
  479. enc3 = enc4 = 64;
  480. } else if(isNaN(chr3)) {
  481. enc4 = 64;
  482. }
  483. result +=
  484. keyStr.charAt(enc1) +
  485. keyStr.charAt(enc2) +
  486. keyStr.charAt(enc3) +
  487. keyStr.charAt(enc4);
  488. chr1 = chr2 = chr3 = '';
  489. enc1 = enc2 = enc3 = enc4 = '';
  490. } while(i < text.length);
  491. return result;
  492. };
  493. var mergeHeaders = function () {
  494. // Use the first header object as base.
  495. var result = arguments[0];
  496. // Iterate through the remaining header objects and add them.
  497. for(var i = 1; i < arguments.length; i++) {
  498. var currentHeaders = arguments[i];
  499. for(var header in currentHeaders) {
  500. if(currentHeaders.hasOwnProperty(header)) {
  501. result[header] = currentHeaders[header];
  502. }
  503. }
  504. }
  505. // Return the merged headers.
  506. return result;
  507. };
  508. var ajax = function (method, url, options, callback) {
  509. // Adjust parameters.
  510. if(typeof options === 'function') {
  511. callback = options;
  512. options = {};
  513. }
  514. // Set default parameter values.
  515. options.cache = options.cache || false;
  516. options.data = options.data || {};
  517. options.headers = options.headers || {};
  518. options.jsonp = options.jsonp || false;
  519. options.async = options.async === undefined ? true : options.async;
  520. // Merge the various header objects.
  521. var headers = mergeHeaders({
  522. 'accept': '*/*',
  523. 'content-type': 'application/x-www-form-urlencoded;charset=UTF-8'
  524. }, ajax.headers, options.headers);
  525. // Encode the data according to the content-type.
  526. var payload;
  527. if (headers['content-type'] === 'application/json') {
  528. payload = JSON.stringify(options.data);
  529. } else {
  530. payload = encodeUsingUrlEncoding(options.data);
  531. }
  532. // Specially prepare GET requests: Setup the query string, handle caching and make a JSONP call
  533. // if neccessary.
  534. if(method === 'GET') {
  535. // Setup the query string.
  536. var queryString = [];
  537. if(payload) {
  538. queryString.push(payload);
  539. payload = null;
  540. }
  541. // Handle caching.
  542. if(!options.cache) {
  543. queryString.push('_=' + (new Date()).getTime());
  544. }
  545. // If neccessary prepare the query string for a JSONP call.
  546. if(options.jsonp) {
  547. queryString.push('callback=' + options.jsonp);
  548. queryString.push('jsonp=' + options.jsonp);
  549. }
  550. // Merge the query string and attach it to the url.
  551. queryString = queryString.join('&');
  552. if (queryString.length > 1) {
  553. if (url.indexOf('?') > -1) {
  554. url += '&' + queryString;
  555. } else {
  556. url += '?' + queryString;
  557. }
  558. }
  559. // Make a JSONP call if neccessary.
  560. if(options.jsonp) {
  561. var head = document.getElementsByTagName('head')[0];
  562. var script = document.createElement('script');
  563. script.type = 'text/javascript';
  564. script.src = url;
  565. head.appendChild(script);
  566. return;
  567. }
  568. }
  569. // Since we got here, it is no JSONP request, so make a normal XHR request.
  570. getXhr(function (err, xhr) {
  571. if(err) return callback(err);
  572. // Open the request.
  573. xhr.open(method, url, options.async);
  574. // Set the request headers.
  575. for(var header in headers) {
  576. if(headers.hasOwnProperty(header)) {
  577. xhr.setRequestHeader(header, headers[header]);
  578. }
  579. }
  580. // Handle the request events.
  581. xhr.onreadystatechange = function () {
  582. if(xhr.readyState === 4) {
  583. var data = xhr.responseText || '';
  584. // If no callback is given, return.
  585. if(!callback) {
  586. return;
  587. }
  588. // Return an object that provides access to the data as text and JSON.
  589. callback(xhr.status, {
  590. text: function () {
  591. return data;
  592. },
  593. json: function () {
  594. try {
  595. return JSON.parse(data)
  596. } catch (e) {
  597. f.error('Can not parse JSON. URL: ' + url);
  598. return {};
  599. }
  600. }
  601. });
  602. }
  603. };
  604. // Actually send the XHR request.
  605. xhr.send(payload);
  606. });
  607. };
  608. // Define the external interface.
  609. var http = {
  610. authBasic: function (username, password) {
  611. ajax.headers['Authorization'] = 'Basic ' + base64(username + ':' + password);
  612. },
  613. connect: function (url, options, callback) {
  614. return ajax('CONNECT', url, options, callback);
  615. },
  616. del: function (url, options, callback) {
  617. return ajax('DELETE', url, options, callback);
  618. },
  619. get: function (url, options, callback) {
  620. return ajax('GET', url, options, callback);
  621. },
  622. head: function (url, options, callback) {
  623. return ajax('HEAD', url, options, callback);
  624. },
  625. headers: function (headers) {
  626. ajax.headers = headers || {};
  627. },
  628. isAllowed: function (url, verb, callback) {
  629. this.options(url, function (status, data) {
  630. callback(data.text().indexOf(verb) !== -1);
  631. });
  632. },
  633. options: function (url, options, callback) {
  634. return ajax('OPTIONS', url, options, callback);
  635. },
  636. patch: function (url, options, callback) {
  637. return ajax('PATCH', url, options, callback);
  638. },
  639. post: function (url, options, callback) {
  640. return ajax('POST', url, options, callback);
  641. },
  642. put: function (url, options, callback) {
  643. return ajax('PUT', url, options, callback);
  644. },
  645. trace: function (url, options, callback) {
  646. return ajax('TRACE', url, options, callback);
  647. }
  648. };
  649. var methode = options.type ? options.type.toLowerCase() : 'get';
  650. http[methode](options.url, options, function (status, data) {
  651. // file: protocol always gives status code 0, so check for data
  652. if (status === 200 || (status === 0 && data.text())) {
  653. options.success(data.json(), status, null);
  654. } else {
  655. options.error(data.text(), status, null);
  656. }
  657. });
  658. }
  659. var _cookie = {
  660. create: function(name,value,minutes,domain) {
  661. var expires;
  662. if (minutes) {
  663. var date = new Date();
  664. date.setTime(date.getTime()+(minutes*60*1000));
  665. expires = "; expires="+date.toGMTString();
  666. }
  667. else expires = "";
  668. domain = (domain)? "domain="+domain+";" : "";
  669. document.cookie = name+"="+value+expires+";"+domain+"path=/";
  670. },
  671. read: function(name) {
  672. var nameEQ = name + "=";
  673. var ca = document.cookie.split(';');
  674. for(var i=0;i < ca.length;i++) {
  675. var c = ca[i];
  676. while (c.charAt(0)==' ') c = c.substring(1,c.length);
  677. if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length,c.length);
  678. }
  679. return null;
  680. },
  681. remove: function(name) {
  682. this.create(name,"",-1);
  683. }
  684. };
  685. var cookie_noop = {
  686. create: function(name,value,minutes,domain) {},
  687. read: function(name) { return null; },
  688. remove: function(name) {}
  689. };
  690. // move dependent functions to a container so that
  691. // they can be overriden easier in no jquery environment (node.js)
  692. var f = {
  693. extend: $ ? $.extend : _extend,
  694. deepExtend: _deepExtend,
  695. each: $ ? $.each : _each,
  696. ajax: $ ? $.ajax : (typeof document !== 'undefined' ? _ajax : function() {}),
  697. cookie: typeof document !== 'undefined' ? _cookie : cookie_noop,
  698. detectLanguage: detectLanguage,
  699. escape: _escape,
  700. log: function(str) {
  701. if (o.debug && typeof console !== "undefined") console.log(str);
  702. },
  703. error: function(str) {
  704. if (typeof console !== "undefined") console.error(str);
  705. },
  706. getCountyIndexOfLng: function(lng) {
  707. var lng_index = 0;
  708. if (lng === 'nb-NO' || lng === 'nn-NO' || lng === 'nb-no' || lng === 'nn-no') lng_index = 1;
  709. return lng_index;
  710. },
  711. toLanguages: function(lng, fallbackLng) {
  712. var log = this.log;
  713. fallbackLng = fallbackLng || o.fallbackLng;
  714. if (typeof fallbackLng === 'string')
  715. fallbackLng = [fallbackLng];
  716. function applyCase(l) {
  717. var ret = l;
  718. if (typeof l === 'string' && l.indexOf('-') > -1) {
  719. var parts = l.split('-');
  720. ret = o.lowerCaseLng ?
  721. parts[0].toLowerCase() + '-' + parts[1].toLowerCase() :
  722. parts[0].toLowerCase() + '-' + parts[1].toUpperCase();
  723. } else {
  724. ret = o.lowerCaseLng ? l.toLowerCase() : l;
  725. }
  726. return ret;
  727. }
  728. var languages = [];
  729. var whitelist = o.lngWhitelist || false;
  730. var addLanguage = function(language){
  731. //reject langs not whitelisted
  732. if(!whitelist || whitelist.indexOf(language) > -1){
  733. languages.push(language);
  734. }else{
  735. log('rejecting non-whitelisted language: ' + language);
  736. }
  737. };
  738. if (typeof lng === 'string' && lng.indexOf('-') > -1) {
  739. var parts = lng.split('-');
  740. if (o.load !== 'unspecific') addLanguage(applyCase(lng));
  741. if (o.load !== 'current') addLanguage(applyCase(parts[this.getCountyIndexOfLng(lng)]));
  742. } else {
  743. addLanguage(applyCase(lng));
  744. }
  745. for (var i = 0; i < fallbackLng.length; i++) {
  746. if (languages.indexOf(fallbackLng[i]) === -1 && fallbackLng[i]) languages.push(applyCase(fallbackLng[i]));
  747. }
  748. return languages;
  749. },
  750. regexEscape: function(str) {
  751. return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
  752. },
  753. regexReplacementEscape: function(strOrFn) {
  754. if (typeof strOrFn === 'string') {
  755. return strOrFn.replace(/\$/g, "$$$$");
  756. } else {
  757. return strOrFn;
  758. }
  759. },
  760. localStorage: {
  761. setItem: function(key, value) {
  762. if (window.localStorage) {
  763. try {
  764. window.localStorage.setItem(key, value);
  765. } catch (e) {
  766. f.log('failed to set value for key "' + key + '" to localStorage.');
  767. }
  768. }
  769. },
  770. getItem: function(key, value) {
  771. if (window.localStorage) {
  772. try {
  773. return window.localStorage.getItem(key, value);
  774. } catch (e) {
  775. f.log('failed to get value for key "' + key + '" from localStorage.');
  776. return undefined;
  777. }
  778. }
  779. }
  780. }
  781. };
  782. function init(options, cb) {
  783. if (typeof options === 'function') {
  784. cb = options;
  785. options = {};
  786. }
  787. options = options || {};
  788. // override defaults with passed in options
  789. f.extend(o, options);
  790. delete o.fixLng; /* passed in each time */
  791. // override functions: .log(), .detectLanguage(), etc
  792. if (o.functions) {
  793. delete o.functions;
  794. f.extend(f, options.functions);
  795. }
  796. // create namespace object if namespace is passed in as string
  797. if (typeof o.ns == 'string') {
  798. o.ns = { namespaces: [o.ns], defaultNs: o.ns};
  799. }
  800. // fallback namespaces
  801. if (typeof o.fallbackNS == 'string') {
  802. o.fallbackNS = [o.fallbackNS];
  803. }
  804. // fallback languages
  805. if (typeof o.fallbackLng == 'string' || typeof o.fallbackLng == 'boolean') {
  806. o.fallbackLng = [o.fallbackLng];
  807. }
  808. // escape prefix/suffix
  809. o.interpolationPrefixEscaped = f.regexEscape(o.interpolationPrefix);
  810. o.interpolationSuffixEscaped = f.regexEscape(o.interpolationSuffix);
  811. if (!o.lng) o.lng = f.detectLanguage();
  812. languages = f.toLanguages(o.lng);
  813. currentLng = languages[0];
  814. f.log('currentLng set to: ' + currentLng);
  815. if (o.useCookie && f.cookie.read(o.cookieName) !== currentLng){ //cookie is unset or invalid
  816. f.cookie.create(o.cookieName, currentLng, o.cookieExpirationTime, o.cookieDomain);
  817. }
  818. if (o.detectLngFromLocalStorage && typeof document !== 'undefined' && window.localStorage) {
  819. f.localStorage.setItem('i18next_lng', currentLng);
  820. }
  821. var lngTranslate = translate;
  822. if (options.fixLng) {
  823. lngTranslate = function(key, options) {
  824. options = options || {};
  825. options.lng = options.lng || lngTranslate.lng;
  826. return translate(key, options);
  827. };
  828. lngTranslate.lng = currentLng;
  829. }
  830. pluralExtensions.setCurrentLng(currentLng);
  831. // add JQuery extensions
  832. if ($ && o.setJqueryExt) {
  833. addJqueryFunct && addJqueryFunct();
  834. } else {
  835. addJqueryLikeFunctionality && addJqueryLikeFunctionality();
  836. }
  837. // jQuery deferred
  838. var deferred;
  839. if ($ && $.Deferred) {
  840. deferred = $.Deferred();
  841. }
  842. // return immidiatly if res are passed in
  843. if (o.resStore) {
  844. resStore = o.resStore;
  845. initialized = true;
  846. if (cb) cb(null, lngTranslate);
  847. if (deferred) deferred.resolve(lngTranslate);
  848. if (deferred) return deferred.promise();
  849. return;
  850. }
  851. // languages to load
  852. var lngsToLoad = f.toLanguages(o.lng);
  853. if (typeof o.preload === 'string') o.preload = [o.preload];
  854. for (var i = 0, l = o.preload.length; i < l; i++) {
  855. var pres = f.toLanguages(o.preload[i]);
  856. for (var y = 0, len = pres.length; y < len; y++) {
  857. if (lngsToLoad.indexOf(pres[y]) < 0) {
  858. lngsToLoad.push(pres[y]);
  859. }
  860. }
  861. }
  862. // else load them
  863. i18n.sync.load(lngsToLoad, o, function(err, store) {
  864. resStore = store;
  865. initialized = true;
  866. if (cb) cb(err, lngTranslate);
  867. if (deferred) (!err ? deferred.resolve : deferred.reject)(err || lngTranslate);
  868. });
  869. if (deferred) return deferred.promise();
  870. }
  871. function isInitialized() {
  872. return initialized;
  873. }
  874. function preload(lngs, cb) {
  875. if (typeof lngs === 'string') lngs = [lngs];
  876. for (var i = 0, l = lngs.length; i < l; i++) {
  877. if (o.preload.indexOf(lngs[i]) < 0) {
  878. o.preload.push(lngs[i]);
  879. }
  880. }
  881. return init(cb);
  882. }
  883. function addResourceBundle(lng, ns, resources, deep, overwrite) {
  884. if (typeof ns !== 'string') {
  885. resources = ns;
  886. ns = o.ns.defaultNs;
  887. } else if (o.ns.namespaces.indexOf(ns) < 0) {
  888. o.ns.namespaces.push(ns);
  889. }
  890. resStore[lng] = resStore[lng] || {};
  891. resStore[lng][ns] = resStore[lng][ns] || {};
  892. if (deep) {
  893. f.deepExtend(resStore[lng][ns], resources, overwrite);
  894. } else {
  895. f.extend(resStore[lng][ns], resources);
  896. }
  897. if (o.useLocalStorage) {
  898. sync._storeLocal(resStore);
  899. }
  900. }
  901. function hasResourceBundle(lng, ns) {
  902. if (typeof ns !== 'string') {
  903. ns = o.ns.defaultNs;
  904. }
  905. resStore[lng] = resStore[lng] || {};
  906. var res = resStore[lng][ns] || {};
  907. var hasValues = false;
  908. for(var prop in res) {
  909. if (res.hasOwnProperty(prop)) {
  910. hasValues = true;
  911. }
  912. }
  913. return hasValues;
  914. }
  915. function getResourceBundle(lng, ns) {
  916. if (typeof ns !== 'string') {
  917. ns = o.ns.defaultNs;
  918. }
  919. resStore[lng] = resStore[lng] || {};
  920. return f.extend({}, resStore[lng][ns]);
  921. }
  922. function removeResourceBundle(lng, ns) {
  923. if (typeof ns !== 'string') {
  924. ns = o.ns.defaultNs;
  925. }
  926. resStore[lng] = resStore[lng] || {};
  927. resStore[lng][ns] = {};
  928. if (o.useLocalStorage) {
  929. sync._storeLocal(resStore);
  930. }
  931. }
  932. function addResource(lng, ns, key, value) {
  933. if (typeof ns !== 'string') {
  934. resource = ns;
  935. ns = o.ns.defaultNs;
  936. } else if (o.ns.namespaces.indexOf(ns) < 0) {
  937. o.ns.namespaces.push(ns);
  938. }
  939. resStore[lng] = resStore[lng] || {};
  940. resStore[lng][ns] = resStore[lng][ns] || {};
  941. var keys = key.split(o.keyseparator);
  942. var x = 0;
  943. var node = resStore[lng][ns];
  944. var origRef = node;
  945. while (keys[x]) {
  946. if (x == keys.length - 1)
  947. node[keys[x]] = value;
  948. else {
  949. if (node[keys[x]] == null)
  950. node[keys[x]] = {};
  951. node = node[keys[x]];
  952. }
  953. x++;
  954. }
  955. if (o.useLocalStorage) {
  956. sync._storeLocal(resStore);
  957. }
  958. }
  959. function addResources(lng, ns, resources) {
  960. if (typeof ns !== 'string') {
  961. resources = ns;
  962. ns = o.ns.defaultNs;
  963. } else if (o.ns.namespaces.indexOf(ns) < 0) {
  964. o.ns.namespaces.push(ns);
  965. }
  966. for (var m in resources) {
  967. if (typeof resources[m] === 'string') addResource(lng, ns, m, resources[m]);
  968. }
  969. }
  970. function setDefaultNamespace(ns) {
  971. o.ns.defaultNs = ns;
  972. }
  973. function loadNamespace(namespace, cb) {
  974. loadNamespaces([namespace], cb);
  975. }
  976. function loadNamespaces(namespaces, cb) {
  977. var opts = {
  978. dynamicLoad: o.dynamicLoad,
  979. resGetPath: o.resGetPath,
  980. getAsync: o.getAsync,
  981. customLoad: o.customLoad,
  982. ns: { namespaces: namespaces, defaultNs: ''} /* new namespaces to load */
  983. };
  984. // languages to load
  985. var lngsToLoad = f.toLanguages(o.lng);
  986. if (typeof o.preload === 'string') o.preload = [o.preload];
  987. for (var i = 0, l = o.preload.length; i < l; i++) {
  988. var pres = f.toLanguages(o.preload[i]);
  989. for (var y = 0, len = pres.length; y < len; y++) {
  990. if (lngsToLoad.indexOf(pres[y]) < 0) {
  991. lngsToLoad.push(pres[y]);
  992. }
  993. }
  994. }
  995. // check if we have to load
  996. var lngNeedLoad = [];
  997. for (var a = 0, lenA = lngsToLoad.length; a < lenA; a++) {
  998. var needLoad = false;
  999. var resSet = resStore[lngsToLoad[a]];
  1000. if (resSet) {
  1001. for (var b = 0, lenB = namespaces.length; b < lenB; b++) {
  1002. if (!resSet[namespaces[b]]) needLoad = true;
  1003. }
  1004. } else {
  1005. needLoad = true;
  1006. }
  1007. if (needLoad) lngNeedLoad.push(lngsToLoad[a]);
  1008. }
  1009. if (lngNeedLoad.length) {
  1010. i18n.sync._fetch(lngNeedLoad, opts, function(err, store) {
  1011. var todo = namespaces.length * lngNeedLoad.length;
  1012. // load each file individual
  1013. f.each(namespaces, function(nsIndex, nsValue) {
  1014. // append namespace to namespace array
  1015. if (o.ns.namespaces.indexOf(nsValue) < 0) {
  1016. o.ns.namespaces.push(nsValue);
  1017. }
  1018. f.each(lngNeedLoad, function(lngIndex, lngValue) {
  1019. resStore[lngValue] = resStore[lngValue] || {};
  1020. resStore[lngValue][nsValue] = store[lngValue][nsValue];
  1021. todo--; // wait for all done befor callback
  1022. if (todo === 0 && cb) {
  1023. if (o.useLocalStorage) i18n.sync._storeLocal(resStore);
  1024. cb();
  1025. }
  1026. });
  1027. });
  1028. });
  1029. } else {
  1030. if (cb) cb();
  1031. }
  1032. }
  1033. function setLng(lng, options, cb) {
  1034. if (typeof options === 'function') {
  1035. cb = options;
  1036. options = {};
  1037. } else if (!options) {
  1038. options = {};
  1039. }
  1040. options.lng = lng;
  1041. return init(options, cb);
  1042. }
  1043. function lng() {
  1044. return currentLng;
  1045. }
  1046. function dir() {
  1047. var rtlLangs = [ "ar", "shu", "sqr", "ssh", "xaa", "yhd", "yud", "aao", "abh", "abv", "acm",
  1048. "acq", "acw", "acx", "acy", "adf", "ads", "aeb", "aec", "afb", "ajp", "apc", "apd", "arb",
  1049. "arq", "ars", "ary", "arz", "auz", "avl", "ayh", "ayl", "ayn", "ayp", "bbz", "pga", "he",
  1050. "iw", "ps", "pbt", "pbu", "pst", "prp", "prd", "ur", "ydd", "yds", "yih", "ji", "yi", "hbo",
  1051. "men", "xmn", "fa", "jpr", "peo", "pes", "prs", "dv", "sam"
  1052. ];
  1053. if ( rtlLangs.some( function( lang ) {
  1054. return new RegExp( '^' + lang ).test( currentLng );
  1055. } ) ) {
  1056. return 'rtl';
  1057. }
  1058. return 'ltr';
  1059. }
  1060. function reload(cb) {
  1061. resStore = {};
  1062. setLng(currentLng, cb);
  1063. }
  1064. function noConflict() {
  1065. window.i18next = window.i18n;
  1066. if (conflictReference) {
  1067. window.i18n = conflictReference;
  1068. } else {
  1069. delete window.i18n;
  1070. }
  1071. }
  1072. function addJqueryFunct() {
  1073. // $.t shortcut
  1074. $.t = $.t || translate;
  1075. function parse(ele, key, options) {
  1076. if (key.length === 0) return;
  1077. var attr = 'text';
  1078. if (key.indexOf('[') === 0) {
  1079. var parts = key.split(']');
  1080. key = parts[1];
  1081. attr = parts[0].substr(1, parts[0].length-1);
  1082. }
  1083. if (key.indexOf(';') === key.length-1) {
  1084. key = key.substr(0, key.length-2);
  1085. }
  1086. var optionsToUse;
  1087. if (attr === 'html') {
  1088. optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options;
  1089. ele.html($.t(key, optionsToUse));
  1090. } else if (attr === 'text') {
  1091. optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.text() }, options) : options;
  1092. ele.text($.t(key, optionsToUse));
  1093. } else if (attr === 'prepend') {
  1094. optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options;
  1095. ele.prepend($.t(key, optionsToUse));
  1096. } else if (attr === 'append') {
  1097. optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options;
  1098. ele.append($.t(key, optionsToUse));
  1099. } else if (attr.indexOf("data-") === 0) {
  1100. var dataAttr = attr.substr(("data-").length);
  1101. optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.data(dataAttr) }, options) : options;
  1102. var translated = $.t(key, optionsToUse);
  1103. //we change into the data cache
  1104. ele.data(dataAttr, translated);
  1105. //we change into the dom
  1106. ele.attr(attr, translated);
  1107. } else {
  1108. optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.attr(attr) }, options) : options;
  1109. ele.attr(attr, $.t(key, optionsToUse));
  1110. }
  1111. }
  1112. function localize(ele, options) {
  1113. var key = ele.attr(o.selectorAttr);
  1114. if (!key && typeof key !== 'undefined' && key !== false) key = ele.text() || ele.val();
  1115. if (!key) return;
  1116. var target = ele
  1117. , targetSelector = ele.data("i18n-target");
  1118. if (targetSelector) {
  1119. target = ele.find(targetSelector) || ele;
  1120. }
  1121. if (!options && o.useDataAttrOptions === true) {
  1122. options = ele.data("i18n-options");
  1123. }
  1124. options = options || {};
  1125. if (key.indexOf(';') >= 0) {
  1126. var keys = key.split(';');
  1127. $.each(keys, function(m, k) {
  1128. if (k !== '') parse(target, k, options);
  1129. });
  1130. } else {
  1131. parse(target, key, options);
  1132. }
  1133. if (o.useDataAttrOptions === true) {
  1134. var clone = $.extend({lng: 'non', lngs: [], _origLng: 'non'}, options);
  1135. delete clone.lng;
  1136. delete clone.lngs;
  1137. delete clone._origLng;
  1138. ele.data("i18n-options", clone);
  1139. }
  1140. }
  1141. // fn
  1142. $.fn.i18n = function (options) {
  1143. return this.each(function() {
  1144. // localize element itself
  1145. localize($(this), options);
  1146. // localize childs
  1147. var elements = $(this).find('[' + o.selectorAttr + ']');
  1148. elements.each(function() {
  1149. localize($(this), options);
  1150. });
  1151. });
  1152. };
  1153. }
  1154. function addJqueryLikeFunctionality() {
  1155. function parse(ele, key, options) {
  1156. if (key.length === 0) return;
  1157. var attr = 'text';
  1158. if (key.indexOf('[') === 0) {
  1159. var parts = key.split(']');
  1160. key = parts[1];
  1161. attr = parts[0].substr(1, parts[0].length-1);
  1162. }
  1163. if (key.indexOf(';') === key.length-1) {
  1164. key = key.substr(0, key.length-2);
  1165. }
  1166. if (attr === 'html') {
  1167. ele.innerHTML = translate(key, options);
  1168. } else if (attr === 'text') {
  1169. ele.textContent = translate(key, options);
  1170. } else if (attr === 'prepend') {
  1171. ele.insertAdjacentHTML(translate(key, options), 'afterbegin');
  1172. } else if (attr === 'append') {
  1173. ele.insertAdjacentHTML(translate(key, options), 'beforeend');
  1174. } else {
  1175. ele.setAttribute(attr, translate(key, options));
  1176. }
  1177. }
  1178. function localize(ele, options) {
  1179. var key = ele.getAttribute(o.selectorAttr);
  1180. if (!key && typeof key !== 'undefined' && key !== false) key = ele.textContent || ele.value;
  1181. if (!key) return;
  1182. var target = ele
  1183. , targetSelector = ele.getAttribute("i18n-target");
  1184. if (targetSelector) {
  1185. target = ele.querySelector(targetSelector) || ele;
  1186. }
  1187. if (key.indexOf(';') >= 0) {
  1188. var keys = key.split(';'), index = 0, length = keys.length;
  1189. for ( ; index < length; index++) {
  1190. if (keys[index] !== '') parse(target, keys[index], options);
  1191. }
  1192. } else {
  1193. parse(target, key, options);
  1194. }
  1195. }
  1196. // fn
  1197. i18n.translateObject = function (object, options) {
  1198. // localize childs
  1199. var elements = object.querySelectorAll('[' + o.selectorAttr + ']');
  1200. var index = 0, length = elements.length;
  1201. for ( ; index < length; index++) {
  1202. localize(elements[index], options);
  1203. }
  1204. };
  1205. }
  1206. function applyReplacement(str, replacementHash, nestedKey, options) {
  1207. if (!str) return str;
  1208. options = options || replacementHash; // first call uses replacement hash combined with options
  1209. if (str.indexOf(options.interpolationPrefix || o.interpolationPrefix) < 0) return str;
  1210. var prefix = options.interpolationPrefix ? f.regexEscape(options.interpolationPrefix) : o.interpolationPrefixEscaped
  1211. , suffix = options.interpolationSuffix ? f.regexEscape(options.interpolationSuffix) : o.interpolationSuffixEscaped
  1212. , keyseparator = options.keyseparator || o.keyseparator
  1213. , unEscapingSuffix = 'HTML'+suffix;
  1214. var hash = replacementHash.replace && typeof replacementHash.replace === 'object' ? replacementHash.replace : replacementHash;
  1215. var replacementRegex = new RegExp([prefix, '(.+?)', '(HTML)?', suffix].join(''), 'g');
  1216. var escapeInterpolation = options.escapeInterpolation || o.escapeInterpolation;
  1217. return str.replace(replacementRegex, function (wholeMatch, keyMatch, htmlMatched) {
  1218. // Check for recursive matches of object
  1219. var objectMatching = hash;
  1220. var keyLeaf = keyMatch;
  1221. while (keyLeaf.indexOf(keyseparator) >= 0 && typeof objectMatching === 'object' && objectMatching) {
  1222. var propName = keyLeaf.slice(0, keyLeaf.indexOf(keyseparator));
  1223. keyLeaf = keyLeaf.slice(keyLeaf.indexOf(keyseparator) + 1);
  1224. objectMatching = objectMatching[propName];
  1225. }
  1226. if (objectMatching && typeof objectMatching === 'object' && objectMatching.hasOwnProperty(keyLeaf)) {
  1227. var value = objectMatching[keyLeaf];
  1228. if (escapeInterpolation && !htmlMatched) {
  1229. return f.escape(objectMatching[keyLeaf]);
  1230. } else {
  1231. return objectMatching[keyLeaf];
  1232. }
  1233. } else {
  1234. return wholeMatch;
  1235. }
  1236. });
  1237. }
  1238. // append it to functions
  1239. f.applyReplacement = applyReplacement;
  1240. function applyReuse(translated, options) {
  1241. var comma = ',';
  1242. var options_open = '{';
  1243. var options_close = '}';
  1244. var opts = f.extend({}, options);
  1245. delete opts.postProcess;
  1246. delete opts.isFallbackLookup;
  1247. while (translated.indexOf(o.reusePrefix) != -1) {
  1248. replacementCounter++;
  1249. if (replacementCounter > o.maxRecursion) { break; } // safety net for too much recursion
  1250. var index_of_opening = translated.lastIndexOf(o.reusePrefix);
  1251. var index_of_end_of_closing = translated.indexOf(o.reuseSuffix, index_of_opening) + o.reuseSuffix.length;
  1252. var token = translated.substring(index_of_opening, index_of_end_of_closing);
  1253. var token_without_symbols = token.replace(o.reusePrefix, '').replace(o.reuseSuffix, '');
  1254. if (index_of_end_of_closing <= index_of_opening) {
  1255. f.error('there is an missing closing in following translation value', translated);
  1256. return '';
  1257. }
  1258. if (token_without_symbols.indexOf(comma) != -1) {
  1259. var index_of_token_end_of_closing = token_without_symbols.indexOf(comma);
  1260. 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) {
  1261. var index_of_opts_opening = token_without_symbols.indexOf(options_open, index_of_token_end_of_closing);
  1262. var index_of_opts_end_of_closing = token_without_symbols.indexOf(options_close, index_of_opts_opening) + options_close.length;
  1263. try {
  1264. opts = f.extend(opts, JSON.parse(token_without_symbols.substring(index_of_opts_opening, index_of_opts_end_of_closing)));
  1265. token_without_symbols = token_without_symbols.substring(0, index_of_token_end_of_closing);
  1266. } catch (e) {
  1267. }
  1268. }
  1269. }
  1270. var translated_token = _translate(token_without_symbols, opts);
  1271. translated = translated.replace(token, f.regexReplacementEscape(translated_token));
  1272. }
  1273. return translated;
  1274. }
  1275. function hasContext(options) {
  1276. return (options.context && (typeof options.context == 'string' || typeof options.context == 'number'));
  1277. }
  1278. function needsPlural(options, lng) {
  1279. return (options.count !== undefined && typeof options.count != 'string'/* && pluralExtensions.needsPlural(lng, options.count)*/);
  1280. }
  1281. function needsIndefiniteArticle(options) {
  1282. return (options.indefinite_article !== undefined && typeof options.indefinite_article != 'string' && options.indefinite_article);
  1283. }
  1284. function exists(key, options) {
  1285. options = options || {};
  1286. var notFound = _getDefaultValue(key, options)
  1287. , found = _find(key, options);
  1288. return found !== undefined || found === notFound;
  1289. }
  1290. function translate(key, options) {
  1291. if (!initialized) {
  1292. f.log('i18next not finished initialization. you might have called t function before loading resources finished.')
  1293. if (options && options.defaultValue) {
  1294. return options.detaultValue;
  1295. } else {
  1296. return '';
  1297. }
  1298. };
  1299. replacementCounter = 0;
  1300. return _translate.apply(null, arguments);
  1301. }
  1302. function _getDefaultValue(key, options) {
  1303. return (options.defaultValue !== undefined) ? options.defaultValue : key;
  1304. }
  1305. function _injectSprintfProcessor() {
  1306. var values = [];
  1307. // mh: build array from second argument onwards
  1308. for (var i = 1; i < arguments.length; i++) {
  1309. values.push(arguments[i]);
  1310. }
  1311. return {
  1312. postProcess: 'sprintf',
  1313. sprintf: values
  1314. };
  1315. }
  1316. function _translate(potentialKeys, options) {
  1317. if (typeof options !== 'undefined' && typeof options !== 'object') {
  1318. if (o.shortcutFunction === 'sprintf') {
  1319. // mh: gettext like sprintf syntax found, automatically create sprintf processor
  1320. options = _injectSprintfProcessor.apply(null, arguments);
  1321. } else if (o.shortcutFunction === 'defaultValue') {
  1322. options = {
  1323. defaultValue: options
  1324. }
  1325. }
  1326. } else {
  1327. options = options || {};
  1328. }
  1329. if (typeof o.defaultVariables === 'object') {
  1330. options = f.extend({}, o.defaultVariables, options);
  1331. }
  1332. if (potentialKeys === undefined || potentialKeys === null || potentialKeys === '') return '';
  1333. if (typeof potentialKeys === 'number') {
  1334. potentialKeys = String(potentialKeys);
  1335. }
  1336. if (typeof potentialKeys === 'string') {
  1337. potentialKeys = [potentialKeys];
  1338. }
  1339. var key = potentialKeys[0];
  1340. if (potentialKeys.length > 1) {
  1341. for (var i = 0; i < potentialKeys.length; i++) {
  1342. key = potentialKeys[i];
  1343. if (exists(key, options)) {
  1344. break;
  1345. }
  1346. }
  1347. }
  1348. var notFound = _getDefaultValue(key, options)
  1349. , found = _find(key, options)
  1350. , nsseparator = options.nsseparator || o.nsseparator
  1351. , lngs = options.lng ? f.toLanguages(options.lng, options.fallbackLng) : languages
  1352. , ns = options.ns || o.ns.defaultNs
  1353. , parts;
  1354. // split ns and key
  1355. if (key.indexOf(nsseparator) > -1) {
  1356. parts = key.split(nsseparator);
  1357. ns = parts[0];
  1358. key = parts[1];
  1359. }
  1360. if (found === undefined && o.sendMissing && typeof o.missingKeyHandler === 'function') {
  1361. if (options.lng) {
  1362. o.missingKeyHandler(lngs[0], ns, key, notFound, lngs);
  1363. } else {
  1364. o.missingKeyHandler(o.lng, ns, key, notFound, lngs);
  1365. }
  1366. }
  1367. var postProcessorsToApply,
  1368. postProcessor,
  1369. j;
  1370. if (typeof o.postProcess === 'string' && o.postProcess !== '') {
  1371. postProcessorsToApply = [o.postProcess];
  1372. } else if (typeof o.postProcess === 'array' || typeof o.postProcess === 'object') {
  1373. postProcessorsToApply = o.postProcess;
  1374. } else {
  1375. postProcessorsToApply = [];
  1376. }
  1377. if (typeof options.postProcess === 'string' && options.postProcess !== '') {
  1378. postProcessorsToApply = postProcessorsToApply.concat([options.postProcess]);
  1379. } else if (typeof options.postProcess === 'array' || typeof options.postProcess === 'object') {
  1380. postProcessorsToApply = postProcessorsToApply.concat(options.postProcess);
  1381. }
  1382. if (found !== undefined && postProcessorsToApply.length) {
  1383. for (j = 0; j < postProcessorsToApply.length; j += 1) {
  1384. postProcessor = postProcessorsToApply[j];
  1385. if (postProcessors[postProcessor]) {
  1386. found = postProcessors[postProcessor](found, key, options);
  1387. }
  1388. }
  1389. }
  1390. // process notFound if function exists
  1391. var splitNotFound = notFound;
  1392. if (notFound.indexOf(nsseparator) > -1) {
  1393. parts = notFound.split(nsseparator);
  1394. splitNotFound = parts[1];
  1395. }
  1396. if (splitNotFound === key && o.parseMissingKey) {
  1397. notFound = o.parseMissingKey(notFound);
  1398. }
  1399. if (found === undefined) {
  1400. notFound = applyReplacement(notFound, options);
  1401. notFound = applyReuse(notFound, options);
  1402. if (postProcessorsToApply.length) {
  1403. found = _getDefaultValue(key, options);
  1404. for (j = 0; j < postProcessorsToApply.length; j += 1) {
  1405. postProcessor = postProcessorsToApply[j];
  1406. if (postProcessors[postProcessor]) {
  1407. found = postProcessors[postProcessor](found, key, options);
  1408. }
  1409. }
  1410. }
  1411. }
  1412. return (found !== undefined) ? found : notFound;
  1413. }
  1414. function _find(key, options) {
  1415. options = options || {};
  1416. var optionWithoutCount, translated
  1417. , notFound = _getDefaultValue(key, options)
  1418. , lngs = languages;
  1419. if (!resStore) { return notFound; } // no resStore to translate from
  1420. // CI mode
  1421. if (lngs[0].toLowerCase() === 'cimode') return notFound;
  1422. // passed in lng
  1423. if (options.lngs) lngs = options.lngs;
  1424. if (options.lng) {
  1425. lngs = f.toLanguages(options.lng, options.fallbackLng);
  1426. if (!resStore[lngs[0]]) {
  1427. var oldAsync = o.getAsync;
  1428. o.getAsync = false;
  1429. i18n.sync.load(lngs, o, function(err, store) {
  1430. f.extend(resStore, store);
  1431. o.getAsync = oldAsync;
  1432. });
  1433. }
  1434. }
  1435. var ns = options.ns || o.ns.defaultNs;
  1436. var nsseparator = options.nsseparator || o.nsseparator;
  1437. if (key.indexOf(nsseparator) > -1) {
  1438. var parts = key.split(nsseparator);
  1439. ns = parts[0];
  1440. key = parts[1];
  1441. }
  1442. if (hasContext(options)) {
  1443. optionWithoutCount = f.extend({}, options);
  1444. delete optionWithoutCount.context;
  1445. optionWithoutCount.defaultValue = o.contextNotFound;
  1446. var contextKey = ns + nsseparator + key + '_' + options.context;
  1447. translated = translate(contextKey, optionWithoutCount);
  1448. if (translated != o.contextNotFound) {
  1449. return applyReplacement(translated, { context: options.context }); // apply replacement for context only
  1450. } // else continue translation with original/nonContext key
  1451. }
  1452. if (needsPlural(options, lngs[0])) {
  1453. optionWithoutCount = f.extend({ lngs: [lngs[0]]}, options);
  1454. delete optionWithoutCount.count;
  1455. optionWithoutCount._origLng = optionWithoutCount._origLng || optionWithoutCount.lng || lngs[0];
  1456. delete optionWithoutCount.lng;
  1457. optionWithoutCount.defaultValue = o.pluralNotFound;
  1458. var pluralKey;
  1459. if (!pluralExtensions.needsPlural(lngs[0], options.count)) {
  1460. pluralKey = ns + nsseparator + key;
  1461. } else {
  1462. pluralKey = ns + nsseparator + key + o.pluralSuffix;
  1463. var pluralExtension = pluralExtensions.get(lngs[0], options.count);
  1464. if (pluralExtension >= 0) {
  1465. pluralKey = pluralKey + '_' + pluralExtension;
  1466. } else if (pluralExtension === 1) {
  1467. pluralKey = ns + nsseparator + key; // singular
  1468. }
  1469. }
  1470. translated = translate(pluralKey, optionWithoutCount);
  1471. if (translated != o.pluralNotFound) {
  1472. return applyReplacement(translated, {
  1473. count: options.count,
  1474. interpolationPrefix: options.interpolationPrefix,
  1475. interpolationSuffix: options.interpolationSuffix
  1476. }); // apply replacement for count only
  1477. } else if (lngs.length > 1) {
  1478. // remove failed lng
  1479. var clone = lngs.slice();
  1480. clone.shift();
  1481. options = f.extend(options, { lngs: clone });
  1482. options._origLng = optionWithoutCount._origLng;
  1483. delete options.lng;
  1484. // retry with fallbacks
  1485. translated = translate(ns + nsseparator + key, options);
  1486. if (translated != o.pluralNotFound) return translated;
  1487. } else {
  1488. optionWithoutCount.lng = optionWithoutCount._origLng;
  1489. delete optionWithoutCount._origLng;
  1490. translated = translate(ns + nsseparator + key, optionWithoutCount);
  1491. return applyReplacement(translated, {
  1492. count: options.count,
  1493. interpolationPrefix: options.interpolationPrefix,
  1494. interpolationSuffix: options.interpolationSuffix
  1495. });
  1496. }
  1497. }
  1498. if (needsIndefiniteArticle(options)) {
  1499. var optionsWithoutIndef = f.extend({}, options);
  1500. delete optionsWithoutIndef.indefinite_article;
  1501. optionsWithoutIndef.defaultValue = o.indefiniteNotFound;
  1502. // If we don't have a count, we want the indefinite, if we do have a count, and needsPlural is false
  1503. var indefiniteKey = ns + nsseparator + key + (((options.count && !needsPlural(options, lngs[0])) || !options.count) ? o.indefiniteSuffix : "");
  1504. translated = translate(indefiniteKey, optionsWithoutIndef);
  1505. if (translated != o.indefiniteNotFound) {
  1506. return translated;
  1507. }
  1508. }
  1509. var found;
  1510. var keyseparator = options.keyseparator || o.keyseparator;
  1511. var keys = key.split(keyseparator);
  1512. for (var i = 0, len = lngs.length; i < len; i++ ) {
  1513. if (found !== undefined) break;
  1514. var l = lngs[i];
  1515. var x = 0;
  1516. var value = resStore[l] && resStore[l][ns];
  1517. while (keys[x]) {
  1518. value = value && value[keys[x]];
  1519. x++;
  1520. }
  1521. if (value !== undefined && (!o.showKeyIfEmpty || value !== '')) {
  1522. var valueType = Object.prototype.toString.apply(value);
  1523. if (typeof value === 'string') {
  1524. value = applyReplacement(value, options);
  1525. value = applyReuse(value, options);
  1526. } else if (valueType === '[object Array]' && !o.returnObjectTrees && !options.returnObjectTrees) {
  1527. value = value.join('\n');
  1528. value = applyReplacement(value, options);
  1529. value = applyReuse(value, options);
  1530. } else if (value === null && o.fallbackOnNull === true) {
  1531. value = undefined;
  1532. } else if (value !== null) {
  1533. if (!o.returnObjectTrees && !options.returnObjectTrees) {
  1534. if (o.objectTreeKeyHandler && typeof o.objectTreeKeyHandler == 'function') {
  1535. value = o.objectTreeKeyHandler(key, value, l, ns, options);
  1536. } else {
  1537. value = 'key \'' + ns + ':' + key + ' (' + l + ')\' ' +
  1538. 'returned an object instead of string.';
  1539. f.log(value);
  1540. }
  1541. } else if (valueType !== '[object Number]' && valueType !== '[object Function]' && valueType !== '[object RegExp]') {
  1542. var copy = (valueType === '[object Array]') ? [] : {}; // apply child translation on a copy
  1543. f.each(value, function(m) {
  1544. copy[m] = _translate(ns + nsseparator + key + keyseparator + m, options);
  1545. });
  1546. value = copy;
  1547. }
  1548. }
  1549. if (typeof value === 'string' && value.trim() === '' && o.fallbackOnEmpty === true)
  1550. value = undefined;
  1551. found = value;
  1552. }
  1553. }
  1554. if (found === undefined && !options.isFallbackLookup && (o.fallbackToDefaultNS === true || (o.fallbackNS && o.fallbackNS.length > 0))) {
  1555. // set flag for fallback lookup - avoid recursion
  1556. options.isFallbackLookup = true;
  1557. if (o.fallbackNS.length) {
  1558. for (var y = 0, lenY = o.fallbackNS.length; y < lenY; y++) {
  1559. found = _find(o.fallbackNS[y] + nsseparator + key, options);
  1560. if (found || (found==="" && o.fallbackOnEmpty === false)) {
  1561. /* compare value without namespace */
  1562. var foundValue = found.indexOf(nsseparator) > -1 ? found.split(nsseparator)[1] : found
  1563. , notFoundValue = notFound.indexOf(nsseparator) > -1 ? notFound.split(nsseparator)[1] : notFound;
  1564. if (foundValue !== notFoundValue) break;
  1565. }
  1566. }
  1567. } else {
  1568. options.ns = o.ns.defaultNs;
  1569. found = _find(key, options); // fallback to default NS
  1570. }
  1571. options.isFallbackLookup = false;
  1572. }
  1573. return found;
  1574. }
  1575. function detectLanguage() {
  1576. var detectedLng;
  1577. var whitelist = o.lngWhitelist || [];
  1578. var userLngChoices = [];
  1579. // get from qs
  1580. var qsParm = [];
  1581. if (typeof window !== 'undefined') {
  1582. (function() {
  1583. var query = window.location.search.substring(1);
  1584. var params = query.split('&');
  1585. for (var i=0; i<params.length; i++) {
  1586. var pos = params[i].indexOf('=');
  1587. if (pos > 0) {
  1588. var key = params[i].substring(0,pos);
  1589. if (key == o.detectLngQS) {
  1590. userLngChoices.push(params[i].substring(pos+1));
  1591. }
  1592. }
  1593. }
  1594. })();
  1595. }
  1596. // get from cookie
  1597. if (o.useCookie && typeof document !== 'undefined') {
  1598. var c = f.cookie.read(o.cookieName);
  1599. if (c) userLngChoices.push(c);
  1600. }
  1601. // get from localStorage
  1602. if (o.detectLngFromLocalStorage && typeof window !== 'undefined' && window.localStorage) {
  1603. var lang = f.localStorage.getItem('i18next_lng');
  1604. if (lang) {
  1605. userLngChoices.push(lang);
  1606. }
  1607. }
  1608. // get from navigator
  1609. if (typeof navigator !== 'undefined') {
  1610. if (navigator.languages) { // chrome only; not an array, so can't use .push.apply instead of iterating
  1611. for (var i=0;i<navigator.languages.length;i++) {
  1612. userLngChoices.push(navigator.languages[i]);
  1613. }
  1614. }
  1615. if (navigator.userLanguage) {
  1616. userLngChoices.push(navigator.userLanguage);
  1617. }
  1618. if (navigator.language) {
  1619. userLngChoices.push(navigator.language);
  1620. }
  1621. }
  1622. (function() {
  1623. for (var i=0;i<userLngChoices.length;i++) {
  1624. var lng = userLngChoices[i];
  1625. if (lng.indexOf('-') > -1) {
  1626. var parts = lng.split('-');
  1627. lng = o.lowerCaseLng ?
  1628. parts[0].toLowerCase() + '-' + parts[1].toLowerCase() :
  1629. parts[0].toLowerCase() + '-' + parts[1].toUpperCase();
  1630. }
  1631. if (whitelist.length === 0 || whitelist.indexOf(lng) > -1) {
  1632. detectedLng = lng;
  1633. break;
  1634. }
  1635. }
  1636. })();
  1637. //fallback
  1638. if (!detectedLng){
  1639. detectedLng = o.fallbackLng[0];
  1640. }
  1641. return detectedLng;
  1642. }
  1643. // definition http://translate.sourceforge.net/wiki/l10n/pluralforms
  1644. /* [code, name, numbers, pluralsType] */
  1645. var _rules = [
  1646. ["ach", "Acholi", [1,2], 1],
  1647. ["af", "Afrikaans",[1,2], 2],
  1648. ["ak", "Akan", [1,2], 1],
  1649. ["am", "Amharic", [1,2], 1],
  1650. ["an", "Aragonese",[1,2], 2],
  1651. ["ar", "Arabic", [0,1,2,3,11,100],5],
  1652. ["arn", "Mapudungun",[1,2], 1],
  1653. ["ast", "Asturian", [1,2], 2],
  1654. ["ay", "Aymará", [1], 3],
  1655. ["az", "Azerbaijani",[1,2],2],
  1656. ["be", "Belarusian",[1,2,5],4],
  1657. ["bg", "Bulgarian",[1,2], 2],
  1658. ["bn", "Bengali", [1,2], 2],
  1659. ["bo", "Tibetan", [1], 3],
  1660. ["br", "Breton", [1,2], 1],
  1661. ["bs", "Bosnian", [1,2,5],4],
  1662. ["ca", "Catalan", [1,2], 2],
  1663. ["cgg", "Chiga", [1], 3],
  1664. ["cs", "Czech", [1,2,5],6],
  1665. ["csb", "Kashubian",[1,2,5],7],
  1666. ["cy", "Welsh", [1,2,3,8],8],
  1667. ["da", "Danish", [1,2], 2],
  1668. ["de", "German", [1,2], 2],
  1669. ["dev", "Development Fallback", [1,2], 2],
  1670. ["dz", "Dzongkha", [1], 3],
  1671. ["el", "Greek", [1,2], 2],
  1672. ["en", "English", [1,2], 2],
  1673. ["eo", "Esperanto",[1,2], 2],
  1674. ["es", "Spanish", [1,2], 2],
  1675. ["es_ar","Argentinean Spanish", [1,2], 2],
  1676. ["et", "Estonian", [1,2], 2],
  1677. ["eu", "Basque", [1,2], 2],
  1678. ["fa", "Persian", [1], 3],
  1679. ["fi", "Finnish", [1,2], 2],
  1680. ["fil", "Filipino", [1,2], 1],
  1681. ["fo", "Faroese", [1,2], 2],
  1682. ["fr", "French", [1,2], 9],
  1683. ["fur", "Friulian", [1,2], 2],
  1684. ["fy", "Frisian", [1,2], 2],
  1685. ["ga", "Irish", [1,2,3,7,11],10],
  1686. ["gd", "Scottish Gaelic",[1,2,3,20],11],
  1687. ["gl", "Galician", [1,2], 2],
  1688. ["gu", "Gujarati", [1,2], 2],
  1689. ["gun", "Gun", [1,2], 1],
  1690. ["ha", "Hausa", [1,2], 2],
  1691. ["he", "Hebrew", [1,2], 2],
  1692. ["hi", "Hindi", [1,2], 2],
  1693. ["hr", "Croatian", [1,2,5],4],
  1694. ["hu", "Hungarian",[1,2], 2],
  1695. ["hy", "Armenian", [1,2], 2],
  1696. ["ia", "Interlingua",[1,2],2],
  1697. ["id", "Indonesian",[1], 3],
  1698. ["is", "Icelandic",[1,2], 12],
  1699. ["it", "Italian", [1,2], 2],
  1700. ["ja", "Japanese", [1], 3],
  1701. ["jbo", "Lojban", [1], 3],
  1702. ["jv", "Javanese", [0,1], 13],
  1703. ["ka", "Georgian", [1], 3],
  1704. ["kk", "Kazakh", [1], 3],
  1705. ["km", "Khmer", [1], 3],
  1706. ["kn", "Kannada", [1,2], 2],
  1707. ["ko", "Korean", [1], 3],
  1708. ["ku", "Kurdish", [1,2], 2],
  1709. ["kw", "Cornish", [1,2,3,4],14],
  1710. ["ky", "Kyrgyz", [1], 3],
  1711. ["lb", "Letzeburgesch",[1,2],2],
  1712. ["ln", "Lingala", [1,2], 1],
  1713. ["lo", "Lao", [1], 3],
  1714. ["lt", "Lithuanian",[1,2,10],15],
  1715. ["lv", "Latvian", [1,2,0],16],
  1716. ["mai", "Maithili", [1,2], 2],
  1717. ["mfe", "Mauritian Creole",[1,2],1],
  1718. ["mg", "Malagasy", [1,2], 1],
  1719. ["mi", "Maori", [1,2], 1],
  1720. ["mk", "Macedonian",[1,2],17],
  1721. ["ml", "Malayalam",[1,2], 2],
  1722. ["mn", "Mongolian",[1,2], 2],
  1723. ["mnk", "Mandinka", [0,1,2],18],
  1724. ["mr", "Marathi", [1,2], 2],
  1725. ["ms", "Malay", [1], 3],
  1726. ["mt", "Maltese", [1,2,11,20],19],
  1727. ["nah", "Nahuatl", [1,2], 2],
  1728. ["nap", "Neapolitan",[1,2], 2],
  1729. ["nb", "Norwegian Bokmal",[1,2],2],
  1730. ["ne", "Nepali", [1,2], 2],
  1731. ["nl", "Dutch", [1,2], 2],
  1732. ["nn", "Norwegian Nynorsk",[1,2],2],
  1733. ["no", "Norwegian",[1,2], 2],
  1734. ["nso", "Northern Sotho",[1,2],2],
  1735. ["oc", "Occitan", [1,2], 1],
  1736. ["or", "Oriya", [2,1], 2],
  1737. ["pa", "Punjabi", [1,2], 2],
  1738. ["pap", "Papiamento",[1,2], 2],
  1739. ["pl", "Polish", [1,2,5],7],
  1740. ["pms", "Piemontese",[1,2], 2],
  1741. ["ps", "Pashto", [1,2], 2],
  1742. ["pt", "Portuguese",[1,2], 2],
  1743. ["pt_br","Brazilian Portuguese",[1,2], 2],
  1744. ["rm", "Romansh", [1,2], 2],
  1745. ["ro", "Romanian", [1,2,20],20],
  1746. ["ru", "Russian", [1,2,5],4],
  1747. ["sah", "Yakut", [1], 3],
  1748. ["sco", "Scots", [1,2], 2],
  1749. ["se", "Northern Sami",[1,2], 2],
  1750. ["si", "Sinhala", [1,2], 2],
  1751. ["sk", "Slovak", [1,2,5],6],
  1752. ["sl", "Slovenian",[5,1,2,3],21],
  1753. ["so", "Somali", [1,2], 2],
  1754. ["son", "Songhay", [1,2], 2],
  1755. ["sq", "Albanian", [1,2], 2],
  1756. ["sr", "Serbian", [1,2,5],4],
  1757. ["su", "Sundanese",[1], 3],
  1758. ["sv", "Swedish", [1,2], 2],
  1759. ["sw", "Swahili", [1,2], 2],
  1760. ["ta", "Tamil", [1,2], 2],
  1761. ["te", "Telugu", [1,2], 2],
  1762. ["tg", "Tajik", [1,2], 1],
  1763. ["th", "Thai", [1], 3],
  1764. ["ti", "Tigrinya", [1,2], 1],
  1765. ["tk", "Turkmen", [1,2], 2],
  1766. ["tr", "Turkish", [1,2], 1],
  1767. ["tt", "Tatar", [1], 3],
  1768. ["ug", "Uyghur", [1], 3],
  1769. ["uk", "Ukrainian",[1,2,5],4],
  1770. ["ur", "Urdu", [1,2], 2],
  1771. ["uz", "Uzbek", [1,2], 1],
  1772. ["vi", "Vietnamese",[1], 3],
  1773. ["wa", "Walloon", [1,2], 1],
  1774. ["wo", "Wolof", [1], 3],
  1775. ["yo", "Yoruba", [1,2], 2],
  1776. ["zh", "Chinese", [1], 3]
  1777. ];
  1778. var _rulesPluralsTypes = {
  1779. 1: function(n) {return Number(n > 1);},
  1780. 2: function(n) {return Number(n != 1);},
  1781. 3: function(n) {return 0;},
  1782. 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);},
  1783. 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);},
  1784. 6: function(n) {return Number((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2);},
  1785. 7: function(n) {return Number(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);},
  1786. 8: function(n) {return Number((n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3);},
  1787. 9: function(n) {return Number(n >= 2);},
  1788. 10: function(n) {return Number(n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4) ;},
  1789. 11: function(n) {return Number((n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : (n > 2 && n < 20) ? 2 : 3);},
  1790. 12: function(n) {return Number(n%10!=1 || n%100==11);},
  1791. 13: function(n) {return Number(n !== 0);},
  1792. 14: function(n) {return Number((n==1) ? 0 : (n==2) ? 1 : (n == 3) ? 2 : 3);},
  1793. 15: function(n) {return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);},
  1794. 16: function(n) {return Number(n%10==1 && n%100!=11 ? 0 : n !== 0 ? 1 : 2);},
  1795. 17: function(n) {return Number(n==1 || n%10==1 ? 0 : 1);},
  1796. 18: function(n) {return Number(n==0 ? 0 : n==1 ? 1 : 2);},
  1797. 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);},
  1798. 20: function(n) {return Number(n==1 ? 0 : (n===0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2);},
  1799. 21: function(n) {return Number(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? 3 : 0); }
  1800. };
  1801. var pluralExtensions = {
  1802. rules: (function () {
  1803. var l, rules = {};
  1804. for (l=_rules.length; l-- ;) {
  1805. rules[_rules[l][0]] = {
  1806. name: _rules[l][1],
  1807. numbers: _rules[l][2],
  1808. plurals: _rulesPluralsTypes[_rules[l][3]]
  1809. }
  1810. }
  1811. return rules;
  1812. }()),
  1813. // you can add your own pluralExtensions
  1814. addRule: function(lng, obj) {
  1815. pluralExtensions.rules[lng] = obj;
  1816. },
  1817. setCurrentLng: function(lng) {
  1818. if (!pluralExtensions.currentRule || pluralExtensions.currentRule.lng !== lng) {
  1819. var parts = lng.split('-');
  1820. pluralExtensions.currentRule = {
  1821. lng: lng,
  1822. rule: pluralExtensions.rules[parts[0]]
  1823. };
  1824. }
  1825. },
  1826. needsPlural: function(lng, count) {
  1827. var parts = lng.split('-');
  1828. var ext;
  1829. if (pluralExtensions.currentRule && pluralExtensions.currentRule.lng === lng) {
  1830. ext = pluralExtensions.currentRule.rule;
  1831. } else {
  1832. ext = pluralExtensions.rules[parts[f.getCountyIndexOfLng(lng)]];
  1833. }
  1834. if (ext && ext.numbers.length <= 1) {
  1835. return false;
  1836. } else {
  1837. return this.get(lng, count) !== 1;
  1838. }
  1839. },
  1840. get: function(lng, count) {
  1841. var parts = lng.split('-');
  1842. function getResult(l, c) {
  1843. var ext;
  1844. if (pluralExtensions.currentRule && pluralExtensions.currentRule.lng === lng) {
  1845. ext = pluralExtensions.currentRule.rule;
  1846. } else {
  1847. ext = pluralExtensions.rules[l];
  1848. }
  1849. if (ext) {
  1850. var i;
  1851. if (ext.noAbs) {
  1852. i = ext.plurals(c);
  1853. } else {
  1854. i = ext.plurals(Math.abs(c));
  1855. }
  1856. var number = ext.numbers[i];
  1857. if (ext.numbers.length === 2 && ext.numbers[0] === 1) {
  1858. if (number === 2) {
  1859. number = -1; // regular plural
  1860. } else if (number === 1) {
  1861. number = 1; // singular
  1862. }
  1863. }//console.log(count + '-' + number);
  1864. return number;
  1865. } else {
  1866. return c === 1 ? '1' : '-1';
  1867. }
  1868. }
  1869. return getResult(parts[f.getCountyIndexOfLng(lng)], count);
  1870. }
  1871. };
  1872. var postProcessors = {};
  1873. var addPostProcessor = function(name, fc) {
  1874. postProcessors[name] = fc;
  1875. };
  1876. // sprintf support
  1877. var sprintf = (function() {
  1878. function get_type(variable) {
  1879. return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
  1880. }
  1881. function str_repeat(input, multiplier) {
  1882. for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}
  1883. return output.join('');
  1884. }
  1885. var str_format = function() {
  1886. if (!str_format.cache.hasOwnProperty(arguments[0])) {
  1887. str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
  1888. }
  1889. return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
  1890. };
  1891. str_format.format = function(parse_tree, argv) {
  1892. var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
  1893. for (i = 0; i < tree_length; i++) {
  1894. node_type = get_type(parse_tree[i]);
  1895. if (node_type === 'string') {
  1896. output.push(parse_tree[i]);
  1897. }
  1898. else if (node_type === 'array') {
  1899. match = parse_tree[i]; // convenience purposes only
  1900. if (match[2]) { // keyword argument
  1901. arg = argv[cursor];
  1902. for (k = 0; k < match[2].length; k++) {
  1903. if (!arg.hasOwnProperty(match[2][k])) {
  1904. throw(sprintf('[sprintf] property "%s" does not exist', match[2][k]));
  1905. }
  1906. arg = arg[match[2][k]];
  1907. }
  1908. }
  1909. else if (match[1]) { // positional argument (explicit)
  1910. arg = argv[match[1]];
  1911. }
  1912. else { // positional argument (implicit)
  1913. arg = argv[cursor++];
  1914. }
  1915. if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
  1916. throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));
  1917. }
  1918. switch (match[8]) {
  1919. case 'b': arg = arg.toString(2); break;
  1920. case 'c': arg = String.fromCharCode(arg); break;
  1921. case 'd': arg = parseInt(arg, 10); break;
  1922. case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
  1923. case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
  1924. case 'o': arg = arg.toString(8); break;
  1925. case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
  1926. case 'u': arg = Math.abs(arg); break;
  1927. case 'x': arg = arg.toString(16); break;
  1928. case 'X': arg = arg.toString(16).toUpperCase(); break;
  1929. }
  1930. arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
  1931. pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
  1932. pad_length = match[6] - String(arg).length;
  1933. pad = match[6] ? str_repeat(pad_character, pad_length) : '';
  1934. output.push(match[5] ? arg + pad : pad + arg);
  1935. }
  1936. }
  1937. return output.join('');
  1938. };
  1939. str_format.cache = {};
  1940. str_format.parse = function(fmt) {
  1941. var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
  1942. while (_fmt) {
  1943. if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
  1944. parse_tree.push(match[0]);
  1945. }
  1946. else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
  1947. parse_tree.push('%');
  1948. }
  1949. else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
  1950. if (match[2]) {
  1951. arg_names |= 1;
  1952. var field_list = [], replacement_field = match[2], field_match = [];
  1953. if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
  1954. field_list.push(field_match[1]);
  1955. while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
  1956. if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
  1957. field_list.push(field_match[1]);
  1958. }
  1959. else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
  1960. field_list.push(field_match[1]);
  1961. }
  1962. else {
  1963. throw('[sprintf] huh?');
  1964. }
  1965. }
  1966. }
  1967. else {
  1968. throw('[sprintf] huh?');
  1969. }
  1970. match[2] = field_list;
  1971. }
  1972. else {
  1973. arg_names |= 2;
  1974. }
  1975. if (arg_names === 3) {
  1976. throw('[sprintf] mixing positional and named placeholders is not (yet) supported');
  1977. }
  1978. parse_tree.push(match);
  1979. }
  1980. else {
  1981. throw('[sprintf] huh?');
  1982. }
  1983. _fmt = _fmt.substring(match[0].length);
  1984. }
  1985. return parse_tree;
  1986. };
  1987. return str_format;
  1988. })();
  1989. var vsprintf = function(fmt, argv) {
  1990. argv.unshift(fmt);
  1991. return sprintf.apply(null, argv);
  1992. };
  1993. addPostProcessor("sprintf", function(val, key, opts) {
  1994. if (!opts.sprintf) return val;
  1995. if (Object.prototype.toString.apply(opts.sprintf) === '[object Array]') {
  1996. return vsprintf(val, opts.sprintf);
  1997. } else if (typeof opts.sprintf === 'object') {
  1998. return sprintf(val, opts.sprintf);
  1999. }
  2000. return val;
  2001. });
  2002. // public api interface
  2003. i18n.init = init;
  2004. i18n.isInitialized = isInitialized;
  2005. i18n.setLng = setLng;
  2006. i18n.preload = preload;
  2007. i18n.addResourceBundle = addResourceBundle;
  2008. i18n.hasResourceBundle = hasResourceBundle;
  2009. i18n.getResourceBundle = getResourceBundle;
  2010. i18n.addResource = addResource;
  2011. i18n.addResources = addResources;
  2012. i18n.removeResourceBundle = removeResourceBundle;
  2013. i18n.loadNamespace = loadNamespace;
  2014. i18n.loadNamespaces = loadNamespaces;
  2015. i18n.setDefaultNamespace = setDefaultNamespace;
  2016. i18n.t = translate;
  2017. i18n.translate = translate;
  2018. i18n.exists = exists;
  2019. i18n.detectLanguage = f.detectLanguage;
  2020. i18n.pluralExtensions = pluralExtensions;
  2021. i18n.sync = sync;
  2022. i18n.functions = f;
  2023. i18n.lng = lng;
  2024. i18n.dir = dir;
  2025. i18n.addPostProcessor = addPostProcessor;
  2026. i18n.applyReplacement = f.applyReplacement;
  2027. i18n.options = o;
  2028. i18n.noConflict = noConflict;
  2029. })(typeof exports === 'undefined' ? window : exports);