import { __assign } from "tslib";
import { sprintf, vsprintf } from 'sprintf-js';
import Vue from 'vue';
/**
 * This package provides language and locales utilities.
 */
/**
 * French language code.
 */
export var FRENCH = 'fr';
/**
 * English language code.
 */
export var ENGLISH = 'en';
/**
 * Regex to parse and format messages.
 */
var FORMAT_REGEX = /{\d+}/g;
/**
 * String used as a special characters wrapper
 */
var SPECIAL_CHARACTER_PREFIXE = '_';
var SPECIAL_CHARACTER_SUFIXE = '_';
/**
 * Special characters must be represented as their unicode equivalent \u00xxxx
 */
export var SpecialCharacter;
(function (SpecialCharacter) {
    SpecialCharacter["NBSP"] = "160";
    SpecialCharacter["NBHYPHEN"] = "8209";
    SpecialCharacter["EMDASH"] = "8212";
    SpecialCharacter["ENDASH"] = "8211"; // en dash equivalent to unicode :\u002013, HTML entity : &#ndash; => (–)
})(SpecialCharacter || (SpecialCharacter = {}));
export var DebugMode;
(function (DebugMode) {
    DebugMode[DebugMode["Throw"] = 0] = "Throw";
    DebugMode[DebugMode["Warn"] = 1] = "Warn";
    DebugMode[DebugMode["Prod"] = 2] = "Prod";
})(DebugMode || (DebugMode = {}));
export var FormatMode;
(function (FormatMode) {
    FormatMode["Default"] = "";
    FormatMode["Vsprintf"] = "vsprintf";
    FormatMode["Sprintf"] = "sprintf";
})(FormatMode || (FormatMode = {}));
var Messages = /** @class */ (function () {
    function Messages(options) {
        this.options = options;
        this.curLang = ENGLISH;
        this.messages = {};
        this.specialCharacterDict = {};
        if (options) {
            if (options.curLang) {
                this.currentLang(options.curLang);
            }
            if (options.formatMode) {
                this.formatMode = options.formatMode;
            }
        }
        this.initSpecialCharactersDict();
    }
    /**
     * Set the application language globally
     *
     * @param lang The language, for example: 'en'
     */
    Messages.prototype.currentLang = function (lang) {
        if (lang) {
            this.curLang = lang;
            this.curLocale = this.getCurrentLocale();
        }
        return this.curLang;
    };
    /**
     * Get current locale
     */
    Messages.prototype.getCurrentLocale = function () {
        var locale;
        switch (this.curLang) {
            case FRENCH:
                locale = 'fr-CA';
                break;
            case ENGLISH:
            default:
                locale = 'en-CA';
                break;
        }
        return locale;
    };
    Object.defineProperty(Messages.prototype, "currentLocale", {
        get: function () {
            return this.curLocale;
        },
        enumerable: false,
        configurable: true
    });
    /**
     * Adds the messages so that they can be resolved.
     *
     * @param lang The language, for example: 'en'
     * @param messages The messages
     */
    Messages.prototype.addMessages = function (lang, bundle) {
        var languageBundles = this.messages[lang];
        this.messages[lang] = __assign(__assign({}, languageBundles), bundle);
    };
    /**
     * Allows to translate a key into the specified language.
     *
     * The resolution is made in this order:
     *
     * key.nb.modifier
     * key.p.modifier
     * key.nb
     * key.p
     * key.modifier
     * key
     */
    Messages.prototype.translate = function (key, params, nb, modifier, htmlEncodeParams, formatMode) {
        if (params === void 0) { params = []; }
        if (htmlEncodeParams === void 0) { htmlEncodeParams = true; }
        if (formatMode === void 0) { formatMode = this.formatMode; }
        if (!key) {
            throw new Error('The key is empty.');
        }
        var val = this.resolveKey(this.curLang, key, nb, modifier);
        if (htmlEncodeParams && params.length) {
            Object.keys(params).forEach(function (key) { params[key] = htmlEncode(params[key].toString()); });
        }
        if (formatMode === FormatMode.Sprintf || formatMode === FormatMode.Vsprintf) {
            params = Object.assign(this.specialCharacterDict, params);
        }
        val = this.format(val, params, formatMode);
        return val;
    };
    /**
     * format a string with depending on the option formatMode
     * @param {string} val the string to format
     * @param {any[]} params the values to insert in string
     */
    Messages.prototype.format = function (val, params, formatMode) {
        switch (formatMode) {
            case FormatMode.Vsprintf:
                return vsprintf(val, params);
            case FormatMode.Sprintf:
                return sprintf(val, params);
            default:
                return formatRegexp(val, params);
        }
    };
    Messages.prototype.resolveKey = function (lang, key, nb, modifier, encodeParams) {
        var val = undefined;
        if (nb !== undefined && modifier) {
            // key.nb.modifier
            val = this.findKey(lang, key + "." + nb + "." + modifier);
            if (val) {
                return val;
            }
            // key.p.modifier
            if (nb < -1 || nb > 1) {
                val = this.findKey(lang, key + ".p." + modifier);
                if (val) {
                    return val;
                }
            }
        }
        if (nb !== undefined) {
            // key.nb
            val = this.findKey(lang, key + "." + nb);
            if (val) {
                return val;
            }
            // key.p
            if (nb < -1 || nb > 1) {
                val = this.findKey(lang, key + ".p");
                if (val) {
                    return val;
                }
            }
        }
        if (modifier) {
            // key.modifier
            val = this.findKey(lang, key + "." + modifier);
            if (val) {
                return val;
            }
        }
        // key
        val = this.findKey(lang, key);
        if (val) {
            return val;
        }
        var error = "The key " + key + " does not exist. Current lang: " + this.curLang;
        if (this.options && this.options.debug === DebugMode.Throw) {
            throw new Error(error);
        }
        else {
            if (!this.options || this.options.debug === DebugMode.Warn) {
                Vue.prototype.$log.warn(error);
            }
            else {
                Vue.prototype.$log.debug(error);
            }
            return key;
        }
    };
    /**
     * Build the list of special characters that are automatically replaced to the desired pattern
     *
     * Example with '_' as PREFIXE and SUFIXE
     * NBSP => _NBSP_ : '\xOA'
     */
    Messages.prototype.initSpecialCharactersDict = function () {
        var _this = this;
        Object.keys(SpecialCharacter).forEach(function (key) {
            _this.specialCharacterDict["" + SPECIAL_CHARACTER_PREFIXE + key + SPECIAL_CHARACTER_SUFIXE] = String.fromCharCode(SpecialCharacter[key]);
        });
    };
    /**
     * Finds a key in the available messages or returns null.
     *
     * @param lang The language to use
     * @param key The key to find
     */
    Messages.prototype.findKey = function (lang, key) {
        var parts = key.split(':');
        if (parts.length !== 2) {
            var error = "The key " + key + " is invalid. The key needs to be in the format <bundle>:<id>";
            if (this.options && this.options.debug === DebugMode.Throw) {
                throw new Error(error);
            }
            else {
                if (!this.options || this.options.debug === DebugMode.Warn) {
                    Vue.prototype.$log.warn(error);
                }
                else {
                    Vue.prototype.$log.debug(error);
                }
                return undefined;
            }
        }
        var bundleName = parts[0];
        var id = parts[1];
        var langMsgs = this.messages[lang];
        var bundleMsgs = langMsgs && langMsgs[bundleName];
        return bundleMsgs && bundleMsgs[id];
    };
    return Messages;
}());
export { Messages };
/**
 * Formats a value containing parameters.
 *
 * The format is 'This is a {0} containing {1}...'
 */
function formatRegexp(val, params) {
    return val.replace(FORMAT_REGEX, function (match) {
        // TODO: should use the regex variable notation instead of parsing the regex match
        var index = parseInt(match.substring(1, match.length - 1), 10);
        if (index >= params.length) {
            Vue.prototype.$log.warn("The parameter " + index + " doesn't exist while translating: '" + val + "'");
        }
        return params[index];
    });
}
/**
 * Encodes a value so that it can be inserted in an html string.
 * @param val The value to encode
 */
function htmlEncode(val) {
    return val
        .replace(/&/g, '&amp;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;');
}
var MessagePlugin = {
    install: function (v, options) {
        v.prototype.$log.debug('$i18n', 'plugin.install');
        var msg = new Messages(options);
        (v.prototype).$i18n = msg;
    }
};
export default MessagePlugin;
//# sourceMappingURL=i18n.js.map