You're Invited: Meet the Socket team at BSidesSF and RSAC - April 27 - May 1.RSVP
Socket
Sign inDemoInstall
Socket

@tolgee/core

Package Overview
Dependencies
Maintainers
2
Versions
368
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@tolgee/core - npm Package Compare versions

Comparing version

to
5.0.0-rc.704ada9.0

dist/tolgee.esm.js

1090

dist/tolgee.cjs.js

@@ -5,21 +5,14 @@ 'use strict';

const EventEmitter = () => {
let handlers = [];
const listen = (handler) => {
const handlerWrapper = (e) => {
handler(e);
};
handlers.push(handlerWrapper);
return {
unsubscribe: () => {
handlers = handlers.filter((i) => handlerWrapper !== i);
},
};
};
const emit = (data) => {
handlers.forEach((handler) => handler({ value: data }));
};
return Object.freeze({ listen, emit });
function isPromise(value) {
return Boolean(value && typeof value.then === 'function');
}
const valueOrPromise = (value, callback) => {
if (isPromise(value)) {
return Promise.resolve(value).then(callback);
}
else {
return callback(value);
}
};
const missingOptionError = (option) => `Tolgee: You need to specify '${option}' option`;
function isObject(item) {

@@ -51,18 +44,36 @@ return typeof item === 'object' && !Array.isArray(item) && item !== null;

}
function incrementInMap(map, value) {
const currNum = map.get(value) || 0;
map.set(value, currNum + 1);
function sanitizeUrl(url) {
return url ? url.replace(/\/+$/, '') : url;
}
function decrementInMap(map, value) {
let currNum = map.get(value) || 1;
currNum -= 1;
if (currNum <= 0) {
map.delete(value);
function getErrorMessage(error) {
if (typeof error === 'string') {
return error;
}
else {
map.set(value, currNum);
else if (typeof (error === null || error === void 0 ? void 0 : error.message) === 'string') {
return error.message;
}
}
const EventEmitterSelective = () => {
const EventEmitter = (isActive) => {
let handlers = [];
const listen = (handler) => {
const handlerWrapper = (e) => {
handler(e);
};
handlers.push(handlerWrapper);
return {
unsubscribe: () => {
handlers = handlers.filter((i) => handlerWrapper !== i);
},
};
};
const emit = (data) => {
if (isActive()) {
handlers.forEach((handler) => handler({ value: data }));
}
};
return Object.freeze({ listen, emit });
};
const EventEmitterSelective = (isActive, getFallbackNs, getDefaultNs) => {
const listeners = new Set();

@@ -84,4 +95,3 @@ const partialListeners = new Set();

},
keys: new Map(),
namespaces: new Map(),
namespaces: new Set(),
};

@@ -94,40 +104,20 @@ partialListeners.add(handlerWrapper);

subscribeNs: (ns) => {
getFallbackArray(ns).forEach((val) => incrementInMap(handlerWrapper.namespaces, val));
return result;
},
unsubscribeNs: (ns) => {
getFallbackArray(ns).forEach((val) => decrementInMap(handlerWrapper.namespaces, val));
return result;
},
subscribeKey: (descriptor) => {
const { key, ns } = descriptor;
incrementInMap(handlerWrapper.keys, key);
getFallbackArray(ns).forEach((val) => incrementInMap(handlerWrapper.namespaces, val));
getFallbackArray(ns).forEach((val) => handlerWrapper.namespaces.add(val));
if (ns === undefined) {
// subscribing to all namespaces
incrementInMap(handlerWrapper.namespaces, undefined);
// subscribing to default ns
handlerWrapper.namespaces.add(getDefaultNs());
}
return result;
},
unsubscribeKey: (descriptor) => {
const { key, ns } = descriptor;
decrementInMap(handlerWrapper.keys, key);
getFallbackArray(ns).forEach((val) => decrementInMap(handlerWrapper.namespaces, val));
if (ns === undefined) {
// subscribing to all namespaces
decrementInMap(handlerWrapper.namespaces, undefined);
}
return result;
},
};
return result;
};
const callHandlers = (key, ns) => {
const callHandlers = (ns) => {
// everything is implicitly subscribed to fallbacks
// as it can always fall through to it
const fallbackNamespaces = new Set(getFallbackNs());
partialListeners.forEach((handler) => {
const nsMentioned = ns !== undefined;
const nsMatches = handler.namespaces.has(undefined) ||
(ns === null || ns === void 0 ? void 0 : ns.findIndex((ns) => handler.namespaces.has(ns))) !== -1;
const keyMentioned = key !== undefined;
const keyMatches = key === undefined || handler.keys.has(key) || handler.keys.size === 0;
if ((!nsMentioned || nsMatches) && (!keyMentioned || keyMatches)) {
const nsMatches = ns === undefined ||
(ns === null || ns === void 0 ? void 0 : ns.findIndex((ns) => fallbackNamespaces.has(ns) || handler.namespaces.has(ns))) !== -1;
if (nsMatches) {
handler.fn({ value: undefined });

@@ -138,2 +128,3 @@ }

let queue = [];
// merge events in queue into one event
const solveQueue = () => {

@@ -143,35 +134,31 @@ if (queue.length === 0) {

}
const queueCopy = queue;
queue = [];
listeners.forEach((handler) => {
handler({ value: undefined });
});
let namespaces = [];
let keys = [];
queue.forEach((descriptor) => {
if ((descriptor === null || descriptor === void 0 ? void 0 : descriptor.ns) === undefined) {
let namespaces = new Set();
queueCopy.forEach((ns) => {
if (ns === undefined) {
// when no ns specified, it affects all namespaces
namespaces = undefined;
}
else if (namespaces !== undefined) {
namespaces = [...namespaces, ...descriptor.ns];
ns.forEach((ns) => namespaces.add(ns));
}
if ((descriptor === null || descriptor === void 0 ? void 0 : descriptor.key) === undefined) {
keys = undefined;
}
else if (keys !== undefined) {
keys = [...keys, descriptor.key];
}
});
(keys || [undefined]).forEach((key) => {
callHandlers(key, namespaces);
});
queue = [];
const namespacesArray = namespaces
? Array.from(namespaces.keys())
: undefined;
callHandlers(namespacesArray);
};
const emit = (descriptor, delayed) => {
queue.push(descriptor);
if (!delayed) {
solveQueue();
}
else {
Promise.resolve().then(() => {
const emit = (ns, delayed) => {
if (isActive()) {
queue.push(ns);
if (!delayed) {
solveQueue();
});
}
else {
setTimeout(solveQueue, 0);
}
}

@@ -182,16 +169,19 @@ };

const Events = () => {
const onPendingLanguageChange = EventEmitter();
const onLanguageChange = EventEmitter();
const onKeyChange = EventEmitter();
const onLoadingChange = EventEmitter();
const onFetchingChange = EventEmitter();
const onInitialLoaded = EventEmitter();
const onKeyUpdate = EventEmitterSelective();
const onCacheChange = EventEmitter();
const onRunningChange = EventEmitter();
onInitialLoaded.listen(() => onKeyUpdate.emit());
onLanguageChange.listen(() => onKeyUpdate.emit());
const Events = (getFallbackNs, getDefaultNs) => {
let emitterActive = true;
function isActive() {
return emitterActive;
}
const onPendingLanguageChange = EventEmitter(isActive);
const onLanguageChange = EventEmitter(isActive);
const onLoadingChange = EventEmitter(isActive);
const onFetchingChange = EventEmitter(isActive);
const onInitialLoaded = EventEmitter(isActive);
const onRunningChange = EventEmitter(isActive);
const onCacheChange = EventEmitter(isActive);
const onUpdate = EventEmitterSelective(isActive, getFallbackNs, getDefaultNs);
onInitialLoaded.listen(() => onUpdate.emit());
onLanguageChange.listen(() => onUpdate.emit());
onCacheChange.listen(({ value }) => {
onKeyUpdate.emit({ ns: [value.namespace], key: value.key }, true);
onUpdate.emit([value.namespace], true);
});

@@ -214,11 +204,12 @@ const on = (event, handler) => {

return onCacheChange.listen(handler);
case 'keyUpdate':
return onKeyUpdate.listen(handler);
case 'update':
return onUpdate.listen(handler);
}
};
function setEmmiterActive(active) {
emitterActive = active;
}
return Object.freeze({
onPendingLanguageChange,
onLanguageChange,
onKeyChange,
onKeyUpdate,
onLoadingChange,

@@ -229,2 +220,4 @@ onFetchingChange,

onCacheChange,
onUpdate,
setEmmiterActive,
on,

@@ -242,3 +235,3 @@ });

if (typeof value === 'object') {
Object.entries(flattenTranslations(value)).forEach(([flatKey, flatValue]) => {
flattenTranslations(value).forEach((flatValue, flatKey) => {
result.set(key + '.' + flatKey, flatValue);

@@ -253,3 +246,5 @@ });

const decodeCacheKey = (key) => {
const [firstPart, secondPart] = key.split(':');
const [firstPart, ...rest] = key.split(':');
// if namespaces contains ":" it won't get lost
const secondPart = rest.join(':');
return { language: firstPart, namespace: secondPart || '' };

@@ -286,9 +281,10 @@ };

function invalidate() {
asyncRequests.clear();
version += 1;
}
function addRecordInternal(descriptor, data, version) {
function addRecordInternal(descriptor, data, recordVersion) {
const cacheKey = encodeCacheKey(descriptor);
cache.set(cacheKey, {
data: flattenTranslations(data),
version: version,
version: recordVersion,
});

@@ -309,3 +305,3 @@ onCacheChange.emit(descriptor);

var _a;
return (_a = cache.get(encodeCacheKey(descriptor))) === null || _a === void 0 ? void 0 : _a.data;
return (_a = cache.get(encodeCacheKey(withDefaultNs(descriptor)))) === null || _a === void 0 ? void 0 : _a.data;
}

@@ -323,7 +319,7 @@ function getTranslation(descriptor, key) {

if (value !== undefined && value !== null) {
return namespace;
return [namespace];
}
}
}
return Array.from(new Set(namespaces));
return unique(namespaces);
}

@@ -349,5 +345,2 @@ function getTranslationFallback(namespaces, languages, key) {

}
function clear() {
cache.clear();
}
function isFetching(ns) {

@@ -375,3 +368,6 @@ if (isInitialLoading()) {

}
function fetchNormal(keyObject) {
/**
* Fetches production data
*/
function fetchProd(keyObject) {
let dataPromise = undefined;

@@ -383,5 +379,2 @@ if (!dataPromise) {

}
else if (staticDataValue) {
dataPromise = Promise.resolve(staticDataValue);
}
}

@@ -391,6 +384,2 @@ if (!dataPromise) {

}
if (!dataPromise) {
// return empty data, so we know it has already been attempted to fetch
dataPromise = Promise.resolve({});
}
return dataPromise;

@@ -405,8 +394,8 @@ }

console.warn(`Tolgee: Failed to fetch data from dev backend`);
// fallback to normal fetch if dev fails
return fetchNormal(keyObject);
// fallback to prod fetch if dev fails
return fetchProd(keyObject);
});
}
if (!dataPromise) {
dataPromise = fetchNormal(keyObject);
dataPromise = fetchProd(keyObject);
}

@@ -428,3 +417,3 @@ return dataPromise;

}
const dataPromise = fetchData(keyObject, isDev);
const dataPromise = fetchData(keyObject, isDev) || Promise.resolve(undefined);
asyncRequests.set(cacheKey, dataPromise);

@@ -442,3 +431,6 @@ return {

withPromises.forEach((value, i) => {
if (value.new) {
const promiseChanged = asyncRequests.get(value.cacheKey) !== value.promise;
// if promise has changed in between, it means cache been invalidated or
// new data are being fetched
if (value.new && !promiseChanged) {
asyncRequests.delete(value.cacheKey);

@@ -449,2 +441,6 @@ const data = results[i];

}
else if (!getRecord(value.keyObject)) {
// if no data exist, put empty object
addRecord(value.keyObject, {});
}
}

@@ -475,3 +471,2 @@ });

loadRecords,
clear,
getAllRecords,

@@ -481,18 +476,77 @@ });

function isPromise(value) {
return Boolean(value && typeof value.then === 'function');
/******************************************************************************
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.
***************************************************************************** */
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;
}
const valueOrPromise = (value, callback) => {
if (isPromise(value)) {
return Promise.resolve(value).then(callback);
}
else {
return callback(value);
}
const defaultObserverOptions = {
tagAttributes: {
textarea: ['placeholder'],
input: ['value', 'placeholder'],
img: ['alt'],
'*': ['aria-label', 'title'],
},
restrictedElements: ['script', 'style'],
highlightKeys: ['Alt'],
highlightColor: 'rgb(255, 0, 0)',
highlightWidth: 5,
inputPrefix: '%-%tolgee:',
inputSuffix: '%-%',
passToParent: ['option', 'optgroup'],
};
const missingOptionError = (option) => `Tolgee: You need to specify '${option}' option`;
const PluginService = (getLanguage, getInitialOptions, getAvailableLanguages, getTranslationNs, getTranslation, changeTranslation) => {
const DEFAULT_FORMAT_ERROR = 'invalid';
const defaultValues = {
defaultNs: '',
observerOptions: defaultObserverOptions,
observerType: 'invisible',
onFormatError: DEFAULT_FORMAT_ERROR,
};
const combineOptions = (...states) => {
let result = {};
states.forEach((state) => {
result = Object.assign(Object.assign(Object.assign({}, result), state), { observerOptions: Object.assign(Object.assign({}, result.observerOptions), state === null || state === void 0 ? void 0 : state.observerOptions) });
});
return result;
};
const initState = (options, previousState) => {
const initialOptions = combineOptions(defaultValues, previousState === null || previousState === void 0 ? void 0 : previousState.initialOptions, options);
// remove extra '/' from url end
initialOptions.apiUrl = sanitizeUrl(initialOptions.apiUrl);
return {
initialOptions,
activeNamespaces: (previousState === null || previousState === void 0 ? void 0 : previousState.activeNamespaces) || new Map(),
language: previousState === null || previousState === void 0 ? void 0 : previousState.language,
pendingLanguage: previousState === null || previousState === void 0 ? void 0 : previousState.language,
isInitialLoading: false,
isRunning: false,
};
};
const Plugins = (getLanguage, getInitialOptions, getAvailableLanguages, getTranslationNs, getTranslation, changeTranslation) => {
const plugins = {
ui: undefined,
observer: undefined,
};

@@ -509,36 +563,17 @@ const instances = {

};
const onClick = async (event, { keysAndDefaults }) => {
const onClick = async ({ keysAndDefaults, event }) => {
var _a;
const withNs = keysAndDefaults.map(({ key, ns, defaultValue }) => ({
key,
defaultValue,
ns: getFallbackArray(getTranslationNs({ key, ns, defaultValue })),
translation: getTranslation({
const withNs = keysAndDefaults.map(({ key, ns, defaultValue }) => {
return {
key,
ns,
}),
}));
(_a = instances.ui) === null || _a === void 0 ? void 0 : _a.handleElementClick(event, withNs);
defaultValue,
ns: getTranslationNs({ key, ns }),
translation: getTranslation({
key,
ns,
}),
};
});
(_a = instances.ui) === null || _a === void 0 ? void 0 : _a.handleElementClick(withNs, event);
};
const run = () => {
var _a;
instances.ui =
plugins.ui &&
new plugins.ui({
apiKey: getInitialOptions().apiKey,
apiUrl: getInitialOptions().apiUrl,
highlight,
changeTranslation,
});
(_a = instances.observer) === null || _a === void 0 ? void 0 : _a.run({ mouseHighlight: Boolean(instances.ui) });
checkCorrectConfiguration();
};
const checkCorrectConfiguration = () => {
if (instances.languageDetector) {
const availableLanguages = getAvailableLanguages();
if (!availableLanguages) {
throw new Error(missingOptionError('availableLanguages'));
}
}
};
const stop = () => {

@@ -554,10 +589,13 @@ var _a;

const translate = (props) => {
const translation = getTranslation(props);
const translation = getTranslation({
key: props.key,
ns: props.ns,
});
return formatTranslation(Object.assign(Object.assign({}, props), { translation, formatEnabled: true }));
};
const setObserver = (observer) => {
instances.observer = observer === null || observer === void 0 ? void 0 : observer({ translate, onClick });
plugins.observer = observer;
};
const getObserver = () => {
return instances.observer;
const hasObserver = () => {
return Boolean(plugins.observer);
};

@@ -573,6 +611,6 @@ const addFormatter = (formatter) => {

const setUi = (ui) => {
plugins.ui = (ui === null || ui === void 0 ? void 0 : ui.UI) || ui;
plugins.ui = ui;
};
const getUi = () => {
return plugins.ui;
const hasUi = () => {
return Boolean(plugins.ui);
};

@@ -582,2 +620,5 @@ const setLanguageStorage = (storage) => {

};
const getLanguageStorage = () => {
return instances.languageStorage;
};
const setStoredLanguage = (language) => {

@@ -590,2 +631,5 @@ var _a;

};
const getLanguageDetector = () => {
return instances.languageDetector;
};
const detectLanguage = () => {

@@ -620,2 +664,23 @@ if (!instances.languageDetector) {

};
const run = () => {
var _a, _b, _c;
if (!instances.ui) {
const { apiKey, apiUrl, projectId } = getInitialOptions();
instances.ui = (_a = plugins.ui) === null || _a === void 0 ? void 0 : _a.call(plugins, {
apiKey: apiKey,
apiUrl: apiUrl,
projectId,
highlight,
changeTranslation,
});
}
if (!instances.observer) {
instances.observer = (_b = plugins.observer) === null || _b === void 0 ? void 0 : _b.call(plugins, {
translate,
onClick,
options: getInitialOptions().observerOptions,
});
}
(_c = instances.observer) === null || _c === void 0 ? void 0 : _c.run({ mouseHighlight: true });
};
const getDevBackend = () => {

@@ -626,5 +691,7 @@ return instances.devBackend;

var _a;
const { apiKey, apiUrl, projectId } = getInitialOptions();
return (_a = instances.devBackend) === null || _a === void 0 ? void 0 : _a.getRecord({
apiKey: getInitialOptions().apiKey,
apiUrl: getInitialOptions().apiUrl,
apiKey,
apiUrl,
projectId,
language,

@@ -650,21 +717,65 @@ namespace,

};
const formatTranslation = ({ key, translation, defaultValue, noWrap, params, orEmpty, ns, formatEnabled, }) => {
const unwrap = (text) => {
var _a;
if (instances.observer) {
return (_a = instances.observer) === null || _a === void 0 ? void 0 : _a.unwrap(text);
}
return { text, keys: [] };
};
const retranslate = () => {
var _a;
(_a = instances.observer) === null || _a === void 0 ? void 0 : _a.retranslate();
};
function addPlugin(tolgeeInstance, plugin) {
const pluginTools = Object.freeze({
setFinalFormatter,
addFormatter,
setObserver,
hasObserver,
setUi,
hasUi,
setDevBackend,
addBackend,
setLanguageDetector,
setLanguageStorage,
});
plugin(tolgeeInstance, pluginTools);
}
function formatTranslation(_a) {
var _b;
var { formatEnabled } = _a, props = __rest(_a, ["formatEnabled"]);
const { key, translation, defaultValue, noWrap, params, orEmpty, ns } = props;
const formattableTranslation = translation || defaultValue;
let result = formattableTranslation || (orEmpty ? '' : key);
if (instances.observer && !noWrap) {
result = instances.observer.wrap({
key,
translation: result,
defaultValue,
params,
ns,
});
}
const language = getLanguage();
const isFormatEnabled = formatEnabled || !((_a = instances.observer) === null || _a === void 0 ? void 0 : _a.outputNotFormattable);
if (formattableTranslation && language && isFormatEnabled) {
for (const formatter of instances.formatters) {
result = formatter.format({
const isFormatEnabled = formatEnabled || !((_b = instances.observer) === null || _b === void 0 ? void 0 : _b.outputNotFormattable);
const wrap = (result) => {
if (instances.observer && !noWrap) {
return instances.observer.wrap({
key,
translation: result,
defaultValue,
params,
ns,
});
}
return result;
};
result = wrap(result);
try {
if (formattableTranslation && language && isFormatEnabled) {
for (const formatter of instances.formatters) {
result = formatter.format({
translation: result,
language,
params,
});
}
}
if (instances.finalFormatter &&
formattableTranslation &&
language &&
isFormatEnabled) {
result = instances.finalFormatter.format({
translation: result,
language,

@@ -675,14 +786,25 @@ params,

}
if (instances.finalFormatter &&
formattableTranslation &&
language &&
isFormatEnabled) {
result = instances.finalFormatter.format({
translation: result,
language,
params,
});
catch (e) {
// eslint-disable-next-line no-console
console.error(e);
const errorMessage = getErrorMessage(e) || DEFAULT_FORMAT_ERROR;
const onFormatError = getInitialOptions().onFormatError;
const formatErrorType = typeof onFormatError;
if (formatErrorType === 'string') {
result = onFormatError;
}
else if (formatErrorType === 'function') {
result = onFormatError(errorMessage, props);
}
else {
result = DEFAULT_FORMAT_ERROR;
}
// wrap error message, so it's detectable
result = wrap(result);
}
return result;
};
}
function hasDevBackend() {
return Boolean(getDevBackend());
}
const wrap = (params) => {

@@ -695,28 +817,10 @@ var _a;

};
const unwrap = (text) => {
var _a;
if (instances.observer) {
return (_a = instances.observer) === null || _a === void 0 ? void 0 : _a.unwrap(text);
}
return { text, keys: [] };
};
const retranslate = () => {
var _a;
(_a = instances.observer) === null || _a === void 0 ? void 0 : _a.retranslate();
};
return Object.freeze({
setFinalFormatter,
addFormatter,
addPlugin,
formatTranslation,
setObserver,
getObserver,
setUi,
getUi,
addBackend,
setDevBackend,
getDevBackend,
getBackendRecord,
getBackendDevRecord,
setLanguageDetector,
setLanguageStorage,
getLanguageDetector,
getLanguageStorage,
getInitialLanguage,

@@ -728,4 +832,5 @@ setStoredLanguage,

highlight,
unwrap,
wrap,
unwrap,
hasDevBackend,
});

@@ -752,24 +857,5 @@ };

const defaultValues = {
enableLanguageStore: true,
defaultNs: '',
filesUrlPrefix: 'i18n/',
};
const initState = (options, previousState) => {
const initialOptions = Object.assign(Object.assign(Object.assign({}, defaultValues), previousState === null || previousState === void 0 ? void 0 : previousState.initialOptions), options);
// remove extra '/' from url end
const apiUrl = initialOptions.apiUrl;
initialOptions.apiUrl = apiUrl ? apiUrl.replace(/\/+$/, '') : apiUrl;
return {
initialOptions,
activeNamespaces: (previousState === null || previousState === void 0 ? void 0 : previousState.activeNamespaces) || new Map(),
language: previousState === null || previousState === void 0 ? void 0 : previousState.language,
pendingLanguage: previousState === null || previousState === void 0 ? void 0 : previousState.language,
isInitialLoading: false,
isRunning: false,
};
};
const State = (onLanguageChange, onPendingLanguageChange, onRunningChange) => {
let state = initState();
let devCredentials = undefined;
function init(options) {

@@ -796,9 +882,2 @@ state = initState(options, state);

}
function getLanguageOrFail() {
const language = state.language || state.initialOptions.language;
if (!language) {
throw new Error(`No language set`);
}
return language;
}
function setLanguage(language) {

@@ -820,3 +899,3 @@ if (state.language !== language) {

function getInitialOptions() {
return state.initialOptions;
return Object.assign(Object.assign({}, state.initialOptions), devCredentials);
}

@@ -850,2 +929,3 @@ function addActiveNs(ns) {

...(state.initialOptions.ns || [state.initialOptions.defaultNs]),
...getFallbackArray(state.initialOptions.fallbackNs),
...state.activeNamespaces.keys(),

@@ -864,8 +944,8 @@ ]);

}
function getFallbackNamespaces() {
const defaultNs = state.initialOptions.defaultNs;
const fallbackNs = state.initialOptions.fallbackNs;
const fallbackNamespaces = typeof defaultNs === 'string' ? [defaultNs] : [];
return unique([...fallbackNamespaces, ...getFallbackArray(fallbackNs)]);
function getFallbackNs() {
return getFallbackArray(state.initialOptions.fallbackNs);
}
function getDefaultNs(ns) {
return ns === undefined ? state.initialOptions.defaultNs : ns;
}
function getAvailableLanguages() {

@@ -888,2 +968,10 @@ if (state.initialOptions.availableLanguages) {

}
function overrideCredentials(credentials) {
if (credentials) {
devCredentials = Object.assign(Object.assign({}, credentials), { apiUrl: sanitizeUrl(credentials.apiUrl) });
}
else {
devCredentials = undefined;
}
}
return Object.freeze({

@@ -896,3 +984,2 @@ init,

getLanguage,
getLanguageOrFail,
setLanguage,

@@ -906,35 +993,10 @@ getPendingLanguage,

getFallbackLangs,
getFallbackNamespaces,
getFallbackNs,
getDefaultNs,
getAvailableLanguages,
withDefaultNs,
overrideCredentials,
});
};
/******************************************************************************
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.
***************************************************************************** */
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 parseCombinedOptions(_a) {

@@ -946,7 +1008,6 @@ var { ns, noWrap, orEmpty, params } = _a, rest = __rest(_a, ["ns", "noWrap", "orEmpty", "params"]);

orEmpty: orEmpty,
params: Object.assign(Object.assign({}, rest), params),
};
return options;
return Object.assign(Object.assign({}, options), { params: Object.assign({}, rest) });
}
const getTranslateParams = (keyOrProps, ...params) => {
const getTranslateProps = (keyOrProps, ...params) => {
let result = {};

@@ -973,14 +1034,13 @@ let options;

const Controller = ({ events, options }) => {
const Controller = ({ options }) => {
const events = Events(getFallbackNs, getDefaultNs);
const fetchingObserver = ValueObserver(false, () => cache.isFetching(), events.onFetchingChange.emit);
const loadingObserver = ValueObserver(false, () => isLoading(), events.onLoadingChange.emit);
const state = State(events.onLanguageChange, events.onPendingLanguageChange, events.onRunningChange);
const pluginService = PluginService(state.getLanguage, state.getInitialOptions, state.getAvailableLanguages, getTranslationNs, getTranslation, changeTranslation);
const pluginService = Plugins(state.getLanguage, state.getInitialOptions, state.getAvailableLanguages, getTranslationNs, getTranslation, changeTranslation);
const cache = Cache(events.onCacheChange, pluginService.getBackendRecord, pluginService.getBackendDevRecord, state.withDefaultNs, state.isInitialLoading, fetchingObserver, loadingObserver);
state.init(options);
cache.addStaticData(state.getInitialOptions().staticData);
if (isDev()) {
cache.invalidate();
if (options) {
init(options);
}
events.onKeyUpdate.listen(() => {
events.onUpdate.listen(() => {
if (state.isRunning()) {

@@ -990,8 +1050,21 @@ pluginService.retranslate();

});
const t = (...args) => {
// @ts-ignore
const params = getTranslateParams(...args);
const translation = getTranslation(params);
return pluginService.formatTranslation(Object.assign(Object.assign({}, params), { translation }));
};
function getFallbackNs() {
return state.getFallbackNs();
}
function getDefaultNs(ns) {
return state.getDefaultNs(ns);
}
// gets all namespaces where translation could be located
// takes (ns|default, fallback ns)
function getDefaultAndFallbackNs(ns) {
return [...getFallbackArray(getDefaultNs(ns)), ...getFallbackNs()];
}
// gets all namespaces which need to be loaded
// takes (ns|default, initial ns, fallback ns, active ns)
function getRequiredNamespaces(ns) {
return [
...getFallbackArray(ns || getDefaultNs()),
...state.getRequiredNamespaces(),
];
}
function changeTranslation(descriptor, key, value) {

@@ -1010,5 +1083,2 @@ const keyObject = state.withDefaultNs(descriptor);

cache.addStaticData(state.getInitialOptions().staticData);
if (isDev()) {
cache.invalidate();
}
}

@@ -1019,3 +1089,3 @@ function isLoading(ns) {

function isDev() {
return Boolean(state.getInitialOptions().apiKey && pluginService.getDevBackend());
return Boolean(state.getInitialOptions().apiKey && state.getInitialOptions().apiUrl);
}

@@ -1032,3 +1102,3 @@ async function addActiveNs(ns, forget) {

const languages = state.getFallbackLangs(lang);
const namespaces = ns !== undefined ? getFallbackArray(ns) : state.getRequiredNamespaces();
const namespaces = getRequiredNamespaces(ns);
const result = [];

@@ -1050,3 +1120,3 @@ languages.forEach((language) => {

const languages = state.getFallbackLangs(language);
const namespaces = ns !== undefined ? getFallbackArray(ns) : state.getRequiredNamespaces();
const namespaces = getRequiredNamespaces(ns);
const result = [];

@@ -1084,13 +1154,9 @@ languages.forEach((language) => {

}
function getTranslationNs({ key, ns, }) {
const namespaces = ns
? getFallbackArray(ns)
: state.getFallbackNamespaces();
function getTranslationNs({ key, ns }) {
const languages = state.getFallbackLangs();
const namespaces = getDefaultAndFallbackNs(ns);
return cache.getTranslationNs(namespaces, languages, key);
}
function getTranslation({ key, ns, }) {
const namespaces = ns
? getFallbackArray(ns)
: state.getFallbackNamespaces();
function getTranslation({ key, ns }) {
const namespaces = getDefaultAndFallbackNs(ns);
const languages = state.getFallbackLangs();

@@ -1102,3 +1168,2 @@ return cache.getTranslationFallback(namespaces, languages, key);

// fail if there is no language
state.getLanguageOrFail();
return loadRequiredRecords();

@@ -1142,5 +1207,26 @@ });

}
const checkCorrectConfiguration = () => {
const languageComputable = pluginService.getLanguageDetector() || pluginService.getLanguageStorage();
if (languageComputable) {
const availableLanguages = state.getAvailableLanguages();
if (!availableLanguages) {
throw new Error(missingOptionError('availableLanguages'));
}
}
if (!state.getLanguage() && !state.getInitialOptions().defaultLanguage) {
if (languageComputable) {
throw new Error(missingOptionError('defaultLanguage'));
}
else {
throw new Error(missingOptionError('language'));
}
}
};
function run() {
let result = undefined;
checkCorrectConfiguration();
if (!state.isRunning()) {
if (isDev()) {
cache.invalidate();
}
state.setRunning(true);

@@ -1158,3 +1244,9 @@ pluginService.run();

}
return Object.freeze(Object.assign(Object.assign(Object.assign(Object.assign({}, state), pluginService), cache), { init,
const t = (...args) => {
// @ts-ignore
const params = getTranslateProps(...args);
const translation = getTranslation(params);
return pluginService.formatTranslation(Object.assign(Object.assign({}, params), { translation }));
};
return Object.freeze(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, events), state), pluginService), cache), { init,
changeLanguage,

@@ -1164,3 +1256,2 @@ getTranslation,

addActiveNs,
loadRequiredRecords,
loadRecords,

@@ -1176,20 +1267,7 @@ loadRecord,

const Tolgee = (options) => {
const events = Events();
const createTolgee = (options) => {
const controller = Controller({
events,
options,
});
const pluginTools = Object.freeze({
setFinalFormatter: controller.setFinalFormatter,
addFormatter: controller.addFormatter,
setObserver: controller.setObserver,
getObserver: controller.getObserver,
setUi: controller.setUi,
getUi: controller.getUi,
setDevBackend: controller.setDevBackend,
addBackend: controller.addBackend,
setLanguageDetector: controller.setLanguageDetector,
setLanguageStorage: controller.setLanguageStorage,
});
// restarts tolgee while applying callback
const withRestart = (callback) => {

@@ -1202,61 +1280,359 @@ const wasRunning = controller.isRunning();

const tolgee = Object.freeze({
// event listeners
on: events.on,
onKeyUpdate: events.onKeyUpdate.listenSome,
// state
/**
* Listen to tolgee events.
*/
on: controller.on,
/**
* Listen for specific namespaces changes.
*
* ```
* const sub = tolgee.onUpdate(handler)
*
* // subscribe to selected namespace
* sub.subscribeNs(['common'])
*
* // unsubscribe
* sub.unsubscribe()
* ```
*/
onNsUpdate: controller.onUpdate.listenSome,
/**
* Turn off/on events emitting. Is on by default.
*/
setEmmiterActive: controller.setEmmiterActive,
/**
* @return current language if set.
*/
getLanguage: controller.getLanguage,
/**
* `pendingLanguage` represents language which is currently being loaded.
* @return current `pendingLanguage` if set.
*/
getPendingLanguage: controller.getPendingLanguage,
/**
* Change current language.
* - if not running sets `pendingLanguage`, `language` to the new value
* - if running sets `pendingLanguage` to the value, fetches necessary data and then changes `language`
*
* @return Promise which is resolved when `language` is changed.
*/
changeLanguage: controller.changeLanguage,
/**
* Temporarily change translation in cache.
* @return object with revert method.
*/
changeTranslation: controller.changeTranslation,
/**
* Adds namespace(s) list of active namespaces. And if tolgee is running, loads required data.
*/
addActiveNs: controller.addActiveNs,
/**
* Remove namespace(s) from active namespaces.
*
* Tolgee internally counts how many times was each active namespace added,
* so this method will remove namespace only if the counter goes down to 0.
*/
removeActiveNs: controller.removeActiveNs,
/**
* Manually load multiple records from `Backend` (or `DevBackend` when in dev mode)
*
* It loads data together and adds them to cache in one operation, to prevent partly loaded state.
*/
loadRecords: controller.loadRecords,
/**
* Manually load record from `Backend` (or `DevBackend` when in dev mode)
*/
loadRecord: controller.loadRecord,
/**
*
*/
addStaticData: controller.addStaticData,
/**
* Get record from cache.
*/
getRecord: controller.getRecord,
/**
* Get all records from cache.
*/
getAllRecords: controller.getAllRecords,
/**
* @param ns optional list of namespaces that you are interested in
* @return `true` if there are data that need to be fetched.
*/
isLoaded: controller.isLoaded,
/**
* @return `true` if tolgee is loading initial data (triggered by `run`).
*/
isInitialLoading: controller.isInitialLoading,
/**
* @param ns optional list of namespaces that you are interested in
* @return `true` if tolgee is loading some translations for the first time.
*/
isLoading: controller.isLoading,
/**
* @param ns optional list of namespaces that you are interested in
* @return `true` if tolgee is fetching some translations.
*/
isFetching: controller.isFetching,
/**
* @return `true` if tolgee is running.
*/
isRunning: controller.isRunning,
/**
* Changes internal state to running: true and loads initial files.
* Runs runnable plugins mainly Observer if present.
*/
run: controller.run,
/**
* Changes internal state to running: false and stops runnable plugins.
*/
stop: controller.stop,
/**
* Returns translated and formatted key.
* If Observer is present and tolgee is running, wraps result to be identifiable in the DOM.
*/
t: controller.t,
/**
* Highlight keys that match selection.
*/
highlight: controller.highlight,
/**
* @return current Tolgee options.
*/
getInitialOptions: controller.getInitialOptions,
/**
* Tolgee is in dev mode if `DevTools` plugin is used and `apiKey` + `apiUrl` are specified.
* @return `true` if tolgee is in dev mode.
*/
isDev: controller.isDev,
/**
* Wraps translation if there is `Observer` plugin
*/
wrap: controller.wrap,
/**
* Unwrap translation
*/
unwrap: controller.unwrap,
// plugins
use: (plugin) => {
/**
* Override creadentials passed on initialization.
*
* When called in running state, tolgee stops and runs again.
*/
overrideCredentials(credentials) {
withRestart(() => controller.overrideCredentials(credentials));
},
/**
* Add tolgee plugin after initialization.
*
* When called in running state, tolgee stops and runs again.
*/
addPlugin(plugin) {
if (plugin) {
withRestart(() => plugin(tolgee, pluginTools));
withRestart(() => controller.addPlugin(tolgee, plugin));
}
return tolgee;
},
init: (options) => {
withRestart(() => controller.init(options));
/**
* Updates options after instance creation. Extends existing options,
* so it only changes the fields, that are listed.
*
* When called in running state, tolgee stops and runs again.
*/
updateOptions(options) {
if (options) {
withRestart(() => controller.init(options));
}
},
});
return tolgee;
};
/**
* Tolgee chainable constructor.
*
* Usage:
* ```
* const tolgee = Tolgee().use(...).init(...)
* ```
*/
const TolgeeCore = () => {
const state = {
plugins: [],
options: {},
};
const tolgeeChain = Object.freeze({
use(plugin) {
state.plugins.push(plugin);
return tolgeeChain;
},
updateDefaults(options) {
state.options = combineOptions(state.options, options);
return tolgeeChain;
},
init(options) {
const tolgee = createTolgee(combineOptions(state.options, options));
state.plugins.forEach(tolgee.addPlugin);
return tolgee;
},
});
return tolgeeChain;
};
const ERROR_PARAM_EMPTY = 0, ERROR_UNEXPECTED_CHAR = 1, ERROR_UNEXPECTED_END = 2;
class FormatError extends Error {
constructor(code, index, text) {
let error;
if (code === ERROR_PARAM_EMPTY) {
error = 'Empty parameter';
}
else if (code === ERROR_UNEXPECTED_CHAR) {
error = 'Unexpected character';
}
else {
error = 'Unexpected end';
}
super(`Tolgee parser: ${error} at ${index} in "${text}"`);
this.code = code;
this.index = index;
}
}
function isWhitespace(ch) {
return /\s/.test(ch);
}
const STATE_TEXT = 0, STATE_ESCAPE_MAYBE = 1, STATE_ESCAPE = 2, STATE_PARAM = 3, STATE_PARAM_AFTER = 4;
const END_STATES = new Set([
STATE_ESCAPE,
STATE_ESCAPE_MAYBE,
STATE_TEXT,
]);
const CHAR_ESCAPE = "'";
const ESCAPABLE = new Set(['{', '}', CHAR_ESCAPE]);
const isAllowedInParam = (char) => {
return /[0-9a-zA-Z_]/.test(char);
};
function formatParser(translation) {
let state = STATE_TEXT;
let text = '';
let param = '';
let ch = '';
const texts = [];
const params = [];
let i = 0;
function parsingError(code) {
throw new FormatError(code, i, translation);
}
const addText = () => {
texts.push(text);
text = '';
};
const addParamChar = () => {
if (!isAllowedInParam(ch)) {
parsingError(ERROR_UNEXPECTED_CHAR);
}
param += ch;
};
const addParam = () => {
if (param === '') {
parsingError(ERROR_PARAM_EMPTY);
}
params.push(param);
param = '';
};
for (i = 0; i < translation.length; i++) {
ch = translation[i];
switch (state) {
case STATE_TEXT:
if (ch === CHAR_ESCAPE) {
text += ch;
state = STATE_ESCAPE_MAYBE;
}
else if (ch === '{') {
addText();
state = STATE_PARAM;
}
else {
text += ch;
state = STATE_TEXT;
}
break;
case STATE_ESCAPE_MAYBE:
if (ESCAPABLE.has(ch)) {
text = text.slice(0, -1) + ch;
state = STATE_ESCAPE;
}
else {
text += ch;
state = STATE_TEXT;
}
break;
case STATE_ESCAPE:
if (ch === CHAR_ESCAPE) {
state = STATE_TEXT;
}
else {
text += ch;
state = STATE_ESCAPE;
}
break;
case STATE_PARAM:
if (ch === '}') {
addParam();
state = STATE_TEXT;
}
else if (!isWhitespace(ch)) {
addParamChar();
state = STATE_PARAM;
}
else if (param !== '') {
addParam();
state = STATE_PARAM_AFTER;
}
break;
case STATE_PARAM_AFTER:
if (ch == '}') {
state = STATE_TEXT;
}
else if (isWhitespace(ch)) {
state = STATE_PARAM_AFTER;
}
else {
parsingError(ERROR_UNEXPECTED_CHAR);
}
}
}
if (!END_STATES.has(state)) {
parsingError(ERROR_UNEXPECTED_END);
}
addText();
return [texts, params];
}
function formatter(translation, params) {
const [texts, pars] = formatParser(translation);
const result = [texts[0]];
for (let i = 1; i < texts.length; i++) {
const parameter = params === null || params === void 0 ? void 0 : params[pars[i - 1]];
if (parameter === undefined) {
throw new Error(`Missing parameter "${pars[i - 1]}" in "${translation}"`);
}
result.push(String(parameter));
result.push(texts[i]);
}
return result.join('');
}
function createFormatSimple() {
return {
format: ({ translation, params }) => formatter(translation, params),
};
}
const FormatSimple = () => (tolgee, tools) => {
tools.setFinalFormatter(createFormatSimple());
return tolgee;
};
const RESTRICTED_ASCENDANT_ATTRIBUTE = 'data-tolgee-restricted';
const TOLGEE_ATTRIBUTE_NAME = '_tolgee';
const TOLGEE_HIGHLIGHTER_CLASS = '_tolgee-highlighter';
const TOLGEE_WRAPPED_ONLY_DATA_ATTRIBUTE = 'data-tolgee-key-only';
// needs to be same as in @tolgee/ui package
const DEVTOOLS_ID = '__tolgee_dev_tools';
exports.DEVTOOLS_ID = DEVTOOLS_ID;
exports.RESTRICTED_ASCENDANT_ATTRIBUTE = RESTRICTED_ASCENDANT_ATTRIBUTE;
exports.TOLGEE_ATTRIBUTE_NAME = TOLGEE_ATTRIBUTE_NAME;
exports.TOLGEE_HIGHLIGHTER_CLASS = TOLGEE_HIGHLIGHTER_CLASS;
exports.TOLGEE_WRAPPED_ONLY_DATA_ATTRIBUTE = TOLGEE_WRAPPED_ONLY_DATA_ATTRIBUTE;
exports.Tolgee = Tolgee;
exports.FormatSimple = FormatSimple;
exports.TolgeeCore = TolgeeCore;
exports.getFallback = getFallback;
exports.getFallbackArray = getFallbackArray;
exports.getTranslateParams = getTranslateParams;
exports.getTranslateProps = getTranslateProps;
//# sourceMappingURL=tolgee.cjs.js.map

@@ -1,2 +0,2 @@

"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const e=()=>{let e=[];return Object.freeze({listen:n=>{const t=e=>{n(e)};return e.push(t),{unsubscribe:()=>{e=e.filter((e=>t!==e))}}},emit:n=>{e.forEach((e=>e({value:n})))}})};function n(e){return"string"==typeof e?[e]:Array.isArray(e)?e:void 0}function t(e){return n(e)||[]}function a(e,n){return"object"!=typeof(a=n)||Array.isArray(a)||null===a?t(n):t(null==n?void 0:n[e]);var a}function i(e){return Array.from(new Set(e))}function o(e,n){const t=e.get(n)||0;e.set(n,t+1)}function r(e,n){let t=e.get(n)||1;t-=1,t<=0?e.delete(n):e.set(n,t)}const s=()=>{const e=new Set,n=new Set;let a=[];const i=()=>{if(0===a.length)return;e.forEach((e=>{e({value:void 0})}));let t=[],i=[];a.forEach((e=>{void 0===(null==e?void 0:e.ns)?t=void 0:void 0!==t&&(t=[...t,...e.ns]),void 0===(null==e?void 0:e.key)?i=void 0:void 0!==i&&(i=[...i,e.key])})),(i||[void 0]).forEach((e=>{((e,t)=>{n.forEach((n=>{const a=void 0!==t,i=n.namespaces.has(void 0)||-1!==(null==t?void 0:t.findIndex((e=>n.namespaces.has(e)))),o=void 0!==e,r=void 0===e||n.keys.has(e)||0===n.keys.size;a&&!i||o&&!r||n.fn({value:void 0})}))})(e,t)})),a=[]};return Object.freeze({listenSome:e=>{const a={fn:n=>{e(n)},keys:new Map,namespaces:new Map};n.add(a);const i={unsubscribe:()=>{n.delete(a)},subscribeNs:e=>(t(e).forEach((e=>o(a.namespaces,e))),i),unsubscribeNs:e=>(t(e).forEach((e=>r(a.namespaces,e))),i),subscribeKey:e=>{const{key:n,ns:r}=e;return o(a.keys,n),t(r).forEach((e=>o(a.namespaces,e))),void 0===r&&o(a.namespaces,void 0),i},unsubscribeKey:e=>{const{key:n,ns:o}=e;return r(a.keys,n),t(o).forEach((e=>r(a.namespaces,e))),void 0===o&&r(a.namespaces,void 0),i}};return i},listen:n=>{e.add(n);return{unsubscribe:()=>{e.delete(n)}}},emit:(e,n)=>{a.push(e),n?Promise.resolve().then((()=>{i()})):i()}})},g=e=>{const n=new Map;return Object.entries(e).forEach((([e,t])=>{null!=t&&("object"!=typeof t?n.set(e,t):Object.entries(g(t)).forEach((([t,a])=>{n.set(e+"."+t,a)})))})),n},c=e=>{const[n,t]=e.split(":");return{language:n,namespace:t||""}},u=({language:e,namespace:n})=>n?`${e}:${n}`:e,l=(e,n,a,i,o,r,s)=>{const l=new Map,d=new Map;let f={},v=0;function p(n,t,a){const i=u(n);d.set(i,{data:g(t),version:a}),e.emit(n)}function m(e,n){p(e,n,v)}function b(e,n=!1){const t=d.get(u(e));return t&&n?t.version===v:Boolean(t)}function h(e){var n;return null===(n=d.get(u(e)))||void 0===n?void 0:n.data}function y(e){let t;if(!t){const n=f[u(e)];"function"==typeof n?t=n():n&&(t=Promise.resolve(n))}return t||(t=n(e)),t||(t=Promise.resolve({})),t}return Object.freeze({addStaticData:function(e){e&&(f=Object.assign(Object.assign({},f),e),Object.entries(e).forEach((([e,n])=>{if("function"!=typeof n){const t=c(e),a=d.get(e);a&&0!==a.version||p(t,n,0)}})))},invalidate:function(){v+=1},addRecord:m,exists:b,getRecord:h,getTranslation:function(e,n){var t;return null===(t=d.get(u(e)))||void 0===t?void 0:t.data.get(n)},getTranslationNs:function(e,n,t){var a;for(const i of e)for(const e of n){const n=null===(a=d.get(u({language:e,namespace:i})))||void 0===a?void 0:a.data.get(t);if(null!=n)return i}return Array.from(new Set(e))},getTranslationFallback:function(e,n,t){var a;for(const i of e)for(const e of n){const n=null===(a=d.get(u({language:e,namespace:i})))||void 0===a?void 0:a.data.get(t);if(null!=n)return n}},changeTranslation:function(n,t,a){var i;const o=null===(i=d.get(u(n)))||void 0===i?void 0:i.data;null==o||o.set(t,a),e.emit(Object.assign(Object.assign({},n),{key:t}))},isFetching:function(e){if(o())return!0;if(void 0===e)return l.size>0;const n=t(e);return Boolean(Array.from(l.keys()).find((e=>n.includes(c(e).namespace))))},isLoading:function(e,n){const a=t(n);return Boolean(o()||Array.from(l.keys()).find((n=>{const t=c(n);return(!a.length||a.includes(t.namespace))&&!b({namespace:t.namespace,language:e})})))},loadRecords:async function(e,n){const t=e.map((e=>{const t=i(e),o=u(t),r=l.get(o);if(r)return{new:!1,promise:r,keyObject:t,cacheKey:o};const s=function(e,n){var t;let i;return n&&(i=null===(t=a(e))||void 0===t?void 0:t.catch((()=>(console.warn("Tolgee: Failed to fetch data from dev backend"),y(e))))),i||(i=y(e)),i}(t,n);return l.set(o,s),{new:!0,promise:s,keyObject:t,cacheKey:o}}));r.notify(),s.notify();const o=await Promise.all(t.map((e=>e.promise)));return t.forEach(((e,n)=>{if(e.new){l.delete(e.cacheKey);const t=o[n];t&&m(e.keyObject,t)}})),r.notify(),s.notify(),t.map((e=>h(e.keyObject)))},clear:function(){d.clear()},getAllRecords:function(){return Array.from(d.entries()).map((([e,n])=>Object.assign(Object.assign({},c(e)),{data:n.data})))}})};function d(e){return Boolean(e&&"function"==typeof e.then)}const f=(e,n)=>d(e)?Promise.resolve(e).then(n):n(e),v=e=>`Tolgee: You need to specify '${e}' option`,p=(e,n,a,i,o,r)=>{const s={ui:void 0},g={formatters:[],finalFormatter:void 0,observer:void 0,devBackend:void 0,backends:[],ui:void 0,languageDetector:void 0,languageStorage:void 0},c=async(e,{keysAndDefaults:n})=>{var a;const r=n.map((({key:e,ns:n,defaultValue:a})=>({key:e,defaultValue:a,ns:t(i({key:e,ns:n,defaultValue:a})),translation:o({key:e,ns:n})})));null===(a=g.ui)||void 0===a||a.handleElementClick(e,r)},u=()=>{if(g.languageDetector){if(!a())throw new Error(v("availableLanguages"))}},l=(e,n)=>{var t,a;return(null===(a=null===(t=g.observer)||void 0===t?void 0:t.highlight)||void 0===a?void 0:a.call(t,e,n))||{unhighlight(){}}},p=e=>{const n=o(e);return m(Object.assign(Object.assign({},e),{translation:n,formatEnabled:!0}))},m=({key:n,translation:t,defaultValue:a,noWrap:i,params:o,orEmpty:r,ns:s,formatEnabled:c})=>{var u;const l=t||a;let d=l||(r?"":n);g.observer&&!i&&(d=g.observer.wrap({key:n,translation:d,defaultValue:a,params:o,ns:s}));const f=e(),v=c||!(null===(u=g.observer)||void 0===u?void 0:u.outputNotFormattable);if(l&&f&&v)for(const e of g.formatters)d=e.format({translation:d,language:f,params:o});return g.finalFormatter&&l&&f&&v&&(d=g.finalFormatter.format({translation:d,language:f,params:o})),d};return Object.freeze({setFinalFormatter:e=>{g.finalFormatter=e},addFormatter:e=>{e&&g.formatters.push(e)},formatTranslation:m,setObserver:e=>{g.observer=null==e?void 0:e({translate:p,onClick:c})},getObserver:()=>g.observer,setUi:e=>{s.ui=(null==e?void 0:e.UI)||e},getUi:()=>s.ui,addBackend:e=>{e&&g.backends.push(e)},setDevBackend:e=>{g.devBackend=e},getDevBackend:()=>g.devBackend,getBackendRecord:({language:e,namespace:n})=>{for(const t of g.backends){const a=t.getRecord({language:e,namespace:n});if(d(a))return null==a?void 0:a.catch((e=>(console.error(e),{})));if(void 0!==a)return a}},getBackendDevRecord:({language:e,namespace:t})=>{var a;return null===(a=g.devBackend)||void 0===a?void 0:a.getRecord({apiKey:n().apiKey,apiUrl:n().apiUrl,language:e,namespace:t})},setLanguageDetector:e=>{g.languageDetector=e},setLanguageStorage:e=>{g.languageStorage=e},getInitialLanguage:()=>{var e;const n=a(),t=null===(e=g.languageStorage)||void 0===e?void 0:e.getLanguage();return f(t,(e=>n&&!n.includes(e)||!e?(()=>{if(!g.languageDetector)return;const e=a();return g.languageDetector.getLanguage({availableLanguages:e})})():e))},setStoredLanguage:e=>{var n;null===(n=g.languageStorage)||void 0===n||n.setLanguage(e)},run:()=>{var e;g.ui=s.ui&&new s.ui({apiKey:n().apiKey,apiUrl:n().apiUrl,highlight:l,changeTranslation:r}),null===(e=g.observer)||void 0===e||e.run({mouseHighlight:Boolean(g.ui)}),u()},stop:()=>{var e;g.ui=void 0,null===(e=g.observer)||void 0===e||e.stop()},retranslate:()=>{var e;null===(e=g.observer)||void 0===e||e.retranslate()},highlight:l,wrap:e=>{var n;return g.observer?null===(n=g.observer)||void 0===n?void 0:n.wrap(e):e.translation},unwrap:e=>{var n;return g.observer?null===(n=g.observer)||void 0===n?void 0:n.unwrap(e):{text:e,keys:[]}}})},m=(e,n,t)=>{let a=e;return Object.freeze({init:function(e){a=e},notify:function(){const e=n();a!==e&&t(e),a=e}})},b={enableLanguageStore:!0,defaultNs:"",filesUrlPrefix:"i18n/"},h=(e,n)=>{const t=Object.assign(Object.assign(Object.assign({},b),null==n?void 0:n.initialOptions),e),a=t.apiUrl;return t.apiUrl=a?a.replace(/\/+$/,""):a,{initialOptions:t,activeNamespaces:(null==n?void 0:n.activeNamespaces)||new Map,language:null==n?void 0:n.language,pendingLanguage:null==n?void 0:n.language,isInitialLoading:!1,isRunning:!1}};function y(e){var{ns:n,noWrap:t,orEmpty:a,params:i}=e,o=function(e,n){var t={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&n.indexOf(a)<0&&(t[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var i=0;for(a=Object.getOwnPropertySymbols(e);i<a.length;i++)n.indexOf(a[i])<0&&Object.prototype.propertyIsEnumerable.call(e,a[i])&&(t[a[i]]=e[a[i]])}return t}(e,["ns","noWrap","orEmpty","params"]);return{ns:n,noWrap:t,orEmpty:a,params:Object.assign(Object.assign({},o),i)}}const L=(e,...n)=>{let t,a={};return"object"==typeof e?a=e:(a.key=e,"string"==typeof n[0]?(a.defaultValue=n[0],t=n[1]):"object"==typeof n[0]&&(t=n[0])),t&&(a=Object.assign(Object.assign({},y(t)),a)),a},O=({events:e,options:n})=>{const o=m(!1,(()=>u.isFetching()),e.onFetchingChange.emit),r=m(!1,(()=>y()),e.onLoadingChange.emit),s=((e,n,o)=>{let r=h();function s(){return r.language||r.initialOptions.language}function g(){return r.initialOptions}return Object.freeze({init:function(e){r=h(e,r)},isRunning:function(){return r.isRunning},setRunning:function(e){r.isRunning!==e&&(r.isRunning=e,o.emit(e))},isInitialLoading:function(){return r.isInitialLoading},setInitialLoading:function(e){r.isInitialLoading=e},getLanguage:s,getLanguageOrFail:function(){const e=r.language||r.initialOptions.language;if(!e)throw new Error("No language set");return e},setLanguage:function(n){r.language!==n&&(r.language=n,e.emit(n))},getPendingLanguage:function(){return r.pendingLanguage||s()},setPendingLanguage:function(e){r.pendingLanguage!==e&&(r.pendingLanguage=e,n.emit(e))},getInitialOptions:g,addActiveNs:function(e){t(e).forEach((e=>{const n=r.activeNamespaces.get(e);void 0!==n?r.activeNamespaces.set(e,n+1):r.activeNamespaces.set(e,1)}))},removeActiveNs:function(e){t(e).forEach((e=>{const n=r.activeNamespaces.get(e);void 0!==n&&n>1?r.activeNamespaces.set(e,n-1):r.activeNamespaces.delete(e)}))},getRequiredNamespaces:function(){return i([...r.initialOptions.ns||[r.initialOptions.defaultNs],...r.activeNamespaces.keys()])},getFallbackLangs:function(e){const n=e||s();return n?i([n,...a(n,r.initialOptions.fallbackLanguage)]):[]},getFallbackNamespaces:function(){const e=r.initialOptions.defaultNs;return i([..."string"==typeof e?[e]:[],...t(r.initialOptions.fallbackNs)])},getAvailableLanguages:function(){if(r.initialOptions.availableLanguages)return r.initialOptions.availableLanguages;if(r.initialOptions.staticData){const e=Object.keys(r.initialOptions.staticData).map((e=>c(e).language));return Array.from(new Set(e))}},withDefaultNs:function(e){return{namespace:void 0===e.namespace?g().defaultNs:e.namespace,language:e.language}}})})(e.onLanguageChange,e.onPendingLanguageChange,e.onRunningChange),g=p(s.getLanguage,s.getInitialOptions,s.getAvailableLanguages,(function({key:e,ns:n}){const a=n?t(n):s.getFallbackNamespaces(),i=s.getFallbackLangs();return u.getTranslationNs(a,i,e)}),R,b),u=l(e.onCacheChange,g.getBackendRecord,g.getBackendDevRecord,s.withDefaultNs,s.isInitialLoading,o,r);s.init(n),u.addStaticData(s.getInitialOptions().staticData),O()&&u.invalidate(),e.onKeyUpdate.listen((()=>{s.isRunning()&&g.retranslate()}));function b(e,n,t){const a=s.withDefaultNs(e),i=u.getTranslation(a,n);return u.changeTranslation(a,n,t),{revert:()=>{u.changeTranslation(a,n,i)}}}function y(e){return u.isLoading(s.getLanguage(),e)}function O(){return Boolean(s.getInitialOptions().apiKey&&g.getDevBackend())}function k(e,n){const a=function(e,n){const a=s.getFallbackLangs(e),i=void 0!==n?t(n):s.getRequiredNamespaces(),o=[];return a.forEach((e=>{i.forEach((n=>{u.exists({language:e,namespace:n},!0)||o.push({language:e,namespace:n})}))})),o}(e,n);if(a.length)return f(E(a),(()=>{}))}function R({key:e,ns:n}){const a=n?t(n):s.getFallbackNamespaces(),i=s.getFallbackLangs();return u.getTranslationFallback(a,i,e)}function j(){const n=f(function(){if(s.getLanguage())return;if(!s.getInitialOptions().defaultLanguage)throw new Error(v("defaultLanguage"));const e=g.getInitialLanguage();return f(e,(e=>{const n=e||s.getInitialOptions().defaultLanguage;n&&s.setLanguage(n)}))}(),(()=>(s.getLanguageOrFail(),k())));if(d(n))return s.setInitialLoading(!0),o.notify(),r.notify(),Promise.resolve(n).then((()=>{s.setInitialLoading(!1),o.notify(),r.notify(),e.onInitialLoaded.emit()}));e.onInitialLoaded.emit()}function E(e){return u.loadRecords(e,O())}return Object.freeze(Object.assign(Object.assign(Object.assign(Object.assign({},s),g),u),{init:function(e){s.init(e),u.addStaticData(s.getInitialOptions().staticData),O()&&u.invalidate()},changeLanguage:async function(e){s.getPendingLanguage()===e&&s.getLanguage()===e||(s.setPendingLanguage(e),s.isRunning()&&await k(e),e===s.getPendingLanguage()&&(s.setLanguage(e),g.setStoredLanguage(e)))},getTranslation:R,changeTranslation:b,addActiveNs:async function(e,n){n||s.addActiveNs(e),s.isRunning()&&await k(void 0,e)},loadRequiredRecords:k,loadRecords:E,loadRecord:async function(e){return(await E([e]))[0]},isLoading:y,isLoaded:function(e){const n=s.getLanguage();if(!n)return!1;const a=s.getFallbackLangs(n),i=void 0!==e?t(e):s.getRequiredNamespaces(),o=[];return a.forEach((e=>{i.forEach((n=>{u.exists({language:e,namespace:n})||o.push({language:e,namespace:n})}))})),0===o.length},t:(...e)=>{const n=L(...e),t=R(n);return g.formatTranslation(Object.assign(Object.assign({},n),{translation:t}))},isDev:O,run:function(){let e;return s.isRunning()||(s.setRunning(!0),g.run(),e=j()),Promise.resolve(e)},stop:function(){s.isRunning()&&(g.stop(),s.setRunning(!1))}}))};exports.DEVTOOLS_ID="__tolgee_dev_tools",exports.RESTRICTED_ASCENDANT_ATTRIBUTE="data-tolgee-restricted",exports.TOLGEE_ATTRIBUTE_NAME="_tolgee",exports.TOLGEE_HIGHLIGHTER_CLASS="_tolgee-highlighter",exports.TOLGEE_WRAPPED_ONLY_DATA_ATTRIBUTE="data-tolgee-key-only",exports.Tolgee=n=>{const t=(()=>{const n=e(),t=e(),a=e(),i=e(),o=e(),r=e(),g=s(),c=e(),u=e();return r.listen((()=>g.emit())),t.listen((()=>g.emit())),c.listen((({value:e})=>{g.emit({ns:[e.namespace],key:e.key},!0)})),Object.freeze({onPendingLanguageChange:n,onLanguageChange:t,onKeyChange:a,onKeyUpdate:g,onLoadingChange:i,onFetchingChange:o,onInitialLoaded:r,onRunningChange:u,onCacheChange:c,on:(e,a)=>{switch(e){case"pendingLanguage":return n.listen(a);case"language":return t.listen(a);case"loading":return i.listen(a);case"fetching":return o.listen(a);case"initialLoad":return r.listen(a);case"running":return u.listen(a);case"cache":return c.listen(a);case"keyUpdate":return g.listen(a)}}})})(),a=O({events:t,options:n}),i=Object.freeze({setFinalFormatter:a.setFinalFormatter,addFormatter:a.addFormatter,setObserver:a.setObserver,getObserver:a.getObserver,setUi:a.setUi,getUi:a.getUi,setDevBackend:a.setDevBackend,addBackend:a.addBackend,setLanguageDetector:a.setLanguageDetector,setLanguageStorage:a.setLanguageStorage}),o=e=>{const n=a.isRunning();n&&a.stop(),e(),n&&a.run()},r=Object.freeze({on:t.on,onKeyUpdate:t.onKeyUpdate.listenSome,getLanguage:a.getLanguage,getPendingLanguage:a.getPendingLanguage,changeLanguage:a.changeLanguage,changeTranslation:a.changeTranslation,addActiveNs:a.addActiveNs,removeActiveNs:a.removeActiveNs,loadRecords:a.loadRecords,loadRecord:a.loadRecord,addStaticData:a.addStaticData,getRecord:a.getRecord,getAllRecords:a.getAllRecords,isLoaded:a.isLoaded,isInitialLoading:a.isInitialLoading,isLoading:a.isLoading,isFetching:a.isFetching,isRunning:a.isRunning,run:a.run,stop:a.stop,t:a.t,highlight:a.highlight,getInitialOptions:a.getInitialOptions,isDev:a.isDev,wrap:a.wrap,unwrap:a.unwrap,use:e=>(e&&o((()=>e(r,i))),r),init:e=>(o((()=>a.init(e))),r)});return r},exports.getFallback=n,exports.getFallbackArray=t,exports.getTranslateParams=L;
"use strict";function e(e){return Boolean(e&&"function"==typeof e.then)}Object.defineProperty(exports,"__esModule",{value:!0});const n=(n,t)=>e(n)?Promise.resolve(n).then(t):t(n),t=e=>`Tolgee: You need to specify '${e}' option`;function a(e){return"string"==typeof e?[e]:Array.isArray(e)?e:void 0}function i(e){return a(e)||[]}function o(e,n){return"object"!=typeof(t=n)||Array.isArray(t)||null===t?i(n):i(null==n?void 0:n[e]);var t}function r(e){return Array.from(new Set(e))}function s(e){return e?e.replace(/\/+$/,""):e}const c=e=>{let n=[];return Object.freeze({listen:e=>{const t=n=>{e(n)};return n.push(t),{unsubscribe:()=>{n=n.filter((e=>t!==e))}}},emit:t=>{e()&&n.forEach((e=>e({value:t})))}})},g=(e,n,t)=>{const a=new Set,o=new Set;let r=[];const s=()=>{if(0===r.length)return;const e=r;r=[],a.forEach((e=>{e({value:void 0})}));let t=new Set;e.forEach((e=>{void 0===e?t=void 0:void 0!==t&&e.forEach((e=>t.add(e)))}));(e=>{const t=new Set(n());o.forEach((n=>{(void 0===e||-1!==(null==e?void 0:e.findIndex((e=>t.has(e)||n.namespaces.has(e)))))&&n.fn({value:void 0})}))})(t?Array.from(t.keys()):void 0)};return Object.freeze({listenSome:e=>{const n={fn:n=>{e(n)},namespaces:new Set};o.add(n);const a={unsubscribe:()=>{o.delete(n)},subscribeNs:e=>(i(e).forEach((e=>n.namespaces.add(e))),void 0===e&&n.namespaces.add(t()),a)};return a},listen:e=>{a.add(e);return{unsubscribe:()=>{a.delete(e)}}},emit:(n,t)=>{e()&&(r.push(n),t?setTimeout(s,0):s())}})},u=e=>{const n=new Map;return Object.entries(e).forEach((([e,t])=>{null!=t&&("object"!=typeof t?n.set(e,t):u(t).forEach(((t,a)=>{n.set(e+"."+a,t)})))})),n},l=e=>{const[n,...t]=e.split(":");return{language:n,namespace:t.join(":")||""}},d=({language:e,namespace:n})=>n?`${e}:${n}`:e,f=(e,n,t,a,o,s,c)=>{const g=new Map,f=new Map;let p={},v=0;function h(n,t,a){const i=d(n);f.set(i,{data:u(t),version:a}),e.emit(n)}function b(e,n){h(e,n,v)}function m(e,n=!1){const t=f.get(d(e));return t&&n?t.version===v:Boolean(t)}function y(e){var n;return null===(n=f.get(d(a(e))))||void 0===n?void 0:n.data}function O(e){let t;if(!t){const n=p[d(e)];"function"==typeof n&&(t=n())}return t||(t=n(e)),t}return Object.freeze({addStaticData:function(e){e&&(p=Object.assign(Object.assign({},p),e),Object.entries(e).forEach((([e,n])=>{if("function"!=typeof n){const t=l(e),a=f.get(e);a&&0!==a.version||h(t,n,0)}})))},invalidate:function(){g.clear(),v+=1},addRecord:b,exists:m,getRecord:y,getTranslation:function(e,n){var t;return null===(t=f.get(d(e)))||void 0===t?void 0:t.data.get(n)},getTranslationNs:function(e,n,t){var a;for(const i of e)for(const e of n){const n=null===(a=f.get(d({language:e,namespace:i})))||void 0===a?void 0:a.data.get(t);if(null!=n)return[i]}return r(e)},getTranslationFallback:function(e,n,t){var a;for(const i of e)for(const e of n){const n=null===(a=f.get(d({language:e,namespace:i})))||void 0===a?void 0:a.data.get(t);if(null!=n)return n}},changeTranslation:function(n,t,a){var i;const o=null===(i=f.get(d(n)))||void 0===i?void 0:i.data;null==o||o.set(t,a),e.emit(Object.assign(Object.assign({},n),{key:t}))},isFetching:function(e){if(o())return!0;if(void 0===e)return g.size>0;const n=i(e);return Boolean(Array.from(g.keys()).find((e=>n.includes(l(e).namespace))))},isLoading:function(e,n){const t=i(n);return Boolean(o()||Array.from(g.keys()).find((n=>{const a=l(n);return(!t.length||t.includes(a.namespace))&&!m({namespace:a.namespace,language:e})})))},loadRecords:async function(e,n){const i=e.map((e=>{const i=a(e),o=d(i),r=g.get(o);if(r)return{new:!1,promise:r,keyObject:i,cacheKey:o};const s=function(e,n){var a;let i;return n&&(i=null===(a=t(e))||void 0===a?void 0:a.catch((()=>(console.warn("Tolgee: Failed to fetch data from dev backend"),O(e))))),i||(i=O(e)),i}(i,n)||Promise.resolve(void 0);return g.set(o,s),{new:!0,promise:s,keyObject:i,cacheKey:o}}));s.notify(),c.notify();const o=await Promise.all(i.map((e=>e.promise)));return i.forEach(((e,n)=>{const t=g.get(e.cacheKey)!==e.promise;if(e.new&&!t){g.delete(e.cacheKey);const t=o[n];t?b(e.keyObject,t):y(e.keyObject)||b(e.keyObject,{})}})),s.notify(),c.notify(),i.map((e=>y(e.keyObject)))},getAllRecords:function(){return Array.from(f.entries()).map((([e,n])=>Object.assign(Object.assign({},l(e)),{data:n.data})))}})};function p(e,n){var t={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&n.indexOf(a)<0&&(t[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var i=0;for(a=Object.getOwnPropertySymbols(e);i<a.length;i++)n.indexOf(a[i])<0&&Object.prototype.propertyIsEnumerable.call(e,a[i])&&(t[a[i]]=e[a[i]])}return t}const v={defaultNs:"",observerOptions:{tagAttributes:{textarea:["placeholder"],input:["value","placeholder"],img:["alt"],"*":["aria-label","title"]},restrictedElements:["script","style"],highlightKeys:["Alt"],highlightColor:"rgb(255, 0, 0)",highlightWidth:5,inputPrefix:"%-%tolgee:",inputSuffix:"%-%",passToParent:["option","optgroup"]},observerType:"invisible",onFormatError:"invalid"},h=(...e)=>{let n={};return e.forEach((e=>{n=Object.assign(Object.assign(Object.assign({},n),e),{observerOptions:Object.assign(Object.assign({},n.observerOptions),null==e?void 0:e.observerOptions)})})),n},b=(e,n)=>{const t=h(v,null==n?void 0:n.initialOptions,e);return t.apiUrl=s(t.apiUrl),{initialOptions:t,activeNamespaces:(null==n?void 0:n.activeNamespaces)||new Map,language:null==n?void 0:n.language,pendingLanguage:null==n?void 0:n.language,isInitialLoading:!1,isRunning:!1}},m=(t,a,i,o,r,s)=>{const c={ui:void 0,observer:void 0},g={formatters:[],finalFormatter:void 0,observer:void 0,devBackend:void 0,backends:[],ui:void 0,languageDetector:void 0,languageStorage:void 0},u=async({keysAndDefaults:e,event:n})=>{var t;const a=e.map((({key:e,ns:n,defaultValue:t})=>({key:e,defaultValue:t,ns:o({key:e,ns:n}),translation:r({key:e,ns:n})})));null===(t=g.ui)||void 0===t||t.handleElementClick(a,n)},l=(e,n)=>{var t,a;return(null===(a=null===(t=g.observer)||void 0===t?void 0:t.highlight)||void 0===a?void 0:a.call(t,e,n))||{unhighlight(){}}},d=e=>{const n=r({key:e.key,ns:e.ns});return R(Object.assign(Object.assign({},e),{translation:n,formatEnabled:!0}))},f=e=>{c.observer=e},v=()=>Boolean(c.observer),h=e=>{e&&g.formatters.push(e)},b=e=>{g.finalFormatter=e},m=e=>{c.ui=e},y=()=>Boolean(c.ui),O=e=>{g.languageStorage=e},L=e=>{g.languageDetector=e},j=e=>{e&&g.backends.push(e)},k=e=>{g.devBackend=e},w=()=>g.devBackend;function R(e){var n,{formatEnabled:i}=e,o=p(e,["formatEnabled"]);const{key:r,translation:s,defaultValue:c,noWrap:u,params:l,orEmpty:d,ns:f}=o,v=s||c;let h=v||(d?"":r);const b=t(),m=i||!(null===(n=g.observer)||void 0===n?void 0:n.outputNotFormattable),y=e=>g.observer&&!u?g.observer.wrap({key:r,translation:e,defaultValue:c,params:l,ns:f}):e;h=y(h);try{if(v&&b&&m)for(const e of g.formatters)h=e.format({translation:h,language:b,params:l});g.finalFormatter&&v&&b&&m&&(h=g.finalFormatter.format({translation:h,language:b,params:l}))}catch(e){console.error(e);const n=("string"==typeof(O=e)?O:"string"==typeof(null==O?void 0:O.message)?O.message:void 0)||"invalid",t=a().onFormatError,i=typeof t;h="string"===i?t:"function"===i?t(n,o):"invalid",h=y(h)}var O;return h}return Object.freeze({addPlugin:function(e,n){n(e,Object.freeze({setFinalFormatter:b,addFormatter:h,setObserver:f,hasObserver:v,setUi:m,hasUi:y,setDevBackend:k,addBackend:j,setLanguageDetector:L,setLanguageStorage:O}))},formatTranslation:R,getDevBackend:w,getBackendRecord:({language:n,namespace:t})=>{for(const a of g.backends){const i=a.getRecord({language:n,namespace:t});if(e(i))return null==i?void 0:i.catch((e=>(console.error(e),{})));if(void 0!==i)return i}},getBackendDevRecord:({language:e,namespace:n})=>{var t;const{apiKey:i,apiUrl:o,projectId:r}=a();return null===(t=g.devBackend)||void 0===t?void 0:t.getRecord({apiKey:i,apiUrl:o,projectId:r,language:e,namespace:n})},getLanguageDetector:()=>g.languageDetector,getLanguageStorage:()=>g.languageStorage,getInitialLanguage:()=>{var e;const t=i(),a=null===(e=g.languageStorage)||void 0===e?void 0:e.getLanguage();return n(a,(e=>t&&!t.includes(e)||!e?(()=>{if(!g.languageDetector)return;const e=i();return g.languageDetector.getLanguage({availableLanguages:e})})():e))},setStoredLanguage:e=>{var n;null===(n=g.languageStorage)||void 0===n||n.setLanguage(e)},run:()=>{var e,n,t;if(!g.ui){const{apiKey:n,apiUrl:t,projectId:i}=a();g.ui=null===(e=c.ui)||void 0===e?void 0:e.call(c,{apiKey:n,apiUrl:t,projectId:i,highlight:l,changeTranslation:s})}g.observer||(g.observer=null===(n=c.observer)||void 0===n?void 0:n.call(c,{translate:d,onClick:u,options:a().observerOptions})),null===(t=g.observer)||void 0===t||t.run({mouseHighlight:!0})},stop:()=>{var e;g.ui=void 0,null===(e=g.observer)||void 0===e||e.stop()},retranslate:()=>{var e;null===(e=g.observer)||void 0===e||e.retranslate()},highlight:l,unwrap:e=>{var n;return g.observer?null===(n=g.observer)||void 0===n?void 0:n.unwrap(e):{text:e,keys:[]}},wrap:e=>{var n;return g.observer?null===(n=g.observer)||void 0===n?void 0:n.wrap(e):e.translation},hasDevBackend:function(){return Boolean(w())}})},y=(e,n,t)=>{let a=e;return Object.freeze({init:function(e){a=e},notify:function(){const e=n();a!==e&&t(e),a=e}})};const O=(e,...n)=>{let t,a={};return"object"==typeof e?a=e:(a.key=e,"string"==typeof n[0]?(a.defaultValue=n[0],t=n[1]):"object"==typeof n[0]&&(t=n[0])),t&&(a=Object.assign(Object.assign({},function(e){var{ns:n,noWrap:t,orEmpty:a,params:i}=e,o=p(e,["ns","noWrap","orEmpty","params"]);const r={ns:n,noWrap:t,orEmpty:a};return Object.assign(Object.assign({},r),{params:Object.assign({},o)})}(t)),a)),a},L=({options:a})=>{const u=((e,n)=>{let t=!0;function a(){return t}const i=c(a),o=c(a),r=c(a),s=c(a),u=c(a),l=c(a),d=c(a),f=g(a,e,n);return u.listen((()=>f.emit())),o.listen((()=>f.emit())),d.listen((({value:e})=>{f.emit([e.namespace],!0)})),Object.freeze({onPendingLanguageChange:i,onLanguageChange:o,onLoadingChange:r,onFetchingChange:s,onInitialLoaded:u,onRunningChange:l,onCacheChange:d,onUpdate:f,setEmmiterActive:function(e){t=e},on:(e,n)=>{switch(e){case"pendingLanguage":return i.listen(n);case"language":return o.listen(n);case"loading":return r.listen(n);case"fetching":return s.listen(n);case"initialLoad":return u.listen(n);case"running":return l.listen(n);case"cache":return d.listen(n);case"update":return f.listen(n)}}})})(j,k),d=y(!1,(()=>L.isFetching()),u.onFetchingChange.emit),p=y(!1,(()=>A()),u.onLoadingChange.emit),v=((e,n,t)=>{let a,c=b();function g(){return c.language||c.initialOptions.language}function u(){return Object.assign(Object.assign({},c.initialOptions),a)}return Object.freeze({init:function(e){c=b(e,c)},isRunning:function(){return c.isRunning},setRunning:function(e){c.isRunning!==e&&(c.isRunning=e,t.emit(e))},isInitialLoading:function(){return c.isInitialLoading},setInitialLoading:function(e){c.isInitialLoading=e},getLanguage:g,setLanguage:function(n){c.language!==n&&(c.language=n,e.emit(n))},getPendingLanguage:function(){return c.pendingLanguage||g()},setPendingLanguage:function(e){c.pendingLanguage!==e&&(c.pendingLanguage=e,n.emit(e))},getInitialOptions:u,addActiveNs:function(e){i(e).forEach((e=>{const n=c.activeNamespaces.get(e);void 0!==n?c.activeNamespaces.set(e,n+1):c.activeNamespaces.set(e,1)}))},removeActiveNs:function(e){i(e).forEach((e=>{const n=c.activeNamespaces.get(e);void 0!==n&&n>1?c.activeNamespaces.set(e,n-1):c.activeNamespaces.delete(e)}))},getRequiredNamespaces:function(){return r([...c.initialOptions.ns||[c.initialOptions.defaultNs],...i(c.initialOptions.fallbackNs),...c.activeNamespaces.keys()])},getFallbackLangs:function(e){const n=e||g();return n?r([n,...o(n,c.initialOptions.fallbackLanguage)]):[]},getFallbackNs:function(){return i(c.initialOptions.fallbackNs)},getDefaultNs:function(e){return void 0===e?c.initialOptions.defaultNs:e},getAvailableLanguages:function(){if(c.initialOptions.availableLanguages)return c.initialOptions.availableLanguages;if(c.initialOptions.staticData){const e=Object.keys(c.initialOptions.staticData).map((e=>l(e).language));return Array.from(new Set(e))}},withDefaultNs:function(e){return{namespace:void 0===e.namespace?u().defaultNs:e.namespace,language:e.language}},overrideCredentials:function(e){a=e?Object.assign(Object.assign({},e),{apiUrl:s(e.apiUrl)}):void 0}})})(u.onLanguageChange,u.onPendingLanguageChange,u.onRunningChange),h=m(v.getLanguage,v.getInitialOptions,v.getAvailableLanguages,(function({key:e,ns:n}){const t=v.getFallbackLangs(),a=w(n);return L.getTranslationNs(a,t,e)}),D,E),L=f(u.onCacheChange,h.getBackendRecord,h.getBackendDevRecord,v.withDefaultNs,v.isInitialLoading,d,p);function j(){return v.getFallbackNs()}function k(e){return v.getDefaultNs(e)}function w(e){return[...i(k(e)),...j()]}function R(e){return[...i(e||k()),...v.getRequiredNamespaces()]}function E(e,n,t){const a=v.withDefaultNs(e),i=L.getTranslation(a,n);return L.changeTranslation(a,n,t),{revert:()=>{L.changeTranslation(a,n,i)}}}function N(e){v.init(e),L.addStaticData(v.getInitialOptions().staticData)}function A(e){return L.isLoading(v.getLanguage(),e)}function F(){return Boolean(v.getInitialOptions().apiKey&&v.getInitialOptions().apiUrl)}function I(e,t){const a=function(e,n){const t=v.getFallbackLangs(e),a=R(n),i=[];return t.forEach((e=>{a.forEach((n=>{L.exists({language:e,namespace:n},!0)||i.push({language:e,namespace:n})}))})),i}(e,t);if(a.length)return n(P(a),(()=>{}))}function D({key:e,ns:n}){const t=w(n),a=v.getFallbackLangs();return L.getTranslationFallback(t,a,e)}function S(){const a=n(function(){if(v.getLanguage())return;if(!v.getInitialOptions().defaultLanguage)throw new Error(t("defaultLanguage"));const e=h.getInitialLanguage();return n(e,(e=>{const n=e||v.getInitialOptions().defaultLanguage;n&&v.setLanguage(n)}))}(),(()=>I()));if(e(a))return v.setInitialLoading(!0),d.notify(),p.notify(),Promise.resolve(a).then((()=>{v.setInitialLoading(!1),d.notify(),p.notify(),u.onInitialLoaded.emit()}));u.onInitialLoaded.emit()}function P(e){return L.loadRecords(e,F())}a&&N(a),u.onUpdate.listen((()=>{v.isRunning()&&h.retranslate()}));return Object.freeze(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},u),v),h),L),{init:N,changeLanguage:async function(e){v.getPendingLanguage()===e&&v.getLanguage()===e||(v.setPendingLanguage(e),v.isRunning()&&await I(e),e===v.getPendingLanguage()&&(v.setLanguage(e),h.setStoredLanguage(e)))},getTranslation:D,changeTranslation:E,addActiveNs:async function(e,n){n||v.addActiveNs(e),v.isRunning()&&await I(void 0,e)},loadRecords:P,loadRecord:async function(e){return(await P([e]))[0]},isLoading:A,isLoaded:function(e){const n=v.getLanguage();if(!n)return!1;const t=v.getFallbackLangs(n),a=R(e),i=[];return t.forEach((e=>{a.forEach((n=>{L.exists({language:e,namespace:n})||i.push({language:e,namespace:n})}))})),0===i.length},t:(...e)=>{const n=O(...e),t=D(n);return h.formatTranslation(Object.assign(Object.assign({},n),{translation:t}))},isDev:F,run:function(){let e;return(()=>{const e=h.getLanguageDetector()||h.getLanguageStorage();if(e&&!v.getAvailableLanguages())throw new Error(t("availableLanguages"));if(!v.getLanguage()&&!v.getInitialOptions().defaultLanguage)throw e?new Error(t("defaultLanguage")):new Error(t("language"))})(),v.isRunning()||(F()&&L.invalidate(),v.setRunning(!0),h.run(),e=S()),Promise.resolve(e)},stop:function(){v.isRunning()&&(h.stop(),v.setRunning(!1))}}))};class j extends Error{constructor(e,n,t){let a;a=0===e?"Empty parameter":1===e?"Unexpected character":"Unexpected end",super(`Tolgee parser: ${a} at ${n} in "${t}"`),this.code=e,this.index=n}}function k(e){return/\s/.test(e)}const w=new Set([2,1,0]),R=new Set(["{","}","'"]);function E(e,n){const[t,a]=function(e){let n=0,t="",a="",i="";const o=[],r=[];let s=0;function c(n){throw new j(n,s,e)}const g=()=>{o.push(t),t=""},u=()=>{""===a&&c(0),r.push(a),a=""};for(s=0;s<e.length;s++)switch(i=e[s],n){case 0:"'"===i?(t+=i,n=1):"{"===i?(g(),n=3):(t+=i,n=0);break;case 1:R.has(i)?(t=t.slice(0,-1)+i,n=2):(t+=i,n=0);break;case 2:"'"===i?n=0:(t+=i,n=2);break;case 3:"}"===i?(u(),n=0):k(i)?""!==a&&(u(),n=4):(/[0-9a-zA-Z_]/.test(i)||c(1),a+=i,n=3);break;case 4:"}"==i?n=0:k(i)?n=4:c(1)}return w.has(n)||c(2),g(),[o,r]}(e),i=[t[0]];for(let o=1;o<t.length;o++){const r=null==n?void 0:n[a[o-1]];if(void 0===r)throw new Error(`Missing parameter "${a[o-1]}" in "${e}"`);i.push(String(r)),i.push(t[o])}return i.join("")}exports.FormatSimple=()=>(e,n)=>(n.setFinalFormatter({format:({translation:e,params:n})=>E(e,n)}),e),exports.TolgeeCore=()=>{const e={plugins:[],options:{}},n=Object.freeze({use:t=>(e.plugins.push(t),n),updateDefaults:t=>(e.options=h(e.options,t),n),init(n){const t=(e=>{const n=L({options:e}),t=e=>{const t=n.isRunning();t&&n.stop(),e(),t&&n.run()},a=Object.freeze({on:n.on,onNsUpdate:n.onUpdate.listenSome,setEmmiterActive:n.setEmmiterActive,getLanguage:n.getLanguage,getPendingLanguage:n.getPendingLanguage,changeLanguage:n.changeLanguage,changeTranslation:n.changeTranslation,addActiveNs:n.addActiveNs,removeActiveNs:n.removeActiveNs,loadRecords:n.loadRecords,loadRecord:n.loadRecord,addStaticData:n.addStaticData,getRecord:n.getRecord,getAllRecords:n.getAllRecords,isLoaded:n.isLoaded,isInitialLoading:n.isInitialLoading,isLoading:n.isLoading,isFetching:n.isFetching,isRunning:n.isRunning,run:n.run,stop:n.stop,t:n.t,highlight:n.highlight,getInitialOptions:n.getInitialOptions,isDev:n.isDev,wrap:n.wrap,unwrap:n.unwrap,overrideCredentials(e){t((()=>n.overrideCredentials(e)))},addPlugin(e){e&&t((()=>n.addPlugin(a,e)))},updateOptions(e){e&&t((()=>n.init(e)))}});return a})(h(e.options,n));return e.plugins.forEach(t.addPlugin),t}});return n},exports.getFallback=a,exports.getFallbackArray=i,exports.getTranslateProps=O;
//# sourceMappingURL=tolgee.cjs.min.js.map

@@ -7,21 +7,14 @@ (function (global, factory) {

const EventEmitter = () => {
let handlers = [];
const listen = (handler) => {
const handlerWrapper = (e) => {
handler(e);
};
handlers.push(handlerWrapper);
return {
unsubscribe: () => {
handlers = handlers.filter((i) => handlerWrapper !== i);
},
};
};
const emit = (data) => {
handlers.forEach((handler) => handler({ value: data }));
};
return Object.freeze({ listen, emit });
function isPromise(value) {
return Boolean(value && typeof value.then === 'function');
}
const valueOrPromise = (value, callback) => {
if (isPromise(value)) {
return Promise.resolve(value).then(callback);
}
else {
return callback(value);
}
};
const missingOptionError = (option) => `Tolgee: You need to specify '${option}' option`;
function isObject(item) {

@@ -53,18 +46,36 @@ return typeof item === 'object' && !Array.isArray(item) && item !== null;

}
function incrementInMap(map, value) {
const currNum = map.get(value) || 0;
map.set(value, currNum + 1);
function sanitizeUrl(url) {
return url ? url.replace(/\/+$/, '') : url;
}
function decrementInMap(map, value) {
let currNum = map.get(value) || 1;
currNum -= 1;
if (currNum <= 0) {
map.delete(value);
function getErrorMessage(error) {
if (typeof error === 'string') {
return error;
}
else {
map.set(value, currNum);
else if (typeof (error === null || error === void 0 ? void 0 : error.message) === 'string') {
return error.message;
}
}
const EventEmitterSelective = () => {
const EventEmitter = (isActive) => {
let handlers = [];
const listen = (handler) => {
const handlerWrapper = (e) => {
handler(e);
};
handlers.push(handlerWrapper);
return {
unsubscribe: () => {
handlers = handlers.filter((i) => handlerWrapper !== i);
},
};
};
const emit = (data) => {
if (isActive()) {
handlers.forEach((handler) => handler({ value: data }));
}
};
return Object.freeze({ listen, emit });
};
const EventEmitterSelective = (isActive, getFallbackNs, getDefaultNs) => {
const listeners = new Set();

@@ -86,4 +97,3 @@ const partialListeners = new Set();

},
keys: new Map(),
namespaces: new Map(),
namespaces: new Set(),
};

@@ -96,40 +106,20 @@ partialListeners.add(handlerWrapper);

subscribeNs: (ns) => {
getFallbackArray(ns).forEach((val) => incrementInMap(handlerWrapper.namespaces, val));
return result;
},
unsubscribeNs: (ns) => {
getFallbackArray(ns).forEach((val) => decrementInMap(handlerWrapper.namespaces, val));
return result;
},
subscribeKey: (descriptor) => {
const { key, ns } = descriptor;
incrementInMap(handlerWrapper.keys, key);
getFallbackArray(ns).forEach((val) => incrementInMap(handlerWrapper.namespaces, val));
getFallbackArray(ns).forEach((val) => handlerWrapper.namespaces.add(val));
if (ns === undefined) {
// subscribing to all namespaces
incrementInMap(handlerWrapper.namespaces, undefined);
// subscribing to default ns
handlerWrapper.namespaces.add(getDefaultNs());
}
return result;
},
unsubscribeKey: (descriptor) => {
const { key, ns } = descriptor;
decrementInMap(handlerWrapper.keys, key);
getFallbackArray(ns).forEach((val) => decrementInMap(handlerWrapper.namespaces, val));
if (ns === undefined) {
// subscribing to all namespaces
decrementInMap(handlerWrapper.namespaces, undefined);
}
return result;
},
};
return result;
};
const callHandlers = (key, ns) => {
const callHandlers = (ns) => {
// everything is implicitly subscribed to fallbacks
// as it can always fall through to it
const fallbackNamespaces = new Set(getFallbackNs());
partialListeners.forEach((handler) => {
const nsMentioned = ns !== undefined;
const nsMatches = handler.namespaces.has(undefined) ||
(ns === null || ns === void 0 ? void 0 : ns.findIndex((ns) => handler.namespaces.has(ns))) !== -1;
const keyMentioned = key !== undefined;
const keyMatches = key === undefined || handler.keys.has(key) || handler.keys.size === 0;
if ((!nsMentioned || nsMatches) && (!keyMentioned || keyMatches)) {
const nsMatches = ns === undefined ||
(ns === null || ns === void 0 ? void 0 : ns.findIndex((ns) => fallbackNamespaces.has(ns) || handler.namespaces.has(ns))) !== -1;
if (nsMatches) {
handler.fn({ value: undefined });

@@ -140,2 +130,3 @@ }

let queue = [];
// merge events in queue into one event
const solveQueue = () => {

@@ -145,35 +136,31 @@ if (queue.length === 0) {

}
const queueCopy = queue;
queue = [];
listeners.forEach((handler) => {
handler({ value: undefined });
});
let namespaces = [];
let keys = [];
queue.forEach((descriptor) => {
if ((descriptor === null || descriptor === void 0 ? void 0 : descriptor.ns) === undefined) {
let namespaces = new Set();
queueCopy.forEach((ns) => {
if (ns === undefined) {
// when no ns specified, it affects all namespaces
namespaces = undefined;
}
else if (namespaces !== undefined) {
namespaces = [...namespaces, ...descriptor.ns];
ns.forEach((ns) => namespaces.add(ns));
}
if ((descriptor === null || descriptor === void 0 ? void 0 : descriptor.key) === undefined) {
keys = undefined;
}
else if (keys !== undefined) {
keys = [...keys, descriptor.key];
}
});
(keys || [undefined]).forEach((key) => {
callHandlers(key, namespaces);
});
queue = [];
const namespacesArray = namespaces
? Array.from(namespaces.keys())
: undefined;
callHandlers(namespacesArray);
};
const emit = (descriptor, delayed) => {
queue.push(descriptor);
if (!delayed) {
solveQueue();
}
else {
Promise.resolve().then(() => {
const emit = (ns, delayed) => {
if (isActive()) {
queue.push(ns);
if (!delayed) {
solveQueue();
});
}
else {
setTimeout(solveQueue, 0);
}
}

@@ -184,16 +171,19 @@ };

const Events = () => {
const onPendingLanguageChange = EventEmitter();
const onLanguageChange = EventEmitter();
const onKeyChange = EventEmitter();
const onLoadingChange = EventEmitter();
const onFetchingChange = EventEmitter();
const onInitialLoaded = EventEmitter();
const onKeyUpdate = EventEmitterSelective();
const onCacheChange = EventEmitter();
const onRunningChange = EventEmitter();
onInitialLoaded.listen(() => onKeyUpdate.emit());
onLanguageChange.listen(() => onKeyUpdate.emit());
const Events = (getFallbackNs, getDefaultNs) => {
let emitterActive = true;
function isActive() {
return emitterActive;
}
const onPendingLanguageChange = EventEmitter(isActive);
const onLanguageChange = EventEmitter(isActive);
const onLoadingChange = EventEmitter(isActive);
const onFetchingChange = EventEmitter(isActive);
const onInitialLoaded = EventEmitter(isActive);
const onRunningChange = EventEmitter(isActive);
const onCacheChange = EventEmitter(isActive);
const onUpdate = EventEmitterSelective(isActive, getFallbackNs, getDefaultNs);
onInitialLoaded.listen(() => onUpdate.emit());
onLanguageChange.listen(() => onUpdate.emit());
onCacheChange.listen(({ value }) => {
onKeyUpdate.emit({ ns: [value.namespace], key: value.key }, true);
onUpdate.emit([value.namespace], true);
});

@@ -216,11 +206,12 @@ const on = (event, handler) => {

return onCacheChange.listen(handler);
case 'keyUpdate':
return onKeyUpdate.listen(handler);
case 'update':
return onUpdate.listen(handler);
}
};
function setEmmiterActive(active) {
emitterActive = active;
}
return Object.freeze({
onPendingLanguageChange,
onLanguageChange,
onKeyChange,
onKeyUpdate,
onLoadingChange,

@@ -231,2 +222,4 @@ onFetchingChange,

onCacheChange,
onUpdate,
setEmmiterActive,
on,

@@ -244,3 +237,3 @@ });

if (typeof value === 'object') {
Object.entries(flattenTranslations(value)).forEach(([flatKey, flatValue]) => {
flattenTranslations(value).forEach((flatValue, flatKey) => {
result.set(key + '.' + flatKey, flatValue);

@@ -255,3 +248,5 @@ });

const decodeCacheKey = (key) => {
const [firstPart, secondPart] = key.split(':');
const [firstPart, ...rest] = key.split(':');
// if namespaces contains ":" it won't get lost
const secondPart = rest.join(':');
return { language: firstPart, namespace: secondPart || '' };

@@ -288,9 +283,10 @@ };

function invalidate() {
asyncRequests.clear();
version += 1;
}
function addRecordInternal(descriptor, data, version) {
function addRecordInternal(descriptor, data, recordVersion) {
const cacheKey = encodeCacheKey(descriptor);
cache.set(cacheKey, {
data: flattenTranslations(data),
version: version,
version: recordVersion,
});

@@ -311,3 +307,3 @@ onCacheChange.emit(descriptor);

var _a;
return (_a = cache.get(encodeCacheKey(descriptor))) === null || _a === void 0 ? void 0 : _a.data;
return (_a = cache.get(encodeCacheKey(withDefaultNs(descriptor)))) === null || _a === void 0 ? void 0 : _a.data;
}

@@ -325,7 +321,7 @@ function getTranslation(descriptor, key) {

if (value !== undefined && value !== null) {
return namespace;
return [namespace];
}
}
}
return Array.from(new Set(namespaces));
return unique(namespaces);
}

@@ -351,5 +347,2 @@ function getTranslationFallback(namespaces, languages, key) {

}
function clear() {
cache.clear();
}
function isFetching(ns) {

@@ -377,3 +370,6 @@ if (isInitialLoading()) {

}
function fetchNormal(keyObject) {
/**
* Fetches production data
*/
function fetchProd(keyObject) {
let dataPromise = undefined;

@@ -385,5 +381,2 @@ if (!dataPromise) {

}
else if (staticDataValue) {
dataPromise = Promise.resolve(staticDataValue);
}
}

@@ -393,6 +386,2 @@ if (!dataPromise) {

}
if (!dataPromise) {
// return empty data, so we know it has already been attempted to fetch
dataPromise = Promise.resolve({});
}
return dataPromise;

@@ -407,8 +396,8 @@ }

console.warn(`Tolgee: Failed to fetch data from dev backend`);
// fallback to normal fetch if dev fails
return fetchNormal(keyObject);
// fallback to prod fetch if dev fails
return fetchProd(keyObject);
});
}
if (!dataPromise) {
dataPromise = fetchNormal(keyObject);
dataPromise = fetchProd(keyObject);
}

@@ -430,3 +419,3 @@ return dataPromise;

}
const dataPromise = fetchData(keyObject, isDev);
const dataPromise = fetchData(keyObject, isDev) || Promise.resolve(undefined);
asyncRequests.set(cacheKey, dataPromise);

@@ -444,3 +433,6 @@ return {

withPromises.forEach((value, i) => {
if (value.new) {
const promiseChanged = asyncRequests.get(value.cacheKey) !== value.promise;
// if promise has changed in between, it means cache been invalidated or
// new data are being fetched
if (value.new && !promiseChanged) {
asyncRequests.delete(value.cacheKey);

@@ -451,2 +443,6 @@ const data = results[i];

}
else if (!getRecord(value.keyObject)) {
// if no data exist, put empty object
addRecord(value.keyObject, {});
}
}

@@ -477,3 +473,2 @@ });

loadRecords,
clear,
getAllRecords,

@@ -483,18 +478,77 @@ });

function isPromise(value) {
return Boolean(value && typeof value.then === 'function');
/******************************************************************************
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.
***************************************************************************** */
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;
}
const valueOrPromise = (value, callback) => {
if (isPromise(value)) {
return Promise.resolve(value).then(callback);
}
else {
return callback(value);
}
const defaultObserverOptions = {
tagAttributes: {
textarea: ['placeholder'],
input: ['value', 'placeholder'],
img: ['alt'],
'*': ['aria-label', 'title'],
},
restrictedElements: ['script', 'style'],
highlightKeys: ['Alt'],
highlightColor: 'rgb(255, 0, 0)',
highlightWidth: 5,
inputPrefix: '%-%tolgee:',
inputSuffix: '%-%',
passToParent: ['option', 'optgroup'],
};
const missingOptionError = (option) => `Tolgee: You need to specify '${option}' option`;
const PluginService = (getLanguage, getInitialOptions, getAvailableLanguages, getTranslationNs, getTranslation, changeTranslation) => {
const DEFAULT_FORMAT_ERROR = 'invalid';
const defaultValues = {
defaultNs: '',
observerOptions: defaultObserverOptions,
observerType: 'invisible',
onFormatError: DEFAULT_FORMAT_ERROR,
};
const combineOptions = (...states) => {
let result = {};
states.forEach((state) => {
result = Object.assign(Object.assign(Object.assign({}, result), state), { observerOptions: Object.assign(Object.assign({}, result.observerOptions), state === null || state === void 0 ? void 0 : state.observerOptions) });
});
return result;
};
const initState = (options, previousState) => {
const initialOptions = combineOptions(defaultValues, previousState === null || previousState === void 0 ? void 0 : previousState.initialOptions, options);
// remove extra '/' from url end
initialOptions.apiUrl = sanitizeUrl(initialOptions.apiUrl);
return {
initialOptions,
activeNamespaces: (previousState === null || previousState === void 0 ? void 0 : previousState.activeNamespaces) || new Map(),
language: previousState === null || previousState === void 0 ? void 0 : previousState.language,
pendingLanguage: previousState === null || previousState === void 0 ? void 0 : previousState.language,
isInitialLoading: false,
isRunning: false,
};
};
const Plugins = (getLanguage, getInitialOptions, getAvailableLanguages, getTranslationNs, getTranslation, changeTranslation) => {
const plugins = {
ui: undefined,
observer: undefined,
};

@@ -511,36 +565,17 @@ const instances = {

};
const onClick = async (event, { keysAndDefaults }) => {
const onClick = async ({ keysAndDefaults, event }) => {
var _a;
const withNs = keysAndDefaults.map(({ key, ns, defaultValue }) => ({
key,
defaultValue,
ns: getFallbackArray(getTranslationNs({ key, ns, defaultValue })),
translation: getTranslation({
const withNs = keysAndDefaults.map(({ key, ns, defaultValue }) => {
return {
key,
ns,
}),
}));
(_a = instances.ui) === null || _a === void 0 ? void 0 : _a.handleElementClick(event, withNs);
defaultValue,
ns: getTranslationNs({ key, ns }),
translation: getTranslation({
key,
ns,
}),
};
});
(_a = instances.ui) === null || _a === void 0 ? void 0 : _a.handleElementClick(withNs, event);
};
const run = () => {
var _a;
instances.ui =
plugins.ui &&
new plugins.ui({
apiKey: getInitialOptions().apiKey,
apiUrl: getInitialOptions().apiUrl,
highlight,
changeTranslation,
});
(_a = instances.observer) === null || _a === void 0 ? void 0 : _a.run({ mouseHighlight: Boolean(instances.ui) });
checkCorrectConfiguration();
};
const checkCorrectConfiguration = () => {
if (instances.languageDetector) {
const availableLanguages = getAvailableLanguages();
if (!availableLanguages) {
throw new Error(missingOptionError('availableLanguages'));
}
}
};
const stop = () => {

@@ -556,10 +591,13 @@ var _a;

const translate = (props) => {
const translation = getTranslation(props);
const translation = getTranslation({
key: props.key,
ns: props.ns,
});
return formatTranslation(Object.assign(Object.assign({}, props), { translation, formatEnabled: true }));
};
const setObserver = (observer) => {
instances.observer = observer === null || observer === void 0 ? void 0 : observer({ translate, onClick });
plugins.observer = observer;
};
const getObserver = () => {
return instances.observer;
const hasObserver = () => {
return Boolean(plugins.observer);
};

@@ -575,6 +613,6 @@ const addFormatter = (formatter) => {

const setUi = (ui) => {
plugins.ui = (ui === null || ui === void 0 ? void 0 : ui.UI) || ui;
plugins.ui = ui;
};
const getUi = () => {
return plugins.ui;
const hasUi = () => {
return Boolean(plugins.ui);
};

@@ -584,2 +622,5 @@ const setLanguageStorage = (storage) => {

};
const getLanguageStorage = () => {
return instances.languageStorage;
};
const setStoredLanguage = (language) => {

@@ -592,2 +633,5 @@ var _a;

};
const getLanguageDetector = () => {
return instances.languageDetector;
};
const detectLanguage = () => {

@@ -622,2 +666,23 @@ if (!instances.languageDetector) {

};
const run = () => {
var _a, _b, _c;
if (!instances.ui) {
const { apiKey, apiUrl, projectId } = getInitialOptions();
instances.ui = (_a = plugins.ui) === null || _a === void 0 ? void 0 : _a.call(plugins, {
apiKey: apiKey,
apiUrl: apiUrl,
projectId,
highlight,
changeTranslation,
});
}
if (!instances.observer) {
instances.observer = (_b = plugins.observer) === null || _b === void 0 ? void 0 : _b.call(plugins, {
translate,
onClick,
options: getInitialOptions().observerOptions,
});
}
(_c = instances.observer) === null || _c === void 0 ? void 0 : _c.run({ mouseHighlight: true });
};
const getDevBackend = () => {

@@ -628,5 +693,7 @@ return instances.devBackend;

var _a;
const { apiKey, apiUrl, projectId } = getInitialOptions();
return (_a = instances.devBackend) === null || _a === void 0 ? void 0 : _a.getRecord({
apiKey: getInitialOptions().apiKey,
apiUrl: getInitialOptions().apiUrl,
apiKey,
apiUrl,
projectId,
language,

@@ -652,21 +719,65 @@ namespace,

};
const formatTranslation = ({ key, translation, defaultValue, noWrap, params, orEmpty, ns, formatEnabled, }) => {
const unwrap = (text) => {
var _a;
if (instances.observer) {
return (_a = instances.observer) === null || _a === void 0 ? void 0 : _a.unwrap(text);
}
return { text, keys: [] };
};
const retranslate = () => {
var _a;
(_a = instances.observer) === null || _a === void 0 ? void 0 : _a.retranslate();
};
function addPlugin(tolgeeInstance, plugin) {
const pluginTools = Object.freeze({
setFinalFormatter,
addFormatter,
setObserver,
hasObserver,
setUi,
hasUi,
setDevBackend,
addBackend,
setLanguageDetector,
setLanguageStorage,
});
plugin(tolgeeInstance, pluginTools);
}
function formatTranslation(_a) {
var _b;
var { formatEnabled } = _a, props = __rest(_a, ["formatEnabled"]);
const { key, translation, defaultValue, noWrap, params, orEmpty, ns } = props;
const formattableTranslation = translation || defaultValue;
let result = formattableTranslation || (orEmpty ? '' : key);
if (instances.observer && !noWrap) {
result = instances.observer.wrap({
key,
translation: result,
defaultValue,
params,
ns,
});
}
const language = getLanguage();
const isFormatEnabled = formatEnabled || !((_a = instances.observer) === null || _a === void 0 ? void 0 : _a.outputNotFormattable);
if (formattableTranslation && language && isFormatEnabled) {
for (const formatter of instances.formatters) {
result = formatter.format({
const isFormatEnabled = formatEnabled || !((_b = instances.observer) === null || _b === void 0 ? void 0 : _b.outputNotFormattable);
const wrap = (result) => {
if (instances.observer && !noWrap) {
return instances.observer.wrap({
key,
translation: result,
defaultValue,
params,
ns,
});
}
return result;
};
result = wrap(result);
try {
if (formattableTranslation && language && isFormatEnabled) {
for (const formatter of instances.formatters) {
result = formatter.format({
translation: result,
language,
params,
});
}
}
if (instances.finalFormatter &&
formattableTranslation &&
language &&
isFormatEnabled) {
result = instances.finalFormatter.format({
translation: result,
language,

@@ -677,14 +788,25 @@ params,

}
if (instances.finalFormatter &&
formattableTranslation &&
language &&
isFormatEnabled) {
result = instances.finalFormatter.format({
translation: result,
language,
params,
});
catch (e) {
// eslint-disable-next-line no-console
console.error(e);
const errorMessage = getErrorMessage(e) || DEFAULT_FORMAT_ERROR;
const onFormatError = getInitialOptions().onFormatError;
const formatErrorType = typeof onFormatError;
if (formatErrorType === 'string') {
result = onFormatError;
}
else if (formatErrorType === 'function') {
result = onFormatError(errorMessage, props);
}
else {
result = DEFAULT_FORMAT_ERROR;
}
// wrap error message, so it's detectable
result = wrap(result);
}
return result;
};
}
function hasDevBackend() {
return Boolean(getDevBackend());
}
const wrap = (params) => {

@@ -697,28 +819,10 @@ var _a;

};
const unwrap = (text) => {
var _a;
if (instances.observer) {
return (_a = instances.observer) === null || _a === void 0 ? void 0 : _a.unwrap(text);
}
return { text, keys: [] };
};
const retranslate = () => {
var _a;
(_a = instances.observer) === null || _a === void 0 ? void 0 : _a.retranslate();
};
return Object.freeze({
setFinalFormatter,
addFormatter,
addPlugin,
formatTranslation,
setObserver,
getObserver,
setUi,
getUi,
addBackend,
setDevBackend,
getDevBackend,
getBackendRecord,
getBackendDevRecord,
setLanguageDetector,
setLanguageStorage,
getLanguageDetector,
getLanguageStorage,
getInitialLanguage,

@@ -730,4 +834,5 @@ setStoredLanguage,

highlight,
unwrap,
wrap,
unwrap,
hasDevBackend,
});

@@ -754,24 +859,5 @@ };

const defaultValues = {
enableLanguageStore: true,
defaultNs: '',
filesUrlPrefix: 'i18n/',
};
const initState = (options, previousState) => {
const initialOptions = Object.assign(Object.assign(Object.assign({}, defaultValues), previousState === null || previousState === void 0 ? void 0 : previousState.initialOptions), options);
// remove extra '/' from url end
const apiUrl = initialOptions.apiUrl;
initialOptions.apiUrl = apiUrl ? apiUrl.replace(/\/+$/, '') : apiUrl;
return {
initialOptions,
activeNamespaces: (previousState === null || previousState === void 0 ? void 0 : previousState.activeNamespaces) || new Map(),
language: previousState === null || previousState === void 0 ? void 0 : previousState.language,
pendingLanguage: previousState === null || previousState === void 0 ? void 0 : previousState.language,
isInitialLoading: false,
isRunning: false,
};
};
const State = (onLanguageChange, onPendingLanguageChange, onRunningChange) => {
let state = initState();
let devCredentials = undefined;
function init(options) {

@@ -798,9 +884,2 @@ state = initState(options, state);

}
function getLanguageOrFail() {
const language = state.language || state.initialOptions.language;
if (!language) {
throw new Error(`No language set`);
}
return language;
}
function setLanguage(language) {

@@ -822,3 +901,3 @@ if (state.language !== language) {

function getInitialOptions() {
return state.initialOptions;
return Object.assign(Object.assign({}, state.initialOptions), devCredentials);
}

@@ -852,2 +931,3 @@ function addActiveNs(ns) {

...(state.initialOptions.ns || [state.initialOptions.defaultNs]),
...getFallbackArray(state.initialOptions.fallbackNs),
...state.activeNamespaces.keys(),

@@ -866,8 +946,8 @@ ]);

}
function getFallbackNamespaces() {
const defaultNs = state.initialOptions.defaultNs;
const fallbackNs = state.initialOptions.fallbackNs;
const fallbackNamespaces = typeof defaultNs === 'string' ? [defaultNs] : [];
return unique([...fallbackNamespaces, ...getFallbackArray(fallbackNs)]);
function getFallbackNs() {
return getFallbackArray(state.initialOptions.fallbackNs);
}
function getDefaultNs(ns) {
return ns === undefined ? state.initialOptions.defaultNs : ns;
}
function getAvailableLanguages() {

@@ -890,2 +970,10 @@ if (state.initialOptions.availableLanguages) {

}
function overrideCredentials(credentials) {
if (credentials) {
devCredentials = Object.assign(Object.assign({}, credentials), { apiUrl: sanitizeUrl(credentials.apiUrl) });
}
else {
devCredentials = undefined;
}
}
return Object.freeze({

@@ -898,3 +986,2 @@ init,

getLanguage,
getLanguageOrFail,
setLanguage,

@@ -908,35 +995,10 @@ getPendingLanguage,

getFallbackLangs,
getFallbackNamespaces,
getFallbackNs,
getDefaultNs,
getAvailableLanguages,
withDefaultNs,
overrideCredentials,
});
};
/******************************************************************************
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.
***************************************************************************** */
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 parseCombinedOptions(_a) {

@@ -948,7 +1010,6 @@ var { ns, noWrap, orEmpty, params } = _a, rest = __rest(_a, ["ns", "noWrap", "orEmpty", "params"]);

orEmpty: orEmpty,
params: Object.assign(Object.assign({}, rest), params),
};
return options;
return Object.assign(Object.assign({}, options), { params: Object.assign({}, rest) });
}
const getTranslateParams = (keyOrProps, ...params) => {
const getTranslateProps = (keyOrProps, ...params) => {
let result = {};

@@ -975,14 +1036,13 @@ let options;

const Controller = ({ events, options }) => {
const Controller = ({ options }) => {
const events = Events(getFallbackNs, getDefaultNs);
const fetchingObserver = ValueObserver(false, () => cache.isFetching(), events.onFetchingChange.emit);
const loadingObserver = ValueObserver(false, () => isLoading(), events.onLoadingChange.emit);
const state = State(events.onLanguageChange, events.onPendingLanguageChange, events.onRunningChange);
const pluginService = PluginService(state.getLanguage, state.getInitialOptions, state.getAvailableLanguages, getTranslationNs, getTranslation, changeTranslation);
const pluginService = Plugins(state.getLanguage, state.getInitialOptions, state.getAvailableLanguages, getTranslationNs, getTranslation, changeTranslation);
const cache = Cache(events.onCacheChange, pluginService.getBackendRecord, pluginService.getBackendDevRecord, state.withDefaultNs, state.isInitialLoading, fetchingObserver, loadingObserver);
state.init(options);
cache.addStaticData(state.getInitialOptions().staticData);
if (isDev()) {
cache.invalidate();
if (options) {
init(options);
}
events.onKeyUpdate.listen(() => {
events.onUpdate.listen(() => {
if (state.isRunning()) {

@@ -992,8 +1052,21 @@ pluginService.retranslate();

});
const t = (...args) => {
// @ts-ignore
const params = getTranslateParams(...args);
const translation = getTranslation(params);
return pluginService.formatTranslation(Object.assign(Object.assign({}, params), { translation }));
};
function getFallbackNs() {
return state.getFallbackNs();
}
function getDefaultNs(ns) {
return state.getDefaultNs(ns);
}
// gets all namespaces where translation could be located
// takes (ns|default, fallback ns)
function getDefaultAndFallbackNs(ns) {
return [...getFallbackArray(getDefaultNs(ns)), ...getFallbackNs()];
}
// gets all namespaces which need to be loaded
// takes (ns|default, initial ns, fallback ns, active ns)
function getRequiredNamespaces(ns) {
return [
...getFallbackArray(ns || getDefaultNs()),
...state.getRequiredNamespaces(),
];
}
function changeTranslation(descriptor, key, value) {

@@ -1012,5 +1085,2 @@ const keyObject = state.withDefaultNs(descriptor);

cache.addStaticData(state.getInitialOptions().staticData);
if (isDev()) {
cache.invalidate();
}
}

@@ -1021,3 +1091,3 @@ function isLoading(ns) {

function isDev() {
return Boolean(state.getInitialOptions().apiKey && pluginService.getDevBackend());
return Boolean(state.getInitialOptions().apiKey && state.getInitialOptions().apiUrl);
}

@@ -1034,3 +1104,3 @@ async function addActiveNs(ns, forget) {

const languages = state.getFallbackLangs(lang);
const namespaces = ns !== undefined ? getFallbackArray(ns) : state.getRequiredNamespaces();
const namespaces = getRequiredNamespaces(ns);
const result = [];

@@ -1052,3 +1122,3 @@ languages.forEach((language) => {

const languages = state.getFallbackLangs(language);
const namespaces = ns !== undefined ? getFallbackArray(ns) : state.getRequiredNamespaces();
const namespaces = getRequiredNamespaces(ns);
const result = [];

@@ -1086,13 +1156,9 @@ languages.forEach((language) => {

}
function getTranslationNs({ key, ns, }) {
const namespaces = ns
? getFallbackArray(ns)
: state.getFallbackNamespaces();
function getTranslationNs({ key, ns }) {
const languages = state.getFallbackLangs();
const namespaces = getDefaultAndFallbackNs(ns);
return cache.getTranslationNs(namespaces, languages, key);
}
function getTranslation({ key, ns, }) {
const namespaces = ns
? getFallbackArray(ns)
: state.getFallbackNamespaces();
function getTranslation({ key, ns }) {
const namespaces = getDefaultAndFallbackNs(ns);
const languages = state.getFallbackLangs();

@@ -1104,3 +1170,2 @@ return cache.getTranslationFallback(namespaces, languages, key);

// fail if there is no language
state.getLanguageOrFail();
return loadRequiredRecords();

@@ -1144,5 +1209,26 @@ });

}
const checkCorrectConfiguration = () => {
const languageComputable = pluginService.getLanguageDetector() || pluginService.getLanguageStorage();
if (languageComputable) {
const availableLanguages = state.getAvailableLanguages();
if (!availableLanguages) {
throw new Error(missingOptionError('availableLanguages'));
}
}
if (!state.getLanguage() && !state.getInitialOptions().defaultLanguage) {
if (languageComputable) {
throw new Error(missingOptionError('defaultLanguage'));
}
else {
throw new Error(missingOptionError('language'));
}
}
};
function run() {
let result = undefined;
checkCorrectConfiguration();
if (!state.isRunning()) {
if (isDev()) {
cache.invalidate();
}
state.setRunning(true);

@@ -1160,3 +1246,9 @@ pluginService.run();

}
return Object.freeze(Object.assign(Object.assign(Object.assign(Object.assign({}, state), pluginService), cache), { init,
const t = (...args) => {
// @ts-ignore
const params = getTranslateProps(...args);
const translation = getTranslation(params);
return pluginService.formatTranslation(Object.assign(Object.assign({}, params), { translation }));
};
return Object.freeze(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, events), state), pluginService), cache), { init,
changeLanguage,

@@ -1166,3 +1258,2 @@ getTranslation,

addActiveNs,
loadRequiredRecords,
loadRecords,

@@ -1178,20 +1269,7 @@ loadRecord,

const Tolgee = (options) => {
const events = Events();
const createTolgee = (options) => {
const controller = Controller({
events,
options,
});
const pluginTools = Object.freeze({
setFinalFormatter: controller.setFinalFormatter,
addFormatter: controller.addFormatter,
setObserver: controller.setObserver,
getObserver: controller.getObserver,
setUi: controller.setUi,
getUi: controller.getUi,
setDevBackend: controller.setDevBackend,
addBackend: controller.addBackend,
setLanguageDetector: controller.setLanguageDetector,
setLanguageStorage: controller.setLanguageStorage,
});
// restarts tolgee while applying callback
const withRestart = (callback) => {

@@ -1204,61 +1282,359 @@ const wasRunning = controller.isRunning();

const tolgee = Object.freeze({
// event listeners
on: events.on,
onKeyUpdate: events.onKeyUpdate.listenSome,
// state
/**
* Listen to tolgee events.
*/
on: controller.on,
/**
* Listen for specific namespaces changes.
*
* ```
* const sub = tolgee.onUpdate(handler)
*
* // subscribe to selected namespace
* sub.subscribeNs(['common'])
*
* // unsubscribe
* sub.unsubscribe()
* ```
*/
onNsUpdate: controller.onUpdate.listenSome,
/**
* Turn off/on events emitting. Is on by default.
*/
setEmmiterActive: controller.setEmmiterActive,
/**
* @return current language if set.
*/
getLanguage: controller.getLanguage,
/**
* `pendingLanguage` represents language which is currently being loaded.
* @return current `pendingLanguage` if set.
*/
getPendingLanguage: controller.getPendingLanguage,
/**
* Change current language.
* - if not running sets `pendingLanguage`, `language` to the new value
* - if running sets `pendingLanguage` to the value, fetches necessary data and then changes `language`
*
* @return Promise which is resolved when `language` is changed.
*/
changeLanguage: controller.changeLanguage,
/**
* Temporarily change translation in cache.
* @return object with revert method.
*/
changeTranslation: controller.changeTranslation,
/**
* Adds namespace(s) list of active namespaces. And if tolgee is running, loads required data.
*/
addActiveNs: controller.addActiveNs,
/**
* Remove namespace(s) from active namespaces.
*
* Tolgee internally counts how many times was each active namespace added,
* so this method will remove namespace only if the counter goes down to 0.
*/
removeActiveNs: controller.removeActiveNs,
/**
* Manually load multiple records from `Backend` (or `DevBackend` when in dev mode)
*
* It loads data together and adds them to cache in one operation, to prevent partly loaded state.
*/
loadRecords: controller.loadRecords,
/**
* Manually load record from `Backend` (or `DevBackend` when in dev mode)
*/
loadRecord: controller.loadRecord,
/**
*
*/
addStaticData: controller.addStaticData,
/**
* Get record from cache.
*/
getRecord: controller.getRecord,
/**
* Get all records from cache.
*/
getAllRecords: controller.getAllRecords,
/**
* @param ns optional list of namespaces that you are interested in
* @return `true` if there are data that need to be fetched.
*/
isLoaded: controller.isLoaded,
/**
* @return `true` if tolgee is loading initial data (triggered by `run`).
*/
isInitialLoading: controller.isInitialLoading,
/**
* @param ns optional list of namespaces that you are interested in
* @return `true` if tolgee is loading some translations for the first time.
*/
isLoading: controller.isLoading,
/**
* @param ns optional list of namespaces that you are interested in
* @return `true` if tolgee is fetching some translations.
*/
isFetching: controller.isFetching,
/**
* @return `true` if tolgee is running.
*/
isRunning: controller.isRunning,
/**
* Changes internal state to running: true and loads initial files.
* Runs runnable plugins mainly Observer if present.
*/
run: controller.run,
/**
* Changes internal state to running: false and stops runnable plugins.
*/
stop: controller.stop,
/**
* Returns translated and formatted key.
* If Observer is present and tolgee is running, wraps result to be identifiable in the DOM.
*/
t: controller.t,
/**
* Highlight keys that match selection.
*/
highlight: controller.highlight,
/**
* @return current Tolgee options.
*/
getInitialOptions: controller.getInitialOptions,
/**
* Tolgee is in dev mode if `DevTools` plugin is used and `apiKey` + `apiUrl` are specified.
* @return `true` if tolgee is in dev mode.
*/
isDev: controller.isDev,
/**
* Wraps translation if there is `Observer` plugin
*/
wrap: controller.wrap,
/**
* Unwrap translation
*/
unwrap: controller.unwrap,
// plugins
use: (plugin) => {
/**
* Override creadentials passed on initialization.
*
* When called in running state, tolgee stops and runs again.
*/
overrideCredentials(credentials) {
withRestart(() => controller.overrideCredentials(credentials));
},
/**
* Add tolgee plugin after initialization.
*
* When called in running state, tolgee stops and runs again.
*/
addPlugin(plugin) {
if (plugin) {
withRestart(() => plugin(tolgee, pluginTools));
withRestart(() => controller.addPlugin(tolgee, plugin));
}
return tolgee;
},
init: (options) => {
withRestart(() => controller.init(options));
/**
* Updates options after instance creation. Extends existing options,
* so it only changes the fields, that are listed.
*
* When called in running state, tolgee stops and runs again.
*/
updateOptions(options) {
if (options) {
withRestart(() => controller.init(options));
}
},
});
return tolgee;
};
/**
* Tolgee chainable constructor.
*
* Usage:
* ```
* const tolgee = Tolgee().use(...).init(...)
* ```
*/
const TolgeeCore = () => {
const state = {
plugins: [],
options: {},
};
const tolgeeChain = Object.freeze({
use(plugin) {
state.plugins.push(plugin);
return tolgeeChain;
},
updateDefaults(options) {
state.options = combineOptions(state.options, options);
return tolgeeChain;
},
init(options) {
const tolgee = createTolgee(combineOptions(state.options, options));
state.plugins.forEach(tolgee.addPlugin);
return tolgee;
},
});
return tolgeeChain;
};
const ERROR_PARAM_EMPTY = 0, ERROR_UNEXPECTED_CHAR = 1, ERROR_UNEXPECTED_END = 2;
class FormatError extends Error {
constructor(code, index, text) {
let error;
if (code === ERROR_PARAM_EMPTY) {
error = 'Empty parameter';
}
else if (code === ERROR_UNEXPECTED_CHAR) {
error = 'Unexpected character';
}
else {
error = 'Unexpected end';
}
super(`Tolgee parser: ${error} at ${index} in "${text}"`);
this.code = code;
this.index = index;
}
}
function isWhitespace(ch) {
return /\s/.test(ch);
}
const STATE_TEXT = 0, STATE_ESCAPE_MAYBE = 1, STATE_ESCAPE = 2, STATE_PARAM = 3, STATE_PARAM_AFTER = 4;
const END_STATES = new Set([
STATE_ESCAPE,
STATE_ESCAPE_MAYBE,
STATE_TEXT,
]);
const CHAR_ESCAPE = "'";
const ESCAPABLE = new Set(['{', '}', CHAR_ESCAPE]);
const isAllowedInParam = (char) => {
return /[0-9a-zA-Z_]/.test(char);
};
function formatParser(translation) {
let state = STATE_TEXT;
let text = '';
let param = '';
let ch = '';
const texts = [];
const params = [];
let i = 0;
function parsingError(code) {
throw new FormatError(code, i, translation);
}
const addText = () => {
texts.push(text);
text = '';
};
const addParamChar = () => {
if (!isAllowedInParam(ch)) {
parsingError(ERROR_UNEXPECTED_CHAR);
}
param += ch;
};
const addParam = () => {
if (param === '') {
parsingError(ERROR_PARAM_EMPTY);
}
params.push(param);
param = '';
};
for (i = 0; i < translation.length; i++) {
ch = translation[i];
switch (state) {
case STATE_TEXT:
if (ch === CHAR_ESCAPE) {
text += ch;
state = STATE_ESCAPE_MAYBE;
}
else if (ch === '{') {
addText();
state = STATE_PARAM;
}
else {
text += ch;
state = STATE_TEXT;
}
break;
case STATE_ESCAPE_MAYBE:
if (ESCAPABLE.has(ch)) {
text = text.slice(0, -1) + ch;
state = STATE_ESCAPE;
}
else {
text += ch;
state = STATE_TEXT;
}
break;
case STATE_ESCAPE:
if (ch === CHAR_ESCAPE) {
state = STATE_TEXT;
}
else {
text += ch;
state = STATE_ESCAPE;
}
break;
case STATE_PARAM:
if (ch === '}') {
addParam();
state = STATE_TEXT;
}
else if (!isWhitespace(ch)) {
addParamChar();
state = STATE_PARAM;
}
else if (param !== '') {
addParam();
state = STATE_PARAM_AFTER;
}
break;
case STATE_PARAM_AFTER:
if (ch == '}') {
state = STATE_TEXT;
}
else if (isWhitespace(ch)) {
state = STATE_PARAM_AFTER;
}
else {
parsingError(ERROR_UNEXPECTED_CHAR);
}
}
}
if (!END_STATES.has(state)) {
parsingError(ERROR_UNEXPECTED_END);
}
addText();
return [texts, params];
}
function formatter(translation, params) {
const [texts, pars] = formatParser(translation);
const result = [texts[0]];
for (let i = 1; i < texts.length; i++) {
const parameter = params === null || params === void 0 ? void 0 : params[pars[i - 1]];
if (parameter === undefined) {
throw new Error(`Missing parameter "${pars[i - 1]}" in "${translation}"`);
}
result.push(String(parameter));
result.push(texts[i]);
}
return result.join('');
}
function createFormatSimple() {
return {
format: ({ translation, params }) => formatter(translation, params),
};
}
const FormatSimple = () => (tolgee, tools) => {
tools.setFinalFormatter(createFormatSimple());
return tolgee;
};
const RESTRICTED_ASCENDANT_ATTRIBUTE = 'data-tolgee-restricted';
const TOLGEE_ATTRIBUTE_NAME = '_tolgee';
const TOLGEE_HIGHLIGHTER_CLASS = '_tolgee-highlighter';
const TOLGEE_WRAPPED_ONLY_DATA_ATTRIBUTE = 'data-tolgee-key-only';
// needs to be same as in @tolgee/ui package
const DEVTOOLS_ID = '__tolgee_dev_tools';
exports.DEVTOOLS_ID = DEVTOOLS_ID;
exports.RESTRICTED_ASCENDANT_ATTRIBUTE = RESTRICTED_ASCENDANT_ATTRIBUTE;
exports.TOLGEE_ATTRIBUTE_NAME = TOLGEE_ATTRIBUTE_NAME;
exports.TOLGEE_HIGHLIGHTER_CLASS = TOLGEE_HIGHLIGHTER_CLASS;
exports.TOLGEE_WRAPPED_ONLY_DATA_ATTRIBUTE = TOLGEE_WRAPPED_ONLY_DATA_ATTRIBUTE;
exports.Tolgee = Tolgee;
exports.FormatSimple = FormatSimple;
exports.TolgeeCore = TolgeeCore;
exports.getFallback = getFallback;
exports.getFallbackArray = getFallbackArray;
exports.getTranslateParams = getTranslateParams;
exports.getTranslateProps = getTranslateProps;

@@ -1265,0 +1641,0 @@ Object.defineProperty(exports, '__esModule', { value: true });

@@ -1,2 +0,2 @@

!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((e="undefined"!=typeof globalThis?globalThis:e||self)["@tolgee/core"]={})}(this,(function(e){"use strict";const n=()=>{let e=[];return Object.freeze({listen:n=>{const t=e=>{n(e)};return e.push(t),{unsubscribe:()=>{e=e.filter((e=>t!==e))}}},emit:n=>{e.forEach((e=>e({value:n})))}})};function t(e){return"string"==typeof e?[e]:Array.isArray(e)?e:void 0}function a(e){return t(e)||[]}function i(e,n){return"object"!=typeof(t=n)||Array.isArray(t)||null===t?a(n):a(null==n?void 0:n[e]);var t}function o(e){return Array.from(new Set(e))}function s(e,n){const t=e.get(n)||0;e.set(n,t+1)}function r(e,n){let t=e.get(n)||1;t-=1,t<=0?e.delete(n):e.set(n,t)}const g=()=>{const e=new Set,n=new Set;let t=[];const i=()=>{if(0===t.length)return;e.forEach((e=>{e({value:void 0})}));let a=[],i=[];t.forEach((e=>{void 0===(null==e?void 0:e.ns)?a=void 0:void 0!==a&&(a=[...a,...e.ns]),void 0===(null==e?void 0:e.key)?i=void 0:void 0!==i&&(i=[...i,e.key])})),(i||[void 0]).forEach((e=>{((e,t)=>{n.forEach((n=>{const a=void 0!==t,i=n.namespaces.has(void 0)||-1!==(null==t?void 0:t.findIndex((e=>n.namespaces.has(e)))),o=void 0!==e,s=void 0===e||n.keys.has(e)||0===n.keys.size;a&&!i||o&&!s||n.fn({value:void 0})}))})(e,a)})),t=[]};return Object.freeze({listenSome:e=>{const t={fn:n=>{e(n)},keys:new Map,namespaces:new Map};n.add(t);const i={unsubscribe:()=>{n.delete(t)},subscribeNs:e=>(a(e).forEach((e=>s(t.namespaces,e))),i),unsubscribeNs:e=>(a(e).forEach((e=>r(t.namespaces,e))),i),subscribeKey:e=>{const{key:n,ns:o}=e;return s(t.keys,n),a(o).forEach((e=>s(t.namespaces,e))),void 0===o&&s(t.namespaces,void 0),i},unsubscribeKey:e=>{const{key:n,ns:o}=e;return r(t.keys,n),a(o).forEach((e=>r(t.namespaces,e))),void 0===o&&r(t.namespaces,void 0),i}};return i},listen:n=>{e.add(n);return{unsubscribe:()=>{e.delete(n)}}},emit:(e,n)=>{t.push(e),n?Promise.resolve().then((()=>{i()})):i()}})},c=e=>{const n=new Map;return Object.entries(e).forEach((([e,t])=>{null!=t&&("object"!=typeof t?n.set(e,t):Object.entries(c(t)).forEach((([t,a])=>{n.set(e+"."+t,a)})))})),n},u=e=>{const[n,t]=e.split(":");return{language:n,namespace:t||""}},l=({language:e,namespace:n})=>n?`${e}:${n}`:e,d=(e,n,t,i,o,s,r)=>{const g=new Map,d=new Map;let f={},v=0;function p(n,t,a){const i=l(n);d.set(i,{data:c(t),version:a}),e.emit(n)}function m(e,n){p(e,n,v)}function b(e,n=!1){const t=d.get(l(e));return t&&n?t.version===v:Boolean(t)}function h(e){var n;return null===(n=d.get(l(e)))||void 0===n?void 0:n.data}function y(e){let t;if(!t){const n=f[l(e)];"function"==typeof n?t=n():n&&(t=Promise.resolve(n))}return t||(t=n(e)),t||(t=Promise.resolve({})),t}return Object.freeze({addStaticData:function(e){e&&(f=Object.assign(Object.assign({},f),e),Object.entries(e).forEach((([e,n])=>{if("function"!=typeof n){const t=u(e),a=d.get(e);a&&0!==a.version||p(t,n,0)}})))},invalidate:function(){v+=1},addRecord:m,exists:b,getRecord:h,getTranslation:function(e,n){var t;return null===(t=d.get(l(e)))||void 0===t?void 0:t.data.get(n)},getTranslationNs:function(e,n,t){var a;for(const i of e)for(const e of n){const n=null===(a=d.get(l({language:e,namespace:i})))||void 0===a?void 0:a.data.get(t);if(null!=n)return i}return Array.from(new Set(e))},getTranslationFallback:function(e,n,t){var a;for(const i of e)for(const e of n){const n=null===(a=d.get(l({language:e,namespace:i})))||void 0===a?void 0:a.data.get(t);if(null!=n)return n}},changeTranslation:function(n,t,a){var i;const o=null===(i=d.get(l(n)))||void 0===i?void 0:i.data;null==o||o.set(t,a),e.emit(Object.assign(Object.assign({},n),{key:t}))},isFetching:function(e){if(o())return!0;if(void 0===e)return g.size>0;const n=a(e);return Boolean(Array.from(g.keys()).find((e=>n.includes(u(e).namespace))))},isLoading:function(e,n){const t=a(n);return Boolean(o()||Array.from(g.keys()).find((n=>{const a=u(n);return(!t.length||t.includes(a.namespace))&&!b({namespace:a.namespace,language:e})})))},loadRecords:async function(e,n){const a=e.map((e=>{const a=i(e),o=l(a),s=g.get(o);if(s)return{new:!1,promise:s,keyObject:a,cacheKey:o};const r=function(e,n){var a;let i;return n&&(i=null===(a=t(e))||void 0===a?void 0:a.catch((()=>(console.warn("Tolgee: Failed to fetch data from dev backend"),y(e))))),i||(i=y(e)),i}(a,n);return g.set(o,r),{new:!0,promise:r,keyObject:a,cacheKey:o}}));s.notify(),r.notify();const o=await Promise.all(a.map((e=>e.promise)));return a.forEach(((e,n)=>{if(e.new){g.delete(e.cacheKey);const t=o[n];t&&m(e.keyObject,t)}})),s.notify(),r.notify(),a.map((e=>h(e.keyObject)))},clear:function(){d.clear()},getAllRecords:function(){return Array.from(d.entries()).map((([e,n])=>Object.assign(Object.assign({},u(e)),{data:n.data})))}})};function f(e){return Boolean(e&&"function"==typeof e.then)}const v=(e,n)=>f(e)?Promise.resolve(e).then(n):n(e),p=e=>`Tolgee: You need to specify '${e}' option`,m=(e,n,t,i,o,s)=>{const r={ui:void 0},g={formatters:[],finalFormatter:void 0,observer:void 0,devBackend:void 0,backends:[],ui:void 0,languageDetector:void 0,languageStorage:void 0},c=async(e,{keysAndDefaults:n})=>{var t;const s=n.map((({key:e,ns:n,defaultValue:t})=>({key:e,defaultValue:t,ns:a(i({key:e,ns:n,defaultValue:t})),translation:o({key:e,ns:n})})));null===(t=g.ui)||void 0===t||t.handleElementClick(e,s)},u=()=>{if(g.languageDetector){if(!t())throw new Error(p("availableLanguages"))}},l=(e,n)=>{var t,a;return(null===(a=null===(t=g.observer)||void 0===t?void 0:t.highlight)||void 0===a?void 0:a.call(t,e,n))||{unhighlight(){}}},d=e=>{const n=o(e);return m(Object.assign(Object.assign({},e),{translation:n,formatEnabled:!0}))},m=({key:n,translation:t,defaultValue:a,noWrap:i,params:o,orEmpty:s,ns:r,formatEnabled:c})=>{var u;const l=t||a;let d=l||(s?"":n);g.observer&&!i&&(d=g.observer.wrap({key:n,translation:d,defaultValue:a,params:o,ns:r}));const f=e(),v=c||!(null===(u=g.observer)||void 0===u?void 0:u.outputNotFormattable);if(l&&f&&v)for(const e of g.formatters)d=e.format({translation:d,language:f,params:o});return g.finalFormatter&&l&&f&&v&&(d=g.finalFormatter.format({translation:d,language:f,params:o})),d};return Object.freeze({setFinalFormatter:e=>{g.finalFormatter=e},addFormatter:e=>{e&&g.formatters.push(e)},formatTranslation:m,setObserver:e=>{g.observer=null==e?void 0:e({translate:d,onClick:c})},getObserver:()=>g.observer,setUi:e=>{r.ui=(null==e?void 0:e.UI)||e},getUi:()=>r.ui,addBackend:e=>{e&&g.backends.push(e)},setDevBackend:e=>{g.devBackend=e},getDevBackend:()=>g.devBackend,getBackendRecord:({language:e,namespace:n})=>{for(const t of g.backends){const a=t.getRecord({language:e,namespace:n});if(f(a))return null==a?void 0:a.catch((e=>(console.error(e),{})));if(void 0!==a)return a}},getBackendDevRecord:({language:e,namespace:t})=>{var a;return null===(a=g.devBackend)||void 0===a?void 0:a.getRecord({apiKey:n().apiKey,apiUrl:n().apiUrl,language:e,namespace:t})},setLanguageDetector:e=>{g.languageDetector=e},setLanguageStorage:e=>{g.languageStorage=e},getInitialLanguage:()=>{var e;const n=t(),a=null===(e=g.languageStorage)||void 0===e?void 0:e.getLanguage();return v(a,(e=>n&&!n.includes(e)||!e?(()=>{if(!g.languageDetector)return;const e=t();return g.languageDetector.getLanguage({availableLanguages:e})})():e))},setStoredLanguage:e=>{var n;null===(n=g.languageStorage)||void 0===n||n.setLanguage(e)},run:()=>{var e;g.ui=r.ui&&new r.ui({apiKey:n().apiKey,apiUrl:n().apiUrl,highlight:l,changeTranslation:s}),null===(e=g.observer)||void 0===e||e.run({mouseHighlight:Boolean(g.ui)}),u()},stop:()=>{var e;g.ui=void 0,null===(e=g.observer)||void 0===e||e.stop()},retranslate:()=>{var e;null===(e=g.observer)||void 0===e||e.retranslate()},highlight:l,wrap:e=>{var n;return g.observer?null===(n=g.observer)||void 0===n?void 0:n.wrap(e):e.translation},unwrap:e=>{var n;return g.observer?null===(n=g.observer)||void 0===n?void 0:n.unwrap(e):{text:e,keys:[]}}})},b=(e,n,t)=>{let a=e;return Object.freeze({init:function(e){a=e},notify:function(){const e=n();a!==e&&t(e),a=e}})},h={enableLanguageStore:!0,defaultNs:"",filesUrlPrefix:"i18n/"},y=(e,n)=>{const t=Object.assign(Object.assign(Object.assign({},h),null==n?void 0:n.initialOptions),e),a=t.apiUrl;return t.apiUrl=a?a.replace(/\/+$/,""):a,{initialOptions:t,activeNamespaces:(null==n?void 0:n.activeNamespaces)||new Map,language:null==n?void 0:n.language,pendingLanguage:null==n?void 0:n.language,isInitialLoading:!1,isRunning:!1}};function L(e){var{ns:n,noWrap:t,orEmpty:a,params:i}=e,o=function(e,n){var t={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&n.indexOf(a)<0&&(t[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var i=0;for(a=Object.getOwnPropertySymbols(e);i<a.length;i++)n.indexOf(a[i])<0&&Object.prototype.propertyIsEnumerable.call(e,a[i])&&(t[a[i]]=e[a[i]])}return t}(e,["ns","noWrap","orEmpty","params"]);return{ns:n,noWrap:t,orEmpty:a,params:Object.assign(Object.assign({},o),i)}}const O=(e,...n)=>{let t,a={};return"object"==typeof e?a=e:(a.key=e,"string"==typeof n[0]?(a.defaultValue=n[0],t=n[1]):"object"==typeof n[0]&&(t=n[0])),t&&(a=Object.assign(Object.assign({},L(t)),a)),a},k=({events:e,options:n})=>{const t=b(!1,(()=>c.isFetching()),e.onFetchingChange.emit),s=b(!1,(()=>h()),e.onLoadingChange.emit),r=((e,n,t)=>{let s=y();function r(){return s.language||s.initialOptions.language}function g(){return s.initialOptions}return Object.freeze({init:function(e){s=y(e,s)},isRunning:function(){return s.isRunning},setRunning:function(e){s.isRunning!==e&&(s.isRunning=e,t.emit(e))},isInitialLoading:function(){return s.isInitialLoading},setInitialLoading:function(e){s.isInitialLoading=e},getLanguage:r,getLanguageOrFail:function(){const e=s.language||s.initialOptions.language;if(!e)throw new Error("No language set");return e},setLanguage:function(n){s.language!==n&&(s.language=n,e.emit(n))},getPendingLanguage:function(){return s.pendingLanguage||r()},setPendingLanguage:function(e){s.pendingLanguage!==e&&(s.pendingLanguage=e,n.emit(e))},getInitialOptions:g,addActiveNs:function(e){a(e).forEach((e=>{const n=s.activeNamespaces.get(e);void 0!==n?s.activeNamespaces.set(e,n+1):s.activeNamespaces.set(e,1)}))},removeActiveNs:function(e){a(e).forEach((e=>{const n=s.activeNamespaces.get(e);void 0!==n&&n>1?s.activeNamespaces.set(e,n-1):s.activeNamespaces.delete(e)}))},getRequiredNamespaces:function(){return o([...s.initialOptions.ns||[s.initialOptions.defaultNs],...s.activeNamespaces.keys()])},getFallbackLangs:function(e){const n=e||r();return n?o([n,...i(n,s.initialOptions.fallbackLanguage)]):[]},getFallbackNamespaces:function(){const e=s.initialOptions.defaultNs;return o([..."string"==typeof e?[e]:[],...a(s.initialOptions.fallbackNs)])},getAvailableLanguages:function(){if(s.initialOptions.availableLanguages)return s.initialOptions.availableLanguages;if(s.initialOptions.staticData){const e=Object.keys(s.initialOptions.staticData).map((e=>u(e).language));return Array.from(new Set(e))}},withDefaultNs:function(e){return{namespace:void 0===e.namespace?g().defaultNs:e.namespace,language:e.language}}})})(e.onLanguageChange,e.onPendingLanguageChange,e.onRunningChange),g=m(r.getLanguage,r.getInitialOptions,r.getAvailableLanguages,(function({key:e,ns:n}){const t=n?a(n):r.getFallbackNamespaces(),i=r.getFallbackLangs();return c.getTranslationNs(t,i,e)}),R,l),c=d(e.onCacheChange,g.getBackendRecord,g.getBackendDevRecord,r.withDefaultNs,r.isInitialLoading,t,s);r.init(n),c.addStaticData(r.getInitialOptions().staticData),L()&&c.invalidate(),e.onKeyUpdate.listen((()=>{r.isRunning()&&g.retranslate()}));function l(e,n,t){const a=r.withDefaultNs(e),i=c.getTranslation(a,n);return c.changeTranslation(a,n,t),{revert:()=>{c.changeTranslation(a,n,i)}}}function h(e){return c.isLoading(r.getLanguage(),e)}function L(){return Boolean(r.getInitialOptions().apiKey&&g.getDevBackend())}function k(e,n){const t=function(e,n){const t=r.getFallbackLangs(e),i=void 0!==n?a(n):r.getRequiredNamespaces(),o=[];return t.forEach((e=>{i.forEach((n=>{c.exists({language:e,namespace:n},!0)||o.push({language:e,namespace:n})}))})),o}(e,n);if(t.length)return v(E(t),(()=>{}))}function R({key:e,ns:n}){const t=n?a(n):r.getFallbackNamespaces(),i=r.getFallbackLangs();return c.getTranslationFallback(t,i,e)}function j(){const n=v(function(){if(r.getLanguage())return;if(!r.getInitialOptions().defaultLanguage)throw new Error(p("defaultLanguage"));const e=g.getInitialLanguage();return v(e,(e=>{const n=e||r.getInitialOptions().defaultLanguage;n&&r.setLanguage(n)}))}(),(()=>(r.getLanguageOrFail(),k())));if(f(n))return r.setInitialLoading(!0),t.notify(),s.notify(),Promise.resolve(n).then((()=>{r.setInitialLoading(!1),t.notify(),s.notify(),e.onInitialLoaded.emit()}));e.onInitialLoaded.emit()}function E(e){return c.loadRecords(e,L())}return Object.freeze(Object.assign(Object.assign(Object.assign(Object.assign({},r),g),c),{init:function(e){r.init(e),c.addStaticData(r.getInitialOptions().staticData),L()&&c.invalidate()},changeLanguage:async function(e){r.getPendingLanguage()===e&&r.getLanguage()===e||(r.setPendingLanguage(e),r.isRunning()&&await k(e),e===r.getPendingLanguage()&&(r.setLanguage(e),g.setStoredLanguage(e)))},getTranslation:R,changeTranslation:l,addActiveNs:async function(e,n){n||r.addActiveNs(e),r.isRunning()&&await k(void 0,e)},loadRequiredRecords:k,loadRecords:E,loadRecord:async function(e){return(await E([e]))[0]},isLoading:h,isLoaded:function(e){const n=r.getLanguage();if(!n)return!1;const t=r.getFallbackLangs(n),i=void 0!==e?a(e):r.getRequiredNamespaces(),o=[];return t.forEach((e=>{i.forEach((n=>{c.exists({language:e,namespace:n})||o.push({language:e,namespace:n})}))})),0===o.length},t:(...e)=>{const n=O(...e),t=R(n);return g.formatTranslation(Object.assign(Object.assign({},n),{translation:t}))},isDev:L,run:function(){let e;return r.isRunning()||(r.setRunning(!0),g.run(),e=j()),Promise.resolve(e)},stop:function(){r.isRunning()&&(g.stop(),r.setRunning(!1))}}))};e.DEVTOOLS_ID="__tolgee_dev_tools",e.RESTRICTED_ASCENDANT_ATTRIBUTE="data-tolgee-restricted",e.TOLGEE_ATTRIBUTE_NAME="_tolgee",e.TOLGEE_HIGHLIGHTER_CLASS="_tolgee-highlighter",e.TOLGEE_WRAPPED_ONLY_DATA_ATTRIBUTE="data-tolgee-key-only",e.Tolgee=e=>{const t=(()=>{const e=n(),t=n(),a=n(),i=n(),o=n(),s=n(),r=g(),c=n(),u=n();return s.listen((()=>r.emit())),t.listen((()=>r.emit())),c.listen((({value:e})=>{r.emit({ns:[e.namespace],key:e.key},!0)})),Object.freeze({onPendingLanguageChange:e,onLanguageChange:t,onKeyChange:a,onKeyUpdate:r,onLoadingChange:i,onFetchingChange:o,onInitialLoaded:s,onRunningChange:u,onCacheChange:c,on:(n,a)=>{switch(n){case"pendingLanguage":return e.listen(a);case"language":return t.listen(a);case"loading":return i.listen(a);case"fetching":return o.listen(a);case"initialLoad":return s.listen(a);case"running":return u.listen(a);case"cache":return c.listen(a);case"keyUpdate":return r.listen(a)}}})})(),a=k({events:t,options:e}),i=Object.freeze({setFinalFormatter:a.setFinalFormatter,addFormatter:a.addFormatter,setObserver:a.setObserver,getObserver:a.getObserver,setUi:a.setUi,getUi:a.getUi,setDevBackend:a.setDevBackend,addBackend:a.addBackend,setLanguageDetector:a.setLanguageDetector,setLanguageStorage:a.setLanguageStorage}),o=e=>{const n=a.isRunning();n&&a.stop(),e(),n&&a.run()},s=Object.freeze({on:t.on,onKeyUpdate:t.onKeyUpdate.listenSome,getLanguage:a.getLanguage,getPendingLanguage:a.getPendingLanguage,changeLanguage:a.changeLanguage,changeTranslation:a.changeTranslation,addActiveNs:a.addActiveNs,removeActiveNs:a.removeActiveNs,loadRecords:a.loadRecords,loadRecord:a.loadRecord,addStaticData:a.addStaticData,getRecord:a.getRecord,getAllRecords:a.getAllRecords,isLoaded:a.isLoaded,isInitialLoading:a.isInitialLoading,isLoading:a.isLoading,isFetching:a.isFetching,isRunning:a.isRunning,run:a.run,stop:a.stop,t:a.t,highlight:a.highlight,getInitialOptions:a.getInitialOptions,isDev:a.isDev,wrap:a.wrap,unwrap:a.unwrap,use:e=>(e&&o((()=>e(s,i))),s),init:e=>(o((()=>a.init(e))),s)});return s},e.getFallback=t,e.getFallbackArray=a,e.getTranslateParams=O,Object.defineProperty(e,"__esModule",{value:!0})}));
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((e="undefined"!=typeof globalThis?globalThis:e||self)["@tolgee/core"]={})}(this,(function(e){"use strict";function n(e){return Boolean(e&&"function"==typeof e.then)}const t=(e,t)=>n(e)?Promise.resolve(e).then(t):t(e),a=e=>`Tolgee: You need to specify '${e}' option`;function i(e){return"string"==typeof e?[e]:Array.isArray(e)?e:void 0}function o(e){return i(e)||[]}function r(e,n){return"object"!=typeof(t=n)||Array.isArray(t)||null===t?o(n):o(null==n?void 0:n[e]);var t}function s(e){return Array.from(new Set(e))}function c(e){return e?e.replace(/\/+$/,""):e}const g=e=>{let n=[];return Object.freeze({listen:e=>{const t=n=>{e(n)};return n.push(t),{unsubscribe:()=>{n=n.filter((e=>t!==e))}}},emit:t=>{e()&&n.forEach((e=>e({value:t})))}})},u=(e,n,t)=>{const a=new Set,i=new Set;let r=[];const s=()=>{if(0===r.length)return;const e=r;r=[],a.forEach((e=>{e({value:void 0})}));let t=new Set;e.forEach((e=>{void 0===e?t=void 0:void 0!==t&&e.forEach((e=>t.add(e)))}));(e=>{const t=new Set(n());i.forEach((n=>{(void 0===e||-1!==(null==e?void 0:e.findIndex((e=>t.has(e)||n.namespaces.has(e)))))&&n.fn({value:void 0})}))})(t?Array.from(t.keys()):void 0)};return Object.freeze({listenSome:e=>{const n={fn:n=>{e(n)},namespaces:new Set};i.add(n);const a={unsubscribe:()=>{i.delete(n)},subscribeNs:e=>(o(e).forEach((e=>n.namespaces.add(e))),void 0===e&&n.namespaces.add(t()),a)};return a},listen:e=>{a.add(e);return{unsubscribe:()=>{a.delete(e)}}},emit:(n,t)=>{e()&&(r.push(n),t?setTimeout(s,0):s())}})},l=e=>{const n=new Map;return Object.entries(e).forEach((([e,t])=>{null!=t&&("object"!=typeof t?n.set(e,t):l(t).forEach(((t,a)=>{n.set(e+"."+a,t)})))})),n},d=e=>{const[n,...t]=e.split(":");return{language:n,namespace:t.join(":")||""}},f=({language:e,namespace:n})=>n?`${e}:${n}`:e,p=(e,n,t,a,i,r,c)=>{const g=new Map,u=new Map;let p={},v=0;function h(n,t,a){const i=f(n);u.set(i,{data:l(t),version:a}),e.emit(n)}function b(e,n){h(e,n,v)}function m(e,n=!1){const t=u.get(f(e));return t&&n?t.version===v:Boolean(t)}function y(e){var n;return null===(n=u.get(f(a(e))))||void 0===n?void 0:n.data}function O(e){let t;if(!t){const n=p[f(e)];"function"==typeof n&&(t=n())}return t||(t=n(e)),t}return Object.freeze({addStaticData:function(e){e&&(p=Object.assign(Object.assign({},p),e),Object.entries(e).forEach((([e,n])=>{if("function"!=typeof n){const t=d(e),a=u.get(e);a&&0!==a.version||h(t,n,0)}})))},invalidate:function(){g.clear(),v+=1},addRecord:b,exists:m,getRecord:y,getTranslation:function(e,n){var t;return null===(t=u.get(f(e)))||void 0===t?void 0:t.data.get(n)},getTranslationNs:function(e,n,t){var a;for(const i of e)for(const e of n){const n=null===(a=u.get(f({language:e,namespace:i})))||void 0===a?void 0:a.data.get(t);if(null!=n)return[i]}return s(e)},getTranslationFallback:function(e,n,t){var a;for(const i of e)for(const e of n){const n=null===(a=u.get(f({language:e,namespace:i})))||void 0===a?void 0:a.data.get(t);if(null!=n)return n}},changeTranslation:function(n,t,a){var i;const o=null===(i=u.get(f(n)))||void 0===i?void 0:i.data;null==o||o.set(t,a),e.emit(Object.assign(Object.assign({},n),{key:t}))},isFetching:function(e){if(i())return!0;if(void 0===e)return g.size>0;const n=o(e);return Boolean(Array.from(g.keys()).find((e=>n.includes(d(e).namespace))))},isLoading:function(e,n){const t=o(n);return Boolean(i()||Array.from(g.keys()).find((n=>{const a=d(n);return(!t.length||t.includes(a.namespace))&&!m({namespace:a.namespace,language:e})})))},loadRecords:async function(e,n){const i=e.map((e=>{const i=a(e),o=f(i),r=g.get(o);if(r)return{new:!1,promise:r,keyObject:i,cacheKey:o};const s=function(e,n){var a;let i;return n&&(i=null===(a=t(e))||void 0===a?void 0:a.catch((()=>(console.warn("Tolgee: Failed to fetch data from dev backend"),O(e))))),i||(i=O(e)),i}(i,n)||Promise.resolve(void 0);return g.set(o,s),{new:!0,promise:s,keyObject:i,cacheKey:o}}));r.notify(),c.notify();const o=await Promise.all(i.map((e=>e.promise)));return i.forEach(((e,n)=>{const t=g.get(e.cacheKey)!==e.promise;if(e.new&&!t){g.delete(e.cacheKey);const t=o[n];t?b(e.keyObject,t):y(e.keyObject)||b(e.keyObject,{})}})),r.notify(),c.notify(),i.map((e=>y(e.keyObject)))},getAllRecords:function(){return Array.from(u.entries()).map((([e,n])=>Object.assign(Object.assign({},d(e)),{data:n.data})))}})};function v(e,n){var t={};for(var a in e)Object.prototype.hasOwnProperty.call(e,a)&&n.indexOf(a)<0&&(t[a]=e[a]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var i=0;for(a=Object.getOwnPropertySymbols(e);i<a.length;i++)n.indexOf(a[i])<0&&Object.prototype.propertyIsEnumerable.call(e,a[i])&&(t[a[i]]=e[a[i]])}return t}const h="invalid",b={defaultNs:"",observerOptions:{tagAttributes:{textarea:["placeholder"],input:["value","placeholder"],img:["alt"],"*":["aria-label","title"]},restrictedElements:["script","style"],highlightKeys:["Alt"],highlightColor:"rgb(255, 0, 0)",highlightWidth:5,inputPrefix:"%-%tolgee:",inputSuffix:"%-%",passToParent:["option","optgroup"]},observerType:"invisible",onFormatError:h},m=(...e)=>{let n={};return e.forEach((e=>{n=Object.assign(Object.assign(Object.assign({},n),e),{observerOptions:Object.assign(Object.assign({},n.observerOptions),null==e?void 0:e.observerOptions)})})),n},y=(e,n)=>{const t=m(b,null==n?void 0:n.initialOptions,e);return t.apiUrl=c(t.apiUrl),{initialOptions:t,activeNamespaces:(null==n?void 0:n.activeNamespaces)||new Map,language:null==n?void 0:n.language,pendingLanguage:null==n?void 0:n.language,isInitialLoading:!1,isRunning:!1}},O=(e,a,i,o,r,s)=>{const c={ui:void 0,observer:void 0},g={formatters:[],finalFormatter:void 0,observer:void 0,devBackend:void 0,backends:[],ui:void 0,languageDetector:void 0,languageStorage:void 0},u=async({keysAndDefaults:e,event:n})=>{var t;const a=e.map((({key:e,ns:n,defaultValue:t})=>({key:e,defaultValue:t,ns:o({key:e,ns:n}),translation:r({key:e,ns:n})})));null===(t=g.ui)||void 0===t||t.handleElementClick(a,n)},l=(e,n)=>{var t,a;return(null===(a=null===(t=g.observer)||void 0===t?void 0:t.highlight)||void 0===a?void 0:a.call(t,e,n))||{unhighlight(){}}},d=e=>{const n=r({key:e.key,ns:e.ns});return E(Object.assign(Object.assign({},e),{translation:n,formatEnabled:!0}))},f=e=>{c.observer=e},p=()=>Boolean(c.observer),b=e=>{e&&g.formatters.push(e)},m=e=>{g.finalFormatter=e},y=e=>{c.ui=e},O=()=>Boolean(c.ui),L=e=>{g.languageStorage=e},j=e=>{g.languageDetector=e},k=e=>{e&&g.backends.push(e)},w=e=>{g.devBackend=e},R=()=>g.devBackend;function E(n){var t,{formatEnabled:i}=n,o=v(n,["formatEnabled"]);const{key:r,translation:s,defaultValue:c,noWrap:u,params:l,orEmpty:d,ns:f}=o,p=s||c;let b=p||(d?"":r);const m=e(),y=i||!(null===(t=g.observer)||void 0===t?void 0:t.outputNotFormattable),O=e=>g.observer&&!u?g.observer.wrap({key:r,translation:e,defaultValue:c,params:l,ns:f}):e;b=O(b);try{if(p&&m&&y)for(const e of g.formatters)b=e.format({translation:b,language:m,params:l});g.finalFormatter&&p&&m&&y&&(b=g.finalFormatter.format({translation:b,language:m,params:l}))}catch(e){console.error(e);const n=("string"==typeof(L=e)?L:"string"==typeof(null==L?void 0:L.message)?L.message:void 0)||h,t=a().onFormatError,i=typeof t;b="string"===i?t:"function"===i?t(n,o):h,b=O(b)}var L;return b}return Object.freeze({addPlugin:function(e,n){n(e,Object.freeze({setFinalFormatter:m,addFormatter:b,setObserver:f,hasObserver:p,setUi:y,hasUi:O,setDevBackend:w,addBackend:k,setLanguageDetector:j,setLanguageStorage:L}))},formatTranslation:E,getDevBackend:R,getBackendRecord:({language:e,namespace:t})=>{for(const a of g.backends){const i=a.getRecord({language:e,namespace:t});if(n(i))return null==i?void 0:i.catch((e=>(console.error(e),{})));if(void 0!==i)return i}},getBackendDevRecord:({language:e,namespace:n})=>{var t;const{apiKey:i,apiUrl:o,projectId:r}=a();return null===(t=g.devBackend)||void 0===t?void 0:t.getRecord({apiKey:i,apiUrl:o,projectId:r,language:e,namespace:n})},getLanguageDetector:()=>g.languageDetector,getLanguageStorage:()=>g.languageStorage,getInitialLanguage:()=>{var e;const n=i(),a=null===(e=g.languageStorage)||void 0===e?void 0:e.getLanguage();return t(a,(e=>n&&!n.includes(e)||!e?(()=>{if(!g.languageDetector)return;const e=i();return g.languageDetector.getLanguage({availableLanguages:e})})():e))},setStoredLanguage:e=>{var n;null===(n=g.languageStorage)||void 0===n||n.setLanguage(e)},run:()=>{var e,n,t;if(!g.ui){const{apiKey:n,apiUrl:t,projectId:i}=a();g.ui=null===(e=c.ui)||void 0===e?void 0:e.call(c,{apiKey:n,apiUrl:t,projectId:i,highlight:l,changeTranslation:s})}g.observer||(g.observer=null===(n=c.observer)||void 0===n?void 0:n.call(c,{translate:d,onClick:u,options:a().observerOptions})),null===(t=g.observer)||void 0===t||t.run({mouseHighlight:!0})},stop:()=>{var e;g.ui=void 0,null===(e=g.observer)||void 0===e||e.stop()},retranslate:()=>{var e;null===(e=g.observer)||void 0===e||e.retranslate()},highlight:l,unwrap:e=>{var n;return g.observer?null===(n=g.observer)||void 0===n?void 0:n.unwrap(e):{text:e,keys:[]}},wrap:e=>{var n;return g.observer?null===(n=g.observer)||void 0===n?void 0:n.wrap(e):e.translation},hasDevBackend:function(){return Boolean(R())}})},L=(e,n,t)=>{let a=e;return Object.freeze({init:function(e){a=e},notify:function(){const e=n();a!==e&&t(e),a=e}})};const j=(e,...n)=>{let t,a={};return"object"==typeof e?a=e:(a.key=e,"string"==typeof n[0]?(a.defaultValue=n[0],t=n[1]):"object"==typeof n[0]&&(t=n[0])),t&&(a=Object.assign(Object.assign({},function(e){var{ns:n,noWrap:t,orEmpty:a,params:i}=e,o=v(e,["ns","noWrap","orEmpty","params"]);const r={ns:n,noWrap:t,orEmpty:a};return Object.assign(Object.assign({},r),{params:Object.assign({},o)})}(t)),a)),a},k=({options:e})=>{const i=((e,n)=>{let t=!0;function a(){return t}const i=g(a),o=g(a),r=g(a),s=g(a),c=g(a),l=g(a),d=g(a),f=u(a,e,n);return c.listen((()=>f.emit())),o.listen((()=>f.emit())),d.listen((({value:e})=>{f.emit([e.namespace],!0)})),Object.freeze({onPendingLanguageChange:i,onLanguageChange:o,onLoadingChange:r,onFetchingChange:s,onInitialLoaded:c,onRunningChange:l,onCacheChange:d,onUpdate:f,setEmmiterActive:function(e){t=e},on:(e,n)=>{switch(e){case"pendingLanguage":return i.listen(n);case"language":return o.listen(n);case"loading":return r.listen(n);case"fetching":return s.listen(n);case"initialLoad":return c.listen(n);case"running":return l.listen(n);case"cache":return d.listen(n);case"update":return f.listen(n)}}})})(m,k),l=L(!1,(()=>b.isFetching()),i.onFetchingChange.emit),f=L(!1,(()=>A()),i.onLoadingChange.emit),v=((e,n,t)=>{let a,i=y();function g(){return i.language||i.initialOptions.language}function u(){return Object.assign(Object.assign({},i.initialOptions),a)}return Object.freeze({init:function(e){i=y(e,i)},isRunning:function(){return i.isRunning},setRunning:function(e){i.isRunning!==e&&(i.isRunning=e,t.emit(e))},isInitialLoading:function(){return i.isInitialLoading},setInitialLoading:function(e){i.isInitialLoading=e},getLanguage:g,setLanguage:function(n){i.language!==n&&(i.language=n,e.emit(n))},getPendingLanguage:function(){return i.pendingLanguage||g()},setPendingLanguage:function(e){i.pendingLanguage!==e&&(i.pendingLanguage=e,n.emit(e))},getInitialOptions:u,addActiveNs:function(e){o(e).forEach((e=>{const n=i.activeNamespaces.get(e);void 0!==n?i.activeNamespaces.set(e,n+1):i.activeNamespaces.set(e,1)}))},removeActiveNs:function(e){o(e).forEach((e=>{const n=i.activeNamespaces.get(e);void 0!==n&&n>1?i.activeNamespaces.set(e,n-1):i.activeNamespaces.delete(e)}))},getRequiredNamespaces:function(){return s([...i.initialOptions.ns||[i.initialOptions.defaultNs],...o(i.initialOptions.fallbackNs),...i.activeNamespaces.keys()])},getFallbackLangs:function(e){const n=e||g();return n?s([n,...r(n,i.initialOptions.fallbackLanguage)]):[]},getFallbackNs:function(){return o(i.initialOptions.fallbackNs)},getDefaultNs:function(e){return void 0===e?i.initialOptions.defaultNs:e},getAvailableLanguages:function(){if(i.initialOptions.availableLanguages)return i.initialOptions.availableLanguages;if(i.initialOptions.staticData){const e=Object.keys(i.initialOptions.staticData).map((e=>d(e).language));return Array.from(new Set(e))}},withDefaultNs:function(e){return{namespace:void 0===e.namespace?u().defaultNs:e.namespace,language:e.language}},overrideCredentials:function(e){a=e?Object.assign(Object.assign({},e),{apiUrl:c(e.apiUrl)}):void 0}})})(i.onLanguageChange,i.onPendingLanguageChange,i.onRunningChange),h=O(v.getLanguage,v.getInitialOptions,v.getAvailableLanguages,(function({key:e,ns:n}){const t=v.getFallbackLangs(),a=w(n);return b.getTranslationNs(a,t,e)}),D,E),b=p(i.onCacheChange,h.getBackendRecord,h.getBackendDevRecord,v.withDefaultNs,v.isInitialLoading,l,f);function m(){return v.getFallbackNs()}function k(e){return v.getDefaultNs(e)}function w(e){return[...o(k(e)),...m()]}function R(e){return[...o(e||k()),...v.getRequiredNamespaces()]}function E(e,n,t){const a=v.withDefaultNs(e),i=b.getTranslation(a,n);return b.changeTranslation(a,n,t),{revert:()=>{b.changeTranslation(a,n,i)}}}function N(e){v.init(e),b.addStaticData(v.getInitialOptions().staticData)}function A(e){return b.isLoading(v.getLanguage(),e)}function F(){return Boolean(v.getInitialOptions().apiKey&&v.getInitialOptions().apiUrl)}function I(e,n){const a=function(e,n){const t=v.getFallbackLangs(e),a=R(n),i=[];return t.forEach((e=>{a.forEach((n=>{b.exists({language:e,namespace:n},!0)||i.push({language:e,namespace:n})}))})),i}(e,n);if(a.length)return t(T(a),(()=>{}))}function D({key:e,ns:n}){const t=w(n),a=v.getFallbackLangs();return b.getTranslationFallback(t,a,e)}function S(){const e=t(function(){if(v.getLanguage())return;if(!v.getInitialOptions().defaultLanguage)throw new Error(a("defaultLanguage"));const e=h.getInitialLanguage();return t(e,(e=>{const n=e||v.getInitialOptions().defaultLanguage;n&&v.setLanguage(n)}))}(),(()=>I()));if(n(e))return v.setInitialLoading(!0),l.notify(),f.notify(),Promise.resolve(e).then((()=>{v.setInitialLoading(!1),l.notify(),f.notify(),i.onInitialLoaded.emit()}));i.onInitialLoaded.emit()}function T(e){return b.loadRecords(e,F())}e&&N(e),i.onUpdate.listen((()=>{v.isRunning()&&h.retranslate()}));return Object.freeze(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},i),v),h),b),{init:N,changeLanguage:async function(e){v.getPendingLanguage()===e&&v.getLanguage()===e||(v.setPendingLanguage(e),v.isRunning()&&await I(e),e===v.getPendingLanguage()&&(v.setLanguage(e),h.setStoredLanguage(e)))},getTranslation:D,changeTranslation:E,addActiveNs:async function(e,n){n||v.addActiveNs(e),v.isRunning()&&await I(void 0,e)},loadRecords:T,loadRecord:async function(e){return(await T([e]))[0]},isLoading:A,isLoaded:function(e){const n=v.getLanguage();if(!n)return!1;const t=v.getFallbackLangs(n),a=R(e),i=[];return t.forEach((e=>{a.forEach((n=>{b.exists({language:e,namespace:n})||i.push({language:e,namespace:n})}))})),0===i.length},t:(...e)=>{const n=j(...e),t=D(n);return h.formatTranslation(Object.assign(Object.assign({},n),{translation:t}))},isDev:F,run:function(){let e;return(()=>{const e=h.getLanguageDetector()||h.getLanguageStorage();if(e&&!v.getAvailableLanguages())throw new Error(a("availableLanguages"));if(!v.getLanguage()&&!v.getInitialOptions().defaultLanguage)throw e?new Error(a("defaultLanguage")):new Error(a("language"))})(),v.isRunning()||(F()&&b.invalidate(),v.setRunning(!0),h.run(),e=S()),Promise.resolve(e)},stop:function(){v.isRunning()&&(h.stop(),v.setRunning(!1))}}))};class w extends Error{constructor(e,n,t){let a;a=0===e?"Empty parameter":1===e?"Unexpected character":"Unexpected end",super(`Tolgee parser: ${a} at ${n} in "${t}"`),this.code=e,this.index=n}}function R(e){return/\s/.test(e)}const E=new Set([2,1,0]),N=new Set(["{","}","'"]);function A(e,n){const[t,a]=function(e){let n=0,t="",a="",i="";const o=[],r=[];let s=0;function c(n){throw new w(n,s,e)}const g=()=>{o.push(t),t=""},u=()=>{""===a&&c(0),r.push(a),a=""};for(s=0;s<e.length;s++)switch(i=e[s],n){case 0:"'"===i?(t+=i,n=1):"{"===i?(g(),n=3):(t+=i,n=0);break;case 1:N.has(i)?(t=t.slice(0,-1)+i,n=2):(t+=i,n=0);break;case 2:"'"===i?n=0:(t+=i,n=2);break;case 3:"}"===i?(u(),n=0):R(i)?""!==a&&(u(),n=4):(/[0-9a-zA-Z_]/.test(i)||c(1),a+=i,n=3);break;case 4:"}"==i?n=0:R(i)?n=4:c(1)}return E.has(n)||c(2),g(),[o,r]}(e),i=[t[0]];for(let o=1;o<t.length;o++){const r=null==n?void 0:n[a[o-1]];if(void 0===r)throw new Error(`Missing parameter "${a[o-1]}" in "${e}"`);i.push(String(r)),i.push(t[o])}return i.join("")}e.FormatSimple=()=>(e,n)=>(n.setFinalFormatter({format:({translation:e,params:n})=>A(e,n)}),e),e.TolgeeCore=()=>{const e={plugins:[],options:{}},n=Object.freeze({use:t=>(e.plugins.push(t),n),updateDefaults:t=>(e.options=m(e.options,t),n),init(n){const t=(e=>{const n=k({options:e}),t=e=>{const t=n.isRunning();t&&n.stop(),e(),t&&n.run()},a=Object.freeze({on:n.on,onNsUpdate:n.onUpdate.listenSome,setEmmiterActive:n.setEmmiterActive,getLanguage:n.getLanguage,getPendingLanguage:n.getPendingLanguage,changeLanguage:n.changeLanguage,changeTranslation:n.changeTranslation,addActiveNs:n.addActiveNs,removeActiveNs:n.removeActiveNs,loadRecords:n.loadRecords,loadRecord:n.loadRecord,addStaticData:n.addStaticData,getRecord:n.getRecord,getAllRecords:n.getAllRecords,isLoaded:n.isLoaded,isInitialLoading:n.isInitialLoading,isLoading:n.isLoading,isFetching:n.isFetching,isRunning:n.isRunning,run:n.run,stop:n.stop,t:n.t,highlight:n.highlight,getInitialOptions:n.getInitialOptions,isDev:n.isDev,wrap:n.wrap,unwrap:n.unwrap,overrideCredentials(e){t((()=>n.overrideCredentials(e)))},addPlugin(e){e&&t((()=>n.addPlugin(a,e)))},updateOptions(e){e&&t((()=>n.init(e)))}});return a})(m(e.options,n));return e.plugins.forEach(t.addPlugin),t}});return n},e.getFallback=i,e.getFallbackArray=o,e.getTranslateProps=j,Object.defineProperty(e,"__esModule",{value:!0})}));
//# sourceMappingURL=tolgee.umd.min.js.map

@@ -1,17 +0,18 @@

import { CacheDescriptor, CacheDescriptorInternal, CacheDescriptorWithKey, EventEmitterType, FallbackNSTranslation, Options, TranslationsFlat, TranslationValue, TreeTranslationsData, BackendGetRecord, BackendGetDevRecord } from '../../types';
import { CacheDescriptor, CacheDescriptorInternal, CacheDescriptorWithKey, NsFallback, TranslationsFlat, TranslationValue, TreeTranslationsData, BackendGetRecord, BackendGetDevRecord } from '../../types';
import { EventEmitterInstance } from '../Events/EventEmitter';
import { TolgeeStaticData } from '../State/initState';
import { ValueObserverInstance } from '../ValueObserver';
export declare const Cache: (onCacheChange: EventEmitterType<CacheDescriptorWithKey>, backendGetRecord: BackendGetRecord, backendGetDevRecord: BackendGetDevRecord, withDefaultNs: (descriptor: CacheDescriptor) => CacheDescriptorInternal, isInitialLoading: () => boolean, fetchingObserver: ValueObserverInstance<boolean>, loadingObserver: ValueObserverInstance<boolean>) => Readonly<{
addStaticData: (data: Options['staticData']) => void;
export declare const Cache: (onCacheChange: EventEmitterInstance<CacheDescriptorWithKey>, backendGetRecord: BackendGetRecord, backendGetDevRecord: BackendGetDevRecord, withDefaultNs: (descriptor: CacheDescriptor) => CacheDescriptorInternal, isInitialLoading: () => boolean, fetchingObserver: ValueObserverInstance<boolean>, loadingObserver: ValueObserverInstance<boolean>) => Readonly<{
addStaticData: (data: TolgeeStaticData | undefined) => void;
invalidate: () => void;
addRecord: (descriptor: CacheDescriptorInternal, data: TreeTranslationsData) => void;
exists: (descriptor: CacheDescriptorInternal, strict?: boolean) => boolean;
getRecord: (descriptor: CacheDescriptorInternal) => TranslationsFlat | undefined;
getRecord: (descriptor: CacheDescriptor) => TranslationsFlat | undefined;
getTranslation: (descriptor: CacheDescriptorInternal, key: string) => TranslationValue;
getTranslationNs: (namespaces: string[], languages: string[], key: string) => string | string[];
getTranslationNs: (namespaces: string[], languages: string[], key: string) => string[];
getTranslationFallback: (namespaces: string[], languages: string[], key: string) => string | undefined;
changeTranslation: (descriptor: CacheDescriptorInternal, key: string, value: TranslationValue) => void;
isFetching: (ns?: FallbackNSTranslation) => boolean;
isLoading: (language: string | undefined, ns?: FallbackNSTranslation) => boolean;
isFetching: (ns?: NsFallback) => boolean;
isLoading: (language: string | undefined, ns?: NsFallback) => boolean;
loadRecords: (descriptors: CacheDescriptor[], isDev: boolean) => Promise<TranslationsFlat[]>;
clear: () => void;
getAllRecords: () => {

@@ -23,2 +24,2 @@ data: TranslationsFlat;

}>;
export declare type CacheType = ReturnType<typeof Cache>;
export declare type CacheInstance = ReturnType<typeof Cache>;

@@ -1,20 +0,17 @@

import type { EventServiceType } from '../Events/Events';
import { CacheDescriptor, FallbackNSTranslation, Options, TFnType, TranslatePropsInternal } from '../types';
import { CacheDescriptor, NsFallback, TolgeeOptions, TFnType, KeyAndNamespacesInternal } from '../types';
declare type StateServiceProps = {
events: EventServiceType;
options?: Partial<Options>;
options?: Partial<TolgeeOptions>;
};
export declare const Controller: ({ events, options }: StateServiceProps) => Readonly<{
init: (options: Partial<Options>) => void;
export declare const Controller: ({ options }: StateServiceProps) => Readonly<{
init: (options: Partial<TolgeeOptions>) => void;
changeLanguage: (language: string) => Promise<void>;
getTranslation: ({ key, ns, }: Pick<TranslatePropsInternal, 'key' | 'ns'>) => string | undefined;
getTranslation: ({ key, ns }: KeyAndNamespacesInternal) => string | undefined;
changeTranslation: (descriptor: CacheDescriptor, key: string, value: string) => {
revert: () => void;
};
addActiveNs: (ns: FallbackNSTranslation, forget?: boolean) => Promise<void>;
loadRequiredRecords: (lang?: string, ns?: FallbackNSTranslation) => void | Promise<void>;
addActiveNs: (ns: NsFallback, forget?: boolean) => Promise<void>;
loadRecords: (descriptors: CacheDescriptor[]) => Promise<import("../types").TranslationsFlat[]>;
loadRecord: (descriptor: CacheDescriptor) => Promise<import("../types").TranslationsFlat>;
isLoading: (ns?: FallbackNSTranslation) => boolean;
isLoaded: (ns?: FallbackNSTranslation) => boolean;
isLoading: (ns?: NsFallback) => boolean;
isLoaded: (ns?: NsFallback) => boolean;
t: TFnType<import("../types").DefaultParamType, string>;

@@ -24,13 +21,10 @@ isDev: () => boolean;

stop: () => void;
addStaticData: (data: {
[key: string]: import("../types").TreeTranslationsData | (() => Promise<import("../types").TreeTranslationsData>);
} | undefined) => void;
addStaticData: (data: import("./State/initState").TolgeeStaticData | undefined) => void;
invalidate: () => void;
addRecord: (descriptor: import("../types").CacheDescriptorInternal, data: import("../types").TreeTranslationsData) => void;
exists: (descriptor: import("../types").CacheDescriptorInternal, strict?: boolean) => boolean;
getRecord: (descriptor: import("../types").CacheDescriptorInternal) => import("../types").TranslationsFlat | undefined;
getTranslationNs: (namespaces: string[], languages: string[], key: string) => string | string[];
getRecord: (descriptor: CacheDescriptor) => import("../types").TranslationsFlat | undefined;
getTranslationNs: (namespaces: string[], languages: string[], key: string) => string[];
getTranslationFallback: (namespaces: string[], languages: string[], key: string) => string | undefined;
isFetching: (ns?: FallbackNSTranslation) => boolean;
clear: () => void;
isFetching: (ns?: NsFallback) => boolean;
getAllRecords: () => {

@@ -41,8 +35,60 @@ data: import("../types").TranslationsFlat;

}[];
setFinalFormatter: (formatter: import("../types").FinalFormatterInterface | undefined) => void;
addFormatter: (formatter: import("../types").FormatterInterface | undefined) => void;
formatTranslation: ({ key, translation, defaultValue, noWrap, params, orEmpty, ns, formatEnabled, }: {
addPlugin: (tolgeeInstance: Readonly<{
on: import("../types").TolgeeOn<keyof import("../types").EventType>;
onNsUpdate: (handler: import("../types").Listener<undefined>) => import("../types").SubscriptionSelective;
setEmmiterActive: (active: boolean) => void;
getLanguage: () => string | undefined;
getPendingLanguage: () => string | undefined;
changeLanguage: (language: string) => Promise<void>;
changeTranslation: (descriptor: CacheDescriptor, key: string, value: string) => {
revert: () => void;
};
addActiveNs: (ns: NsFallback, forget?: boolean) => Promise<void>;
removeActiveNs: (ns: NsFallback) => void;
loadRecords: (descriptors: CacheDescriptor[]) => Promise<import("../types").TranslationsFlat[]>;
loadRecord: (descriptor: CacheDescriptor) => Promise<import("../types").TranslationsFlat>;
addStaticData: (data: import("./State/initState").TolgeeStaticData | undefined) => void;
getRecord: (descriptor: CacheDescriptor) => import("../types").TranslationsFlat | undefined;
getAllRecords: () => {
data: import("../types").TranslationsFlat;
language: string;
namespace: string;
}[];
isLoaded: (ns?: NsFallback) => boolean;
isInitialLoading: () => boolean;
isLoading: (ns?: NsFallback) => boolean;
isFetching: (ns?: NsFallback) => boolean;
isRunning: () => boolean;
run: () => Promise<void | undefined>;
stop: () => void;
t: TFnType<import("../types").DefaultParamType, string>;
highlight: import("../types").HighlightInterface;
getInitialOptions: () => {
apiUrl?: string | undefined;
apiKey?: string | undefined;
projectId?: string | number | undefined;
language?: string | undefined;
defaultLanguage?: string | undefined;
availableLanguages?: string[] | undefined;
fallbackLanguage?: import("../types").FallbackLanguageOption;
ns?: string[] | undefined;
fallbackNs?: import("../types").FallbackGeneral;
defaultNs: string;
staticData?: import("./State/initState").TolgeeStaticData | undefined;
observerType: "invisible" | "text";
observerOptions: import("./State/observerOptions").ObserverOptionsInternal;
onFormatError: import("../types").OnFormatError;
};
isDev: () => boolean;
wrap: (params: import("../types").WrapperWrapProps) => string | undefined;
unwrap: (text: string) => import("../types").Unwrapped;
overrideCredentials(credentials: import("../types").DevCredentials): void;
addPlugin(plugin: import("../types").TolgeePlugin | undefined): void;
updateOptions(options?: TolgeeOptions | undefined): void;
}>, plugin: import("../types").TolgeePlugin) => void;
formatTranslation: ({ formatEnabled, ...props }: {
key: string;
defaultValue?: string | undefined;
} & import("../types").TranslateOptions<import("../types").DefaultParamType> & {
params?: import("../types").TranslateParams<import("../types").DefaultParamType> | undefined;
} & import("../types").TranslateOptions & {
translation?: string | undefined;

@@ -52,21 +98,7 @@ } & {

}) => string;
setObserver: (observer: import("../types").ObserverInterface | undefined) => void;
getObserver: () => {
unwrap: (text: string) => import("../types").Unwrapped;
wrap: import("../types").WrapperWrapFunction;
retranslate: () => void;
stop: () => void;
run: (props: import("../types").ObserverRunProps) => void;
highlight: import("../types").HighlightInterface;
outputNotFormattable: boolean;
} | undefined;
setUi: (ui: import("../types").UiType | undefined) => void;
getUi: () => import("../types").UiConstructor | undefined;
addBackend: (backend: import("../types").BackendInterface | undefined) => void;
setDevBackend: (backend: import("../types").BackendDevInterface | undefined) => void;
getDevBackend: () => import("../types").BackendDevInterface | undefined;
getDevBackend: () => import("../types").BackendDevMiddleware | undefined;
getBackendRecord: import("../types").BackendGetRecord;
getBackendDevRecord: import("../types").BackendGetRecord;
setLanguageDetector: (detector: import("../types").LanguageDetectorInterface | undefined) => void;
setLanguageStorage: (storage: import("../types").LanguageStorageInterface | undefined) => void;
getLanguageDetector: () => import("../types").LanguageDetectorMiddleware | undefined;
getLanguageStorage: () => import("../types").LanguageStorageMiddleware | undefined;
getInitialLanguage: () => string | Promise<string | undefined> | Promise<string | Promise<string | undefined> | undefined> | undefined;

@@ -76,4 +108,5 @@ setStoredLanguage: (language: string) => void;

highlight: import("../types").HighlightInterface;
unwrap: (text: string) => import("../types").Unwrapped;
wrap: (params: import("../types").WrapperWrapProps) => string | undefined;
unwrap: (text: string) => import("../types").Unwrapped;
hasDevBackend: () => boolean;
isRunning: () => boolean;

@@ -84,15 +117,41 @@ setRunning: (value: boolean) => void;

getLanguage: () => string | undefined;
getLanguageOrFail: () => string;
setLanguage: (language: string) => void;
getPendingLanguage: () => string | undefined;
setPendingLanguage: (language: string) => void;
getInitialOptions: () => Options;
removeActiveNs: (ns: FallbackNSTranslation) => void;
getInitialOptions: () => {
apiUrl?: string | undefined;
apiKey?: string | undefined;
projectId?: string | number | undefined;
language?: string | undefined;
defaultLanguage?: string | undefined;
availableLanguages?: string[] | undefined;
fallbackLanguage?: import("../types").FallbackLanguageOption;
ns?: string[] | undefined;
fallbackNs?: import("../types").FallbackGeneral;
defaultNs: string;
staticData?: import("./State/initState").TolgeeStaticData | undefined;
observerType: "invisible" | "text";
observerOptions: import("./State/observerOptions").ObserverOptionsInternal;
onFormatError: import("../types").OnFormatError;
};
removeActiveNs: (ns: NsFallback) => void;
getRequiredNamespaces: () => string[];
getFallbackLangs: (lang?: string | undefined) => string[];
getFallbackNamespaces: () => string[];
getFallbackNs: () => string[];
getDefaultNs: (ns?: string | undefined) => string;
getAvailableLanguages: () => string[] | undefined;
withDefaultNs: (descriptor: CacheDescriptor) => import("../types").CacheDescriptorInternal;
overrideCredentials: (credentials: import("../types").DevCredentials) => void;
onPendingLanguageChange: import("./Events/EventEmitter").EventEmitterInstance<string>;
onLanguageChange: import("./Events/EventEmitter").EventEmitterInstance<string>;
onLoadingChange: import("./Events/EventEmitter").EventEmitterInstance<boolean>;
onFetchingChange: import("./Events/EventEmitter").EventEmitterInstance<boolean>;
onInitialLoaded: import("./Events/EventEmitter").EventEmitterInstance<void>;
onRunningChange: import("./Events/EventEmitter").EventEmitterInstance<boolean>;
onCacheChange: import("./Events/EventEmitter").EventEmitterInstance<import("../types").CacheDescriptorWithKey>;
onUpdate: import("./Events/EventEmitterSelective").EventEmitterSelectiveInstance;
setEmmiterActive: (active: boolean) => void;
on: import("../types").TolgeeOn<keyof import("../types").EventType>;
}>;
export declare type StateServiceType = ReturnType<typeof Controller>;
export declare type ControllerInstance = ReturnType<typeof Controller>;
export {};

@@ -1,9 +0,9 @@

import { BackendDevInterface, BackendGetRecord, BackendInterface, FormatterInterface, ObserverInterface, TranslatePropsInternal, UiType, FinalFormatterInterface, HighlightInterface, UiConstructor, LanguageDetectorInterface, LanguageStorageInterface, Options, ChangeTranslationInterface, WrapperWrapProps, Unwrapped } from '../../types';
export declare const PluginService: (getLanguage: () => string | undefined, getInitialOptions: () => Options, getAvailableLanguages: () => string[] | undefined, getTranslationNs: (props: TranslatePropsInternal) => string[] | string, getTranslation: (props: TranslatePropsInternal) => string | undefined, changeTranslation: ChangeTranslationInterface) => Readonly<{
setFinalFormatter: (formatter: FinalFormatterInterface | undefined) => void;
addFormatter: (formatter: FormatterInterface | undefined) => void;
formatTranslation: ({ key, translation, defaultValue, noWrap, params, orEmpty, ns, formatEnabled, }: {
import { BackendDevMiddleware, BackendGetRecord, TranslatePropsInternal, HighlightInterface, LanguageDetectorMiddleware, LanguageStorageMiddleware, ChangeTranslationInterface, WrapperWrapProps, Unwrapped, KeyAndNamespacesInternal, TolgeePlugin, TolgeeInstance, TolgeeOptionsInternal } from '../../types';
export declare const Plugins: (getLanguage: () => string | undefined, getInitialOptions: () => TolgeeOptionsInternal, getAvailableLanguages: () => string[] | undefined, getTranslationNs: (props: KeyAndNamespacesInternal) => string[], getTranslation: (props: KeyAndNamespacesInternal) => string | undefined, changeTranslation: ChangeTranslationInterface) => Readonly<{
addPlugin: (tolgeeInstance: TolgeeInstance, plugin: TolgeePlugin) => void;
formatTranslation: ({ formatEnabled, ...props }: {
key: string;
defaultValue?: string | undefined;
} & import("../../types").TranslateOptions<import("../../types").DefaultParamType> & {
params?: import("../../types").TranslateParams<import("../../types").DefaultParamType> | undefined;
} & import("../../types").TranslateOptions & {
translation?: string | undefined;

@@ -13,21 +13,7 @@ } & {

}) => string;
setObserver: (observer: ObserverInterface | undefined) => void;
getObserver: () => {
unwrap: (text: string) => Unwrapped;
wrap: import("../../types").WrapperWrapFunction;
retranslate: () => void;
stop: () => void;
run: (props: import("../../types").ObserverRunProps) => void;
highlight: HighlightInterface;
outputNotFormattable: boolean;
} | undefined;
setUi: (ui: UiType | undefined) => void;
getUi: () => UiConstructor | undefined;
addBackend: (backend: BackendInterface | undefined) => void;
setDevBackend: (backend: BackendDevInterface | undefined) => void;
getDevBackend: () => BackendDevInterface | undefined;
getDevBackend: () => BackendDevMiddleware | undefined;
getBackendRecord: BackendGetRecord;
getBackendDevRecord: BackendGetRecord;
setLanguageDetector: (detector: LanguageDetectorInterface | undefined) => void;
setLanguageStorage: (storage: LanguageStorageInterface | undefined) => void;
getLanguageDetector: () => LanguageDetectorMiddleware | undefined;
getLanguageStorage: () => LanguageStorageMiddleware | undefined;
getInitialLanguage: () => string | Promise<string | undefined> | Promise<string | Promise<string | undefined> | undefined> | undefined;

@@ -39,5 +25,6 @@ setStoredLanguage: (language: string) => void;

highlight: HighlightInterface;
unwrap: (text: string) => Unwrapped;
wrap: (params: WrapperWrapProps) => string | undefined;
unwrap: (text: string) => Unwrapped;
hasDevBackend: () => boolean;
}>;
export declare type PluginServiceType = ReturnType<typeof PluginService>;
export declare type PluginsInstance = ReturnType<typeof Plugins>;

@@ -1,3 +0,8 @@

import { FallbackLanguageOption, FallbackNS, TreeTranslationsData } from '../../types';
export declare type Options = {
import { FallbackGeneral, FallbackLanguageOption, TreeTranslationsData, OnFormatError } from '../../types';
import { ObserverOptions, ObserverOptionsInternal } from './observerOptions';
export declare const DEFAULT_FORMAT_ERROR = "invalid";
export declare type TolgeeStaticData = {
[key: string]: TreeTranslationsData | (() => Promise<TreeTranslationsData>);
};
export declare type TolgeeOptionsInternal = {
/**

@@ -7,6 +12,15 @@ * Initial language

language?: string;
/**
* Tolgee instance url (e.g. https://app.tolgee.io)
*/
apiUrl?: string;
/**
* Project API key (PAK) or Personal Access Token (PAT)
*/
apiKey?: string;
projectId?: number;
/**
* Project id is necessary if you are using PAT
*/
projectId?: number | string;
/**
* Used when auto detection is not available or is turned off

@@ -25,6 +39,2 @@ */

/**
* Store user language in localStorage (default: true)
*/
enableLanguageStore?: boolean;
/**
* Namespaces which should be always fetched

@@ -36,3 +46,3 @@ */

*/
fallbackNs?: FallbackNS;
fallbackNs?: FallbackGeneral;
/**

@@ -43,11 +53,31 @@ * Default namespace when no namespace defined (default: '')

/**
* Prefix used for fetching languages (default: 'i18n/')
* These data go directly to cache or you can specify async
* function which will be used to get the data. Use `:` to add namespace:
*
* ```ts
* {
* 'locale': <translations | async function>
* 'locale:namespace': <translations | async function>
* }
* ```
*/
filesUrlPrefix: string;
staticData?: {
[key: string]: TreeTranslationsData | (() => Promise<TreeTranslationsData>);
};
staticData?: TolgeeStaticData;
/**
* Switches between invisible and text observer. (Default: invisible)
*/
observerType: 'invisible' | 'text';
/**
* Observer options object.
*/
observerOptions: ObserverOptionsInternal;
/**
* Define what to display in case of formatting error. (Default: 'invalid')
*/
onFormatError: OnFormatError;
};
export declare type TolgeeOptions = Partial<Omit<TolgeeOptionsInternal, 'observerOptions'>> & {
observerOptions?: ObserverOptions;
};
export declare type State = {
initialOptions: Options;
initialOptions: TolgeeOptionsInternal;
activeNamespaces: Map<string, number>;

@@ -59,2 +89,3 @@ language: string | undefined;

};
export declare const initState: (options?: Partial<Options>, previousState?: State) => State;
export declare const combineOptions: <T extends TolgeeOptions>(...states: (T | undefined)[]) => T;
export declare const initState: (options?: Partial<TolgeeOptions>, previousState?: State) => State;

@@ -1,5 +0,6 @@

import { CacheDescriptor, CacheDescriptorInternal, EventEmitterType, FallbackNSTranslation } from '../../types';
import { Options } from './initState';
export declare const State: (onLanguageChange: EventEmitterType<string>, onPendingLanguageChange: EventEmitterType<string>, onRunningChange: EventEmitterType<boolean>) => Readonly<{
init: (options?: Partial<Options>) => void;
import { CacheDescriptor, CacheDescriptorInternal, DevCredentials, NsFallback, NsType } from '../../types';
import { EventEmitterInstance } from '../Events/EventEmitter';
import { TolgeeOptions } from './initState';
export declare const State: (onLanguageChange: EventEmitterInstance<string>, onPendingLanguageChange: EventEmitterInstance<string>, onRunningChange: EventEmitterInstance<boolean>) => Readonly<{
init: (options?: Partial<TolgeeOptions>) => void;
isRunning: () => boolean;

@@ -10,14 +11,31 @@ setRunning: (value: boolean) => void;

getLanguage: () => string | undefined;
getLanguageOrFail: () => string;
setLanguage: (language: string) => void;
getPendingLanguage: () => string | undefined;
setPendingLanguage: (language: string) => void;
getInitialOptions: () => Options;
addActiveNs: (ns: FallbackNSTranslation) => void;
removeActiveNs: (ns: FallbackNSTranslation) => void;
getInitialOptions: () => {
apiUrl?: string | undefined;
apiKey?: string | undefined;
projectId?: string | number | undefined;
language?: string | undefined;
defaultLanguage?: string | undefined;
availableLanguages?: string[] | undefined;
fallbackLanguage?: import("../../types").FallbackLanguageOption;
ns?: string[] | undefined;
fallbackNs?: import("../../types").FallbackGeneral;
defaultNs: string;
staticData?: import("./initState").TolgeeStaticData | undefined;
observerType: "invisible" | "text";
observerOptions: import("./observerOptions").ObserverOptionsInternal;
onFormatError: import("../../types").OnFormatError;
};
addActiveNs: (ns: NsFallback) => void;
removeActiveNs: (ns: NsFallback) => void;
getRequiredNamespaces: () => string[];
getFallbackLangs: (lang?: string) => string[];
getFallbackNamespaces: () => string[];
getFallbackNs: () => string[];
getDefaultNs: (ns?: NsType) => string;
getAvailableLanguages: () => string[] | undefined;
withDefaultNs: (descriptor: CacheDescriptor) => CacheDescriptorInternal;
overrideCredentials: (credentials: DevCredentials) => void;
}>;
export declare type StateInstance = ReturnType<typeof State>;

@@ -1,5 +0,5 @@

export declare const ValueObserver: <T = any>(initialValue: T, valueGetter: () => T, handler: (value: T) => void) => Readonly<{
init: (value: T) => void;
notify: () => void;
}>;
export declare type ValueObserverInstance<T> = ReturnType<typeof ValueObserver<T>>;
export declare const ValueObserver: <T = any>(initialValue: T, valueGetter: () => T, handler: (value: T) => void) => ValueObserverInstance<T>;
export declare type ValueObserverInstance<T> = {
readonly init: (value: T) => void;
readonly notify: () => void;
};

@@ -0,3 +1,11 @@

import { FallbackGeneral, FallbackLanguageOption } from './types';
export declare function isPromise(value: any): boolean;
export declare const valueOrPromise: <T, R>(value: T | Promise<T>, callback: (value: T) => R) => R | Promise<R>;
export declare const missingOptionError: (option: string) => string;
export declare function isObject(item: any): boolean;
export declare function getFallback(value: FallbackGeneral): string[] | undefined;
export declare function getFallbackArray(value: FallbackGeneral): string[];
export declare function getFallbackFromStruct(language: string, fallbackLanguage: FallbackLanguageOption): string[];
export declare function unique<T>(arr: T[]): T[];
export declare function sanitizeUrl(url: string | undefined): string | undefined;
export declare function getErrorMessage(error: any): string | undefined;

@@ -1,5 +0,5 @@

export { Tolgee } from './Tolgee';
export { RESTRICTED_ASCENDANT_ATTRIBUTE, DEVTOOLS_ID, TOLGEE_ATTRIBUTE_NAME, TOLGEE_HIGHLIGHTER_CLASS, TOLGEE_WRAPPED_ONLY_DATA_ATTRIBUTE, } from './constants';
export { getFallback, getFallbackArray } from './helpers';
export { TolgeeCore } from './TolgeeCore';
export * from './types';
export { getTranslateParams } from './TranslateParams';
export { getFallback, getFallbackArray } from './Controller/State/helpers';
export { getTranslateProps } from './TranslateParams';
export { FormatSimple } from './FormatSimple/FormatSimple';
import { TFnType, TranslateProps } from './types';
export declare const getTranslateParams: TFnType<any, TranslateProps<any>>;
export declare const getTranslateProps: TFnType<any, TranslateProps<any>>;
{
"name": "@tolgee/core",
"version": "5.0.0-rc.4aa3be8.0",
"version": "5.0.0-rc.704ada9.0",
"description": "Library providing ability to translate messages directly in context of developed application.",
"main": "./dist/tolgee.cjs.js",
"module": "./dist/tolgee.esm.mjs",
"module": "./dist/tolgee.esm.js",
"types": "./lib/index.d.ts",

@@ -24,3 +24,3 @@ "repository": {

"require": "./dist/tolgee.cjs.js",
"import": "./dist/tolgee.esm.mjs"
"import": "./dist/tolgee.esm.js"
},

@@ -53,2 +53,3 @@ "directories": {

"concurrently": "7.3.0",
"intl-messageformat": "^9.9.1",
"jest": "^27.2.4",

@@ -63,3 +64,6 @@ "jest-fetch-mock": "^3.0.3",

},
"gitHead": "2d0148af0a6398057122d53edcf2ad2a5b90163a"
"publishConfig": {
"access": "public"
},
"gitHead": "74603d6afeaa994006817ee9defa1ad1b8b95d17"
}

@@ -1,3 +0,3 @@

import { Tolgee } from '../Tolgee';
import { BackendInterface, TolgeePlugin } from '../types';
import { TolgeeCore } from '../TolgeeCore';
import { BackendMiddleware, TolgeePlugin } from '../types';

@@ -15,3 +15,3 @@ const data = {

const backendNormal: BackendInterface = {
const backendNormal: BackendMiddleware = {
getRecord({ language, namespace = '' }) {

@@ -22,3 +22,3 @@ return data[language]?.[namespace];

const backendDev: BackendInterface = {
const backendDev: BackendMiddleware = {
getRecord() {

@@ -37,3 +37,3 @@ return Promise.resolve({ cancel: 'Dev' });

it('uses plugin to fetch', async () => {
const tolgee = Tolgee()
const tolgee = TolgeeCore()
.use(backendPlugin)

@@ -47,3 +47,3 @@ .init({

tolgee.stop();
tolgee.init({ apiUrl: 'asdfasdf', apiKey: 'test' });
tolgee.overrideCredentials({ apiUrl: 'asdfasdf', apiKey: 'test' });
await tolgee.run();

@@ -50,0 +50,0 @@ expect(tolgee.t({ key: 'cancel', ns: 'common' })).toEqual('Dev');

@@ -1,2 +0,2 @@

import { Tolgee } from '../index';
import { TolgeeCore } from '../index';

@@ -14,3 +14,3 @@ describe('using tolgee as client', () => {

const tolgee = Tolgee({
const tolgee = TolgeeCore().init({
language: 'en',

@@ -17,0 +17,0 @@ ns: ['common'],

@@ -1,6 +0,6 @@

import { Tolgee } from '../index';
import { TolgeeCore } from '../index';
describe('events', () => {
it('emits language change event', async () => {
const tolgee = Tolgee({ language: 'en' });
const tolgee = TolgeeCore().init({ language: 'en' });
const handler = jest.fn((lang) => {});

@@ -13,3 +13,3 @@ tolgee.on('language', handler);

it('correctly emits translation change listeners', async () => {
const tolgee = Tolgee({
const tolgee = TolgeeCore().init({
language: 'en',

@@ -21,7 +21,7 @@ staticData: {

});
const helloHandler = jest.fn((data) => {});
const languageHandler = jest.fn((data) => {});
const helloHandler = jest.fn(() => {});
const languageHandler = jest.fn(() => {});
tolgee.onKeyUpdate(helloHandler).subscribeKey({ key: 'hello' });
tolgee.onKeyUpdate(languageHandler).subscribeKey({ key: 'language' });
tolgee.onNsUpdate(helloHandler);
tolgee.onNsUpdate(languageHandler);

@@ -35,2 +35,27 @@ tolgee.changeTranslation({ language: 'es' }, 'hello', 'Světe');

});
it('stop emitting when turned off', async () => {
const tolgee = TolgeeCore().init({
language: 'en',
staticData: {
en: { hello: 'World', language: 'English' },
es: { hello: 'Mundo', language: 'Spanish' },
},
});
const eventHandler = jest.fn(() => {});
tolgee.on('language', eventHandler);
tolgee.on('pendingLanguage', eventHandler);
await tolgee.changeLanguage('es');
expect(eventHandler).toBeCalledTimes(2);
tolgee.setEmmiterActive(false);
await tolgee.changeLanguage('en');
expect(eventHandler).toBeCalledTimes(2);
tolgee.setEmmiterActive(true);
await tolgee.changeLanguage('es');
expect(eventHandler).toBeCalledTimes(4);
});
});

@@ -1,2 +0,2 @@

import { Tolgee } from '../index';
import { TolgeeCore } from '../index';

@@ -14,3 +14,3 @@ describe('initialization behavior', () => {

const tolgee = Tolgee({
const tolgee = TolgeeCore().init({
language: 'en',

@@ -52,3 +52,3 @@ ns: ['common'],

it("won't start loading when nothing to load", async () => {
const tolgee = Tolgee({
const tolgee = TolgeeCore().init({
language: 'en',

@@ -75,2 +75,14 @@ staticData: {

});
it('emits keyUpdate on initialLoad', async () => {
const tolgee = TolgeeCore().init({
language: 'en',
staticData: { en: { hello: 'world' } },
});
const onKeyChange = jest.fn();
tolgee.on('update', onKeyChange);
expect(onKeyChange).toBeCalledTimes(0);
await tolgee.run();
expect(onKeyChange).toBeCalledTimes(1);
});
});

@@ -1,2 +0,2 @@

import { Tolgee, TolgeePlugin, TolgeeInstance } from '../index';
import { TolgeeCore, TolgeePlugin, TolgeeInstance } from '../index';

@@ -22,3 +22,3 @@ const DetectionPlugin =

it('will detect language without loading', async () => {
tolgee = Tolgee()
tolgee = TolgeeCore()
.use(DetectionPlugin('en'))

@@ -47,3 +47,3 @@ .init({

it('will detect language async', async () => {
tolgee = Tolgee()
tolgee = TolgeeCore()
.use(DetectionPlugin(Promise.resolve('en')))

@@ -74,3 +74,3 @@ .init({

it('will fallback correctly', async () => {
tolgee = Tolgee()
tolgee = TolgeeCore()
.use(DetectionPlugin(Promise.resolve(undefined)))

@@ -91,3 +91,3 @@ .init({

it('will return key before language is loaded', async () => {
tolgee = Tolgee()
tolgee = TolgeeCore()
.use(DetectionPlugin(Promise.resolve('en')))

@@ -109,3 +109,3 @@ .init({

it('will throw error when no avaliableLanguages are set', () => {
tolgee = Tolgee().use(DetectionPlugin('en')).init({
tolgee = TolgeeCore().use(DetectionPlugin('en')).init({
defaultLanguage: 'es',

@@ -118,3 +118,3 @@ });

it('will throw error when no defaultLanguage specified', () => {
tolgee = Tolgee()
tolgee = TolgeeCore()
.use(DetectionPlugin('en'))

@@ -127,4 +127,10 @@ .init({

expect(() => tolgee.run()).toThrow();
expect(() => tolgee.run()).toThrow(/'defaultLanguage'/);
});
it('will throw error when no available languages specified', () => {
tolgee = TolgeeCore().use(DetectionPlugin('en')).init({});
expect(() => tolgee.run()).toThrow(/'availableLanguages'/);
});
});

@@ -1,2 +0,2 @@

import { Tolgee, TreeTranslationsData } from '../index';
import { TolgeeCore, TreeTranslationsData } from '../index';
import { resolvablePromise } from './testTools';

@@ -6,3 +6,3 @@

it('changes language', async () => {
const tolgee = Tolgee({ language: 'en' });
const tolgee = TolgeeCore().init({ language: 'en' });
expect(tolgee.getLanguage()).toEqual('en');

@@ -14,3 +14,3 @@ await tolgee.changeLanguage('es');

it('returns correct translation', async () => {
const tolgee = Tolgee({
const tolgee = TolgeeCore().init({
language: 'en',

@@ -29,3 +29,3 @@ staticData: { en: { hello: 'World' }, es: { hello: 'Mundo' } },

const [promiseEs, resolveEs] = resolvablePromise<TreeTranslationsData>();
const tolgee = Tolgee({
const tolgee = TolgeeCore().init({
language: 'en',

@@ -59,3 +59,3 @@ staticData: {

const tolgee = Tolgee({
const tolgee = TolgeeCore().init({
language: 'es',

@@ -102,3 +102,3 @@ staticData: {

it('will fallback to default value', () => {
const tolgee = Tolgee({
const tolgee = TolgeeCore().init({
defaultLanguage: 'en',

@@ -111,2 +111,26 @@ });

});
it('will throw error when no language specified', () => {
const tolgee = TolgeeCore().init({});
expect(() => tolgee.run()).toThrow(/'language'/);
});
it('loads fallback languages and namespaces', async () => {
const loadNs = jest.fn(() => Promise.resolve(undefined as any));
const tolgee = TolgeeCore().init({
language: 'en',
fallbackNs: ['fallback'],
staticData: {
en: loadNs,
'en:fallback': loadNs,
cs: loadNs,
'cs:fallback': loadNs,
},
});
tolgee.run();
expect(loadNs).toBeCalledTimes(2);
await tolgee.changeLanguage('cs');
expect(loadNs).toBeCalledTimes(4);
});
});

@@ -1,2 +0,2 @@

import { Tolgee, TolgeePlugin, TolgeeInstance } from '../index';
import { TolgeeCore, TolgeePlugin, TolgeeInstance } from '../index';

@@ -25,3 +25,3 @@ describe('language storage plugin', () => {

it('will restore language without loading', async () => {
tolgee = Tolgee()
tolgee = TolgeeCore()
.use(StoragePlugin('en'))

@@ -50,3 +50,3 @@ .init({

it('will restore language async', async () => {
tolgee = Tolgee()
tolgee = TolgeeCore()
.use(StoragePlugin(Promise.resolve('en')))

@@ -77,3 +77,3 @@ .init({

it('will fallback correctly', async () => {
tolgee = Tolgee()
tolgee = TolgeeCore()
.use(StoragePlugin(Promise.resolve(undefined)))

@@ -94,3 +94,3 @@ .init({

it('will return key before language is loaded', async () => {
tolgee = Tolgee()
tolgee = TolgeeCore()
.use(StoragePlugin(Promise.resolve('en')))

@@ -112,3 +112,3 @@ .init({

it('will store language value on language change', async () => {
tolgee = Tolgee()
tolgee = TolgeeCore()
.use(StoragePlugin(Promise.resolve('en')))

@@ -130,3 +130,3 @@ .init({

it('will ignore invalid values', () => {
tolgee = Tolgee()
tolgee = TolgeeCore()
.use(StoragePlugin('eq'))

@@ -144,9 +144,8 @@ .init({

it('will return invalid value if no available languages', () => {
tolgee = Tolgee().use(StoragePlugin('eq')).init({
it('will throw an error when no available languages are specified', () => {
tolgee = TolgeeCore().use(StoragePlugin('eq')).init({
defaultLanguage: 'es',
});
tolgee.run();
expect(tolgee.getLanguage()).toEqual('eq');
expect(() => tolgee.run()).toThrowError('availableLanguages');
});
});

@@ -1,2 +0,2 @@

import { Tolgee, TreeTranslationsData } from '../index';
import { TolgeeCore, TreeTranslationsData } from '../index';
import { resolvablePromise } from './testTools';

@@ -10,3 +10,3 @@

const onFetchingHandler = jest.fn(() => {});
const tolgee = Tolgee({
const tolgee = TolgeeCore().init({
language: 'en',

@@ -13,0 +13,0 @@ staticData: {

@@ -1,2 +0,2 @@

import { Tolgee } from '../index';
import { TolgeeCore } from '../index';

@@ -11,5 +11,6 @@ const tolgeeWithNamespaces = () => {

return Tolgee({
return TolgeeCore().init({
language: 'en',
ns: ['common'],
defaultNs: 'common',
staticData: {

@@ -26,3 +27,3 @@ 'en:common': promiseEnCommon,

it('returns correct translation from namespace', () => {
const tolgee = Tolgee({
const tolgee = TolgeeCore().init({
language: 'en',

@@ -40,3 +41,3 @@ staticData: {

it('uses defaultNs', async () => {
const tolgee = Tolgee({
const tolgee = TolgeeCore().init({
language: 'en',

@@ -82,5 +83,5 @@ defaultNs: 'common',

const tolgee = tolgeeWithNamespaces();
await tolgee.run();
const handler = jest.fn();
tolgee.on('cache', handler);
await tolgee.run();

@@ -91,3 +92,3 @@ expect(tolgee.t({ key: 'cancel', ns: 'common' })).toEqual('Cancel');

await tolgee.addActiveNs('test');
expect(handler).toBeCalledTimes(1);
expect(handler).toBeCalledTimes(2);

@@ -99,3 +100,3 @@ expect(tolgee.t({ key: 'cancel', ns: 'common' })).toEqual('Cancel');

await tolgee.changeLanguage('es');
expect(handler).toBeCalledTimes(2);
expect(handler).toBeCalledTimes(3);

@@ -105,2 +106,24 @@ expect(tolgee.t({ key: 'cancel', ns: 'common' })).toEqual('Cancellar');

});
it('add active namespace with forget', async () => {
const tolgee = tolgeeWithNamespaces();
const handler = jest.fn();
tolgee.on('cache', handler);
await tolgee.run();
// test ns is not loaded
expect(tolgee.t({ key: 'test', ns: 'test' })).toEqual('test');
await tolgee.addActiveNs('test', true);
expect(handler).toBeCalledTimes(2);
// test ns is loaded
expect(tolgee.t({ key: 'test', ns: 'test' })).toEqual('Test');
await tolgee.changeLanguage('es');
expect(handler).toBeCalledTimes(3);
// test ns is not loaded for spanish
expect(tolgee.t({ key: 'test', ns: 'test' })).toEqual('test');
});
});

@@ -1,7 +0,7 @@

import { Tolgee } from '../Tolgee';
import { TolgeeCore } from '../TolgeeCore';
import {
FinalFormatterInterface,
FormatterInterface,
FormatterInterfaceFormatParams,
ObserverInterface,
FinalFormatterMiddleware,
FormatterMiddleware,
FormatterMiddlewareFormatParams,
ObserverMiddleware,
TolgeePlugin,

@@ -12,3 +12,3 @@ WrapperWrapFunction,

const testObserver =
(outputNotFormattable: boolean): ObserverInterface =>
(outputNotFormattable: boolean): ObserverMiddleware =>
() => {

@@ -39,4 +39,4 @@ const wrap: WrapperWrapFunction = ({ key, translation }) => {

const testFormatter1: FormatterInterface = {
format: ({ translation }: FormatterInterfaceFormatParams) => {
const testFormatter1: FormatterMiddleware = {
format: ({ translation }: FormatterMiddlewareFormatParams) => {
return `(1${translation})`;

@@ -46,4 +46,4 @@ },

const testFormatter2: FormatterInterface = {
format: ({ translation }: FormatterInterfaceFormatParams) => {
const testFormatter2: FormatterMiddleware = {
format: ({ translation }: FormatterMiddlewareFormatParams) => {
return `(2${translation})`;

@@ -53,4 +53,4 @@ },

const testFinalFormatter: FinalFormatterInterface = {
format: ({ translation }: FormatterInterfaceFormatParams) => {
const testFinalFormatter: FinalFormatterMiddleware = {
format: ({ translation }: FormatterMiddlewareFormatParams) => {
return { final: translation };

@@ -76,11 +76,11 @@ },

it('wraps and formats translation', () => {
const tolgee = Tolgee({
const tolgee = TolgeeCore().init({
language: 'en',
staticData: { en: { hello: 'world' } },
});
tolgee.use(observerPlugin(false));
tolgee.addPlugin(observerPlugin(false));
tolgee.run();
expect(tolgee.t({ key: 'hello' })).toEqual('hello|world');
tolgee.use(formattersPlugin);
tolgee.addPlugin(formattersPlugin);
expect(tolgee.t({ key: 'hello' })).toEqual({ final: '(2(1hello|world))' });

@@ -91,14 +91,25 @@ tolgee.stop();

it("won't format when observer doesn't return formattable text", () => {
const tolgee = Tolgee({
const tolgee = TolgeeCore().init({
language: 'en',
staticData: { en: { hello: 'world' } },
});
tolgee.use(observerPlugin(true));
tolgee.addPlugin(observerPlugin(true));
tolgee.run();
expect(tolgee.t({ key: 'hello' })).toEqual('hello|world');
tolgee.use(formattersPlugin);
tolgee.addPlugin(formattersPlugin);
expect(tolgee.t({ key: 'hello' })).toEqual('hello|world');
tolgee.stop();
});
it("won't wrap before run", () => {
const tolgee = TolgeeCore().init({
language: 'en',
staticData: { en: { hello: 'world' } },
});
tolgee.addPlugin(observerPlugin(false));
expect(tolgee.t({ key: 'hello' })).toEqual('world');
tolgee.run();
expect(tolgee.t({ key: 'hello' })).toEqual('hello|world');
});
});
import {
CacheAsyncRequests,
CacheDescriptor,
CacheDescriptorInternal,
CacheDescriptorWithKey,
EventEmitterType,
FallbackNSTranslation,
Options,
NsFallback,
TranslationsFlat,

@@ -15,3 +12,5 @@ TranslationValue,

} from '../../types';
import { getFallbackArray } from '../State/helpers';
import { getFallbackArray, unique } from '../../helpers';
import { EventEmitterInstance } from '../Events/EventEmitter';
import { TolgeeStaticData } from '../State/initState';
import { ValueObserverInstance } from '../ValueObserver';

@@ -21,2 +20,7 @@

type CacheAsyncRequests = Map<
string,
Promise<TreeTranslationsData | undefined> | undefined
>;
type CacheRecord = {

@@ -30,3 +34,3 @@ version: number;

export const Cache = (
onCacheChange: EventEmitterType<CacheDescriptorWithKey>,
onCacheChange: EventEmitterInstance<CacheDescriptorWithKey>,
backendGetRecord: BackendGetRecord,

@@ -41,6 +45,6 @@ backendGetDevRecord: BackendGetDevRecord,

const cache: StateCache = new Map();
let staticData: NonNullable<Options['staticData']> = {};
let staticData: NonNullable<TolgeeStaticData> = {};
let version = 0;
function addStaticData(data: Options['staticData']) {
function addStaticData(data: TolgeeStaticData | undefined) {
if (data) {

@@ -61,2 +65,3 @@ staticData = { ...staticData, ...data };

function invalidate() {
asyncRequests.clear();
version += 1;

@@ -68,3 +73,3 @@ }

data: TreeTranslationsData,
version: number
recordVersion: number
) {

@@ -74,3 +79,3 @@ const cacheKey = encodeCacheKey(descriptor);

data: flattenTranslations(data),
version: version,
version: recordVersion,
});

@@ -95,4 +100,4 @@ onCacheChange.emit(descriptor);

function getRecord(descriptor: CacheDescriptorInternal) {
return cache.get(encodeCacheKey(descriptor))?.data;
function getRecord(descriptor: CacheDescriptor) {
return cache.get(encodeCacheKey(withDefaultNs(descriptor)))?.data;
}

@@ -115,7 +120,7 @@

if (value !== undefined && value !== null) {
return namespace;
return [namespace];
}
}
}
return Array.from(new Set(namespaces));
return unique(namespaces);
}

@@ -151,7 +156,3 @@

function clear() {
cache.clear();
}
function isFetching(ns?: FallbackNSTranslation) {
function isFetching(ns?: NsFallback) {
if (isInitialLoading()) {

@@ -172,3 +173,3 @@ return true;

function isLoading(language: string | undefined, ns?: FallbackNSTranslation) {
function isLoading(language: string | undefined, ns?: NsFallback) {
const namespaces = getFallbackArray(ns);

@@ -191,3 +192,6 @@

function fetchNormal(keyObject: CacheDescriptorInternal) {
/**
* Fetches production data
*/
function fetchProd(keyObject: CacheDescriptorInternal) {
let dataPromise = undefined as

@@ -200,4 +204,2 @@ | Promise<TreeTranslationsData | undefined>

dataPromise = staticDataValue();
} else if (staticDataValue) {
dataPromise = Promise.resolve(staticDataValue);
}

@@ -210,6 +212,2 @@ }

if (!dataPromise) {
// return empty data, so we know it has already been attempted to fetch
dataPromise = Promise.resolve({});
}
return dataPromise;

@@ -226,4 +224,4 @@ }

console.warn(`Tolgee: Failed to fetch data from dev backend`);
// fallback to normal fetch if dev fails
return fetchNormal(keyObject);
// fallback to prod fetch if dev fails
return fetchProd(keyObject);
});

@@ -233,3 +231,3 @@ }

if (!dataPromise) {
dataPromise = fetchNormal(keyObject);
dataPromise = fetchProd(keyObject);
}

@@ -254,3 +252,4 @@

}
const dataPromise = fetchData(keyObject, isDev);
const dataPromise =
fetchData(keyObject, isDev) || Promise.resolve(undefined);
asyncRequests.set(cacheKey, dataPromise);

@@ -270,3 +269,7 @@ return {

withPromises.forEach((value, i) => {
if (value.new) {
const promiseChanged =
asyncRequests.get(value.cacheKey) !== value.promise;
// if promise has changed in between, it means cache been invalidated or
// new data are being fetched
if (value.new && !promiseChanged) {
asyncRequests.delete(value.cacheKey);

@@ -276,2 +279,5 @@ const data = results[i];

addRecord(value.keyObject, data);
} else if (!getRecord(value.keyObject)) {
// if no data exist, put empty object
addRecord(value.keyObject, {});
}

@@ -309,3 +315,2 @@ }

loadRecords,
clear,
getAllRecords,

@@ -315,2 +320,2 @@ });

export type CacheType = ReturnType<typeof Cache>;
export type CacheInstance = ReturnType<typeof Cache>;

@@ -13,7 +13,5 @@ import { CacheDescriptorInternal, TreeTranslationsData } from '../../types';

if (typeof value === 'object') {
Object.entries(flattenTranslations(value)).forEach(
([flatKey, flatValue]) => {
result.set(key + '.' + flatKey, flatValue);
}
);
flattenTranslations(value).forEach((flatValue, flatKey) => {
result.set(key + '.' + flatKey, flatValue);
});
return;

@@ -27,3 +25,5 @@ }

export const decodeCacheKey = (key: string): CacheDescriptorInternal => {
const [firstPart, secondPart] = key.split(':');
const [firstPart, ...rest] = key.split(':');
// if namespaces contains ":" it won't get lost
const secondPart = rest.join(':');
return { language: firstPart, namespace: secondPart || '' };

@@ -30,0 +30,0 @@ };

@@ -1,23 +0,24 @@

import type { EventServiceType } from '../Events/Events';
import { Events } from './Events/Events';
import {
CacheDescriptor,
FallbackNSTranslation,
Options,
NsFallback,
TolgeeOptions,
TFnType,
TranslatePropsInternal,
NsType,
KeyAndNamespacesInternal,
} from '../types';
import { Cache } from './Cache/Cache';
import { getFallbackArray } from './State/helpers';
import { PluginService } from './Plugins/Plugins';
import { getFallbackArray } from '../helpers';
import { Plugins } from './Plugins/Plugins';
import { ValueObserver } from './ValueObserver';
import { State } from './State/State';
import { isPromise, missingOptionError, valueOrPromise } from '../helpers';
import { getTranslateParams } from '../TranslateParams';
import { getTranslateProps } from '../TranslateParams';
type StateServiceProps = {
events: EventServiceType;
options?: Partial<Options>;
options?: Partial<TolgeeOptions>;
};
export const Controller = ({ events, options }: StateServiceProps) => {
export const Controller = ({ options }: StateServiceProps) => {
const events = Events(getFallbackNs, getDefaultNs);
const fetchingObserver = ValueObserver<boolean>(

@@ -40,3 +41,3 @@ false,

const pluginService = PluginService(
const pluginService = Plugins(
state.getLanguage,

@@ -60,9 +61,7 @@ state.getInitialOptions,

state.init(options);
cache.addStaticData(state.getInitialOptions().staticData);
if (isDev()) {
cache.invalidate();
if (options) {
init(options);
}
events.onKeyUpdate.listen(() => {
events.onUpdate.listen(() => {
if (state.isRunning()) {

@@ -73,9 +72,25 @@ pluginService.retranslate();

const t: TFnType = (...args) => {
// @ts-ignore
const params = getTranslateParams(...args);
const translation = getTranslation(params);
return pluginService.formatTranslation({ ...params, translation });
};
function getFallbackNs() {
return state.getFallbackNs();
}
function getDefaultNs(ns?: NsType) {
return state.getDefaultNs(ns);
}
// gets all namespaces where translation could be located
// takes (ns|default, fallback ns)
function getDefaultAndFallbackNs(ns?: NsType) {
return [...getFallbackArray(getDefaultNs(ns)), ...getFallbackNs()];
}
// gets all namespaces which need to be loaded
// takes (ns|default, initial ns, fallback ns, active ns)
function getRequiredNamespaces(ns: NsFallback) {
return [
...getFallbackArray(ns || getDefaultNs()),
...state.getRequiredNamespaces(),
];
}
function changeTranslation(

@@ -96,11 +111,8 @@ descriptor: CacheDescriptor,

function init(options: Partial<Options>) {
function init(options: Partial<TolgeeOptions>) {
state.init(options);
cache.addStaticData(state.getInitialOptions().staticData);
if (isDev()) {
cache.invalidate();
}
}
function isLoading(ns?: FallbackNSTranslation) {
function isLoading(ns?: NsFallback) {
return cache.isLoading(state.getLanguage()!, ns);

@@ -111,7 +123,7 @@ }

return Boolean(
state.getInitialOptions().apiKey && pluginService.getDevBackend()
state.getInitialOptions().apiKey && state.getInitialOptions().apiUrl
);
}
async function addActiveNs(ns: FallbackNSTranslation, forget?: boolean) {
async function addActiveNs(ns: NsFallback, forget?: boolean) {
if (!forget) {

@@ -125,6 +137,5 @@ state.addActiveNs(ns);

function getRequiredRecords(lang?: string, ns?: FallbackNSTranslation) {
function getRequiredRecords(lang?: string, ns?: NsFallback) {
const languages = state.getFallbackLangs(lang);
const namespaces =
ns !== undefined ? getFallbackArray(ns) : state.getRequiredNamespaces();
const namespaces = getRequiredNamespaces(ns);
const result: CacheDescriptor[] = [];

@@ -141,3 +152,3 @@ languages.forEach((language) => {

function isLoaded(ns?: FallbackNSTranslation) {
function isLoaded(ns?: NsFallback) {
const language = state.getLanguage();

@@ -148,4 +159,3 @@ if (!language) {

const languages = state.getFallbackLangs(language);
const namespaces =
ns !== undefined ? getFallbackArray(ns) : state.getRequiredNamespaces();
const namespaces = getRequiredNamespaces(ns);
const result: CacheDescriptor[] = [];

@@ -162,3 +172,3 @@ languages.forEach((language) => {

function loadRequiredRecords(lang?: string, ns?: FallbackNSTranslation) {
function loadRequiredRecords(lang?: string, ns?: NsFallback) {
const descriptors = getRequiredRecords(lang, ns);

@@ -191,20 +201,10 @@ if (descriptors.length) {

function getTranslationNs({
key,
ns,
}: Pick<TranslatePropsInternal, 'key' | 'ns'>) {
const namespaces = ns
? getFallbackArray(ns)
: state.getFallbackNamespaces();
function getTranslationNs({ key, ns }: KeyAndNamespacesInternal) {
const languages = state.getFallbackLangs();
const namespaces = getDefaultAndFallbackNs(ns);
return cache.getTranslationNs(namespaces, languages, key);
}
function getTranslation({
key,
ns,
}: Pick<TranslatePropsInternal, 'key' | 'ns'>) {
const namespaces = ns
? getFallbackArray(ns)
: state.getFallbackNamespaces();
function getTranslation({ key, ns }: KeyAndNamespacesInternal) {
const namespaces = getDefaultAndFallbackNs(ns);
const languages = state.getFallbackLangs();

@@ -217,3 +217,2 @@ return cache.getTranslationFallback(namespaces, languages, key);

// fail if there is no language
state.getLanguageOrFail();
return loadRequiredRecords();

@@ -262,5 +261,27 @@ });

const checkCorrectConfiguration = () => {
const languageComputable =
pluginService.getLanguageDetector() || pluginService.getLanguageStorage();
if (languageComputable) {
const availableLanguages = state.getAvailableLanguages();
if (!availableLanguages) {
throw new Error(missingOptionError('availableLanguages'));
}
}
if (!state.getLanguage() && !state.getInitialOptions().defaultLanguage) {
if (languageComputable) {
throw new Error(missingOptionError('defaultLanguage'));
} else {
throw new Error(missingOptionError('language'));
}
}
};
function run() {
let result: Promise<void> | undefined = undefined;
checkCorrectConfiguration();
if (!state.isRunning()) {
if (isDev()) {
cache.invalidate();
}
state.setRunning(true);

@@ -280,3 +301,11 @@ pluginService.run();

const t: TFnType = (...args) => {
// @ts-ignore
const params = getTranslateProps(...args);
const translation = getTranslation(params);
return pluginService.formatTranslation({ ...params, translation });
};
return Object.freeze({
...events,
...state,

@@ -290,3 +319,2 @@ ...pluginService,

addActiveNs,
loadRequiredRecords,
loadRecords,

@@ -303,2 +331,2 @@ loadRecord,

export type StateServiceType = ReturnType<typeof Controller>;
export type ControllerInstance = ReturnType<typeof Controller>;

@@ -1,86 +0,68 @@

import { isPromise, missingOptionError, valueOrPromise } from '../../helpers';
import { getErrorMessage, isPromise, valueOrPromise } from '../../helpers';
import {
BackendDevInterface,
BackendDevMiddleware,
BackendGetRecord,
BackendInterface,
FormatterInterface,
ObserverInterface,
BackendMiddleware,
FormatterMiddleware,
ObserverMiddleware,
TranslatePropsInternal,
TranslationOnClick,
UiInterface,
UiLibInterface,
UiType,
FinalFormatterInterface,
UiMiddleware,
FinalFormatterMiddleware,
HighlightInterface,
UiConstructor,
UiKeyOption,
LanguageDetectorInterface,
LanguageStorageInterface,
Options,
LanguageDetectorMiddleware,
LanguageStorageMiddleware,
ChangeTranslationInterface,
WrapperWrapProps,
Unwrapped,
KeyAndNamespacesInternal,
TolgeePlugin,
TolgeeInstance,
TolgeeOptionsInternal,
FormatErrorHandler,
} from '../../types';
import { getFallbackArray } from '../State/helpers';
import { DEFAULT_FORMAT_ERROR } from '../State/initState';
export const PluginService = (
export const Plugins = (
getLanguage: () => string | undefined,
getInitialOptions: () => Options,
getInitialOptions: () => TolgeeOptionsInternal,
getAvailableLanguages: () => string[] | undefined,
getTranslationNs: (props: TranslatePropsInternal) => string[] | string,
getTranslation: (props: TranslatePropsInternal) => string | undefined,
getTranslationNs: (props: KeyAndNamespacesInternal) => string[],
getTranslation: (props: KeyAndNamespacesInternal) => string | undefined,
changeTranslation: ChangeTranslationInterface
) => {
const plugins = {
ui: undefined as UiConstructor | undefined,
ui: undefined as UiMiddleware | undefined,
observer: undefined as ObserverMiddleware | undefined,
};
const instances = {
formatters: [] as FormatterInterface[],
finalFormatter: undefined as FinalFormatterInterface | undefined,
observer: undefined as ReturnType<ObserverInterface> | undefined,
devBackend: undefined as BackendDevInterface | undefined,
backends: [] as BackendInterface[],
ui: undefined as UiInterface | undefined,
languageDetector: undefined as LanguageDetectorInterface | undefined,
languageStorage: undefined as LanguageStorageInterface | undefined,
formatters: [] as FormatterMiddleware[],
finalFormatter: undefined as FinalFormatterMiddleware | undefined,
observer: undefined as ReturnType<ObserverMiddleware> | undefined,
devBackend: undefined as BackendDevMiddleware | undefined,
backends: [] as BackendMiddleware[],
ui: undefined as ReturnType<UiMiddleware> | undefined,
languageDetector: undefined as LanguageDetectorMiddleware | undefined,
languageStorage: undefined as LanguageStorageMiddleware | undefined,
};
const onClick: TranslationOnClick = async (event, { keysAndDefaults }) => {
const onClick: TranslationOnClick = async ({ keysAndDefaults, event }) => {
const withNs: UiKeyOption[] = keysAndDefaults.map(
({ key, ns, defaultValue }) => ({
key,
defaultValue,
ns: getFallbackArray(getTranslationNs({ key, ns, defaultValue })),
translation: getTranslation({
({ key, ns, defaultValue }) => {
return {
key,
ns,
}),
})
defaultValue,
ns: getTranslationNs({ key, ns }),
translation: getTranslation({
key,
ns,
}),
};
}
);
instances.ui?.handleElementClick(event, withNs);
instances.ui?.handleElementClick(withNs, event);
};
const run = () => {
instances.ui =
plugins.ui &&
new plugins.ui({
apiKey: getInitialOptions().apiKey!,
apiUrl: getInitialOptions().apiUrl!,
highlight,
changeTranslation,
});
instances.observer?.run({ mouseHighlight: Boolean(instances.ui) });
checkCorrectConfiguration();
};
const checkCorrectConfiguration = () => {
if (instances.languageDetector) {
const availableLanguages = getAvailableLanguages();
if (!availableLanguages) {
throw new Error(missingOptionError('availableLanguages'));
}
}
};
const stop = () => {

@@ -96,15 +78,18 @@ instances.ui = undefined;

const translate = (props: TranslatePropsInternal) => {
const translation = getTranslation(props);
const translation = getTranslation({
key: props.key,
ns: props.ns,
});
return formatTranslation({ ...props, translation, formatEnabled: true });
};
const setObserver = (observer: ObserverInterface | undefined) => {
instances.observer = observer?.({ translate, onClick });
const setObserver = (observer: ObserverMiddleware | undefined) => {
plugins.observer = observer;
};
const getObserver = () => {
return instances.observer;
const hasObserver = () => {
return Boolean(plugins.observer);
};
const addFormatter = (formatter: FormatterInterface | undefined) => {
const addFormatter = (formatter: FormatterMiddleware | undefined) => {
if (formatter) {

@@ -116,3 +101,3 @@ instances.formatters.push(formatter);

const setFinalFormatter = (
formatter: FinalFormatterInterface | undefined
formatter: FinalFormatterMiddleware | undefined
) => {

@@ -122,12 +107,12 @@ instances.finalFormatter = formatter;

const setUi = (ui: UiType | undefined) => {
plugins.ui = (ui as UiLibInterface)?.UI || ui;
const setUi = (ui: UiMiddleware | undefined) => {
plugins.ui = ui as UiMiddleware;
};
const getUi = () => {
return plugins.ui;
const hasUi = () => {
return Boolean(plugins.ui);
};
const setLanguageStorage = (
storage: LanguageStorageInterface | undefined
storage: LanguageStorageMiddleware | undefined
) => {

@@ -137,2 +122,6 @@ instances.languageStorage = storage;

const getLanguageStorage = () => {
return instances.languageStorage;
};
const setStoredLanguage = (language: string) => {

@@ -143,3 +132,3 @@ instances.languageStorage?.setLanguage(language);

const setLanguageDetector = (
detector: LanguageDetectorInterface | undefined
detector: LanguageDetectorMiddleware | undefined
) => {

@@ -149,2 +138,6 @@ instances.languageDetector = detector;

const getLanguageDetector = () => {
return instances.languageDetector;
};
const detectLanguage = () => {

@@ -177,3 +170,3 @@ if (!instances.languageDetector) {

const addBackend = (backend: BackendInterface | undefined) => {
const addBackend = (backend: BackendMiddleware | undefined) => {
if (backend) {

@@ -184,6 +177,27 @@ instances.backends.push(backend);

const setDevBackend = (backend: BackendDevInterface | undefined) => {
const setDevBackend = (backend: BackendDevMiddleware | undefined) => {
instances.devBackend = backend;
};
const run = () => {
if (!instances.ui) {
const { apiKey, apiUrl, projectId } = getInitialOptions();
instances.ui = plugins.ui?.({
apiKey: apiKey!,
apiUrl: apiUrl!,
projectId,
highlight,
changeTranslation,
});
}
if (!instances.observer) {
instances.observer = plugins.observer?.({
translate,
onClick,
options: getInitialOptions().observerOptions,
});
}
instances.observer?.run({ mouseHighlight: true });
};
const getDevBackend = () => {

@@ -194,5 +208,7 @@ return instances.devBackend;

const getBackendDevRecord: BackendGetRecord = ({ language, namespace }) => {
const { apiKey, apiUrl, projectId } = getInitialOptions();
return instances.devBackend?.getRecord({
apiKey: getInitialOptions().apiKey,
apiUrl: getInitialOptions().apiUrl,
apiKey,
apiUrl,
projectId,
language,

@@ -220,23 +236,37 @@ namespace,

const formatTranslation = ({
key,
translation,
defaultValue,
noWrap,
params,
orEmpty,
ns,
const unwrap = (text: string): Unwrapped => {
if (instances.observer) {
return instances.observer?.unwrap(text);
}
return { text, keys: [] };
};
const retranslate = () => {
instances.observer?.retranslate();
};
function addPlugin(tolgeeInstance: TolgeeInstance, plugin: TolgeePlugin) {
const pluginTools = Object.freeze({
setFinalFormatter,
addFormatter,
setObserver,
hasObserver,
setUi,
hasUi,
setDevBackend,
addBackend,
setLanguageDetector,
setLanguageStorage,
});
plugin(tolgeeInstance, pluginTools);
}
function formatTranslation({
formatEnabled,
}: TranslatePropsInternal & { formatEnabled?: boolean }) => {
...props
}: TranslatePropsInternal & { formatEnabled?: boolean }) {
const { key, translation, defaultValue, noWrap, params, orEmpty, ns } =
props;
const formattableTranslation = translation || defaultValue;
let result = formattableTranslation || (orEmpty ? '' : key);
if (instances.observer && !noWrap) {
result = instances.observer.wrap({
key,
translation: result,
defaultValue,
params,
ns,
});
}

@@ -246,6 +276,35 @@ const language = getLanguage();

formatEnabled || !instances.observer?.outputNotFormattable;
if (formattableTranslation && language && isFormatEnabled) {
for (const formatter of instances.formatters) {
result = formatter.format({
const wrap = (result: string) => {
if (instances.observer && !noWrap) {
return instances.observer.wrap({
key,
translation: result,
defaultValue,
params,
ns,
});
}
return result;
};
result = wrap(result);
try {
if (formattableTranslation && language && isFormatEnabled) {
for (const formatter of instances.formatters) {
result = formatter.format({
translation: result,
language,
params,
});
}
}
if (
instances.finalFormatter &&
formattableTranslation &&
language &&
isFormatEnabled
) {
result = instances.finalFormatter.format({
translation: result,
language,

@@ -255,19 +314,26 @@ params,

}
} catch (e: any) {
// eslint-disable-next-line no-console
console.error(e);
const errorMessage = getErrorMessage(e) || DEFAULT_FORMAT_ERROR;
const onFormatError = getInitialOptions().onFormatError;
const formatErrorType = typeof onFormatError;
if (formatErrorType === 'string') {
result = onFormatError as string;
} else if (formatErrorType === 'function') {
result = (onFormatError as FormatErrorHandler)(errorMessage, props);
} else {
result = DEFAULT_FORMAT_ERROR;
}
// wrap error message, so it's detectable
result = wrap(result);
}
if (
instances.finalFormatter &&
formattableTranslation &&
language &&
isFormatEnabled
) {
result = instances.finalFormatter.format({
translation: result,
language,
params,
});
}
return result;
};
}
function hasDevBackend() {
return Boolean(getDevBackend());
}
const wrap = (params: WrapperWrapProps) => {

@@ -280,28 +346,10 @@ if (instances.observer) {

const unwrap = (text: string): Unwrapped => {
if (instances.observer) {
return instances.observer?.unwrap(text);
}
return { text, keys: [] };
};
const retranslate = () => {
instances.observer?.retranslate();
};
return Object.freeze({
setFinalFormatter,
addFormatter,
addPlugin,
formatTranslation,
setObserver,
getObserver,
setUi,
getUi,
addBackend,
setDevBackend,
getDevBackend,
getBackendRecord,
getBackendDevRecord,
setLanguageDetector,
setLanguageStorage,
getLanguageDetector,
getLanguageStorage,
getInitialLanguage,

@@ -313,7 +361,8 @@ setStoredLanguage,

highlight,
unwrap,
wrap,
unwrap,
hasDevBackend,
});
};
export type PluginServiceType = ReturnType<typeof PluginService>;
export type PluginsInstance = ReturnType<typeof Plugins>;
import {
FallbackGeneral,
FallbackLanguageOption,
FallbackNS,
TreeTranslationsData,
OnFormatError,
} from '../../types';
import { sanitizeUrl } from '../../helpers';
import {
defaultObserverOptions,
ObserverOptions,
ObserverOptionsInternal,
} from './observerOptions';
export type Options = {
export const DEFAULT_FORMAT_ERROR = 'invalid';
export type TolgeeStaticData = {
[key: string]: TreeTranslationsData | (() => Promise<TreeTranslationsData>);
};
export type TolgeeOptionsInternal = {
/**

@@ -12,9 +25,23 @@ * Initial language

language?: string;
/**
* Tolgee instance url (e.g. https://app.tolgee.io)
*/
apiUrl?: string;
/**
* Project API key (PAK) or Personal Access Token (PAT)
*/
apiKey?: string;
projectId?: number;
/**
* Project id is necessary if you are using PAT
*/
projectId?: number | string;
/**
* Used when auto detection is not available or is turned off
*/
defaultLanguage?: string;
/**

@@ -25,2 +52,3 @@ * Languages which can be used for language detection

availableLanguages?: string[];
/**

@@ -30,14 +58,13 @@ * Language which is used when no translation is available for current one

fallbackLanguage?: FallbackLanguageOption;
/**
* Store user language in localStorage (default: true)
*/
enableLanguageStore?: boolean;
/**
* Namespaces which should be always fetched
*/
ns?: string[];
/**
* Namespaces to be used to find translation when no explicit namespace set.
*/
fallbackNs?: FallbackNS;
fallbackNs?: FallbackGeneral;
/**

@@ -47,13 +74,40 @@ * Default namespace when no namespace defined (default: '')

defaultNs: string;
/**
* Prefix used for fetching languages (default: 'i18n/')
* These data go directly to cache or you can specify async
* function which will be used to get the data. Use `:` to add namespace:
*
* ```ts
* {
* 'locale': <translations | async function>
* 'locale:namespace': <translations | async function>
* }
* ```
*/
filesUrlPrefix: string;
staticData?: {
[key: string]: TreeTranslationsData | (() => Promise<TreeTranslationsData>);
};
staticData?: TolgeeStaticData;
/**
* Switches between invisible and text observer. (Default: invisible)
*/
observerType: 'invisible' | 'text';
/**
* Observer options object.
*/
observerOptions: ObserverOptionsInternal;
/**
* Define what to display in case of formatting error. (Default: 'invalid')
*/
onFormatError: OnFormatError;
};
export type TolgeeOptions = Partial<
Omit<TolgeeOptionsInternal, 'observerOptions'>
> & {
observerOptions?: ObserverOptions;
};
export type State = {
initialOptions: Options;
initialOptions: TolgeeOptionsInternal;
activeNamespaces: Map<string, number>;

@@ -66,20 +120,38 @@ language: string | undefined;

const defaultValues: Options = {
enableLanguageStore: true,
const defaultValues: TolgeeOptionsInternal = {
defaultNs: '',
filesUrlPrefix: 'i18n/',
observerOptions: defaultObserverOptions,
observerType: 'invisible',
onFormatError: DEFAULT_FORMAT_ERROR,
};
export const combineOptions = <T extends TolgeeOptions>(
...states: (T | undefined)[]
) => {
let result = {} as T;
states.forEach((state) => {
result = {
...result,
...state,
observerOptions: {
...result.observerOptions,
...state?.observerOptions,
},
};
});
return result;
};
export const initState = (
options?: Partial<Options>,
options?: Partial<TolgeeOptions>,
previousState?: State
): State => {
const initialOptions = {
...defaultValues,
...previousState?.initialOptions,
...options,
};
const initialOptions = combineOptions(
defaultValues,
previousState?.initialOptions,
options
) as TolgeeOptionsInternal;
// remove extra '/' from url end
const apiUrl = initialOptions.apiUrl;
initialOptions.apiUrl = apiUrl ? apiUrl.replace(/\/+$/, '') : apiUrl;
initialOptions.apiUrl = sanitizeUrl(initialOptions.apiUrl);

@@ -86,0 +158,0 @@ return {

import {
CacheDescriptor,
CacheDescriptorInternal,
EventEmitterType,
FallbackNSTranslation,
DevCredentials,
NsFallback,
NsType,
} from '../../types';
import { decodeCacheKey } from '../Cache/helpers';
import { getFallbackArray, getFallbackFromStruct, unique } from './helpers';
import { initState, Options } from './initState';
import { EventEmitterInstance } from '../Events/EventEmitter';
import {
getFallbackArray,
getFallbackFromStruct,
sanitizeUrl,
unique,
} from '../../helpers';
import { initState, TolgeeOptions } from './initState';
export const State = (
onLanguageChange: EventEmitterType<string>,
onPendingLanguageChange: EventEmitterType<string>,
onRunningChange: EventEmitterType<boolean>
onLanguageChange: EventEmitterInstance<string>,
onPendingLanguageChange: EventEmitterInstance<string>,
onRunningChange: EventEmitterInstance<boolean>
) => {
let state = initState();
let devCredentials: DevCredentials = undefined;
function init(options?: Partial<Options>) {
function init(options?: Partial<TolgeeOptions>) {
state = initState(options, state);

@@ -45,10 +54,2 @@ }

function getLanguageOrFail() {
const language = state.language || state.initialOptions.language;
if (!language) {
throw new Error(`No language set`);
}
return language;
}
function setLanguage(language: string) {

@@ -73,6 +74,6 @@ if (state.language !== language) {

function getInitialOptions() {
return state.initialOptions;
return { ...state.initialOptions, ...devCredentials };
}
function addActiveNs(ns: FallbackNSTranslation) {
function addActiveNs(ns: NsFallback) {
const namespaces = getFallbackArray(ns);

@@ -89,3 +90,3 @@ namespaces.forEach((namespace) => {

function removeActiveNs(ns: FallbackNSTranslation) {
function removeActiveNs(ns: NsFallback) {
const namespaces = getFallbackArray(ns);

@@ -105,2 +106,3 @@ namespaces.forEach((namespace) => {

...(state.initialOptions.ns || [state.initialOptions.defaultNs]),
...getFallbackArray(state.initialOptions.fallbackNs),
...state.activeNamespaces.keys(),

@@ -121,9 +123,10 @@ ]);

function getFallbackNamespaces() {
const defaultNs = state.initialOptions.defaultNs;
const fallbackNs = state.initialOptions.fallbackNs;
const fallbackNamespaces = typeof defaultNs === 'string' ? [defaultNs] : [];
return unique([...fallbackNamespaces, ...getFallbackArray(fallbackNs)]);
function getFallbackNs() {
return getFallbackArray(state.initialOptions.fallbackNs);
}
function getDefaultNs(ns?: NsType) {
return ns === undefined ? state.initialOptions.defaultNs : ns;
}
function getAvailableLanguages() {

@@ -150,2 +153,13 @@ if (state.initialOptions.availableLanguages) {

function overrideCredentials(credentials: DevCredentials) {
if (credentials) {
devCredentials = {
...credentials,
apiUrl: sanitizeUrl(credentials.apiUrl),
};
} else {
devCredentials = undefined;
}
}
return Object.freeze({

@@ -158,3 +172,2 @@ init,

getLanguage,
getLanguageOrFail,
setLanguage,

@@ -168,6 +181,10 @@ getPendingLanguage,

getFallbackLangs,
getFallbackNamespaces,
getFallbackNs,
getDefaultNs,
getAvailableLanguages,
withDefaultNs,
overrideCredentials,
});
};
export type StateInstance = ReturnType<typeof State>;

@@ -5,3 +5,3 @@ export const ValueObserver = <T = any>(

handler: (value: T) => void
) => {
): ValueObserverInstance<T> => {
let previousValue: T = initialValue;

@@ -24,2 +24,5 @@ function init(value: T) {

export type ValueObserverInstance<T> = ReturnType<typeof ValueObserver<T>>;
export type ValueObserverInstance<T> = {
readonly init: (value: T) => void;
readonly notify: () => void;
};

@@ -0,1 +1,7 @@

import {
FallbackGeneral,
FallbackLanguageObject,
FallbackLanguageOption,
} from './types';
export function isPromise(value: any) {

@@ -18,1 +24,48 @@ return Boolean(value && typeof value.then === 'function');

`Tolgee: You need to specify '${option}' option`;
export function isObject(item: any) {
return typeof item === 'object' && !Array.isArray(item) && item !== null;
}
export function getFallback(value: FallbackGeneral): string[] | undefined {
if (typeof value === 'string') {
return [value];
}
if (Array.isArray(value)) {
return value;
}
return undefined;
}
export function getFallbackArray(value: FallbackGeneral): string[] {
return getFallback(value) || [];
}
export function getFallbackFromStruct(
language: string,
fallbackLanguage: FallbackLanguageOption
) {
if (isObject(fallbackLanguage)) {
return getFallbackArray(
(fallbackLanguage as FallbackLanguageObject)?.[language]
);
} else {
return getFallbackArray(fallbackLanguage as FallbackGeneral);
}
}
export function unique<T>(arr: T[]) {
return Array.from(new Set(arr));
}
export function sanitizeUrl(url: string | undefined) {
return url ? url.replace(/\/+$/, '') : url;
}
export function getErrorMessage(error: any): string | undefined {
if (typeof error === 'string') {
return error;
} else if (typeof error?.message === 'string') {
return error.message;
}
}

@@ -1,11 +0,5 @@

export { Tolgee } from './Tolgee';
export {
RESTRICTED_ASCENDANT_ATTRIBUTE,
DEVTOOLS_ID,
TOLGEE_ATTRIBUTE_NAME,
TOLGEE_HIGHLIGHTER_CLASS,
TOLGEE_WRAPPED_ONLY_DATA_ATTRIBUTE,
} from './constants';
export { getFallback, getFallbackArray } from './helpers';
export { TolgeeCore } from './TolgeeCore';
export * from './types';
export { getTranslateParams } from './TranslateParams';
export { getFallback, getFallbackArray } from './Controller/State/helpers';
export { getTranslateProps } from './TranslateParams';
export { FormatSimple } from './FormatSimple/FormatSimple';

@@ -1,2 +0,2 @@

import { getTranslateParams } from './TranslateParams';
import { getTranslateProps } from './TranslateParams';
import { TranslateProps } from './types';

@@ -8,10 +8,10 @@

noWrap: true,
ns: [],
ns: 'test',
orEmpty: true,
params: { yo: 'yo', ns: '(this is param not namespace)' },
params: { yo: 'yo' },
};
describe('getTranslateParams', () => {
describe('getTranslateProps', () => {
it('manages regular params', () => {
const result = getTranslateParams(testParams);
const result = getTranslateProps(testParams);
expect(result).toEqual(testParams);

@@ -21,3 +21,3 @@ });

it('manages key with default value', () => {
const result = getTranslateParams('test', 'Test');
const result = getTranslateProps('test', 'Test');
expect(result).toEqual({ key: 'test', defaultValue: 'Test' });

@@ -27,3 +27,3 @@ });

it('manages key with options', () => {
const result = getTranslateParams('test', { noWrap: true, yo: 'yo' });
const result = getTranslateProps('test', { noWrap: true, yo: 'yo' });
expect(result).toEqual({ key: 'test', noWrap: true, params: { yo: 'yo' } });

@@ -33,10 +33,7 @@ });

it('manages key default and options', () => {
const result = getTranslateParams('test', 'Test', {
const result = getTranslateProps('test', 'Test', {
noWrap: true,
ns: [],
ns: 'test',
orEmpty: true,
yo: 'yo',
params: {
ns: '(this is param not namespace)',
},
});

@@ -43,0 +40,0 @@ expect(result).toEqual(testParams);

@@ -14,16 +14,17 @@ import {

...rest
}: CombinedOptions<any>): Partial<TranslateProps> {
const options: Required<TranslateOptions<any>> = {
}: Partial<TranslateProps>): Partial<TranslateProps> {
const options: Required<TranslateOptions> = {
ns: ns!,
noWrap: noWrap!,
orEmpty: orEmpty!,
};
return {
...options,
params: {
...rest,
...params,
},
};
return options;
}
export const getTranslateParams: TFnType<any, TranslateProps<any>> = (
export const getTranslateProps: TFnType<any, TranslateProps<any>> = (
keyOrProps,

@@ -30,0 +31,0 @@ ...params

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet