/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-non-null-assertion */
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
/* eslint-disable @typescript-eslint/prefer-for-of */
// #region Imports
import { PureEventEmitter } from '@breadstone/mosaik-elements';
export var Translator;
(function (Translator) {
    Translator.DEFAULT_LANGUAGE = 'en';
    Translator.DEFAULT_LANGUAGE_RESOLVER = () => {
        Object.keys(localStorage).forEach((key) => {
            if (key.startsWith('language')) {
                return localStorage.getItem(key);
            }
            return Translator.DEFAULT_LANGUAGE;
        });
        return Translator.DEFAULT_LANGUAGE;
    };
})(Translator || (Translator = {}));
/**
 * A translator is used to translate keys into strings.
 *
 * @public
 */
export class TranslatorService {
    // #region Fields
    _languageChanged;
    _translations = {};
    _currentLanguage;
    // #endregion
    // #region Ctor
    constructor(defaultLangOrFn) {
        this._languageChanged = new PureEventEmitter();
        this._currentLanguage = (defaultLangOrFn instanceof Function
            ? defaultLangOrFn()
            : defaultLangOrFn) ?? Translator.DEFAULT_LANGUAGE;
    }
    // #endregion
    // #region Properties
    /**
     * Gets or sets the `currentLanguage` property.
     *
     * @public
     */
    get currentLanguage() {
        return this._currentLanguage;
    }
    set currentLanguage(value) {
        if (!this._translations[value]) {
            throw new Error(`No translations available for language: ${value}`);
        }
        this._currentLanguage = value;
        this._languageChanged.emit(value);
    }
    /**
     * Returns the `languageChanged` property.
     *
     * @public
     * @readonly
     */
    get languageChanged() {
        return this._languageChanged;
    }
    // #endregion
    // #region Methods
    /**
     * Adds the given translations for the given language.
     *
     * @public
     */
    addTranslations(lang, translations) {
        this._translations[lang] = translations;
    }
    /**
     * Translates the given key.
     *
     * @public
     */
    translate(key, ...args) {
        const language = this._currentLanguage;
        const languageDict = this._translations[language];
        const fallback = `### ${key} ###`;
        if (!languageDict) {
            console.warn(`[Translator] No translations available for language: ${language}`);
            return fallback;
        }
        let translation = this.getTranslation(key, languageDict);
        if (!translation) {
            console.warn(`[Translator] Translation not found for key: ${key}`);
            translation = fallback;
        }
        translation = args.length > 0
            ? this.format(translation, ...args)
            : translation;
        return translation;
    }
    /**
     * Gets the translation for the given key.
     * The splitter is used to split the key into parts. Aktually the noting is used as splitter.
     *
     * @private
     */
    getTranslation(key, translations, options = { splitter: '' }) {
        const keys = options.splitter
            ? key.split(options.splitter)
            : key;
        let currentTranslation = translations;
        if (options.splitter) {
            for (let i = 0; i < keys.length; i++) {
                if (typeof currentTranslation === 'string') {
                    return currentTranslation;
                }
                try {
                    if (currentTranslation) {
                        const translationKey = keys[i];
                        if (translationKey.length > 0) {
                            currentTranslation = currentTranslation[translationKey];
                        }
                    }
                }
                catch (error) {
                    currentTranslation = undefined;
                }
            }
        }
        else {
            currentTranslation = translations[key];
        }
        return typeof currentTranslation === 'string' ? currentTranslation : undefined;
    }
    /**
     * Formats the given string with the given arguments.
     *
     * @private
     */
    format(self, ...args) {
        const allArgs = new Array();
        args.forEach((x) => {
            if (Array.isArray(x)) {
                x.forEach((y) => {
                    allArgs.push(y);
                });
            }
            else {
                allArgs.push(x);
            }
        });
        return self.replace(/{(\d+)}/g, (match, index) => {
            if (allArgs[index] !== undefined) {
                return allArgs[index];
            }
            return match;
        });
    }
}
/**
 * @public
 */
export class TranslatorServiceLocator {
    // #region Fields
    static _current = null;
    // #endregion
    // #region Properties
    static get current() {
        if (!TranslatorServiceLocator.isSet()) {
            throw new Error('\'Translator\' not set.');
        }
        return TranslatorServiceLocator._current;
    }
    // #endregion
    // #region Methods
    static isSet() {
        return TranslatorServiceLocator._current !== null;
    }
    static set(current) {
        TranslatorServiceLocator._current = current;
    }
}
TranslatorServiceLocator.set(new TranslatorService());
//# sourceMappingURL=TranslatorService.js.map