UNPKG

@betterstore/react

Version:

E-commerce for Developers

1,344 lines (1,321 loc) 1.26 MB
'use strict'; var React = require('react'); var ReactDOM = require('react-dom'); var jsxRuntime = require('react/jsx-runtime'); function _interopNamespaceDefault(e) { var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React); var ReactDOM__namespace = /*#__PURE__*/_interopNamespaceDefault(ReactDOM); const createStoreImpl = (createState) => { let state; const listeners = /* @__PURE__ */ new Set(); const setState = (partial, replace) => { const nextState = typeof partial === "function" ? partial(state) : partial; if (!Object.is(nextState, state)) { const previousState = state; state = (replace != null ? replace : typeof nextState !== "object" || nextState === null) ? nextState : Object.assign({}, state, nextState); listeners.forEach((listener) => listener(state, previousState)); } }; const getState = () => state; const getInitialState = () => initialState; const subscribe = (listener) => { listeners.add(listener); return () => listeners.delete(listener); }; const api = { setState, getState, getInitialState, subscribe }; const initialState = state = createState(setState, getState, api); return api; }; const createStore = (createState) => createState ? createStoreImpl(createState) : createStoreImpl; const identity = (arg) => arg; function useStore(api, selector = identity) { const slice = React.useSyncExternalStore( api.subscribe, () => selector(api.getState()), () => selector(api.getInitialState()) ); React.useDebugValue(slice); return slice; } const createImpl = (createState) => { const api = createStore(createState); const useBoundStore = (selector) => useStore(api, selector); Object.assign(useBoundStore, api); return useBoundStore; }; const create = (createState) => createState ? createImpl(createState) : createImpl; function createJSONStorage(getStorage, options) { let storage; try { storage = getStorage(); } catch (e) { return; } const persistStorage = { getItem: (name) => { var _a; const parse = (str2) => { if (str2 === null) { return null; } return JSON.parse(str2, void 0 ); }; const str = (_a = storage.getItem(name)) != null ? _a : null; if (str instanceof Promise) { return str.then(parse); } return parse(str); }, setItem: (name, newValue) => storage.setItem(name, JSON.stringify(newValue, void 0 )), removeItem: (name) => storage.removeItem(name) }; return persistStorage; } const toThenable = (fn) => (input) => { try { const result = fn(input); if (result instanceof Promise) { return result; } return { then(onFulfilled) { return toThenable(onFulfilled)(result); }, catch(_onRejected) { return this; } }; } catch (e) { return { then(_onFulfilled) { return this; }, catch(onRejected) { return toThenable(onRejected)(e); } }; } }; const persistImpl = (config, baseOptions) => (set, get, api) => { let options = { storage: createJSONStorage(() => localStorage), partialize: (state) => state, version: 0, merge: (persistedState, currentState) => ({ ...currentState, ...persistedState }), ...baseOptions }; let hasHydrated = false; const hydrationListeners = /* @__PURE__ */ new Set(); const finishHydrationListeners = /* @__PURE__ */ new Set(); let storage = options.storage; if (!storage) { return config( (...args) => { console.warn( `[zustand persist middleware] Unable to update item '${options.name}', the given storage is currently unavailable.` ); set(...args); }, get, api ); } const setItem = () => { const state = options.partialize({ ...get() }); return storage.setItem(options.name, { state, version: options.version }); }; const savedSetState = api.setState; api.setState = (state, replace) => { savedSetState(state, replace); void setItem(); }; const configResult = config( (...args) => { set(...args); void setItem(); }, get, api ); api.getInitialState = () => configResult; let stateFromStorage; const hydrate = () => { var _a, _b; if (!storage) return; hasHydrated = false; hydrationListeners.forEach((cb) => { var _a2; return cb((_a2 = get()) != null ? _a2 : configResult); }); const postRehydrationCallback = ((_b = options.onRehydrateStorage) == null ? void 0 : _b.call(options, (_a = get()) != null ? _a : configResult)) || void 0; return toThenable(storage.getItem.bind(storage))(options.name).then((deserializedStorageValue) => { if (deserializedStorageValue) { if (typeof deserializedStorageValue.version === "number" && deserializedStorageValue.version !== options.version) { if (options.migrate) { const migration = options.migrate( deserializedStorageValue.state, deserializedStorageValue.version ); if (migration instanceof Promise) { return migration.then((result) => [true, result]); } return [true, migration]; } console.error( `State loaded from storage couldn't be migrated since no migrate function was provided` ); } else { return [false, deserializedStorageValue.state]; } } return [false, void 0]; }).then((migrationResult) => { var _a2; const [migrated, migratedState] = migrationResult; stateFromStorage = options.merge( migratedState, (_a2 = get()) != null ? _a2 : configResult ); set(stateFromStorage, true); if (migrated) { return setItem(); } }).then(() => { postRehydrationCallback == null ? void 0 : postRehydrationCallback(stateFromStorage, void 0); stateFromStorage = get(); hasHydrated = true; finishHydrationListeners.forEach((cb) => cb(stateFromStorage)); }).catch((e) => { postRehydrationCallback == null ? void 0 : postRehydrationCallback(void 0, e); }); }; api.persist = { setOptions: (newOptions) => { options = { ...options, ...newOptions }; if (newOptions.storage) { storage = newOptions.storage; } }, clearStorage: () => { storage == null ? void 0 : storage.removeItem(options.name); }, getOptions: () => options, rehydrate: () => hydrate(), hasHydrated: () => hasHydrated, onHydrate: (cb) => { hydrationListeners.add(cb); return () => { hydrationListeners.delete(cb); }; }, onFinishHydration: (cb) => { finishHydrationListeners.add(cb); return () => { finishHydrationListeners.delete(cb); }; } }; if (!options.skipHydration) { hydrate(); } return stateFromStorage || configResult; }; const persist = persistImpl; const generateLineItemId = (item) => { return btoa(JSON.stringify({ productId: item.productId, variantOptions: item.variantOptions, metadata: item.metadata, })); }; const useCart = create()(persist((set, get) => ({ lineItems: [], addItem: (product, additionalParams) => set((state) => { var _a, _b, _c; const productId = product.id; const selectedVariant = ((_a = product.productVariants) !== null && _a !== void 0 ? _a : []).find((v) => v.variantOptions.every((vOpt) => { var _a; return (_a = additionalParams === null || additionalParams === void 0 ? void 0 : additionalParams.variantOptions) === null || _a === void 0 ? void 0 : _a.some((iOpt) => vOpt.name === iOpt.name && vOpt.value === iOpt.value); })) || null; const formattedNewItem = { productId: productId, product: product, quantity: (_b = additionalParams === null || additionalParams === void 0 ? void 0 : additionalParams.quantity) !== null && _b !== void 0 ? _b : 1, selectedVariant, variantOptions: (_c = additionalParams === null || additionalParams === void 0 ? void 0 : additionalParams.variantOptions) !== null && _c !== void 0 ? _c : [], metadata: additionalParams === null || additionalParams === void 0 ? void 0 : additionalParams.metadata, }; const id = generateLineItemId(formattedNewItem); const existingItemIndex = state.lineItems.findIndex((item) => item.id === id); if (existingItemIndex !== -1) { const updatedItems = [...state.lineItems]; updatedItems[existingItemIndex] = Object.assign(Object.assign({}, updatedItems[existingItemIndex]), { quantity: updatedItems[existingItemIndex].quantity + formattedNewItem.quantity }); return { lineItems: updatedItems }; } return { lineItems: [...state.lineItems, Object.assign(Object.assign({}, formattedNewItem), { id })], }; }), removeItem: (id) => set((state) => ({ lineItems: state.lineItems.filter((i) => i.id !== id), })), updateQuantity: (id, quantity) => set((state) => ({ lineItems: state.lineItems.map((i) => i.id === id ? Object.assign(Object.assign({}, i), { quantity }) : i), })), getProductQuantity: (productId) => { const items = get().lineItems.filter((item) => item.productId === productId); return items.reduce((acc, item) => acc + item.quantity, 0); }, clearCart: () => set({ lineItems: [] }), }), { name: "cart", })); /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __rest(s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; } function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __spreadArray(to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); } typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; const isString$3 = obj => typeof obj === 'string'; const defer = () => { let res; let rej; const promise = new Promise((resolve, reject) => { res = resolve; rej = reject; }); promise.resolve = res; promise.reject = rej; return promise; }; const makeString = object => { if (object == null) return ''; return '' + object; }; const copy = (a, s, t) => { a.forEach(m => { if (s[m]) t[m] = s[m]; }); }; const lastOfPathSeparatorRegExp = /###/g; const cleanKey = key => key && key.indexOf('###') > -1 ? key.replace(lastOfPathSeparatorRegExp, '.') : key; const canNotTraverseDeeper = object => !object || isString$3(object); const getLastOfPath = (object, path, Empty) => { const stack = !isString$3(path) ? path : path.split('.'); let stackIndex = 0; while (stackIndex < stack.length - 1) { if (canNotTraverseDeeper(object)) return {}; const key = cleanKey(stack[stackIndex]); if (!object[key] && Empty) object[key] = new Empty(); if (Object.prototype.hasOwnProperty.call(object, key)) { object = object[key]; } else { object = {}; } ++stackIndex; } if (canNotTraverseDeeper(object)) return {}; return { obj: object, k: cleanKey(stack[stackIndex]) }; }; const setPath = (object, path, newValue) => { const { obj, k } = getLastOfPath(object, path, Object); if (obj !== undefined || path.length === 1) { obj[k] = newValue; return; } let e = path[path.length - 1]; let p = path.slice(0, path.length - 1); let last = getLastOfPath(object, p, Object); while (last.obj === undefined && p.length) { e = `${p[p.length - 1]}.${e}`; p = p.slice(0, p.length - 1); last = getLastOfPath(object, p, Object); if (last?.obj && typeof last.obj[`${last.k}.${e}`] !== 'undefined') { last.obj = undefined; } } last.obj[`${last.k}.${e}`] = newValue; }; const pushPath = (object, path, newValue, concat) => { const { obj, k } = getLastOfPath(object, path, Object); obj[k] = obj[k] || []; obj[k].push(newValue); }; const getPath = (object, path) => { const { obj, k } = getLastOfPath(object, path); if (!obj) return undefined; if (!Object.prototype.hasOwnProperty.call(obj, k)) return undefined; return obj[k]; }; const getPathWithDefaults = (data, defaultData, key) => { const value = getPath(data, key); if (value !== undefined) { return value; } return getPath(defaultData, key); }; const deepExtend = (target, source, overwrite) => { for (const prop in source) { if (prop !== '__proto__' && prop !== 'constructor') { if (prop in target) { if (isString$3(target[prop]) || target[prop] instanceof String || isString$3(source[prop]) || source[prop] instanceof String) { if (overwrite) target[prop] = source[prop]; } else { deepExtend(target[prop], source[prop], overwrite); } } else { target[prop] = source[prop]; } } } return target; }; const regexEscape = str => str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); var _entityMap = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;', '/': '&#x2F;' }; const escape = data => { if (isString$3(data)) { return data.replace(/[&<>"'\/]/g, s => _entityMap[s]); } return data; }; class RegExpCache { constructor(capacity) { this.capacity = capacity; this.regExpMap = new Map(); this.regExpQueue = []; } getRegExp(pattern) { const regExpFromCache = this.regExpMap.get(pattern); if (regExpFromCache !== undefined) { return regExpFromCache; } const regExpNew = new RegExp(pattern); if (this.regExpQueue.length === this.capacity) { this.regExpMap.delete(this.regExpQueue.shift()); } this.regExpMap.set(pattern, regExpNew); this.regExpQueue.push(pattern); return regExpNew; } } const chars = [' ', ',', '?', '!', ';']; const looksLikeObjectPathRegExpCache = new RegExpCache(20); const looksLikeObjectPath = (key, nsSeparator, keySeparator) => { nsSeparator = nsSeparator || ''; keySeparator = keySeparator || ''; const possibleChars = chars.filter(c => nsSeparator.indexOf(c) < 0 && keySeparator.indexOf(c) < 0); if (possibleChars.length === 0) return true; const r = looksLikeObjectPathRegExpCache.getRegExp(`(${possibleChars.map(c => c === '?' ? '\\?' : c).join('|')})`); let matched = !r.test(key); if (!matched) { const ki = key.indexOf(keySeparator); if (ki > 0 && !r.test(key.substring(0, ki))) { matched = true; } } return matched; }; const deepFind = function (obj, path) { let keySeparator = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '.'; if (!obj) return undefined; if (obj[path]) { if (!Object.prototype.hasOwnProperty.call(obj, path)) return undefined; return obj[path]; } const tokens = path.split(keySeparator); let current = obj; for (let i = 0; i < tokens.length;) { if (!current || typeof current !== 'object') { return undefined; } let next; let nextPath = ''; for (let j = i; j < tokens.length; ++j) { if (j !== i) { nextPath += keySeparator; } nextPath += tokens[j]; next = current[nextPath]; if (next !== undefined) { if (['string', 'number', 'boolean'].indexOf(typeof next) > -1 && j < tokens.length - 1) { continue; } i += j - i + 1; break; } } current = next; } return current; }; const getCleanedCode = code => code?.replace('_', '-'); const consoleLogger = { type: 'logger', log(args) { this.output('log', args); }, warn(args) { this.output('warn', args); }, error(args) { this.output('error', args); }, output(type, args) { console?.[type]?.apply?.(console, args); } }; class Logger { constructor(concreteLogger) { let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; this.init(concreteLogger, options); } init(concreteLogger) { let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; this.prefix = options.prefix || 'i18next:'; this.logger = concreteLogger || consoleLogger; this.options = options; this.debug = options.debug; } log() { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return this.forward(args, 'log', '', true); } warn() { for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } return this.forward(args, 'warn', '', true); } error() { for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { args[_key3] = arguments[_key3]; } return this.forward(args, 'error', ''); } deprecate() { for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { args[_key4] = arguments[_key4]; } return this.forward(args, 'warn', 'WARNING DEPRECATED: ', true); } forward(args, lvl, prefix, debugOnly) { if (debugOnly && !this.debug) return null; if (isString$3(args[0])) args[0] = `${prefix}${this.prefix} ${args[0]}`; return this.logger[lvl](args); } create(moduleName) { return new Logger(this.logger, { ...{ prefix: `${this.prefix}:${moduleName}:` }, ...this.options }); } clone(options) { options = options || this.options; options.prefix = options.prefix || this.prefix; return new Logger(this.logger, options); } } var baseLogger = new Logger(); class EventEmitter { constructor() { this.observers = {}; } on(events, listener) { events.split(' ').forEach(event => { if (!this.observers[event]) this.observers[event] = new Map(); const numListeners = this.observers[event].get(listener) || 0; this.observers[event].set(listener, numListeners + 1); }); return this; } off(event, listener) { if (!this.observers[event]) return; if (!listener) { delete this.observers[event]; return; } this.observers[event].delete(listener); } emit(event) { for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { args[_key - 1] = arguments[_key]; } if (this.observers[event]) { const cloned = Array.from(this.observers[event].entries()); cloned.forEach(_ref => { let [observer, numTimesAdded] = _ref; for (let i = 0; i < numTimesAdded; i++) { observer(...args); } }); } if (this.observers['*']) { const cloned = Array.from(this.observers['*'].entries()); cloned.forEach(_ref2 => { let [observer, numTimesAdded] = _ref2; for (let i = 0; i < numTimesAdded; i++) { observer.apply(observer, [event, ...args]); } }); } } } class ResourceStore extends EventEmitter { constructor(data) { let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { ns: ['translation'], defaultNS: 'translation' }; super(); this.data = data || {}; this.options = options; if (this.options.keySeparator === undefined) { this.options.keySeparator = '.'; } if (this.options.ignoreJSONStructure === undefined) { this.options.ignoreJSONStructure = true; } } addNamespaces(ns) { if (this.options.ns.indexOf(ns) < 0) { this.options.ns.push(ns); } } removeNamespaces(ns) { const index = this.options.ns.indexOf(ns); if (index > -1) { this.options.ns.splice(index, 1); } } getResource(lng, ns, key) { let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; const keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator; const ignoreJSONStructure = options.ignoreJSONStructure !== undefined ? options.ignoreJSONStructure : this.options.ignoreJSONStructure; let path; if (lng.indexOf('.') > -1) { path = lng.split('.'); } else { path = [lng, ns]; if (key) { if (Array.isArray(key)) { path.push(...key); } else if (isString$3(key) && keySeparator) { path.push(...key.split(keySeparator)); } else { path.push(key); } } } const result = getPath(this.data, path); if (!result && !ns && !key && lng.indexOf('.') > -1) { lng = path[0]; ns = path[1]; key = path.slice(2).join('.'); } if (result || !ignoreJSONStructure || !isString$3(key)) return result; return deepFind(this.data?.[lng]?.[ns], key, keySeparator); } addResource(lng, ns, key, value) { let options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : { silent: false }; const keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator; let path = [lng, ns]; if (key) path = path.concat(keySeparator ? key.split(keySeparator) : key); if (lng.indexOf('.') > -1) { path = lng.split('.'); value = ns; ns = path[1]; } this.addNamespaces(ns); setPath(this.data, path, value); if (!options.silent) this.emit('added', lng, ns, key, value); } addResources(lng, ns, resources) { let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : { silent: false }; for (const m in resources) { if (isString$3(resources[m]) || Array.isArray(resources[m])) this.addResource(lng, ns, m, resources[m], { silent: true }); } if (!options.silent) this.emit('added', lng, ns, resources); } addResourceBundle(lng, ns, resources, deep, overwrite) { let options = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : { silent: false, skipCopy: false }; let path = [lng, ns]; if (lng.indexOf('.') > -1) { path = lng.split('.'); deep = resources; resources = ns; ns = path[1]; } this.addNamespaces(ns); let pack = getPath(this.data, path) || {}; if (!options.skipCopy) resources = JSON.parse(JSON.stringify(resources)); if (deep) { deepExtend(pack, resources, overwrite); } else { pack = { ...pack, ...resources }; } setPath(this.data, path, pack); if (!options.silent) this.emit('added', lng, ns, resources); } removeResourceBundle(lng, ns) { if (this.hasResourceBundle(lng, ns)) { delete this.data[lng][ns]; } this.removeNamespaces(ns); this.emit('removed', lng, ns); } hasResourceBundle(lng, ns) { return this.getResource(lng, ns) !== undefined; } getResourceBundle(lng, ns) { if (!ns) ns = this.options.defaultNS; return this.getResource(lng, ns); } getDataByLanguage(lng) { return this.data[lng]; } hasLanguageSomeTranslations(lng) { const data = this.getDataByLanguage(lng); const n = data && Object.keys(data) || []; return !!n.find(v => data[v] && Object.keys(data[v]).length > 0); } toJSON() { return this.data; } } var postProcessor = { processors: {}, addPostProcessor(module) { this.processors[module.name] = module; }, handle(processors, value, key, options, translator) { processors.forEach(processor => { value = this.processors[processor]?.process(value, key, options, translator) ?? value; }); return value; } }; const checkedLoadedFor = {}; const shouldHandleAsObject = res => !isString$3(res) && typeof res !== 'boolean' && typeof res !== 'number'; class Translator extends EventEmitter { constructor(services) { let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; super(); copy(['resourceStore', 'languageUtils', 'pluralResolver', 'interpolator', 'backendConnector', 'i18nFormat', 'utils'], services, this); this.options = options; if (this.options.keySeparator === undefined) { this.options.keySeparator = '.'; } this.logger = baseLogger.create('translator'); } changeLanguage(lng) { if (lng) this.language = lng; } exists(key) { let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { interpolation: {} }; if (key == null) { return false; } const resolved = this.resolve(key, options); return resolved?.res !== undefined; } extractFromKey(key, options) { let nsSeparator = options.nsSeparator !== undefined ? options.nsSeparator : this.options.nsSeparator; if (nsSeparator === undefined) nsSeparator = ':'; const keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator; let namespaces = options.ns || this.options.defaultNS || []; const wouldCheckForNsInKey = nsSeparator && key.indexOf(nsSeparator) > -1; const seemsNaturalLanguage = !this.options.userDefinedKeySeparator && !options.keySeparator && !this.options.userDefinedNsSeparator && !options.nsSeparator && !looksLikeObjectPath(key, nsSeparator, keySeparator); if (wouldCheckForNsInKey && !seemsNaturalLanguage) { const m = key.match(this.interpolator.nestingRegexp); if (m && m.length > 0) { return { key, namespaces: isString$3(namespaces) ? [namespaces] : namespaces }; } const parts = key.split(nsSeparator); if (nsSeparator !== keySeparator || nsSeparator === keySeparator && this.options.ns.indexOf(parts[0]) > -1) namespaces = parts.shift(); key = parts.join(keySeparator); } return { key, namespaces: isString$3(namespaces) ? [namespaces] : namespaces }; } translate(keys, options, lastKey) { if (typeof options !== 'object' && this.options.overloadTranslationOptionHandler) { options = this.options.overloadTranslationOptionHandler(arguments); } if (typeof options === 'object') options = { ...options }; if (!options) options = {}; if (keys == null) return ''; if (!Array.isArray(keys)) keys = [String(keys)]; const returnDetails = options.returnDetails !== undefined ? options.returnDetails : this.options.returnDetails; const keySeparator = options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator; const { key, namespaces } = this.extractFromKey(keys[keys.length - 1], options); const namespace = namespaces[namespaces.length - 1]; const lng = options.lng || this.language; const appendNamespaceToCIMode = options.appendNamespaceToCIMode || this.options.appendNamespaceToCIMode; if (lng?.toLowerCase() === 'cimode') { if (appendNamespaceToCIMode) { const nsSeparator = options.nsSeparator || this.options.nsSeparator; if (returnDetails) { return { res: `${namespace}${nsSeparator}${key}`, usedKey: key, exactUsedKey: key, usedLng: lng, usedNS: namespace, usedParams: this.getUsedParamsDetails(options) }; } return `${namespace}${nsSeparator}${key}`; } if (returnDetails) { return { res: key, usedKey: key, exactUsedKey: key, usedLng: lng, usedNS: namespace, usedParams: this.getUsedParamsDetails(options) }; } return key; } const resolved = this.resolve(keys, options); let res = resolved?.res; const resUsedKey = resolved?.usedKey || key; const resExactUsedKey = resolved?.exactUsedKey || key; const noObject = ['[object Number]', '[object Function]', '[object RegExp]']; const joinArrays = options.joinArrays !== undefined ? options.joinArrays : this.options.joinArrays; const handleAsObjectInI18nFormat = !this.i18nFormat || this.i18nFormat.handleAsObject; const needsPluralHandling = options.count !== undefined && !isString$3(options.count); const hasDefaultValue = Translator.hasDefaultValue(options); const defaultValueSuffix = needsPluralHandling ? this.pluralResolver.getSuffix(lng, options.count, options) : ''; const defaultValueSuffixOrdinalFallback = options.ordinal && needsPluralHandling ? this.pluralResolver.getSuffix(lng, options.count, { ordinal: false }) : ''; const needsZeroSuffixLookup = needsPluralHandling && !options.ordinal && options.count === 0; const defaultValue = needsZeroSuffixLookup && options[`defaultValue${this.options.pluralSeparator}zero`] || options[`defaultValue${defaultValueSuffix}`] || options[`defaultValue${defaultValueSuffixOrdinalFallback}`] || options.defaultValue; let resForObjHndl = res; if (handleAsObjectInI18nFormat && !res && hasDefaultValue) { resForObjHndl = defaultValue; } const handleAsObject = shouldHandleAsObject(resForObjHndl); const resType = Object.prototype.toString.apply(resForObjHndl); if (handleAsObjectInI18nFormat && resForObjHndl && handleAsObject && noObject.indexOf(resType) < 0 && !(isString$3(joinArrays) && Array.isArray(resForObjHndl))) { if (!options.returnObjects && !this.options.returnObjects) { if (!this.options.returnedObjectHandler) { this.logger.warn('accessing an object - but returnObjects options is not enabled!'); } const r = this.options.returnedObjectHandler ? this.options.returnedObjectHandler(resUsedKey, resForObjHndl, { ...options, ns: namespaces }) : `key '${key} (${this.language})' returned an object instead of string.`; if (returnDetails) { resolved.res = r; resolved.usedParams = this.getUsedParamsDetails(options); return resolved; } return r; } if (keySeparator) { const resTypeIsArray = Array.isArray(resForObjHndl); const copy = resTypeIsArray ? [] : {}; const newKeyToUse = resTypeIsArray ? resExactUsedKey : resUsedKey; for (const m in resForObjHndl) { if (Object.prototype.hasOwnProperty.call(resForObjHndl, m)) { const deepKey = `${newKeyToUse}${keySeparator}${m}`; if (hasDefaultValue && !res) { copy[m] = this.translate(deepKey, { ...options, defaultValue: shouldHandleAsObject(defaultValue) ? defaultValue[m] : undefined, ...{ joinArrays: false, ns: namespaces } }); } else { copy[m] = this.translate(deepKey, { ...options, ...{ joinArrays: false, ns: namespaces } }); } if (copy[m] === deepKey) copy[m] = resForObjHndl[m]; } } res = copy; } } else if (handleAsObjectInI18nFormat && isString$3(joinArrays) && Array.isArray(res)) { res = res.join(joinArrays); if (res) res = this.extendTranslation(res, keys, options, lastKey); } else { let usedDefault = false; let usedKey = false; if (!this.isValidLookup(res) && hasDefaultValue) { usedDefault = true; res = defaultValue; } if (!this.isValidLookup(res)) { usedKey = true; res = key; } const missingKeyNoValueFallbackToKey = options.missingKeyNoValueFallbackToKey || this.options.missingKeyNoValueFallbackToKey; const resForMissing = missingKeyNoValueFallbackToKey && usedKey ? undefined : res; const updateMissing = hasDefaultValue && defaultValue !== res && this.options.updateMissing; if (usedKey || usedDefault || updateMissing) { this.logger.log(updateMissing ? 'updateKey' : 'missingKey', lng, namespace, key, updateMissing ? defaultValue : res); if (keySeparator) { const fk = this.resolve(key, { ...options, keySeparator: false }); if (fk && fk.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.'); } let lngs = []; const fallbackLngs = this.languageUtils.getFallbackCodes(this.options.fallbackLng, options.lng || this.language); if (this.options.saveMissingTo === 'fallback' && fallbackLngs && fallbackLngs[0]) { for (let i = 0; i < fallbackLngs.length; i++) { lngs.push(fallbackLngs[i]); } } else if (this.options.saveMissingTo === 'all') { lngs = this.languageUtils.toResolveHierarchy(options.lng || this.language); } else { lngs.push(options.lng || this.language); } const send = (l, k, specificDefaultValue) => { const defaultForMissing = hasDefaultValue && specificDefaultValue !== res ? specificDefaultValue : resForMissing; if (this.options.missingKeyHandler) { this.options.missingKeyHandler(l, namespace, k, defaultForMissing, updateMissing, options); } else if (this.backendConnector?.saveMissing) { this.backendConnector.saveMissing(l, namespace, k, defaultForMissing, updateMissing, options); } this.emit('missingKey', l, namespace, k, res); }; if (this.options.saveMissing) { if (this.options.saveMissingPlurals && needsPluralHandling) { lngs.forEach(language => { const suffixes = this.pluralResolver.getSuffixes(language, options); if (needsZeroSuffixLookup && options[`defaultValue${this.options.pluralSeparator}zero`] && suffixes.indexOf(`${this.options.pluralSeparator}zero`) < 0) { suffixes.push(`${this.options.pluralSeparator}zero`); } suffixes.forEach(suffix => { send([language], key + suffix, options[`defaultValue${suffix}`] || defaultValue); }); }); } else { send(lngs, key, defaultValue); } } } res = this.extendTranslation(res, keys, options, resolved, lastKey); if (usedKey && res === key && this.options.appendNamespaceToMissingKey) res = `${namespace}:${key}`; if ((usedKey || usedDefault) && this.options.parseMissingKeyHandler) { res = this.options.parseMissingKeyHandler(this.options.appendNamespaceToMissingKey ? `${namespace}:${key}` : key, usedDefault ? res : undefined); } } if (returnDetails) { resolved.res = res; resolved.usedParams = this.getUsedParamsDetails(options); return resolved; } return res; } extendTranslation(res, key, options, resolved, lastKey) { var _this = this; if (this.i18nFormat?.parse) { res = this.i18nFormat.parse(res, { ...this.options.interpolation.defaultVariables, ...options }, options.lng || this.language || resolved.usedLng, resolved.usedNS, resolved.usedKey, { resolved }); } else if (!options.skipInterpolation) { if (options.interpolation) this.interpolator.init({ ...options, ...{ interpolation: { ...this.options.interpolation, ...options.interpolation } } }); const skipOnVariables = isString$3(res) && (options?.interpolation?.skipOnVariables !== undefined ? options.interpolation.skipOnVariables : this.options.interpolation.skipOnVariables); let nestBef; if (skipOnVariables) { const nb = res.match(this.interpolator.nestingRegexp); nestBef = nb && nb.length; } let data = options.replace && !isString$3(options.replace) ? options.replace : options; if (this.options.interpolation.defaultVariables) data = { ...this.options.interpolation.defaultVariables, ...data }; res = this.interpolator.interpolate(res, data, options.lng || this.language || resolved.usedLng, options); if (skipOnVariables) { const na = res.match(this.interpolator.nestingRegexp); const nestAft = na && na.length; if (nestBef < nestAft) options.nest = false; } if (!options.lng && resolved && resolved.res) options.lng = this.language || resolved.usedLng; if (options.nest !== false) res = this.interpolator.nest(res, function () { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } if (lastKey?.[0] === args[0] && !options.context) { _this.logger.warn(`It seems you are nesting recursively key: ${args[0]} in key: ${key[0]}`); return null; } return _this.translate(...args, key); }, options); if (options.interpolation) this.interpolator.reset(); } const postProcess = options.postProcess || this.options.postProcess; const postProcessorNames = isString$3(postProcess) ? [postProcess] : postProcess; if (res != null && postProcessorNames?.length && options.applyPostProcessor !== false) { res = postProcessor.handle(postProcessorNames, res, key, this.options && this.options.postProcessPassResolved ? { i18nResolved: { ...resolved, usedParams: this.getUsedParamsDetails(options) }, ...options } : options, this); } return res; } resolve(keys) { let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; let found; let usedKey; let exactUsedKey; let usedLng; let usedNS; if (isString$3(keys)) keys = [keys]; keys.forEach(k => { if (this.isValidLookup(found)) return; const extracted = this.extractFromKey(k, options); const key = extracted.key; usedKey = key; let namespaces = extracted.namespaces; if (this.options.fallbackNS) namespaces = namespaces.concat(this.options.fallbackNS); const needsPluralHandling = options.count !== undefined && !isString$3(options.count); const needsZeroSuffixLookup = needsPluralHandling && !options.ordinal && options.count === 0; const needsContextHandling = options.context !== undefined && (isString$3(options.context) || typeof options.context === 'number') && options.context !== ''; const codes = options.lngs ? options.lngs : this.languageUtils.toResolveHierarchy(options.lng || this.language, options.fallbackLng); namespaces.forEach(ns => { if (this.isValidLookup(found)) return; usedNS = ns; if (!checkedLoadedFor[`${codes[0]}-${ns}`] && this.utils?.hasLoadedNamespace && !this.utils?.hasLoadedNamespace(usedNS)) { checkedLoadedFor[`${codes[0]}-${ns}`] = true; this.logger.warn(`key "${usedKey}" for languages "${codes.join(', ')}" won't get resolved as namespace "${usedNS}" 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!!!'); } codes.forEach(code => { if (this.isValidLookup(found)) return; usedLng = code; const finalKeys = [key]; if (this.i18nFormat?.addLookupKeys) { this.i18nFormat.addLookupKeys(finalKeys, key, code, ns, options); } else { let pluralSuffix; if (needsPluralHandling) pluralSuffix = this.pluralResolver.getSuffix(code, options.count, options); const zeroSuffix = `${this.options.pluralSeparator}zero`; const ordinalPrefix = `${this.options.pluralSeparator}ordinal${this.options.pluralSeparator}`; if (needsPluralHandling) { finalKeys.push(key + pluralSuffix); if (options.ordinal && pluralSuffix.indexOf(ordinalPrefix) === 0) { finalKeys.push(key + pluralSuffix.replace(ordinalPrefix, this.options.pluralSeparator)); } if (needsZeroSuffixLookup) { finalKeys.push(key + zeroSuffix); } } if (needsContextHandling) { const contextKey = `${key}${this.options.contextSeparator}${options.context}`; finalKeys.push(contextKey); if (needsPluralHandling) { finalKeys.push(contextKey + pluralSuffix); if (options.ordinal && pluralSuffix.indexOf(ordinalPrefix) === 0) { finalKeys.push(contextKey + pluralSuffix.replace(ordinalPrefix, this.options.pluralSeparator)); } if (needsZeroSuffixLookup) { finalKeys.push(contextKey + zeroSuffix); } } } } let possibleKey; while (possibleKey = finalKeys.pop()) { if (!this.isValidLookup(found)) { exactUsedKey = possibleKey; found = this.getResource(code, ns, possibleKey, options); } } }); }); }); return { res: found, usedKey, exactUsedKey, usedLng, usedNS }; } isValidLookup(res) { return res !== undefined && !(!this.options.returnNull && res === null) && !(!this.options.returnEmptyString && res === ''); } getResource(code, ns, key) { let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; if (this.i18nFormat?.getResource) return this.i18nFormat.getResource(code, ns, key, options); return this.resourceStore.getResource(code, ns, key, options); } getUsedParamsDetails() { let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; const optionsKeys = ['defaultValue', 'ordinal', 'context', 'replace', 'lng', 'lngs', 'fallbackLng', 'ns', 'keySeparator', 'nsSeparator', 'returnObjects', 'returnDetails', 'joinArrays', 'postProcess', 'interpolation']; const useOptionsReplaceForData = options.replace && !isString$3(options.replace); let data = useOptionsReplaceForData ? options.replace : options; if (useOptionsReplaceForData && typeof options.count !== 'undefined') { data.count = options.count; } if (this.options.interpolation.defaultVariables) { data = { ...this.options.interpolation.defaultVariables, ...data }; } if (!useOptionsReplaceForData) { data = { ...data }; for (const key of optionsKeys) { delete data[key]; } } return data; } static hasDefaultValue(options) { const prefix = 'defaultValue'; for (const option in options) { if (Object.prototype.hasOwnProperty.call(options, option) && prefix === option.substring(0, prefix.length) && undefined !== options[option]) { return true; } } return false; } } class LanguageUtil { constructor(options) { this.options = options; this.supportedLngs = this.options.supportedLngs || false; this.logger = baseLogger.create('languageUtils'); } getScriptPartFromCode(code) { code = getCleanedCode(code); if (!code || code.indexOf('-') < 0) return null; const p = code.split('-'); if (p.length === 2) return null; p.pop(); if (p[p.length - 1].toLowerCase() === 'x') return null; return this.formatLanguageCode(p.join('-')); } getLanguagePartFromCode(code) { code = getCleanedCode(code); if (!code || code.indexOf('-') < 0) return code; const p = code.split('-'); return this.formatLanguageCode(p[0]); } formatLanguageCode(code) { if (isString$3(code) && code.indexOf('-') > -1) { let formattedCode; try { formattedCode = Intl.getCanonicalLocales(code)[0]; } catch (e) {} if (formattedCode && this.options.lowerCaseLng) { formattedCode = formattedCode.toLowerCase(); } if (formattedCode) return formattedCode; if (this.options.lowerCaseLng) { return code.toLowerCase(); } return code; } return this.options.cleanCode || this.options.lowerCaseLng ? code.toLowerCase() : code; } isSupportedCode(code) { if (this.options.load === 'languageOnly' || this.options.nonExplicitSupportedLngs) { code = this.getLanguagePartFromCode(code); } return !this.supportedLngs || !this.supportedLngs.length || this.supportedLngs.indexOf(code) > -1; } getBestMatchFromCodes(codes) { if (!codes) return null; let found; codes.forEach(code => { if (found) return; const cleanedLng = this.formatLanguageCode(code); if (!this.options.supportedLngs || this.isSupportedCode(cleanedLng)) found = cleanedLng; }); if (!found && this.options.supportedLngs) { codes.forEach(code => { if (found) return; const lngOnly = this.getLanguagePartFromCode(code); if (this.isSupportedCode(lngOnly)) return found = lngOnly; found = this.options.supportedLngs.find(supportedLng => { if (supportedLng === lngOnly) return supportedLng; if (supportedLng.indexOf('-') < 0 && lngOnly.indexOf('-') < 0) return; if (supportedLng.indexOf('-') > 0 && lngOnly.indexOf('-') < 0 && supportedLng.substring(0, supportedLng.indexOf('-')) === lngOnly) return supportedLng; if (supportedLng.indexOf(lngOnly) === 0 && lngOnly.length > 1) return supportedLng; }); }); } if (!found) found = this.getFallbackCodes(this.options.fallbackLng)[0]; return found; } getFallbackCodes(fallbacks, code) { if (!fallbacks) return []; if (typeof fallbacks === 'function') fallbacks = fallbacks(code); if (isString$3(fallbacks)) fallbacks = [fallbacks]; if (Array.isArray(fallbacks)) return fallbacks; if (!code) return fallbacks.default || []; let found = fallbacks[code]; if (!found) found = fallbacks[this.getScriptPartFromCode(code)]; if (!found) found = fallbacks[this.formatLanguageCode(code)]; if (!found) found = fallbacks[this.getLanguagePartFromCode(code)]; if (!found) found = fallbacks.default; return found || []; } toResolveHierarchy(code, fallbackCode) { const fallbackCodes = this.getFallbackCodes(fallbackCode || this.options.fallbackLng || [], code); const codes = []; const addCode = c => { if (!c) return; if (this.isSupportedCode(c)) { codes.push(c); } else { this.logger.warn(`rejecting language code not found in supportedLngs: ${c}`); } }; if (isString$3(code) && (code.indexOf('-') > -1 || code.indexOf('_') > -1)) { if (this.options.load !== 'languageOnly') addCode(this.formatLanguageCode(code)); i