UNPKG

locize-lastused

Version:

Using API lastUsed using in node.js, in the browser and for deno.

202 lines (201 loc) 7.9 kB
//#region lib/utils.js const arr = []; const each = arr.forEach; const slice = arr.slice; function defaults(obj) { each.call(slice.call(arguments, 1), (source) => { if (source) { for (const prop in source) if (obj[prop] === void 0) obj[prop] = source[prop]; } }); return obj; } function debounce(func, wait, immediate) { let timeout; return function() { const context = this; const args = arguments; const later = function() { timeout = null; if (!immediate) func.apply(context, args); }; const callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); }; } function isMissingOption(obj, props) { return props.reduce((mem, p) => { if (mem) return mem; if (!obj || !obj[p] || typeof obj[p] !== "string" || !obj[p].toLowerCase() === p.toLowerCase()) { const err = `i18next-lastused :: got "${obj[p]}" in options for ${p} which is invalid.`; console.warn(err); return err; } return false; }, false); } function replaceIn(str, arr, options) { let ret = str; arr.forEach((s) => { const regexp = new RegExp(`{{${s}}}`, "g"); ret = ret.replace(regexp, options[s]); }); return ret; } //#endregion //#region lib/request.js const g = typeof globalThis !== "undefined" ? globalThis : typeof global !== "undefined" ? global : typeof window !== "undefined" ? window : void 0; let fetchApi; if (typeof fetch === "function") fetchApi = fetch; else if (g && typeof g.fetch === "function") fetchApi = g.fetch; const XmlHttpRequestApi = (typeof XMLHttpRequest === "function" || typeof XMLHttpRequest === "object") && g ? g.XMLHttpRequest : void 0; const ActiveXObjectApi = typeof ActiveXObject === "function" && g ? g.ActiveXObject : void 0; const requestWithFetch = (options, url, payload, callback) => { const resolver = (response) => { const resourceNotExisting = response.headers && response.headers.get("x-cache") === "Error from cloudfront"; if (!response.ok) return callback(response.statusText || "Error", { status: response.status, resourceNotExisting }); response.text().then((data) => { callback(null, { status: response.status, data, resourceNotExisting }); }).catch(callback); }; const headers = { Authorization: options.authorize && options.apiKey ? options.apiKey : void 0, "Content-Type": "application/json" }; if (typeof window === "undefined" && typeof global !== "undefined" && typeof global.process !== "undefined" && global.process.versions && global.process.versions.node) headers["User-Agent"] = `locize-lastused (node/${global.process.version}; ${global.process.platform} ${global.process.arch})`; if (typeof fetch === "function") fetch(url, { method: payload ? "POST" : "GET", body: payload ? JSON.stringify(payload) : void 0, headers }).then(resolver).catch(callback); else fetchApi(url, { method: payload ? "POST" : "GET", body: payload ? JSON.stringify(payload) : void 0, headers }).then(resolver).catch(callback); }; const requestWithXmlHttpRequest = (options, url, payload, callback) => { try { const x = XmlHttpRequestApi ? new XmlHttpRequestApi() : new ActiveXObjectApi("MSXML2.XMLHTTP.3.0"); x.open(payload ? "POST" : "GET", url, 1); if (!options.crossDomain) x.setRequestHeader("X-Requested-With", "XMLHttpRequest"); if (options.authorize && options.apiKey) x.setRequestHeader("Authorization", options.apiKey); if (payload || options.setContentTypeJSON) x.setRequestHeader("Content-Type", "application/json"); x.onreadystatechange = () => { const resourceNotExisting = x.getResponseHeader("x-cache") === "Error from cloudfront"; x.readyState > 3 && callback(x.status >= 400 ? x.statusText : null, { status: x.status, data: x.responseText, resourceNotExisting }); }; x.send(JSON.stringify(payload)); } catch (e) { console && console.log(e); } }; const request = (options, url, payload, callback) => { if (typeof payload === "function") { callback = payload; payload = void 0; } callback = callback || (() => {}); if (fetchApi) return requestWithFetch(options, url, payload, callback); if (XmlHttpRequestApi || ActiveXObjectApi) return requestWithXmlHttpRequest(options, url, payload, callback); callback(/* @__PURE__ */ new Error("No fetch and no xhr implementation found!")); }; //#endregion //#region lib/index.js const getDefaults = () => { return { lastUsedPath: "https://api.locize.app/used/{{projectId}}/{{version}}/{{lng}}/{{ns}}", referenceLng: "en", crossDomain: true, setContentTypeJSON: false, version: "latest", debounceSubmit: 9e4, allowedHosts: ["localhost"] }; }; const locizeLastUsed = { init(options) { const isI18next = options.t && typeof options.t === "function"; if (isI18next && !options.options.locizeLastUsed.projectId && options.options.backend.projectId) options.options.locizeLastUsed.projectId = options.options.backend.projectId; if (isI18next && !options.options.locizeLastUsed.version && options.options.backend.version) options.options.locizeLastUsed.version = options.options.backend.version; if (isI18next && !options.options.locizeLastUsed.apiKey && options.options.backend.apiKey) options.options.locizeLastUsed.apiKey = options.options.backend.apiKey; if (isI18next && !options.options.locizeLastUsed.referenceLng && options.options.backend.referenceLng) options.options.locizeLastUsed.referenceLng = options.options.backend.referenceLng; if (isI18next && !options.options.locizeLastUsed.referenceLng && options.options.fallbackLng && Array.isArray(options.options.fallbackLng) && options.options.fallbackLng[0] !== "dev") options.options.locizeLastUsed.referenceLng = options.options.fallbackLng[0]; this.options = isI18next ? defaults(options.options.locizeLastUsed, this.options || {}, getDefaults()) : defaults(options, this.options || {}, getDefaults()); const hostname = typeof window !== "undefined" && window.location && window.location.hostname; if (hostname) this.isAllowed = this.options.allowedHosts.indexOf(hostname) > -1; else this.isAllowed = true; this.submitting = null; this.pending = {}; this.done = {}; this.submit = debounce(this.submit, this.options.debounceSubmit); if (isI18next) this.interceptI18next(options); }, interceptI18next(i18next) { const origGetResource = i18next.services.resourceStore.getResource; i18next.services.resourceStore.getResource = (lng, ns, key, options) => { if (key) this.used(ns, key); return origGetResource.call(i18next.services.resourceStore, lng, ns, key, options); }; }, used(ns, key, callback) { ["pending", "done"].forEach((k) => { if (this.done[ns] && this.done[ns][key]) return; if (!this[k][ns]) this[k][ns] = {}; this[k][ns][key] = true; }); this.submit(callback); }, submit(callback) { if (!this.isAllowed) return callback && callback(/* @__PURE__ */ new Error("not allowed")); if (this.submitting) return this.submit(callback); const isMissing = isMissingOption(this.options, [ "projectId", "version", "apiKey", "referenceLng" ]); if (isMissing) return callback && callback(new Error(isMissing)); this.submitting = this.pending; this.pending = {}; const namespaces = Object.keys(this.submitting); let todo = namespaces.length; const doneOne = (err) => { todo--; if (!todo) { this.submitting = null; if (callback) callback(err); } }; namespaces.forEach((ns) => { const keys = Object.keys(this.submitting[ns]); const url = replaceIn(this.options.lastUsedPath, [ "projectId", "version", "lng", "ns" ], defaults({ lng: this.options.referenceLng, ns }, this.options)); if (keys.length) request(defaults({ authorize: true }, this.options), url, keys, doneOne); else doneOne(); }); } }; locizeLastUsed.type = "3rdParty"; //#endregion module.exports = locizeLastUsed;