diff --git a/activities/XOEditor.activity/index.html b/activities/XOEditor.activity/index.html
index 4253b111b..67697537a 100644
--- a/activities/XOEditor.activity/index.html
+++ b/activities/XOEditor.activity/index.html
@@ -13,7 +13,6 @@
-
diff --git a/activities/XOEditor.activity/js/activity.js b/activities/XOEditor.activity/js/activity.js
index 2fd699663..13e4e9d53 100644
--- a/activities/XOEditor.activity/js/activity.js
+++ b/activities/XOEditor.activity/js/activity.js
@@ -4,7 +4,7 @@ define(["sugar-web/activity/activity",'easeljs','tweenjs','activity/editor','act
requirejs(['domReady!'], function (doc) {
// Initialize the activity.
- requirejs(['sugar-web/graphics/xocolor',"sugar-web/env","sugar-web/datastore","tutorial","webL10n"], function(xocol,env,datastore,tutorial,webL10n) {
+ requirejs(['sugar-web/graphics/xocolor',"sugar-web/env","sugar-web/datastore","tutorial","l10n"], function(xocol,env,datastore,tutorial,l10n) {
act.setup();
env.getEnvironment(function(err, environment) {
currentenv = environment;
@@ -12,7 +12,7 @@ define(["sugar-web/activity/activity",'easeljs','tweenjs','activity/editor','act
// Set current language to Sugarizer
var defaultLanguage =(typeof chrome != "undefined" && chrome.app && chrome.app.runtime) ? chrome.i18n.getUILanguage(): navigator.language;
var language = environment.user ? environment.user.language : defaultLanguage;
- webL10n.language.code = language;
+ l10n.init(language);
});
act.getXOColor(function (error, colors) {
runactivity(act,xocol,doc,colors,env,datastore,tutorial);
@@ -69,7 +69,7 @@ function runactivity(act,xocolor,doc,colors,env,datastore,tutorial){
document.getElementById("stop-button").addEventListener('click', function (event) {
e.stop();
});
-
+
// Full screen.
document.getElementById("fullscreen-button").addEventListener('click', function() {
document.getElementById("main-toolbar").style.opacity = 0;
@@ -100,4 +100,3 @@ function runactivity(act,xocolor,doc,colors,env,datastore,tutorial){
}
init();
}
-
diff --git a/activities/XOEditor.activity/lib/axios.min.js b/activities/XOEditor.activity/lib/axios.min.js
new file mode 100644
index 000000000..fc6c8b618
--- /dev/null
+++ b/activities/XOEditor.activity/lib/axios.min.js
@@ -0,0 +1,3 @@
+/* axios v0.21.1 | (c) 2020 by Matt Zabriskie */
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.axios=t():e.axios=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";function r(e){var t=new i(e),n=s(i.prototype.request,t);return o.extend(n,i.prototype,t),o.extend(n,t),n}var o=n(2),s=n(3),i=n(4),a=n(22),u=n(10),c=r(u);c.Axios=i,c.create=function(e){return r(a(c.defaults,e))},c.Cancel=n(23),c.CancelToken=n(24),c.isCancel=n(9),c.all=function(e){return Promise.all(e)},c.spread=n(25),c.isAxiosError=n(26),e.exports=c,e.exports.default=c},function(e,t,n){"use strict";function r(e){return"[object Array]"===R.call(e)}function o(e){return"undefined"==typeof e}function s(e){return null!==e&&!o(e)&&null!==e.constructor&&!o(e.constructor)&&"function"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}function i(e){return"[object ArrayBuffer]"===R.call(e)}function a(e){return"undefined"!=typeof FormData&&e instanceof FormData}function u(e){var t;return t="undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer}function c(e){return"string"==typeof e}function f(e){return"number"==typeof e}function p(e){return null!==e&&"object"==typeof e}function d(e){if("[object Object]"!==R.call(e))return!1;var t=Object.getPrototypeOf(e);return null===t||t===Object.prototype}function l(e){return"[object Date]"===R.call(e)}function h(e){return"[object File]"===R.call(e)}function m(e){return"[object Blob]"===R.call(e)}function y(e){return"[object Function]"===R.call(e)}function g(e){return p(e)&&y(e.pipe)}function v(e){return"undefined"!=typeof URLSearchParams&&e instanceof URLSearchParams}function x(e){return e.replace(/^\s*/,"").replace(/\s*$/,"")}function w(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product&&"NativeScript"!==navigator.product&&"NS"!==navigator.product)&&("undefined"!=typeof window&&"undefined"!=typeof document)}function b(e,t){if(null!==e&&"undefined"!=typeof e)if("object"!=typeof e&&(e=[e]),r(e))for(var n=0,o=e.length;n=200&&e<300}};u.headers={common:{Accept:"application/json, text/plain, */*"}},s.forEach(["delete","get","head"],function(e){u.headers[e]={}}),s.forEach(["post","put","patch"],function(e){u.headers[e]=s.merge(a)}),e.exports=u},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t){r.forEach(e,function(n,r){r!==t&&r.toUpperCase()===t.toUpperCase()&&(e[t]=n,delete e[r])})}},function(e,t,n){"use strict";var r=n(2),o=n(13),s=n(16),i=n(5),a=n(17),u=n(20),c=n(21),f=n(14);e.exports=function(e){return new Promise(function(t,n){var p=e.data,d=e.headers;r.isFormData(p)&&delete d["Content-Type"];var l=new XMLHttpRequest;if(e.auth){var h=e.auth.username||"",m=e.auth.password?unescape(encodeURIComponent(e.auth.password)):"";d.Authorization="Basic "+btoa(h+":"+m)}var y=a(e.baseURL,e.url);if(l.open(e.method.toUpperCase(),i(y,e.params,e.paramsSerializer),!0),l.timeout=e.timeout,l.onreadystatechange=function(){if(l&&4===l.readyState&&(0!==l.status||l.responseURL&&0===l.responseURL.indexOf("file:"))){var r="getAllResponseHeaders"in l?u(l.getAllResponseHeaders()):null,s=e.responseType&&"text"!==e.responseType?l.response:l.responseText,i={data:s,status:l.status,statusText:l.statusText,headers:r,config:e,request:l};o(t,n,i),l=null}},l.onabort=function(){l&&(n(f("Request aborted",e,"ECONNABORTED",l)),l=null)},l.onerror=function(){n(f("Network Error",e,null,l)),l=null},l.ontimeout=function(){var t="timeout of "+e.timeout+"ms exceeded";e.timeoutErrorMessage&&(t=e.timeoutErrorMessage),n(f(t,e,"ECONNABORTED",l)),l=null},r.isStandardBrowserEnv()){var g=(e.withCredentials||c(y))&&e.xsrfCookieName?s.read(e.xsrfCookieName):void 0;g&&(d[e.xsrfHeaderName]=g)}if("setRequestHeader"in l&&r.forEach(d,function(e,t){"undefined"==typeof p&&"content-type"===t.toLowerCase()?delete d[t]:l.setRequestHeader(t,e)}),r.isUndefined(e.withCredentials)||(l.withCredentials=!!e.withCredentials),e.responseType)try{l.responseType=e.responseType}catch(t){if("json"!==e.responseType)throw t}"function"==typeof e.onDownloadProgress&&l.addEventListener("progress",e.onDownloadProgress),"function"==typeof e.onUploadProgress&&l.upload&&l.upload.addEventListener("progress",e.onUploadProgress),e.cancelToken&&e.cancelToken.promise.then(function(e){l&&(l.abort(),n(e),l=null)}),p||(p=null),l.send(p)})}},function(e,t,n){"use strict";var r=n(14);e.exports=function(e,t,n){var o=n.config.validateStatus;n.status&&o&&!o(n.status)?t(r("Request failed with status code "+n.status,n.config,null,n.request,n)):e(n)}},function(e,t,n){"use strict";var r=n(15);e.exports=function(e,t,n,o,s){var i=new Error(e);return r(i,t,n,o,s)}},function(e,t){"use strict";e.exports=function(e,t,n,r,o){return e.config=t,n&&(e.code=n),e.request=r,e.response=o,e.isAxiosError=!0,e.toJSON=function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:this.config,code:this.code}},e}},function(e,t,n){"use strict";var r=n(2);e.exports=r.isStandardBrowserEnv()?function(){return{write:function(e,t,n,o,s,i){var a=[];a.push(e+"="+encodeURIComponent(t)),r.isNumber(n)&&a.push("expires="+new Date(n).toGMTString()),r.isString(o)&&a.push("path="+o),r.isString(s)&&a.push("domain="+s),i===!0&&a.push("secure"),document.cookie=a.join("; ")},read:function(e){var t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove:function(e){this.write(e,"",Date.now()-864e5)}}}():function(){return{write:function(){},read:function(){return null},remove:function(){}}}()},function(e,t,n){"use strict";var r=n(18),o=n(19);e.exports=function(e,t){return e&&!r(t)?o(e,t):t}},function(e,t){"use strict";e.exports=function(e){return/^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(e)}},function(e,t){"use strict";e.exports=function(e,t){return t?e.replace(/\/+$/,"")+"/"+t.replace(/^\/+/,""):e}},function(e,t,n){"use strict";var r=n(2),o=["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"];e.exports=function(e){var t,n,s,i={};return e?(r.forEach(e.split("\n"),function(e){if(s=e.indexOf(":"),t=r.trim(e.substr(0,s)).toLowerCase(),n=r.trim(e.substr(s+1)),t){if(i[t]&&o.indexOf(t)>=0)return;"set-cookie"===t?i[t]=(i[t]?i[t]:[]).concat([n]):i[t]=i[t]?i[t]+", "+n:n}}),i):i}},function(e,t,n){"use strict";var r=n(2);e.exports=r.isStandardBrowserEnv()?function(){function e(e){var t=e;return n&&(o.setAttribute("href",t),t=o.href),o.setAttribute("href",t),{href:o.href,protocol:o.protocol?o.protocol.replace(/:$/,""):"",host:o.host,search:o.search?o.search.replace(/^\?/,""):"",hash:o.hash?o.hash.replace(/^#/,""):"",hostname:o.hostname,port:o.port,pathname:"/"===o.pathname.charAt(0)?o.pathname:"/"+o.pathname}}var t,n=/(msie|trident)/i.test(navigator.userAgent),o=document.createElement("a");return t=e(window.location.href),function(n){var o=r.isString(n)?e(n):n;return o.protocol===t.protocol&&o.host===t.host}}():function(){return function(){return!0}}()},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t){function n(e,t){return r.isPlainObject(e)&&r.isPlainObject(t)?r.merge(e,t):r.isPlainObject(t)?r.merge({},t):r.isArray(t)?t.slice():t}function o(o){r.isUndefined(t[o])?r.isUndefined(e[o])||(s[o]=n(void 0,e[o])):s[o]=n(e[o],t[o])}t=t||{};var s={},i=["url","method","data"],a=["headers","auth","proxy","params"],u=["baseURL","transformRequest","transformResponse","paramsSerializer","timeout","timeoutMessage","withCredentials","adapter","responseType","xsrfCookieName","xsrfHeaderName","onUploadProgress","onDownloadProgress","decompress","maxContentLength","maxBodyLength","maxRedirects","transport","httpAgent","httpsAgent","cancelToken","socketPath","responseEncoding"],c=["validateStatus"];r.forEach(i,function(e){r.isUndefined(t[e])||(s[e]=n(void 0,t[e]))}),r.forEach(a,o),r.forEach(u,function(o){r.isUndefined(t[o])?r.isUndefined(e[o])||(s[o]=n(void 0,e[o])):s[o]=n(void 0,t[o])}),r.forEach(c,function(r){r in t?s[r]=n(e[r],t[r]):r in e&&(s[r]=n(void 0,e[r]))});var f=i.concat(a).concat(u).concat(c),p=Object.keys(e).concat(Object.keys(t)).filter(function(e){return f.indexOf(e)===-1});return r.forEach(p,o),s}},function(e,t){"use strict";function n(e){this.message=e}n.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},n.prototype.__CANCEL__=!0,e.exports=n},function(e,t,n){"use strict";function r(e){if("function"!=typeof e)throw new TypeError("executor must be a function.");var t;this.promise=new Promise(function(e){t=e});var n=this;e(function(e){n.reason||(n.reason=new o(e),t(n.reason))})}var o=n(23);r.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},r.source=function(){var e,t=new r(function(t){e=t});return{token:t,cancel:e}},e.exports=r},function(e,t){"use strict";e.exports=function(e){return function(t){return e.apply(null,t)}}},function(e,t){"use strict";e.exports=function(e){return"object"==typeof e&&e.isAxiosError===!0}}])});
+//# sourceMappingURL=axios.min.map
\ No newline at end of file
diff --git a/activities/XOEditor.activity/lib/i18next.min.js b/activities/XOEditor.activity/lib/i18next.min.js
new file mode 100644
index 000000000..00b2fd83e
--- /dev/null
+++ b/activities/XOEditor.activity/lib/i18next.min.js
@@ -0,0 +1 @@
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).i18next=t()}(this,function(){"use strict";function e(t){return(e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(t)}function t(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function n(e){for(var n=1;n1&&void 0!==arguments[1]?arguments[1]:{};i(this,e),this.init(t,n)}return r(e,[{key:"init",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};this.prefix=t.prefix||"i18next:",this.logger=e||p,this.options=t,this.debug=t.debug}},{key:"setDebug",value:function(e){this.debug=e}},{key:"log",value:function(){for(var e=arguments.length,t=new Array(e),n=0;n1?t-1:0),i=1;i-1?e.replace(/###/g,"."):e}function o(){return!e||"string"==typeof e}for(var r="string"!=typeof t?[].concat(t):t.split(".");r.length>1;){if(o())return{};var a=i(r.shift());!e[a]&&n&&(e[a]=new n),e=Object.prototype.hasOwnProperty.call(e,a)?e[a]:{}}return o()?{}:{obj:e,k:i(r.shift())}}function y(e,t,n){var i=v(e,t,Object);i.obj[i.k]=n}function m(e,t){var n=v(e,t),i=n.obj,o=n.k;if(i)return i[o]}function b(e,t,n){var i=m(e,n);return void 0!==i?i:m(t,n)}function k(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}var x={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"};function S(e){return"string"==typeof e?e.replace(/[&<>"'\/]/g,function(e){return x[e]}):e}var w="undefined"!=typeof window&&window.navigator&&window.navigator.userAgent&&window.navigator.userAgent.indexOf("MSIE")>-1;var L=function(e){function t(e){var n,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{ns:["translation"],defaultNS:"translation"};return i(this,t),n=s(this,u(t).call(this)),w&&f.call(a(n)),n.data=e||{},n.options=o,void 0===n.options.keySeparator&&(n.options.keySeparator="."),void 0===n.options.ignoreJSONStructure&&(n.options.ignoreJSONStructure=!0),n}return c(t,f),r(t,[{key:"addNamespaces",value:function(e){this.options.ns.indexOf(e)<0&&this.options.ns.push(e)}},{key:"removeNamespaces",value:function(e){var t=this.options.ns.indexOf(e);t>-1&&this.options.ns.splice(t,1)}},{key:"getResource",value:function(e,t,n){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},o=void 0!==i.keySeparator?i.keySeparator:this.options.keySeparator,r=void 0!==i.ignoreJSONStructure?i.ignoreJSONStructure:this.options.ignoreJSONStructure,a=[e,t];n&&"string"!=typeof n&&(a=a.concat(n)),n&&"string"==typeof n&&(a=a.concat(o?n.split(o):n)),e.indexOf(".")>-1&&(a=e.split("."));var s=m(this.data,a);return s||!r||"string"!=typeof n?s:function e(t,n){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:".";if(t){if(t[n])return t[n];for(var o=n.split(i),r=t,a=0;aa+s;)s++,l=r[u=o.slice(a,a+s).join(i)];if(void 0===l)return;if("string"==typeof l)return l;if(u&&"string"==typeof l[u])return l[u];var c=o.slice(a+s).join(i);return c?e(l,c,i):void 0}r=r[o[a]]}return r}}(this.data&&this.data[e]&&this.data[e][t],n,o)}},{key:"addResource",value:function(e,t,n,i){var o=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{silent:!1},r=this.options.keySeparator;void 0===r&&(r=".");var a=[e,t];n&&(a=a.concat(r?n.split(r):n)),e.indexOf(".")>-1&&(i=t,t=(a=e.split("."))[1]),this.addNamespaces(t),y(this.data,a,i),o.silent||this.emit("added",e,t,n,i)}},{key:"addResources",value:function(e,t,n){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{silent:!1};for(var o in n)"string"!=typeof n[o]&&"[object Array]"!==Object.prototype.toString.apply(n[o])||this.addResource(e,t,o,n[o],{silent:!0});i.silent||this.emit("added",e,t,n)}},{key:"addResourceBundle",value:function(e,t,i,o,r){var a=arguments.length>5&&void 0!==arguments[5]?arguments[5]:{silent:!1},s=[e,t];e.indexOf(".")>-1&&(o=i,i=t,t=(s=e.split("."))[1]),this.addNamespaces(t);var u=m(this.data,s)||{};o?function e(t,n,i){for(var o in n)"__proto__"!==o&&"constructor"!==o&&(o in t?"string"==typeof t[o]||t[o]instanceof String||"string"==typeof n[o]||n[o]instanceof String?i&&(t[o]=n[o]):e(t[o],n[o],i):t[o]=n[o]);return t}(u,i,r):u=n({},u,i),y(this.data,s,u),a.silent||this.emit("added",e,t,i)}},{key:"removeResourceBundle",value:function(e,t){this.hasResourceBundle(e,t)&&delete this.data[e][t],this.removeNamespaces(t),this.emit("removed",e,t)}},{key:"hasResourceBundle",value:function(e,t){return void 0!==this.getResource(e,t)}},{key:"getResourceBundle",value:function(e,t){return t||(t=this.options.defaultNS),"v1"===this.options.compatibilityAPI?n({},{},this.getResource(e,t)):this.getResource(e,t)}},{key:"getDataByLanguage",value:function(e){return this.data[e]}},{key:"toJSON",value:function(){return this.data}}]),t}(),O={processors:{},addPostProcessor:function(e){this.processors[e.name]=e},handle:function(e,t,n,i,o){var r=this;return e.forEach(function(e){r.processors[e]&&(t=r.processors[e].process(t,n,i,o))}),t}},N={},R=function(t){function o(e){var t,n,r,l,c=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return i(this,o),t=s(this,u(o).call(this)),w&&f.call(a(t)),n=["resourceStore","languageUtils","pluralResolver","interpolator","backendConnector","i18nFormat","utils"],r=e,l=a(t),n.forEach(function(e){r[e]&&(l[e]=r[e])}),t.options=c,void 0===t.options.keySeparator&&(t.options.keySeparator="."),t.logger=g.create("translator"),t}return c(o,f),r(o,[{key:"changeLanguage",value:function(e){e&&(this.language=e)}},{key:"exists",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{interpolation:{}},n=this.resolve(e,t);return n&&void 0!==n.res}},{key:"extractFromKey",value:function(e,t){var n=void 0!==t.nsSeparator?t.nsSeparator:this.options.nsSeparator;void 0===n&&(n=":");var i=void 0!==t.keySeparator?t.keySeparator:this.options.keySeparator,o=t.ns||this.options.defaultNS;if(n&&e.indexOf(n)>-1){var r=e.match(this.interpolator.nestingRegexp);if(r&&r.length>0)return{key:e,namespaces:o};var a=e.split(n);(n!==i||n===i&&this.options.ns.indexOf(a[0])>-1)&&(o=a.shift()),e=a.join(i)}return"string"==typeof o&&(o=[o]),{key:e,namespaces:o}}},{key:"translate",value:function(t,i,r){var a=this;if("object"!==e(i)&&this.options.overloadTranslationOptionHandler&&(i=this.options.overloadTranslationOptionHandler(arguments)),i||(i={}),null==t)return"";Array.isArray(t)||(t=[String(t)]);var s=void 0!==i.keySeparator?i.keySeparator:this.options.keySeparator,u=this.extractFromKey(t[t.length-1],i),l=u.key,c=u.namespaces,p=c[c.length-1],g=i.lng||this.language,f=i.appendNamespaceToCIMode||this.options.appendNamespaceToCIMode;if(g&&"cimode"===g.toLowerCase()){if(f){var h=i.nsSeparator||this.options.nsSeparator;return p+h+l}return l}var d=this.resolve(t,i),v=d&&d.res,y=d&&d.usedKey||l,m=d&&d.exactUsedKey||l,b=Object.prototype.toString.apply(v),k=void 0!==i.joinArrays?i.joinArrays:this.options.joinArrays,x=!this.i18nFormat||this.i18nFormat.handleAsObject;if(x&&v&&("string"!=typeof v&&"boolean"!=typeof v&&"number"!=typeof v)&&["[object Number]","[object Function]","[object RegExp]"].indexOf(b)<0&&("string"!=typeof k||"[object Array]"!==b)){if(!i.returnObjects&&!this.options.returnObjects)return this.logger.warn("accessing an object - but returnObjects options is not enabled!"),this.options.returnedObjectHandler?this.options.returnedObjectHandler(y,v,i):"key '".concat(l," (").concat(this.language,")' returned an object instead of string.");if(s){var S="[object Array]"===b,w=S?[]:{},L=S?m:y;for(var O in v)if(Object.prototype.hasOwnProperty.call(v,O)){var N="".concat(L).concat(s).concat(O);w[O]=this.translate(N,n({},i,{joinArrays:!1,ns:c})),w[O]===N&&(w[O]=v[O])}v=w}}else if(x&&"string"==typeof k&&"[object Array]"===b)(v=v.join(k))&&(v=this.extendTranslation(v,t,i,r));else{var R=!1,C=!1,j=void 0!==i.count&&"string"!=typeof i.count,E=o.hasDefaultValue(i),P=j?this.pluralResolver.getSuffix(g,i.count):"",F=i["defaultValue".concat(P)]||i.defaultValue;!this.isValidLookup(v)&&E&&(R=!0,v=F),this.isValidLookup(v)||(C=!0,v=l);var V=E&&F!==v&&this.options.updateMissing;if(C||R||V){if(this.logger.log(V?"updateKey":"missingKey",g,p,l,V?F:v),s){var T=this.resolve(l,n({},i,{keySeparator:!1}));T&&T.res&&this.logger.warn("Seems the loaded translations were in flat JSON format instead of nested. Either set keySeparator: false on init or make sure your translations are published in nested format.")}var A=[],U=this.languageUtils.getFallbackCodes(this.options.fallbackLng,i.lng||this.language);if("fallback"===this.options.saveMissingTo&&U&&U[0])for(var I=0;I1&&void 0!==arguments[1]?arguments[1]:{};return"string"==typeof e&&(e=[e]),e.forEach(function(e){if(!a.isValidLookup(t)){var u=a.extractFromKey(e,s),l=u.key;n=l;var c=u.namespaces;a.options.fallbackNS&&(c=c.concat(a.options.fallbackNS));var p=void 0!==s.count&&"string"!=typeof s.count,g=void 0!==s.context&&"string"==typeof s.context&&""!==s.context,f=s.lngs?s.lngs:a.languageUtils.toResolveHierarchy(s.lng||a.language,s.fallbackLng);c.forEach(function(e){a.isValidLookup(t)||(r=e,!N["".concat(f[0],"-").concat(e)]&&a.utils&&a.utils.hasLoadedNamespace&&!a.utils.hasLoadedNamespace(r)&&(N["".concat(f[0],"-").concat(e)]=!0,a.logger.warn('key "'.concat(n,'" for languages "').concat(f.join(", "),'" won\'t get resolved as namespace "').concat(r,'" was not yet loaded'),"This means something IS WRONG in your setup. You access the t function before i18next.init / i18next.loadNamespace / i18next.changeLanguage was done. Wait for the callback or Promise to resolve before accessing it!!!")),f.forEach(function(n){if(!a.isValidLookup(t)){o=n;var r,u,c=l,f=[c];if(a.i18nFormat&&a.i18nFormat.addLookupKeys)a.i18nFormat.addLookupKeys(f,l,n,e,s);else p&&(r=a.pluralResolver.getSuffix(n,s.count)),p&&g&&f.push(c+r),g&&f.push(c+="".concat(a.options.contextSeparator).concat(s.context)),p&&f.push(c+=r);for(;u=f.pop();)a.isValidLookup(t)||(i=u,t=a.getResource(n,e,u,s))}}))})}}),{res:t,usedKey:n,exactUsedKey:i,usedLng:o,usedNS:r}}},{key:"isValidLookup",value:function(e){return!(void 0===e||!this.options.returnNull&&null===e||!this.options.returnEmptyString&&""===e)}},{key:"getResource",value:function(e,t,n){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};return this.i18nFormat&&this.i18nFormat.getResource?this.i18nFormat.getResource(e,t,n,i):this.resourceStore.getResource(e,t,n,i)}}],[{key:"hasDefaultValue",value:function(e){for(var t in e)if(Object.prototype.hasOwnProperty.call(e,t)&&"defaultValue"===t.substring(0,"defaultValue".length)&&void 0!==e[t])return!0;return!1}}]),o}();function C(e){return e.charAt(0).toUpperCase()+e.slice(1)}var j=function(){function e(t){i(this,e),this.options=t,this.whitelist=this.options.supportedLngs||!1,this.supportedLngs=this.options.supportedLngs||!1,this.logger=g.create("languageUtils")}return r(e,[{key:"getScriptPartFromCode",value:function(e){if(!e||e.indexOf("-")<0)return null;var t=e.split("-");return 2===t.length?null:(t.pop(),"x"===t[t.length-1].toLowerCase()?null:this.formatLanguageCode(t.join("-")))}},{key:"getLanguagePartFromCode",value:function(e){if(!e||e.indexOf("-")<0)return e;var t=e.split("-");return this.formatLanguageCode(t[0])}},{key:"formatLanguageCode",value:function(e){if("string"==typeof e&&e.indexOf("-")>-1){var t=["hans","hant","latn","cyrl","cans","mong","arab"],n=e.split("-");return this.options.lowerCaseLng?n=n.map(function(e){return e.toLowerCase()}):2===n.length?(n[0]=n[0].toLowerCase(),n[1]=n[1].toUpperCase(),t.indexOf(n[1].toLowerCase())>-1&&(n[1]=C(n[1].toLowerCase()))):3===n.length&&(n[0]=n[0].toLowerCase(),2===n[1].length&&(n[1]=n[1].toUpperCase()),"sgn"!==n[0]&&2===n[2].length&&(n[2]=n[2].toUpperCase()),t.indexOf(n[1].toLowerCase())>-1&&(n[1]=C(n[1].toLowerCase())),t.indexOf(n[2].toLowerCase())>-1&&(n[2]=C(n[2].toLowerCase()))),n.join("-")}return this.options.cleanCode||this.options.lowerCaseLng?e.toLowerCase():e}},{key:"isWhitelisted",value:function(e){return this.logger.deprecate("languageUtils.isWhitelisted",'function "isWhitelisted" will be renamed to "isSupportedCode" in the next major - please make sure to rename it\'s usage asap.'),this.isSupportedCode(e)}},{key:"isSupportedCode",value:function(e){return("languageOnly"===this.options.load||this.options.nonExplicitSupportedLngs)&&(e=this.getLanguagePartFromCode(e)),!this.supportedLngs||!this.supportedLngs.length||this.supportedLngs.indexOf(e)>-1}},{key:"getBestMatchFromCodes",value:function(e){var t,n=this;return e?(e.forEach(function(e){if(!t){var i=n.formatLanguageCode(e);n.options.supportedLngs&&!n.isSupportedCode(i)||(t=i)}}),!t&&this.options.supportedLngs&&e.forEach(function(e){if(!t){var i=n.getLanguagePartFromCode(e);if(n.isSupportedCode(i))return t=i;t=n.options.supportedLngs.find(function(e){if(0===e.indexOf(i))return e})}}),t||(t=this.getFallbackCodes(this.options.fallbackLng)[0]),t):null}},{key:"getFallbackCodes",value:function(e,t){if(!e)return[];if("function"==typeof e&&(e=e(t)),"string"==typeof e&&(e=[e]),"[object Array]"===Object.prototype.toString.apply(e))return e;if(!t)return e.default||[];var n=e[t];return n||(n=e[this.getScriptPartFromCode(t)]),n||(n=e[this.formatLanguageCode(t)]),n||(n=e[this.getLanguagePartFromCode(t)]),n||(n=e.default),n||[]}},{key:"toResolveHierarchy",value:function(e,t){var n=this,i=this.getFallbackCodes(t||this.options.fallbackLng||[],e),o=[],r=function(e){e&&(n.isSupportedCode(e)?o.push(e):n.logger.warn("rejecting language code not found in supportedLngs: ".concat(e)))};return"string"==typeof e&&e.indexOf("-")>-1?("languageOnly"!==this.options.load&&r(this.formatLanguageCode(e)),"languageOnly"!==this.options.load&&"currentOnly"!==this.options.load&&r(this.getScriptPartFromCode(e)),"currentOnly"!==this.options.load&&r(this.getLanguagePartFromCode(e))):"string"==typeof e&&r(this.formatLanguageCode(e)),i.forEach(function(e){o.indexOf(e)<0&&r(n.formatLanguageCode(e))}),o}}]),e}(),E=[{lngs:["ach","ak","am","arn","br","fil","gun","ln","mfe","mg","mi","oc","pt","pt-BR","tg","tl","ti","tr","uz","wa"],nr:[1,2],fc:1},{lngs:["af","an","ast","az","bg","bn","ca","da","de","dev","el","en","eo","es","et","eu","fi","fo","fur","fy","gl","gu","ha","hi","hu","hy","ia","it","kk","kn","ku","lb","mai","ml","mn","mr","nah","nap","nb","ne","nl","nn","no","nso","pa","pap","pms","ps","pt-PT","rm","sco","se","si","so","son","sq","sv","sw","ta","te","tk","ur","yo"],nr:[1,2],fc:2},{lngs:["ay","bo","cgg","fa","ht","id","ja","jbo","ka","km","ko","ky","lo","ms","sah","su","th","tt","ug","vi","wo","zh"],nr:[1],fc:3},{lngs:["be","bs","cnr","dz","hr","ru","sr","uk"],nr:[1,2,5],fc:4},{lngs:["ar"],nr:[0,1,2,3,11,100],fc:5},{lngs:["cs","sk"],nr:[1,2,5],fc:6},{lngs:["csb","pl"],nr:[1,2,5],fc:7},{lngs:["cy"],nr:[1,2,3,8],fc:8},{lngs:["fr"],nr:[1,2],fc:9},{lngs:["ga"],nr:[1,2,3,7,11],fc:10},{lngs:["gd"],nr:[1,2,3,20],fc:11},{lngs:["is"],nr:[1,2],fc:12},{lngs:["jv"],nr:[0,1],fc:13},{lngs:["kw"],nr:[1,2,3,4],fc:14},{lngs:["lt"],nr:[1,2,10],fc:15},{lngs:["lv"],nr:[1,2,0],fc:16},{lngs:["mk"],nr:[1,2],fc:17},{lngs:["mnk"],nr:[0,1,2],fc:18},{lngs:["mt"],nr:[1,2,11,20],fc:19},{lngs:["or"],nr:[2,1],fc:2},{lngs:["ro"],nr:[1,2,20],fc:20},{lngs:["sl"],nr:[5,1,2,3],fc:21},{lngs:["he","iw"],nr:[1,2,20,21],fc:22}],P={1:function(e){return Number(e>1)},2:function(e){return Number(1!=e)},3:function(e){return 0},4:function(e){return Number(e%10==1&&e%100!=11?0:e%10>=2&&e%10<=4&&(e%100<10||e%100>=20)?1:2)},5:function(e){return Number(0==e?0:1==e?1:2==e?2:e%100>=3&&e%100<=10?3:e%100>=11?4:5)},6:function(e){return Number(1==e?0:e>=2&&e<=4?1:2)},7:function(e){return Number(1==e?0:e%10>=2&&e%10<=4&&(e%100<10||e%100>=20)?1:2)},8:function(e){return Number(1==e?0:2==e?1:8!=e&&11!=e?2:3)},9:function(e){return Number(e>=2)},10:function(e){return Number(1==e?0:2==e?1:e<7?2:e<11?3:4)},11:function(e){return Number(1==e||11==e?0:2==e||12==e?1:e>2&&e<20?2:3)},12:function(e){return Number(e%10!=1||e%100==11)},13:function(e){return Number(0!==e)},14:function(e){return Number(1==e?0:2==e?1:3==e?2:3)},15:function(e){return Number(e%10==1&&e%100!=11?0:e%10>=2&&(e%100<10||e%100>=20)?1:2)},16:function(e){return Number(e%10==1&&e%100!=11?0:0!==e?1:2)},17:function(e){return Number(1==e||e%10==1&&e%100!=11?0:1)},18:function(e){return Number(0==e?0:1==e?1:2)},19:function(e){return Number(1==e?0:0==e||e%100>1&&e%100<11?1:e%100>10&&e%100<20?2:3)},20:function(e){return Number(1==e?0:0==e||e%100>0&&e%100<20?1:2)},21:function(e){return Number(e%100==1?1:e%100==2?2:e%100==3||e%100==4?3:0)},22:function(e){return Number(1==e?0:2==e?1:(e<0||e>10)&&e%10==0?2:3)}};var F=function(){function e(t){var n,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};i(this,e),this.languageUtils=t,this.options=o,this.logger=g.create("pluralResolver"),this.rules=(n={},E.forEach(function(e){e.lngs.forEach(function(t){n[t]={numbers:e.nr,plurals:P[e.fc]}})}),n)}return r(e,[{key:"addRule",value:function(e,t){this.rules[e]=t}},{key:"getRule",value:function(e){return this.rules[e]||this.rules[this.languageUtils.getLanguagePartFromCode(e)]}},{key:"needsPlural",value:function(e){var t=this.getRule(e);return t&&t.numbers.length>1}},{key:"getPluralFormsOfKey",value:function(e,t){return this.getSuffixes(e).map(function(e){return t+e})}},{key:"getSuffixes",value:function(e){var t=this,n=this.getRule(e);return n?n.numbers.map(function(n){return t.getSuffix(e,n)}):[]}},{key:"getSuffix",value:function(e,t){var n=this,i=this.getRule(e);if(i){var o=i.noAbs?i.plurals(t):i.plurals(Math.abs(t)),r=i.numbers[o];this.options.simplifyPluralSuffix&&2===i.numbers.length&&1===i.numbers[0]&&(2===r?r="plural":1===r&&(r=""));var a=function(){return n.options.prepend&&r.toString()?n.options.prepend+r.toString():r.toString()};return"v1"===this.options.compatibilityJSON?1===r?"":"number"==typeof r?"_plural_".concat(r.toString()):a():"v2"===this.options.compatibilityJSON?a():this.options.simplifyPluralSuffix&&2===i.numbers.length&&1===i.numbers[0]?a():this.options.prepend&&o.toString()?this.options.prepend+o.toString():o.toString()}return this.logger.warn("no plural rule found for: ".concat(e)),""}}]),e}(),V=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};i(this,e),this.logger=g.create("interpolator"),this.options=t,this.format=t.interpolation&&t.interpolation.format||function(e){return e},this.init(t)}return r(e,[{key:"init",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};e.interpolation||(e.interpolation={escapeValue:!0});var t=e.interpolation;this.escape=void 0!==t.escape?t.escape:S,this.escapeValue=void 0===t.escapeValue||t.escapeValue,this.useRawValueToEscape=void 0!==t.useRawValueToEscape&&t.useRawValueToEscape,this.prefix=t.prefix?k(t.prefix):t.prefixEscaped||"{{",this.suffix=t.suffix?k(t.suffix):t.suffixEscaped||"}}",this.formatSeparator=t.formatSeparator?t.formatSeparator:t.formatSeparator||",",this.unescapePrefix=t.unescapeSuffix?"":t.unescapePrefix||"-",this.unescapeSuffix=this.unescapePrefix?"":t.unescapeSuffix||"",this.nestingPrefix=t.nestingPrefix?k(t.nestingPrefix):t.nestingPrefixEscaped||k("$t("),this.nestingSuffix=t.nestingSuffix?k(t.nestingSuffix):t.nestingSuffixEscaped||k(")"),this.nestingOptionsSeparator=t.nestingOptionsSeparator?t.nestingOptionsSeparator:t.nestingOptionsSeparator||",",this.maxReplaces=t.maxReplaces?t.maxReplaces:1e3,this.alwaysFormat=void 0!==t.alwaysFormat&&t.alwaysFormat,this.resetRegExp()}},{key:"reset",value:function(){this.options&&this.init(this.options)}},{key:"resetRegExp",value:function(){var e="".concat(this.prefix,"(.+?)").concat(this.suffix);this.regexp=new RegExp(e,"g");var t="".concat(this.prefix).concat(this.unescapePrefix,"(.+?)").concat(this.unescapeSuffix).concat(this.suffix);this.regexpUnescape=new RegExp(t,"g");var n="".concat(this.nestingPrefix,"(.+?)").concat(this.nestingSuffix);this.nestingRegexp=new RegExp(n,"g")}},{key:"interpolate",value:function(e,t,i,o){var r,a,s,u=this,l=this.options&&this.options.interpolation&&this.options.interpolation.defaultVariables||{};function c(e){return e.replace(/\$/g,"$$$$")}var p=function(e){if(e.indexOf(u.formatSeparator)<0){var r=b(t,l,e);return u.alwaysFormat?u.format(r,void 0,i,n({},o,t,{interpolationkey:e})):r}var a=e.split(u.formatSeparator),s=a.shift().trim(),c=a.join(u.formatSeparator).trim();return u.format(b(t,l,s),c,i,n({},o,t,{interpolationkey:s}))};this.resetRegExp();var g=o&&o.missingInterpolationHandler||this.options.missingInterpolationHandler,f=o&&o.interpolation&&o.interpolation.skipOnVariables||this.options.interpolation.skipOnVariables;return[{regex:this.regexpUnescape,safeValue:function(e){return c(e)}},{regex:this.regexp,safeValue:function(e){return u.escapeValue?c(u.escape(e)):c(e)}}].forEach(function(t){for(s=0;r=t.regex.exec(e);){if(void 0===(a=p(r[1].trim())))if("function"==typeof g){var n=g(e,r,o);a="string"==typeof n?n:""}else{if(f){a=r[0];continue}u.logger.warn("missed to pass in variable ".concat(r[1]," for interpolating ").concat(e)),a=""}else"string"==typeof a||u.useRawValueToEscape||(a=d(a));var i=t.safeValue(a);if(e=e.replace(r[0],i),f?(t.regex.lastIndex+=i.length,t.regex.lastIndex-=r[0].length):t.regex.lastIndex=0,++s>=u.maxReplaces)break}}),e}},{key:"nest",value:function(e,t){var i,o,r=this,a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},s=n({},a);function u(e,t){var i=this.nestingOptionsSeparator;if(e.indexOf(i)<0)return e;var o=e.split(new RegExp("".concat(i,"[ ]*{"))),r="{".concat(o[1]);e=o[0],r=(r=this.interpolate(r,s)).replace(/'/g,'"');try{s=JSON.parse(r),t&&(s=n({},t,s))}catch(t){return this.logger.warn("failed parsing options string in nesting for key ".concat(e),t),"".concat(e).concat(i).concat(r)}return delete s.defaultValue,e}for(s.applyPostProcessor=!1,delete s.defaultValue;i=this.nestingRegexp.exec(e);){var l=[],c=!1;if(-1!==i[0].indexOf(this.formatSeparator)&&!/{.*}/.test(i[1])){var p=i[1].split(this.formatSeparator).map(function(e){return e.trim()});i[1]=p.shift(),l=p,c=!0}if((o=t(u.call(this,i[1].trim(),s),s))&&i[0]===e&&"string"!=typeof o)return o;"string"!=typeof o&&(o=d(o)),o||(this.logger.warn("missed to resolve ".concat(i[1]," for nesting ").concat(e)),o=""),c&&(o=l.reduce(function(e,t){return r.format(e,t,a.lng,n({},a,{interpolationkey:i[1].trim()}))},o.trim())),e=e.replace(i[0],o),this.regexp.lastIndex=0}return e}}]),e}();var T=function(e){function t(e,n,o){var r,l=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};return i(this,t),r=s(this,u(t).call(this)),w&&f.call(a(r)),r.backend=e,r.store=n,r.services=o,r.languageUtils=o.languageUtils,r.options=l,r.logger=g.create("backendConnector"),r.state={},r.queue=[],r.backend&&r.backend.init&&r.backend.init(o,l.backend,l),r}return c(t,f),r(t,[{key:"queueLoad",value:function(e,t,n,i){var o=this,r=[],a=[],s=[],u=[];return e.forEach(function(e){var i=!0;t.forEach(function(t){var s="".concat(e,"|").concat(t);!n.reload&&o.store.hasResourceBundle(e,t)?o.state[s]=2:o.state[s]<0||(1===o.state[s]?a.indexOf(s)<0&&a.push(s):(o.state[s]=1,i=!1,a.indexOf(s)<0&&a.push(s),r.indexOf(s)<0&&r.push(s),u.indexOf(t)<0&&u.push(t)))}),i||s.push(e)}),(r.length||a.length)&&this.queue.push({pending:a,loaded:{},errors:[],callback:i}),{toLoad:r,pending:a,toLoadLanguages:s,toLoadNamespaces:u}}},{key:"loaded",value:function(e,t,n){var i=e.split("|"),o=i[0],r=i[1];t&&this.emit("failedLoading",o,r,t),n&&this.store.addResourceBundle(o,r,n),this.state[e]=t?-1:2;var a={};this.queue.forEach(function(n){var i,s,u,l,c,p;i=n.loaded,s=r,l=v(i,[o],Object),c=l.obj,p=l.k,c[p]=c[p]||[],u&&(c[p]=c[p].concat(s)),u||c[p].push(s),function(e,t){for(var n=e.indexOf(t);-1!==n;)e.splice(n,1),n=e.indexOf(t)}(n.pending,e),t&&n.errors.push(t),0!==n.pending.length||n.done||(Object.keys(n.loaded).forEach(function(e){a[e]||(a[e]=[]),n.loaded[e].length&&n.loaded[e].forEach(function(t){a[e].indexOf(t)<0&&a[e].push(t)})}),n.done=!0,n.errors.length?n.callback(n.errors):n.callback())}),this.emit("loaded",a),this.queue=this.queue.filter(function(e){return!e.done})}},{key:"read",value:function(e,t,n){var i=this,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,r=arguments.length>4&&void 0!==arguments[4]?arguments[4]:350,a=arguments.length>5?arguments[5]:void 0;return e.length?this.backend[n](e,t,function(s,u){s&&u&&o<5?setTimeout(function(){i.read.call(i,e,t,n,o+1,2*r,a)},r):a(s,u)}):a(null,{})}},{key:"prepareLoading",value:function(e,t){var n=this,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},o=arguments.length>3?arguments[3]:void 0;if(!this.backend)return this.logger.warn("No backend was added via i18next.use. Will not load resources."),o&&o();"string"==typeof e&&(e=this.languageUtils.toResolveHierarchy(e)),"string"==typeof t&&(t=[t]);var r=this.queueLoad(e,t,i,o);if(!r.toLoad.length)return r.pending.length||o(),null;r.toLoad.forEach(function(e){n.loadOne(e)})}},{key:"load",value:function(e,t,n){this.prepareLoading(e,t,{},n)}},{key:"reload",value:function(e,t,n){this.prepareLoading(e,t,{reload:!0},n)}},{key:"loadOne",value:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",i=e.split("|"),o=i[0],r=i[1];this.read(o,r,"read",void 0,void 0,function(i,a){i&&t.logger.warn("".concat(n,"loading namespace ").concat(r," for language ").concat(o," failed"),i),!i&&a&&t.logger.log("".concat(n,"loaded namespace ").concat(r," for language ").concat(o),a),t.loaded(e,i,a)})}},{key:"saveMissing",value:function(e,t,i,o,r){var a=arguments.length>5&&void 0!==arguments[5]?arguments[5]:{};this.services.utils&&this.services.utils.hasLoadedNamespace&&!this.services.utils.hasLoadedNamespace(t)?this.logger.warn('did not save key "'.concat(i,'" as the namespace "').concat(t,'" was not yet loaded'),"This means something IS WRONG in your setup. You access the t function before i18next.init / i18next.loadNamespace / i18next.changeLanguage was done. Wait for the callback or Promise to resolve before accessing it!!!"):null!=i&&""!==i&&(this.backend&&this.backend.create&&this.backend.create(e,t,i,o,null,n({},a,{isUpdate:r})),e&&e[0]&&this.store.addResource(e[0],t,i,o))}}]),t}();function A(e){return"string"==typeof e.ns&&(e.ns=[e.ns]),"string"==typeof e.fallbackLng&&(e.fallbackLng=[e.fallbackLng]),"string"==typeof e.fallbackNS&&(e.fallbackNS=[e.fallbackNS]),e.whitelist&&(e.whitelist&&e.whitelist.indexOf("cimode")<0&&(e.whitelist=e.whitelist.concat(["cimode"])),e.supportedLngs=e.whitelist),e.nonExplicitWhitelist&&(e.nonExplicitSupportedLngs=e.nonExplicitWhitelist),e.supportedLngs&&e.supportedLngs.indexOf("cimode")<0&&(e.supportedLngs=e.supportedLngs.concat(["cimode"])),e}function U(){}return new(function(t){function o(){var e,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=arguments.length>1?arguments[1]:void 0;if(i(this,o),e=s(this,u(o).call(this)),w&&f.call(a(e)),e.options=A(t),e.services={},e.logger=g,e.modules={external:[]},n&&!e.isInitialized&&!t.isClone){if(!e.options.initImmediate)return e.init(t,n),s(e,a(e));setTimeout(function(){e.init(t,n)},0)}return e}return c(o,f),r(o,[{key:"init",value:function(){var t=this,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},o=arguments.length>1?arguments[1]:void 0;function r(e){return e?"function"==typeof e?new e:e:null}if("function"==typeof i&&(o=i,i={}),i.whitelist&&!i.supportedLngs&&this.logger.deprecate("whitelist",'option "whitelist" will be renamed to "supportedLngs" in the next major - please make sure to rename this option asap.'),i.nonExplicitWhitelist&&!i.nonExplicitSupportedLngs&&this.logger.deprecate("whitelist",'options "nonExplicitWhitelist" will be renamed to "nonExplicitSupportedLngs" in the next major - please make sure to rename this option asap.'),this.options=n({},{debug:!1,initImmediate:!0,ns:["translation"],defaultNS:["translation"],fallbackLng:["dev"],fallbackNS:!1,whitelist:!1,nonExplicitWhitelist:!1,supportedLngs:!1,nonExplicitSupportedLngs:!1,load:"all",preload:!1,simplifyPluralSuffix:!0,keySeparator:".",nsSeparator:":",pluralSeparator:"_",contextSeparator:"_",partialBundledLanguages:!1,saveMissing:!1,updateMissing:!1,saveMissingTo:"fallback",saveMissingPlurals:!0,missingKeyHandler:!1,missingInterpolationHandler:!1,postProcess:!1,postProcessPassResolved:!1,returnNull:!0,returnEmptyString:!0,returnObjects:!1,joinArrays:!1,returnedObjectHandler:!1,parseMissingKeyHandler:!1,appendNamespaceToMissingKey:!1,appendNamespaceToCIMode:!1,overloadTranslationOptionHandler:function(t){var n={};if("object"===e(t[1])&&(n=t[1]),"string"==typeof t[1]&&(n.defaultValue=t[1]),"string"==typeof t[2]&&(n.tDescription=t[2]),"object"===e(t[2])||"object"===e(t[3])){var i=t[3]||t[2];Object.keys(i).forEach(function(e){n[e]=i[e]})}return n},interpolation:{escapeValue:!0,format:function(e,t,n,i){return e},prefix:"{{",suffix:"}}",formatSeparator:",",unescapePrefix:"-",nestingPrefix:"$t(",nestingSuffix:")",nestingOptionsSeparator:",",maxReplaces:1e3,skipOnVariables:!1}},this.options,A(i)),this.format=this.options.interpolation.format,o||(o=U),!this.options.isClone){this.modules.logger?g.init(r(this.modules.logger),this.options):g.init(null,this.options);var a=new j(this.options);this.store=new L(this.options.resources,this.options);var s=this.services;s.logger=g,s.resourceStore=this.store,s.languageUtils=a,s.pluralResolver=new F(a,{prepend:this.options.pluralSeparator,compatibilityJSON:this.options.compatibilityJSON,simplifyPluralSuffix:this.options.simplifyPluralSuffix}),s.interpolator=new V(this.options),s.utils={hasLoadedNamespace:this.hasLoadedNamespace.bind(this)},s.backendConnector=new T(r(this.modules.backend),s.resourceStore,s,this.options),s.backendConnector.on("*",function(e){for(var n=arguments.length,i=new Array(n>1?n-1:0),o=1;o1?n-1:0),o=1;o0&&"dev"!==u[0]&&(this.options.lng=u[0])}this.services.languageDetector||this.options.lng||this.logger.warn("init: no languageDetector is used and no lng is defined");["getResource","hasResourceBundle","getResourceBundle","getDataByLanguage"].forEach(function(e){t[e]=function(){var n;return(n=t.store)[e].apply(n,arguments)}});["addResource","addResources","addResourceBundle","removeResourceBundle"].forEach(function(e){t[e]=function(){var n;return(n=t.store)[e].apply(n,arguments),t}});var l=h(),c=function(){var e=function(e,n){t.isInitialized&&t.logger.warn("init: i18next is already initialized. You should call init just once!"),t.isInitialized=!0,t.options.isClone||t.logger.log("initialized",t.options),t.emit("initialized",t.options),l.resolve(n),o(e,n)};if(t.languages&&"v1"!==t.options.compatibilityAPI&&!t.isInitialized)return e(null,t.t.bind(t));t.changeLanguage(t.options.lng,e)};return this.options.resources||!this.options.initImmediate?c():setTimeout(c,0),l}},{key:"loadResources",value:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:U,i="string"==typeof e?e:this.language;if("function"==typeof e&&(n=e),!this.options.resources||this.options.partialBundledLanguages){if(i&&"cimode"===i.toLowerCase())return n();var o=[],r=function(e){e&&t.services.languageUtils.toResolveHierarchy(e).forEach(function(e){o.indexOf(e)<0&&o.push(e)})};if(i)r(i);else this.services.languageUtils.getFallbackCodes(this.options.fallbackLng).forEach(function(e){return r(e)});this.options.preload&&this.options.preload.forEach(function(e){return r(e)}),this.services.backendConnector.load(o,this.options.ns,n)}else n(null)}},{key:"reloadResources",value:function(e,t,n){var i=h();return e||(e=this.languages),t||(t=this.options.ns),n||(n=U),this.services.backendConnector.reload(e,t,function(e){i.resolve(),n(e)}),i}},{key:"use",value:function(e){if(!e)throw new Error("You are passing an undefined module! Please check the object you are passing to i18next.use()");if(!e.type)throw new Error("You are passing a wrong module! Please check the object you are passing to i18next.use()");return"backend"===e.type&&(this.modules.backend=e),("logger"===e.type||e.log&&e.warn&&e.error)&&(this.modules.logger=e),"languageDetector"===e.type&&(this.modules.languageDetector=e),"i18nFormat"===e.type&&(this.modules.i18nFormat=e),"postProcessor"===e.type&&O.addPostProcessor(e),"3rdParty"===e.type&&this.modules.external.push(e),this}},{key:"changeLanguage",value:function(e,t){var n=this;this.isLanguageChangingTo=e;var i=h();this.emit("languageChanging",e);var o=function(e){var o="string"==typeof e?e:n.services.languageUtils.getBestMatchFromCodes(e);o&&(n.language||(n.language=o,n.languages=n.services.languageUtils.toResolveHierarchy(o)),n.translator.language||n.translator.changeLanguage(o),n.services.languageDetector&&n.services.languageDetector.cacheUserLanguage(o)),n.loadResources(o,function(e){!function(e,o){o?(n.language=o,n.languages=n.services.languageUtils.toResolveHierarchy(o),n.translator.changeLanguage(o),n.isLanguageChangingTo=void 0,n.emit("languageChanged",o),n.logger.log("languageChanged",o)):n.isLanguageChangingTo=void 0,i.resolve(function(){return n.t.apply(n,arguments)}),t&&t(e,function(){return n.t.apply(n,arguments)})}(e,o)})};return e||!this.services.languageDetector||this.services.languageDetector.async?!e&&this.services.languageDetector&&this.services.languageDetector.async?this.services.languageDetector.detect(o):o(e):o(this.services.languageDetector.detect()),i}},{key:"getFixedT",value:function(t,i){var o=this,r=function t(i,r){var a;if("object"!==e(r)){for(var s=arguments.length,u=new Array(s>2?s-2:0),l=2;l1&&void 0!==arguments[1]?arguments[1]:{};if(!this.isInitialized)return this.logger.warn("hasLoadedNamespace: i18next was not initialized",this.languages),!1;if(!this.languages||!this.languages.length)return this.logger.warn("hasLoadedNamespace: i18n.languages were undefined or empty",this.languages),!1;var i=this.languages[0],o=!!this.options&&this.options.fallbackLng,r=this.languages[this.languages.length-1];if("cimode"===i.toLowerCase())return!0;var a=function(e,n){var i=t.services.backendConnector.state["".concat(e,"|").concat(n)];return-1===i||2===i};if(n.precheck){var s=n.precheck(this,a);if(void 0!==s)return s}return!!this.hasResourceBundle(i,e)||(!this.services.backendConnector.backend||!(!a(i,e)||o&&!a(r,e)))}},{key:"loadNamespaces",value:function(e,t){var n=this,i=h();return this.options.ns?("string"==typeof e&&(e=[e]),e.forEach(function(e){n.options.ns.indexOf(e)<0&&n.options.ns.push(e)}),this.loadResources(function(e){i.resolve(),t&&t(e)}),i):(t&&t(),Promise.resolve())}},{key:"loadLanguages",value:function(e,t){var n=h();"string"==typeof e&&(e=[e]);var i=this.options.preload||[],o=e.filter(function(e){return i.indexOf(e)<0});return o.length?(this.options.preload=i.concat(o),this.loadResources(function(e){n.resolve(),t&&t(e)}),n):(t&&t(),Promise.resolve())}},{key:"dir",value:function(e){if(e||(e=this.languages&&this.languages.length>0?this.languages[0]:this.language),!e)return"rtl";return["ar","shu","sqr","ssh","xaa","yhd","yud","aao","abh","abv","acm","acq","acw","acx","acy","adf","ads","aeb","aec","afb","ajp","apc","apd","arb","arq","ars","ary","arz","auz","avl","ayh","ayl","ayn","ayp","bbz","pga","he","iw","ps","pbt","pbu","pst","prp","prd","ug","ur","ydd","yds","yih","ji","yi","hbo","men","xmn","fa","jpr","peo","pes","prs","dv","sam"].indexOf(this.services.languageUtils.getLanguagePartFromCode(e))>=0?"rtl":"ltr"}},{key:"createInstance",value:function(){return new o(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},arguments.length>1?arguments[1]:void 0)}},{key:"cloneInstance",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:U,r=n({},this.options,t,{isClone:!0}),a=new o(r);return["store","services","language"].forEach(function(t){a[t]=e[t]}),a.services=n({},this.services),a.services.utils={hasLoadedNamespace:a.hasLoadedNamespace.bind(a)},a.translator=new R(a.services,a.options),a.translator.on("*",function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),i=1;i {
+ await i18next.init({
+ lng: lang,
+ fallbackLng: "en",
+ resources: {}
+ }).then(() => {
+ l10n.language.direction = i18next.dir();
+ l10n.switchTo(lang);
+ });
+ };
+
+ l10n.get = (key, parameter) => {
+ return i18next.t(key, parameter);
+ };
+
+ l10n.loadLanguageResource = (lang) => {
+ return new Promise((resolve, reject) => {
+ axios.get("./locales/" + lang + ".json").then((response) => {
+ resolve(response.data);
+ }).catch((error) => {
+ console.log("Failed to load " + lang + " language: " + error);
+ resolve(null); // Resolve with null to indicate failure
+ });
+ });
+ };
+
+ l10n.switchTo = (lang) => {
+ if (!i18next.hasResourceBundle(lang, "translation")) {
+ console.log("Loading " + lang + " language");
+ l10n.loadLanguageResource(lang).then((locales) => {
+ if (locales !== null) {
+ i18next.addResourceBundle(lang, "translation", locales);
+ i18next.changeLanguage(lang);
+ triggerLocalizedEvent();
+ } else {
+ l10n.init("en");
+ }
+ });
+ } else {
+ i18next.changeLanguage(lang);
+ triggerLocalizedEvent();
+ }
+ };
+
+
+ function triggerLocalizedEvent() {
+ const event = new Event("localized");
+ window.dispatchEvent(event);
+ };
+
+ return l10n;
+});
diff --git a/activities/XOEditor.activity/lib/sugar-web/activity/activity.js b/activities/XOEditor.activity/lib/sugar-web/activity/activity.js
index c3524b432..61143d166 100644
--- a/activities/XOEditor.activity/lib/sugar-web/activity/activity.js
+++ b/activities/XOEditor.activity/lib/sugar-web/activity/activity.js
@@ -1,12 +1,11 @@
-define(["webL10n",
- "sugar-web/activity/shortcut",
+define(["sugar-web/activity/shortcut",
"sugar-web/bus",
"sugar-web/env",
"sugar-web/datastore",
"sugar-web/presence",
"sugar-web/graphics/icon",
"sugar-web/graphics/activitypalette"], function (
- l10n, shortcut, bus, env, datastore, presence, icon, activitypalette) {
+ shortcut, bus, env, datastore, presence, icon, activitypalette) {
'use strict';
@@ -22,8 +21,6 @@ define(["webL10n",
activity.setup = function () {
bus.listen();
- l10n.start();
-
function sendPauseEvent() {
var pauseEvent = document.createEvent("CustomEvent");
pauseEvent.initCustomEvent('activityPause', false, false, {
diff --git a/activities/XOEditor.activity/lib/sugar-web/package.json b/activities/XOEditor.activity/lib/sugar-web/package.json
index f2e3555b2..0c2dec139 100644
--- a/activities/XOEditor.activity/lib/sugar-web/package.json
+++ b/activities/XOEditor.activity/lib/sugar-web/package.json
@@ -2,7 +2,6 @@
"volo": {
"baseUrl": "lib",
"dependencies": {
- "webL10n": "github:sugarlabs/webL10n",
"mustache": "github:janl/mustache.js/0.7.2",
"text": "github:requirejs/text"
}
diff --git a/activities/XOEditor.activity/lib/sugar-web/test/loader.js b/activities/XOEditor.activity/lib/sugar-web/test/loader.js
index aec983753..7c83cc931 100644
--- a/activities/XOEditor.activity/lib/sugar-web/test/loader.js
+++ b/activities/XOEditor.activity/lib/sugar-web/test/loader.js
@@ -9,8 +9,7 @@ requirejs.config({
paths: {
"sugar-web": ".",
"mustache": "lib/mustache",
- "text": "lib/text",
- "webL10n": "lib/webL10n"
+ "text": "lib/text"
},
// ask Require.js to load these files (all our tests)
diff --git a/activities/XOEditor.activity/lib/tutorial.js b/activities/XOEditor.activity/lib/tutorial.js
index e3397cd8e..b6c3e851a 100644
--- a/activities/XOEditor.activity/lib/tutorial.js
+++ b/activities/XOEditor.activity/lib/tutorial.js
@@ -1,4 +1,4 @@
-define(["webL10n"], function(l10n) {
+define(["l10n"], function(l10n) {
var tutorial = {};
tutorial.start = function() {
@@ -36,7 +36,7 @@ define(["webL10n"], function(l10n) {
document.querySelector(step.element).style.display != "none" &&
document.querySelector(step.element).getBoundingClientRect().y != 0)
);
-
+
introJs()
.setOptions({
tooltipClass: "customTooltip",
diff --git a/activities/XOEditor.activity/lib/webL10n.js b/activities/XOEditor.activity/lib/webL10n.js
deleted file mode 100644
index f76d66a5e..000000000
--- a/activities/XOEditor.activity/lib/webL10n.js
+++ /dev/null
@@ -1,1029 +0,0 @@
-/**
- * Copyright (c) 2011-2013 Fabien Cazenave, Mozilla.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-/*jshint browser: true, devel: true, es5: true, globalstrict: true */
-'use strict';
-
-define(function (require) {
- var gL10nData = {};
- var gTextData = '';
- var gTextProp = 'textContent';
- var gLanguage = '';
- var gMacros = {};
- var gReadyState = 'loading';
-
- /**
- * Synchronously loading l10n resources significantly minimizes flickering
- * from displaying the app with non-localized strings and then updating the
- * strings. Although this will block all script execution on this page, we
- * expect that the l10n resources are available locally on flash-storage.
- *
- * As synchronous XHR is generally considered as a bad idea, we're still
- * loading l10n resources asynchronously -- but we keep this in a setting,
- * just in case... and applications using this library should hide their
- * content until the `localized' event happens.
- */
-
- var gAsyncResourceLoading = true; // read-only
-
-
- /**
- * Debug helpers
- *
- * gDEBUG == 0: don't display any console message
- * gDEBUG == 1: display only warnings, not logs
- * gDEBUG == 2: display all console messages
- */
-
- var gDEBUG = 1;
-
- function consoleLog(message) {
- if (gDEBUG >= 2) {
- console.log('[l10n] ' + message);
- }
- };
-
- function consoleWarn(message) {
- if (gDEBUG) {
- console.warn('[l10n] ' + message);
- }
- };
-
-
- /**
- * DOM helpers for the so-called "HTML API".
- *
- * These functions are written for modern browsers. For old versions of IE,
- * they're overridden in the 'startup' section at the end of this file.
- */
-
- function getL10nResourceLinks() {
- return document.querySelectorAll('link[type="application/l10n"]');
- }
-
- function getL10nDictionary() {
- var script = document.querySelector('script[type="application/l10n"]');
- // TODO: support multiple and external JSON dictionaries
- return script ? JSON.parse(script.innerHTML) : null;
- }
-
- function getTranslatableChildren(element) {
- return element ? element.querySelectorAll('*[data-l10n-id]') : [];
- }
-
- function getL10nAttributes(element) {
- if (!element)
- return {};
-
- var l10nId = element.getAttribute('data-l10n-id');
- var l10nArgs = element.getAttribute('data-l10n-args');
- var args = {};
- if (l10nArgs) {
- try {
- args = JSON.parse(l10nArgs);
- } catch (e) {
- consoleWarn('could not parse arguments for #' + l10nId);
- }
- }
- return { id: l10nId, args: args };
- }
-
- function fireL10nReadyEvent(lang) {
- var evtObject = document.createEvent('Event');
- evtObject.initEvent('localized', true, false);
- evtObject.language = lang;
- document.dispatchEvent(evtObject);
- }
-
- function xhrLoadText(url, onSuccess, onFailure, asynchronous) {
- onSuccess = onSuccess || function _onSuccess(data) {};
- onFailure = onFailure || function _onFailure() {
- consoleWarn(url + ' not found.');
- };
-
- var xhr = new XMLHttpRequest();
- xhr.open('GET', url, asynchronous);
- if (xhr.overrideMimeType) {
- xhr.overrideMimeType('text/plain; charset=utf-8');
- }
- xhr.onreadystatechange = function() {
- if (xhr.readyState == 4) {
- if (xhr.status == 200 || xhr.status === 0) {
- onSuccess(xhr.responseText);
- } else {
- onFailure();
- }
- }
- };
- xhr.onerror = onFailure;
- xhr.ontimeout = onFailure;
-
- // in Firefox OS with the app:// protocol, trying to XHR a non-existing
- // URL will raise an exception here -- hence this ugly try...catch.
- try {
- xhr.send(null);
- } catch (e) {
- onFailure();
- }
- }
-
-
- /**
- * l10n resource parser:
- * - reads (async XHR) the l10n resource matching `lang';
- * - imports linked resources (synchronously) when specified;
- * - parses the text data (fills `gL10nData' and `gTextData');
- * - triggers success/failure callbacks when done.
- *
- * @param {string} href
- * URL of the l10n resource to parse.
- *
- * @param {string} lang
- * locale (language) to parse.
- *
- * @param {Function} successCallback
- * triggered when the l10n resource has been successully parsed.
- *
- * @param {Function} failureCallback
- * triggered when the an error has occured.
- *
- * @return {void}
- * uses the following global variables: gL10nData, gTextData, gTextProp.
- */
-
- function parseResource(href, lang, successCallback, failureCallback) {
- var baseURL = href.replace(/[^\/]*$/, '') || './';
-
- // handle escaped characters (backslashes) in a string
- function evalString(text) {
- if (text.lastIndexOf('\\') < 0)
- return text;
- return text.replace(/\\\\/g, '\\')
- .replace(/\\n/g, '\n')
- .replace(/\\r/g, '\r')
- .replace(/\\t/g, '\t')
- .replace(/\\b/g, '\b')
- .replace(/\\f/g, '\f')
- .replace(/\\{/g, '{')
- .replace(/\\}/g, '}')
- .replace(/\\"/g, '"')
- .replace(/\\'/g, "'");
- }
-
- // parse *.properties text data into an l10n dictionary
- function parseProperties(text) {
- var dictionary = [];
-
- // token expressions
- var reBlank = /^\s*|\s*$/;
- var reComment = /^\s*#|^\s*$/;
- var reSection = /^\s*\[(.*)\]\s*$/;
- var reImport = /^\s*@import\s+url\((.*)\)\s*$/i;
- var reSplit = /^([^=\s]*)\s*=\s*(.+)$/; // TODO: escape EOLs with '\'
-
- // parse the *.properties file into an associative array
- function parseRawLines(rawText, extendedSyntax) {
- var entries = rawText.replace(reBlank, '').split(/[\r\n]+/);
- var currentLang = '*';
- var genericLang = lang.replace(/-[a-z]+$/i, '');
- var skipLang = false;
- var match = '';
-
- for (var i = 0; i < entries.length; i++) {
- var line = entries[i];
-
- // comment or blank line?
- if (reComment.test(line))
- continue;
-
- // the extended syntax supports [lang] sections and @import rules
- if (extendedSyntax) {
- if (reSection.test(line)) { // section start?
- match = reSection.exec(line);
- currentLang = match[1];
- skipLang = (currentLang !== '*') &&
- (currentLang !== lang) && (currentLang !== genericLang);
- continue;
- } else if (skipLang) {
- continue;
- }
- if (reImport.test(line)) { // @import rule?
- match = reImport.exec(line);
- loadImport(baseURL + match[1]); // load the resource synchronously
- }
- }
-
- // key-value pair
- var tmp = line.match(reSplit);
- if (tmp && tmp.length == 3) {
- dictionary[tmp[1]] = evalString(tmp[2]);
- }
- }
- }
-
- // import another *.properties file
- function loadImport(url) {
- xhrLoadText(url, function(content) {
- parseRawLines(content, false); // don't allow recursive imports
- }, null, false); // load synchronously
- }
-
- // fill the dictionary
- parseRawLines(text, true);
- return dictionary;
- }
-
- // load and parse l10n data (warning: global variables are used here)
- xhrLoadText(href, function(response) {
- gTextData += response; // mostly for debug
-
- // parse *.properties text data into an l10n dictionary
- var data = parseProperties(response);
-
- // find attribute descriptions, if any
- for (var key in data) {
- var id, prop, index = key.lastIndexOf('.');
- if (index > 0) { // an attribute has been specified
- id = key.substring(0, index);
- prop = key.substr(index + 1);
- } else { // no attribute: assuming text content by default
- id = key;
- prop = gTextProp;
- }
- if (!gL10nData[id]) {
- gL10nData[id] = {};
- }
- gL10nData[id][prop] = data[key];
- }
-
- // trigger callback
- if (successCallback) {
- successCallback();
- }
- }, failureCallback, gAsyncResourceLoading);
- };
-
- // load and parse all resources for the specified locale
- function loadLocale(lang, callback) {
- callback = callback || function _callback() {};
-
- clear();
- gLanguage = lang;
-
- // check all nodes
- // and load the resource files
- var langLinks = getL10nResourceLinks();
- var langCount = langLinks.length;
- if (langCount == 0) {
- // we might have a pre-compiled dictionary instead
- var dict = getL10nDictionary();
- if (dict && dict.locales && dict.default_locale) {
- consoleLog('using the embedded JSON directory, early way out');
- gL10nData = dict.locales[lang] || dict.locales[dict.default_locale];
- callback();
- } else {
- consoleLog('no resource to load, early way out');
- }
- // early way out
- fireL10nReadyEvent(lang);
- gReadyState = 'complete';
- return;
- }
-
- // start the callback when all resources are loaded
- var onResourceLoaded = null;
- var gResourceCount = 0;
- onResourceLoaded = function() {
- gResourceCount++;
- if (gResourceCount >= langCount) {
- callback();
- fireL10nReadyEvent(lang);
- gReadyState = 'complete';
- }
- };
-
- // load all resource files
- function l10nResourceLink(link) {
- var href = link.href;
- var type = link.type;
- this.load = function(lang, callback) {
- var applied = lang;
- parseResource(href, lang, callback, function() {
- consoleWarn(href + ' not found.');
- applied = '';
- });
- return applied; // return lang if found, an empty string if not found
- };
- }
-
- for (var i = 0; i < langCount; i++) {
- var resource = new l10nResourceLink(langLinks[i]);
- var rv = resource.load(lang, onResourceLoaded);
- if (rv != lang) { // lang not found, used default resource instead
- consoleWarn('"' + lang + '" resource not found');
- gLanguage = '';
- }
- }
- }
-
- // clear all l10n data
- function clear() {
- gL10nData = {};
- gTextData = '';
- gLanguage = '';
- // TODO: clear all non predefined macros.
- // There's no such macro /yet/ but we're planning to have some...
- }
-
-
- /**
- * Get rules for plural forms (shared with JetPack), see:
- * http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
- * https://github.com/mozilla/addon-sdk/blob/master/python-lib/plural-rules-generator.p
- *
- * @param {string} lang
- * locale (language) used.
- *
- * @return {Function}
- * returns a function that gives the plural form name for a given integer:
- * var fun = getPluralRules('en');
- * fun(1) -> 'one'
- * fun(0) -> 'other'
- * fun(1000) -> 'other'.
- */
-
- function getPluralRules(lang) {
- var locales2rules = {
- 'af': 3,
- 'ak': 4,
- 'am': 4,
- 'ar': 1,
- 'asa': 3,
- 'az': 0,
- 'be': 11,
- 'bem': 3,
- 'bez': 3,
- 'bg': 3,
- 'bh': 4,
- 'bm': 0,
- 'bn': 3,
- 'bo': 0,
- 'br': 20,
- 'brx': 3,
- 'bs': 11,
- 'ca': 3,
- 'cgg': 3,
- 'chr': 3,
- 'cs': 12,
- 'cy': 17,
- 'da': 3,
- 'de': 3,
- 'dv': 3,
- 'dz': 0,
- 'ee': 3,
- 'el': 3,
- 'en': 3,
- 'eo': 3,
- 'es': 3,
- 'et': 3,
- 'eu': 3,
- 'fa': 0,
- 'ff': 5,
- 'fi': 3,
- 'fil': 4,
- 'fo': 3,
- 'fr': 5,
- 'fur': 3,
- 'fy': 3,
- 'ga': 8,
- 'gd': 24,
- 'gl': 3,
- 'gsw': 3,
- 'gu': 3,
- 'guw': 4,
- 'gv': 23,
- 'ha': 3,
- 'haw': 3,
- 'he': 2,
- 'hi': 4,
- 'hr': 11,
- 'hu': 0,
- 'id': 0,
- 'ig': 0,
- 'ii': 0,
- 'is': 3,
- 'it': 3,
- 'iu': 7,
- 'ja': 0,
- 'jmc': 3,
- 'jv': 0,
- 'ka': 0,
- 'kab': 5,
- 'kaj': 3,
- 'kcg': 3,
- 'kde': 0,
- 'kea': 0,
- 'kk': 3,
- 'kl': 3,
- 'km': 0,
- 'kn': 0,
- 'ko': 0,
- 'ksb': 3,
- 'ksh': 21,
- 'ku': 3,
- 'kw': 7,
- 'lag': 18,
- 'lb': 3,
- 'lg': 3,
- 'ln': 4,
- 'lo': 0,
- 'lt': 10,
- 'lv': 6,
- 'mas': 3,
- 'mg': 4,
- 'mk': 16,
- 'ml': 3,
- 'mn': 3,
- 'mo': 9,
- 'mr': 3,
- 'ms': 0,
- 'mt': 15,
- 'my': 0,
- 'nah': 3,
- 'naq': 7,
- 'nb': 3,
- 'nd': 3,
- 'ne': 3,
- 'nl': 3,
- 'nn': 3,
- 'no': 3,
- 'nr': 3,
- 'nso': 4,
- 'ny': 3,
- 'nyn': 3,
- 'om': 3,
- 'or': 3,
- 'pa': 3,
- 'pap': 3,
- 'pl': 13,
- 'ps': 3,
- 'pt': 3,
- 'rm': 3,
- 'ro': 9,
- 'rof': 3,
- 'ru': 11,
- 'rwk': 3,
- 'sah': 0,
- 'saq': 3,
- 'se': 7,
- 'seh': 3,
- 'ses': 0,
- 'sg': 0,
- 'sh': 11,
- 'shi': 19,
- 'sk': 12,
- 'sl': 14,
- 'sma': 7,
- 'smi': 7,
- 'smj': 7,
- 'smn': 7,
- 'sms': 7,
- 'sn': 3,
- 'so': 3,
- 'sq': 3,
- 'sr': 11,
- 'ss': 3,
- 'ssy': 3,
- 'st': 3,
- 'sv': 3,
- 'sw': 3,
- 'syr': 3,
- 'ta': 3,
- 'te': 3,
- 'teo': 3,
- 'th': 0,
- 'ti': 4,
- 'tig': 3,
- 'tk': 3,
- 'tl': 4,
- 'tn': 3,
- 'to': 0,
- 'tr': 0,
- 'ts': 3,
- 'tzm': 22,
- 'uk': 11,
- 'ur': 3,
- 've': 3,
- 'vi': 0,
- 'vun': 3,
- 'wa': 4,
- 'wae': 3,
- 'wo': 0,
- 'xh': 3,
- 'xog': 3,
- 'yo': 0,
- 'zh': 0,
- 'zu': 3
- };
-
- // utility functions for plural rules methods
- function isIn(n, list) {
- return list.indexOf(n) !== -1;
- }
- function isBetween(n, start, end) {
- return start <= n && n <= end;
- }
-
- // list of all plural rules methods:
- // map an integer to the plural form name to use
- var pluralRules = {
- '0': function(n) {
- return 'other';
- },
- '1': function(n) {
- if ((isBetween((n % 100), 3, 10)))
- return 'few';
- if (n === 0)
- return 'zero';
- if ((isBetween((n % 100), 11, 99)))
- return 'many';
- if (n == 2)
- return 'two';
- if (n == 1)
- return 'one';
- return 'other';
- },
- '2': function(n) {
- if (n !== 0 && (n % 10) === 0)
- return 'many';
- if (n == 2)
- return 'two';
- if (n == 1)
- return 'one';
- return 'other';
- },
- '3': function(n) {
- if (n == 1)
- return 'one';
- return 'other';
- },
- '4': function(n) {
- if ((isBetween(n, 0, 1)))
- return 'one';
- return 'other';
- },
- '5': function(n) {
- if ((isBetween(n, 0, 2)) && n != 2)
- return 'one';
- return 'other';
- },
- '6': function(n) {
- if (n === 0)
- return 'zero';
- if ((n % 10) == 1 && (n % 100) != 11)
- return 'one';
- return 'other';
- },
- '7': function(n) {
- if (n == 2)
- return 'two';
- if (n == 1)
- return 'one';
- return 'other';
- },
- '8': function(n) {
- if ((isBetween(n, 3, 6)))
- return 'few';
- if ((isBetween(n, 7, 10)))
- return 'many';
- if (n == 2)
- return 'two';
- if (n == 1)
- return 'one';
- return 'other';
- },
- '9': function(n) {
- if (n === 0 || n != 1 && (isBetween((n % 100), 1, 19)))
- return 'few';
- if (n == 1)
- return 'one';
- return 'other';
- },
- '10': function(n) {
- if ((isBetween((n % 10), 2, 9)) && !(isBetween((n % 100), 11, 19)))
- return 'few';
- if ((n % 10) == 1 && !(isBetween((n % 100), 11, 19)))
- return 'one';
- return 'other';
- },
- '11': function(n) {
- if ((isBetween((n % 10), 2, 4)) && !(isBetween((n % 100), 12, 14)))
- return 'few';
- if ((n % 10) === 0 ||
- (isBetween((n % 10), 5, 9)) ||
- (isBetween((n % 100), 11, 14)))
- return 'many';
- if ((n % 10) == 1 && (n % 100) != 11)
- return 'one';
- return 'other';
- },
- '12': function(n) {
- if ((isBetween(n, 2, 4)))
- return 'few';
- if (n == 1)
- return 'one';
- return 'other';
- },
- '13': function(n) {
- if ((isBetween((n % 10), 2, 4)) && !(isBetween((n % 100), 12, 14)))
- return 'few';
- if (n != 1 && (isBetween((n % 10), 0, 1)) ||
- (isBetween((n % 10), 5, 9)) ||
- (isBetween((n % 100), 12, 14)))
- return 'many';
- if (n == 1)
- return 'one';
- return 'other';
- },
- '14': function(n) {
- if ((isBetween((n % 100), 3, 4)))
- return 'few';
- if ((n % 100) == 2)
- return 'two';
- if ((n % 100) == 1)
- return 'one';
- return 'other';
- },
- '15': function(n) {
- if (n === 0 || (isBetween((n % 100), 2, 10)))
- return 'few';
- if ((isBetween((n % 100), 11, 19)))
- return 'many';
- if (n == 1)
- return 'one';
- return 'other';
- },
- '16': function(n) {
- if ((n % 10) == 1 && n != 11)
- return 'one';
- return 'other';
- },
- '17': function(n) {
- if (n == 3)
- return 'few';
- if (n === 0)
- return 'zero';
- if (n == 6)
- return 'many';
- if (n == 2)
- return 'two';
- if (n == 1)
- return 'one';
- return 'other';
- },
- '18': function(n) {
- if (n === 0)
- return 'zero';
- if ((isBetween(n, 0, 2)) && n !== 0 && n != 2)
- return 'one';
- return 'other';
- },
- '19': function(n) {
- if ((isBetween(n, 2, 10)))
- return 'few';
- if ((isBetween(n, 0, 1)))
- return 'one';
- return 'other';
- },
- '20': function(n) {
- if ((isBetween((n % 10), 3, 4) || ((n % 10) == 9)) && !(
- isBetween((n % 100), 10, 19) ||
- isBetween((n % 100), 70, 79) ||
- isBetween((n % 100), 90, 99)
- ))
- return 'few';
- if ((n % 1000000) === 0 && n !== 0)
- return 'many';
- if ((n % 10) == 2 && !isIn((n % 100), [12, 72, 92]))
- return 'two';
- if ((n % 10) == 1 && !isIn((n % 100), [11, 71, 91]))
- return 'one';
- return 'other';
- },
- '21': function(n) {
- if (n === 0)
- return 'zero';
- if (n == 1)
- return 'one';
- return 'other';
- },
- '22': function(n) {
- if ((isBetween(n, 0, 1)) || (isBetween(n, 11, 99)))
- return 'one';
- return 'other';
- },
- '23': function(n) {
- if ((isBetween((n % 10), 1, 2)) || (n % 20) === 0)
- return 'one';
- return 'other';
- },
- '24': function(n) {
- if ((isBetween(n, 3, 10) || isBetween(n, 13, 19)))
- return 'few';
- if (isIn(n, [2, 12]))
- return 'two';
- if (isIn(n, [1, 11]))
- return 'one';
- return 'other';
- }
- };
-
- // return a function that gives the plural form name for a given integer
- var index = locales2rules[lang.replace(/-.*$/, '')];
- if (!(index in pluralRules)) {
- consoleWarn('plural form unknown for [' + lang + ']');
- return function() { return 'other'; };
- }
- return pluralRules[index];
- }
-
- // pre-defined 'plural' macro
- gMacros.plural = function(str, param, key, prop) {
- var n = parseFloat(param);
- if (isNaN(n))
- return str;
-
- // TODO: support other properties (l20n still doesn't...)
- if (prop != gTextProp)
- return str;
-
- // initialize _pluralRules
- if (!gMacros._pluralRules) {
- gMacros._pluralRules = getPluralRules(gLanguage);
- }
- var index = '[' + gMacros._pluralRules(n) + ']';
-
- // try to find a [zero|one|two] key if it's defined
- if (n === 0 && (key + '[zero]') in gL10nData) {
- str = gL10nData[key + '[zero]'][prop];
- } else if (n == 1 && (key + '[one]') in gL10nData) {
- str = gL10nData[key + '[one]'][prop];
- } else if (n == 2 && (key + '[two]') in gL10nData) {
- str = gL10nData[key + '[two]'][prop];
- } else if ((key + index) in gL10nData) {
- str = gL10nData[key + index][prop];
- } else if ((key + '[other]') in gL10nData) {
- str = gL10nData[key + '[other]'][prop];
- }
-
- return str;
- };
-
-
- /**
- * l10n dictionary functions
- */
-
- // fetch an l10n object, warn if not found, apply `args' if possible
- function getL10nData(key, args) {
- var data = gL10nData[key];
- if (!data) {
- consoleWarn('#' + key + ' missing for [' + gLanguage + ']');
- }
-
- /** This is where l10n expressions should be processed.
- * The plan is to support C-style expressions from the l20n project;
- * until then, only two kinds of simple expressions are supported:
- * {[ index ]} and {{ arguments }}.
- */
- var rv = {};
- for (var prop in data) {
- var str = data[prop];
- str = substIndexes(str, args, key, prop);
- str = substArguments(str, args);
- rv[prop] = str;
- }
- return rv;
- }
-
- // replace {[macros]} with their values
- function substIndexes(str, args, key, prop) {
- var reIndex = /\{\[\s*([a-zA-Z]+)\(([a-zA-Z]+)\)\s*\]\}/;
- var reMatch = reIndex.exec(str);
- if (!reMatch || !reMatch.length)
- return str;
-
- // an index/macro has been found
- // Note: at the moment, only one parameter is supported
- var macroName = reMatch[1];
- var paramName = reMatch[2];
- var param;
- if (args && paramName in args) {
- param = args[paramName];
- } else if (paramName in gL10nData) {
- param = gL10nData[paramName];
- }
-
- // there's no macro parser yet: it has to be defined in gMacros
- if (macroName in gMacros) {
- var macro = gMacros[macroName];
- str = macro(str, param, key, prop);
- }
- return str;
- }
-
- // replace {{arguments}} with their values
- function substArguments(str, args) {
- var reArgs = /\{\{\s*([a-zA-Z\.]+)\s*\}\}/;
- var match = reArgs.exec(str);
- while (match) {
- if (!match || match.length < 2)
- return str; // argument key not found
-
- var arg = match[1];
- var sub = '';
- if (arg in args) {
- sub = args[arg];
- } else if (arg in gL10nData) {
- sub = gL10nData[arg][gTextProp];
- } else {
- consoleWarn('could not find argument {{' + arg + '}}');
- return str;
- }
-
- str = str.substring(0, match.index) + sub +
- str.substr(match.index + match[0].length);
- match = reArgs.exec(str);
- }
- return str;
- }
-
- // translate an HTML element
- function translateElement(element) {
- var l10n = getL10nAttributes(element);
- if (!l10n.id)
- return;
-
- // get the related l10n object
- var data = getL10nData(l10n.id, l10n.args);
- if (!data) {
- consoleWarn('#' + l10n.id + ' missing for [' + gLanguage + ']');
- return;
- }
-
- // translate element (TODO: security checks?)
- // for the node content, replace the content of the first child textNode
- // and clear other child textNodes
- if (data[gTextProp]) { // XXX
- if (getChildElementCount(element) === 0) {
- element[gTextProp] = data[gTextProp];
- } else {
- var children = element.childNodes,
- found = false;
- for (var i = 0, l = children.length; i < l; i++) {
- if (children[i].nodeType === 3 &&
- /\S/.test(children[i].textContent)) { // XXX
- // using nodeValue seems cross-browser
- if (found) {
- children[i].nodeValue = '';
- } else {
- children[i].nodeValue = data[gTextProp];
- found = true;
- }
- }
- }
- if (!found) {
- consoleWarn('unexpected error, could not translate element content');
- }
- }
- delete data[gTextProp];
- }
-
- for (var k in data) {
- element[k] = data[k];
- }
- }
-
- // webkit browsers don't currently support 'children' on SVG elements...
- function getChildElementCount(element) {
- if (element.children) {
- return element.children.length;
- }
- if (typeof element.childElementCount !== 'undefined') {
- return element.childElementCount;
- }
- var count = 0;
- for (var i = 0; i < element.childNodes.length; i++) {
- count += element.nodeType === 1 ? 1 : 0;
- }
- return count;
- }
-
- // translate an HTML subtree
- function translateFragment(element) {
- element = element || document.documentElement;
-
- // check all translatable children (= w/ a `data-l10n-id' attribute)
- var children = getTranslatableChildren(element);
- var elementCount = children.length;
- for (var i = 0; i < elementCount; i++) {
- translateElement(children[i]);
- }
-
- // translate element itself if necessary
- translateElement(element);
- }
-
- // Startup & Public API
-
- function l10nStartup() {
- gReadyState = 'interactive';
- consoleLog('loading [' + navigator.language + '] resources, ' +
- (gAsyncResourceLoading ? 'asynchronously.' : 'synchronously.'));
-
- // load the default locale and translate the document if required
- if (document.documentElement.lang === navigator.language) {
- loadLocale(navigator.language);
- } else {
- loadLocale(navigator.language, translateFragment);
- }
- }
-
- // public API
- var l10n = {
- start: function() {
- if (document.readyState === 'complete' ||
- document.readyState === 'interactive') {
- window.setTimeout(l10nStartup);
- } else {
- document.addEventListener('DOMContentLoaded', l10nStartup);
- }
- },
-
- // get a localized string
- get: function l10n_get(key, args, fallback) {
- var data = getL10nData(key, args) || fallback;
- if (data) {
- return 'textContent' in data ? data.textContent : '';
- }
- return '{{' + key + '}}';
- },
-
- // get|set the document language and direction
- get language() {
- return {
- // get|set the document language (ISO-639-1)
- get code() { return gLanguage; },
- set code(lang) { loadLocale(lang, translateFragment); },
-
- // get the direction (ltr|rtl) of the current language
- get direction() {
- // http://www.w3.org/International/questions/qa-scripts
- // Arabic, Hebrew, Farsi, Pashto, Urdu
- var rtlList = ['ar', 'he', 'fa', 'ps', 'ur'];
- return (rtlList.indexOf(gLanguage) >= 0) ? 'rtl' : 'ltr';
- }
- };
- },
-
- // translate an element or document fragment
- translate: translateFragment,
-
- // get (a clone of) the dictionary for the current locale
- get dictionary() { return JSON.parse(JSON.stringify(gL10nData)); },
-
- // this can be used to prevent race conditions
- get readyState() { return gReadyState; },
- ready: function l10n_ready(callback) {
- if (!callback)
- return;
-
- if (gReadyState == 'complete') {
- window.setTimeout(callback);
- } else {
- window.addEventListener('localized', callback);
- }
- }
- };
-
- return l10n;
-});
diff --git a/activities/XOEditor.activity/locale.ini b/activities/XOEditor.activity/locale.ini
deleted file mode 100644
index 06c029af4..000000000
--- a/activities/XOEditor.activity/locale.ini
+++ /dev/null
@@ -1,64 +0,0 @@
-[*]
-TutoPrev=Prev
-TutoNext=Next
-TutoEnd=End
-TutoExplainTitle=XO Editor Activity
-TutoExplainContent=Welcome into the XO Editor activity. XO Editor allow you to customize easily your buddy icon colors
-TutoSaveTitle=Save colours
-TutoSaveContent=Click here to set the current color in the middle as your buddy's color
-TutoResetTitle=Reset board
-TutoResetContent=Click here to reset the board as it was at the beginning. It's useful if you've played to move color combinations
-TutoCanvasTitle=Color variations
-TutoCanvasContent=Here are all existing color combinations. Click on a combination, it will instantly appear on the buddy in the middle to allow you to see if you like it. If so and if you want to keep it, click on the Save button then quit the activity
-
-[en]
-TutoPrev=Prev
-TutoNext=Next
-TutoEnd=End
-TutoExplainTitle=XO Editor Activity
-TutoExplainContent=Welcome into the XO Editor activity. XO Editor allow you to customize easily your buddy icon colors
-TutoSaveTitle=Save colours
-TutoSaveContent=Click here to set the current color in the middle as your buddy's color
-TutoResetTitle=Reset board
-TutoResetContent=Click here to reset the board as it was at the beginning. It's useful if you've played to move color combinations
-TutoCanvasTitle=Color variations
-TutoCanvasContent=Here are all existing color combinations. Click on a combination, it will instantly appear on the buddy in the middle to allow you to see if you like it. If so and if you want to keep it, click on the Save button then quit the activity
-
-[es]
-TutoPrev=Ant
-TutoNext=Sig
-TutoEnd=Fin
-TutoExplainTitle=Actividad "XO Editor"
-TutoExplainContent=Bienvenido a la actividad "XO Editor". "XO Editor" permite al alumno personalizar el conjunto de colores de su personaje
-TutoSaveTitle=Guardar colores
-TutoSaveContent=Haz clic aquí para elegir el color que aparece en el medio de la pantalla como tu color de personaje
-TutoResetTitle=Reiniciar
-TutoResetContent=Haz clic aquí para reiniciar tu selección. Te será útil si has experimentado combinando colores y quieres volver al color inicial
-TutoCanvasTitle=Variaciones de color
-TutoCanvasContent=Aquí podrás ver todas las combinaciones de colores disponibles. Haz clic en una combinación y aparecerá sobre el personaje (en el centro de la pantalla). Si te gusta, haz clic en Guardar y sal de la actividad
-
-[fr]
-TutoPrev=Préc
-TutoNext=Suiv
-TutoEnd=Fin
-TutoExplainTitle=Activité XO Editor
-TutoExplainContent=Bienvenue dans l'activité XO Editor. L'activité XO Editor vous permet de changer facilement votre couleur favorite qui est utilisée pour tous les icônes du Sugarizer
-TutoSaveTitle=Enregistrer couleurs
-TutoSaveContent=Cliquer ici pour enregistrer la couleur actuelle au milieu de l'écran comme votre couleur favorite
-TutoResetTitle=Réinitialiser
-TutoResetContent=Cliquez ici pour initialiser le plateau comme il était au début. C'est utile si vous vous êtes amusé à bouger les combinaisons de couleurs
-TutoCanvasTitle=Palette de couleurs
-TutoCanvasContent=Ceci sont toutes le combinaisons de couleurs possibles pour Sugarizer. Cliquez sur une combinaison et vous pourrez l'essayer sur l'icône du milieu pour voir si elle vous plait. Si c'est le cas et que vous voulez la conserver, cliquez sur le bouton Enregistrer et voilà !
-
-[pl]
-TutoPrev=Poprz
-TutoNext=Dalej
-TutoEnd=Koniec
-TutoExplainTitle=Edytor XO
-TutoExplainContent=Witaj w Edytorze XO. Edytorze kolorów twojego ludzika.
-TutoSaveTitle=Zapisz kolory
-TutoSaveContent=Kliknij aby zapisać kolory ludzika.
-TutoResetTitle=Resetuj kolory
-TutoResetContent=Kliknij aby zrestować kolory ludzika.
-TutoCanvasTitle=Kombinacje kolorów
-TutoCanvasContent=Tutaj możesz wybrać zestaw kolorów. Pojawi się on na ludziku na środku ekranu. Możesz także ruszać kolorowymi kółkami po całej planszy.
diff --git a/activities/XOEditor.activity/locales/en.json b/activities/XOEditor.activity/locales/en.json
new file mode 100644
index 000000000..9a0d8a9c3
--- /dev/null
+++ b/activities/XOEditor.activity/locales/en.json
@@ -0,0 +1,13 @@
+{
+ "TutoPrev": "Prev",
+ "TutoNext": "Next",
+ "TutoEnd": "End",
+ "TutoExplainTitle": "XO Editor Activity",
+ "TutoExplainContent": "Welcome into the XO Editor activity. XO Editor allow you to customize easily your buddy icon colors",
+ "TutoSaveTitle": "Save colours",
+ "TutoSaveContent": "Click here to set the current color in the middle as your buddy's color",
+ "TutoResetTitle": "Reset board",
+ "TutoResetContent": "Click here to reset the board as it was at the beginning. It's useful if you've played to move color combinations",
+ "TutoCanvasTitle": "Color variations",
+ "TutoCanvasContent": "Here are all existing color combinations. Click on a combination, it will instantly appear on the buddy in the middle to allow you to see if you like it. If so and if you want to keep it, click on the Save button then quit the activity"
+}
diff --git a/activities/XOEditor.activity/locales/es.json b/activities/XOEditor.activity/locales/es.json
new file mode 100644
index 000000000..ca0036d57
--- /dev/null
+++ b/activities/XOEditor.activity/locales/es.json
@@ -0,0 +1,13 @@
+{
+ "TutoPrev": "Ant",
+ "TutoNext": "Sig",
+ "TutoEnd": "Fin",
+ "TutoExplainTitle": "Actividad \"XO Editor\"",
+ "TutoExplainContent": "Bienvenido a la actividad \"XO Editor\". \"XO Editor\" permite al alumno personalizar el conjunto de colores de su personaje",
+ "TutoSaveTitle": "Guardar colores",
+ "TutoSaveContent": "Haz clic aquí para elegir el color que aparece en el medio de la pantalla como tu color de personaje",
+ "TutoResetTitle": "Reiniciar",
+ "TutoResetContent": "Haz clic aquí para reiniciar tu selección. Te será útil si has experimentado combinando colores y quieres volver al color inicial",
+ "TutoCanvasTitle": "Variaciones de color",
+ "TutoCanvasContent": "Aquí podrás ver todas las combinaciones de colores disponibles. Haz clic en una combinación y aparecerá sobre el personaje (en el centro de la pantalla). Si te gusta, haz clic en Guardar y sal de la actividad"
+}
diff --git a/activities/XOEditor.activity/locales/fr.json b/activities/XOEditor.activity/locales/fr.json
new file mode 100644
index 000000000..d4e655f54
--- /dev/null
+++ b/activities/XOEditor.activity/locales/fr.json
@@ -0,0 +1,13 @@
+{
+ "TutoPrev": "Préc",
+ "TutoNext": "Suiv",
+ "TutoEnd": "Fin",
+ "TutoExplainTitle": "Activité XO Editor",
+ "TutoExplainContent": "Bienvenue dans l'activité XO Editor. L'activité XO Editor vous permet de changer facilement votre couleur favorite qui est utilisée pour tous les icônes du Sugarizer",
+ "TutoSaveTitle": "Enregistrer couleurs",
+ "TutoSaveContent": "Cliquer ici pour enregistrer la couleur actuelle au milieu de l'écran comme votre couleur favorite",
+ "TutoResetTitle": "Réinitialiser",
+ "TutoResetContent": "Cliquez ici pour initialiser le plateau comme il était au début. C'est utile si vous vous êtes amusé à bouger les combinaisons de couleurs",
+ "TutoCanvasTitle": "Palette de couleurs",
+ "TutoCanvasContent": "Ceci sont toutes le combinaisons de couleurs possibles pour Sugarizer. Cliquez sur une combinaison et vous pourrez l'essayer sur l'icône du milieu pour voir si elle vous plait. Si c'est le cas et que vous voulez la conserver, cliquez sur le bouton Enregistrer et voilà !"
+}
diff --git a/activities/XOEditor.activity/locales/pl.json b/activities/XOEditor.activity/locales/pl.json
new file mode 100644
index 000000000..bc11f4a8d
--- /dev/null
+++ b/activities/XOEditor.activity/locales/pl.json
@@ -0,0 +1,13 @@
+{
+ "TutoPrev": "Poprz",
+ "TutoNext": "Dalej",
+ "TutoEnd": "Koniec",
+ "TutoExplainTitle": "Edytor XO",
+ "TutoExplainContent": "Witaj w Edytorze XO. Edytorze kolorów twojego ludzika.",
+ "TutoSaveTitle": "Zapisz kolory",
+ "TutoSaveContent": "Kliknij aby zapisać kolory ludzika.",
+ "TutoResetTitle": "Resetuj kolory",
+ "TutoResetContent": "Kliknij aby zrestować kolory ludzika.",
+ "TutoCanvasTitle": "Kombinacje kolorów",
+ "TutoCanvasContent": "Tutaj możesz wybrać zestaw kolorów. Pojawi się on na ludziku na środku ekranu. Możesz także ruszać kolorowymi kółkami po całej planszy."
+}
diff --git a/activities/XOEditor.activity/po/en.po b/activities/XOEditor.activity/po/en.po
deleted file mode 100644
index 5d567c7b9..000000000
--- a/activities/XOEditor.activity/po/en.po
+++ /dev/null
@@ -1,70 +0,0 @@
-#. extracted from ../locale.ini
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: Sun Apr 11 2021 11:33:40 GMT+0200 (heure d’été d’Europe centrale)\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME \n"
-"Language-Team: LANGUAGE \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"X-Generator: ini2po 0.0.1\n"
-
-#: TutoPrev
-msgctxt "TutoPrev"
-msgid "Prev"
-msgstr "Prev"
-
-#: TutoNext
-msgctxt "TutoNext"
-msgid "Next"
-msgstr "Next"
-
-#: TutoEnd
-msgctxt "TutoEnd"
-msgid "End"
-msgstr "End"
-
-#: TutoExplainTitle
-msgctxt "TutoExplainTitle"
-msgid "XO Editor Activity"
-msgstr "XO Editor Activity"
-
-#: TutoExplainContent
-msgctxt "TutoExplainContent"
-msgid "Welcome into the XO Editor activity. XO Editor allow you to customize easily your buddy icon colors"
-msgstr "Welcome into the XO Editor activity. XO Editor allow you to customize easily your buddy icon colors"
-
-#: TutoSaveTitle
-msgctxt "TutoSaveTitle"
-msgid "Save colours"
-msgstr "Save colours"
-
-#: TutoSaveContent
-msgctxt "TutoSaveContent"
-msgid "Click here to set the current color in the middle as your buddy's color"
-msgstr "Click here to set the current color in the middle as your buddy's color"
-
-#: TutoResetTitle
-msgctxt "TutoResetTitle"
-msgid "Reset board"
-msgstr "Reset board"
-
-#: TutoResetContent
-msgctxt "TutoResetContent"
-msgid "Click here to reset the board as it was at the beginning. It's useful if you've played to move color combinations"
-msgstr "Click here to reset the board as it was at the beginning. It's useful if you've played to move color combinations"
-
-#: TutoCanvasTitle
-msgctxt "TutoCanvasTitle"
-msgid "Color variations"
-msgstr "Color variations"
-
-#: TutoCanvasContent
-msgctxt "TutoCanvasContent"
-msgid "Here are all existing color combinations. Click on a combination, it will instantly appear on the buddy in the middle to allow you to see if you like it. If so and if you want to keep it, click on the Save button then quit the activity"
-msgstr "Here are all existing color combinations. Click on a combination, it will instantly appear on the buddy in the middle to allow you to see if you like it. If so and if you want to keep it, click on the Save button then quit the activity"
-
diff --git a/activities/XOEditor.activity/po/es.po b/activities/XOEditor.activity/po/es.po
deleted file mode 100644
index aaa3172e4..000000000
--- a/activities/XOEditor.activity/po/es.po
+++ /dev/null
@@ -1,70 +0,0 @@
-#. extracted from ../locale.ini
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: Sun Apr 11 2021 11:33:40 GMT+0200 (heure d’été d’Europe centrale)\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME \n"
-"Language-Team: LANGUAGE \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"X-Generator: ini2po 0.0.1\n"
-
-#: TutoPrev
-msgctxt "TutoPrev"
-msgid "Prev"
-msgstr "Ant"
-
-#: TutoNext
-msgctxt "TutoNext"
-msgid "Next"
-msgstr "Sig"
-
-#: TutoEnd
-msgctxt "TutoEnd"
-msgid "End"
-msgstr "Fin"
-
-#: TutoExplainTitle
-msgctxt "TutoExplainTitle"
-msgid "XO Editor Activity"
-msgstr "Actividad \"XO Editor\""
-
-#: TutoExplainContent
-msgctxt "TutoExplainContent"
-msgid "Welcome into the XO Editor activity. XO Editor allow you to customize easily your buddy icon colors"
-msgstr "Bienvenido a la actividad \"XO Editor\". \"XO Editor\" permite al alumno personalizar el conjunto de colores de su personaje"
-
-#: TutoSaveTitle
-msgctxt "TutoSaveTitle"
-msgid "Save colours"
-msgstr "Guardar colores"
-
-#: TutoSaveContent
-msgctxt "TutoSaveContent"
-msgid "Click here to set the current color in the middle as your buddy's color"
-msgstr "Haz clic aquí para elegir el color que aparece en el medio de la pantalla como tu color de personaje"
-
-#: TutoResetTitle
-msgctxt "TutoResetTitle"
-msgid "Reset board"
-msgstr "Reiniciar"
-
-#: TutoResetContent
-msgctxt "TutoResetContent"
-msgid "Click here to reset the board as it was at the beginning. It's useful if you've played to move color combinations"
-msgstr "Haz clic aquí para reiniciar tu selección. Te será útil si has experimentado combinando colores y quieres volver al color inicial"
-
-#: TutoCanvasTitle
-msgctxt "TutoCanvasTitle"
-msgid "Color variations"
-msgstr "Variaciones de color"
-
-#: TutoCanvasContent
-msgctxt "TutoCanvasContent"
-msgid "Here are all existing color combinations. Click on a combination, it will instantly appear on the buddy in the middle to allow you to see if you like it. If so and if you want to keep it, click on the Save button then quit the activity"
-msgstr "Aquí podrás ver todas las combinaciones de colores disponibles. Haz clic en una combinación y aparecerá sobre el personaje (en el centro de la pantalla). Si te gusta, haz clic en Guardar y sal de la actividad"
-
diff --git a/activities/XOEditor.activity/po/fr.po b/activities/XOEditor.activity/po/fr.po
deleted file mode 100644
index 0253eefc1..000000000
--- a/activities/XOEditor.activity/po/fr.po
+++ /dev/null
@@ -1,70 +0,0 @@
-#. extracted from ../locale.ini
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: Sun Apr 11 2021 11:33:40 GMT+0200 (heure d’été d’Europe centrale)\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME \n"
-"Language-Team: LANGUAGE \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"X-Generator: ini2po 0.0.1\n"
-
-#: TutoPrev
-msgctxt "TutoPrev"
-msgid "Prev"
-msgstr "Préc"
-
-#: TutoNext
-msgctxt "TutoNext"
-msgid "Next"
-msgstr "Suiv"
-
-#: TutoEnd
-msgctxt "TutoEnd"
-msgid "End"
-msgstr "Fin"
-
-#: TutoExplainTitle
-msgctxt "TutoExplainTitle"
-msgid "XO Editor Activity"
-msgstr "Activité XO Editor"
-
-#: TutoExplainContent
-msgctxt "TutoExplainContent"
-msgid "Welcome into the XO Editor activity. XO Editor allow you to customize easily your buddy icon colors"
-msgstr "Bienvenue dans l'activité XO Editor. L'activité XO Editor vous permet de changer facilement votre couleur favorite qui est utilisée pour tous les icônes du Sugarizer"
-
-#: TutoSaveTitle
-msgctxt "TutoSaveTitle"
-msgid "Save colours"
-msgstr "Enregistrer couleurs"
-
-#: TutoSaveContent
-msgctxt "TutoSaveContent"
-msgid "Click here to set the current color in the middle as your buddy's color"
-msgstr "Cliquer ici pour enregistrer la couleur actuelle au milieu de l'écran comme votre couleur favorite"
-
-#: TutoResetTitle
-msgctxt "TutoResetTitle"
-msgid "Reset board"
-msgstr "Réinitialiser"
-
-#: TutoResetContent
-msgctxt "TutoResetContent"
-msgid "Click here to reset the board as it was at the beginning. It's useful if you've played to move color combinations"
-msgstr "Cliquez ici pour initialiser le plateau comme il était au début. C'est utile si vous vous êtes amusé à bouger les combinaisons de couleurs"
-
-#: TutoCanvasTitle
-msgctxt "TutoCanvasTitle"
-msgid "Color variations"
-msgstr "Palette de couleurs"
-
-#: TutoCanvasContent
-msgctxt "TutoCanvasContent"
-msgid "Here are all existing color combinations. Click on a combination, it will instantly appear on the buddy in the middle to allow you to see if you like it. If so and if you want to keep it, click on the Save button then quit the activity"
-msgstr "Ceci sont toutes le combinaisons de couleurs possibles pour Sugarizer. Cliquez sur une combinaison et vous pourrez l'essayer sur l'icône du milieu pour voir si elle vous plait. Si c'est le cas et que vous voulez la conserver, cliquez sur le bouton Enregistrer et voilà !"
-
diff --git a/activities/XOEditor.activity/po/pl.po b/activities/XOEditor.activity/po/pl.po
deleted file mode 100644
index f222a3c83..000000000
--- a/activities/XOEditor.activity/po/pl.po
+++ /dev/null
@@ -1,70 +0,0 @@
-#. extracted from ../locale.ini
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: Sun Apr 11 2021 11:33:40 GMT+0200 (heure d’été d’Europe centrale)\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME \n"
-"Language-Team: LANGUAGE \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"X-Generator: ini2po 0.0.1\n"
-
-#: TutoPrev
-msgctxt "TutoPrev"
-msgid "Prev"
-msgstr "Poprz"
-
-#: TutoNext
-msgctxt "TutoNext"
-msgid "Next"
-msgstr "Dalej"
-
-#: TutoEnd
-msgctxt "TutoEnd"
-msgid "End"
-msgstr "Koniec"
-
-#: TutoExplainTitle
-msgctxt "TutoExplainTitle"
-msgid "XO Editor Activity"
-msgstr "Edytor XO"
-
-#: TutoExplainContent
-msgctxt "TutoExplainContent"
-msgid "Welcome into the XO Editor activity. XO Editor allow you to customize easily your buddy icon colors"
-msgstr "Witaj w Edytorze XO. Edytorze kolorów twojego ludzika."
-
-#: TutoSaveTitle
-msgctxt "TutoSaveTitle"
-msgid "Save colours"
-msgstr "Zapisz kolory"
-
-#: TutoSaveContent
-msgctxt "TutoSaveContent"
-msgid "Click here to set the current color in the middle as your buddy's color"
-msgstr "Kliknij aby zapisać kolory ludzika."
-
-#: TutoResetTitle
-msgctxt "TutoResetTitle"
-msgid "Reset board"
-msgstr "Resetuj kolory"
-
-#: TutoResetContent
-msgctxt "TutoResetContent"
-msgid "Click here to reset the board as it was at the beginning. It's useful if you've played to move color combinations"
-msgstr "Kliknij aby zrestować kolory ludzika."
-
-#: TutoCanvasTitle
-msgctxt "TutoCanvasTitle"
-msgid "Color variations"
-msgstr "Kombinacje kolorów"
-
-#: TutoCanvasContent
-msgctxt "TutoCanvasContent"
-msgid "Here are all existing color combinations. Click on a combination, it will instantly appear on the buddy in the middle to allow you to see if you like it. If so and if you want to keep it, click on the Save button then quit the activity"
-msgstr "Tutaj możesz wybrać zestaw kolorów. Pojawi się on na ludziku na środku ekranu. Możesz także ruszać kolorowymi kółkami po całej planszy."
-
diff --git a/activities/XOEditor.activity/po/template.pot b/activities/XOEditor.activity/po/template.pot
deleted file mode 100644
index 663f7a003..000000000
--- a/activities/XOEditor.activity/po/template.pot
+++ /dev/null
@@ -1,70 +0,0 @@
-#. extracted from ../locale.ini
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: Sat May 08 2021 22:26:09 GMT+0200 (heure d’été d’Europe centrale)\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME \n"
-"Language-Team: LANGUAGE \n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"X-Generator: ini2po 0.0.1\n"
-
-#: TutoPrev
-msgctxt "TutoPrev"
-msgid "Prev"
-msgstr "Prev"
-
-#: TutoNext
-msgctxt "TutoNext"
-msgid "Next"
-msgstr "Next"
-
-#: TutoEnd
-msgctxt "TutoEnd"
-msgid "End"
-msgstr "End"
-
-#: TutoExplainTitle
-msgctxt "TutoExplainTitle"
-msgid "XO Editor Activity"
-msgstr "XO Editor Activity"
-
-#: TutoExplainContent
-msgctxt "TutoExplainContent"
-msgid "Welcome into the XO Editor activity. XO Editor allow you to customize easily your buddy icon colors"
-msgstr "Welcome into the XO Editor activity. XO Editor allow you to customize easily your buddy icon colors"
-
-#: TutoSaveTitle
-msgctxt "TutoSaveTitle"
-msgid "Save colours"
-msgstr "Save colours"
-
-#: TutoSaveContent
-msgctxt "TutoSaveContent"
-msgid "Click here to set the current color in the middle as your buddy's color"
-msgstr "Click here to set the current color in the middle as your buddy's color"
-
-#: TutoResetTitle
-msgctxt "TutoResetTitle"
-msgid "Reset board"
-msgstr "Reset board"
-
-#: TutoResetContent
-msgctxt "TutoResetContent"
-msgid "Click here to reset the board as it was at the beginning. It's useful if you've played to move color combinations"
-msgstr "Click here to reset the board as it was at the beginning. It's useful if you've played to move color combinations"
-
-#: TutoCanvasTitle
-msgctxt "TutoCanvasTitle"
-msgid "Color variations"
-msgstr "Color variations"
-
-#: TutoCanvasContent
-msgctxt "TutoCanvasContent"
-msgid "Here are all existing color combinations. Click on a combination, it will instantly appear on the buddy in the middle to allow you to see if you like it. If so and if you want to keep it, click on the Save button then quit the activity"
-msgstr "Here are all existing color combinations. Click on a combination, it will instantly appear on the buddy in the middle to allow you to see if you like it. If so and if you want to keep it, click on the Save button then quit the activity"
-