"use strict";
/**
 * 国际化模块
 */
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.$t = exports.t = exports.getLang = exports.getParkLang = exports.getLangFromHeader = exports.translate = exports.$translate = exports.init = exports.i18n = exports.DEFAULT_LANG = void 0;
var mslib_1 = require("mslib");
var Redis_1 = require("./Redis");
var Contants_1 = require("./Contants");
var Config_1 = require("./Config");
/**
 * 默认语种 `zh_CN`
 */
exports.DEFAULT_LANG = 'zh_CN';
/**
 * i18n实例
 *
 * 如果已开启国际化开关{@link Config}，那么模块被加载时，{@link redisClient} 创建成功后(语言包存储在redis)，会自动创建该实例，否则为空
 *
 * ```ts
 * import { i18n, t, $t } from "refs/nslib";
 *
 * //翻译数据，语种优先级：请求头 > 车场主语言 > zh_CN
 * t('(主相机)', parkId);
 *
 * //翻译非标数据(数据库)，语种优先级：请求头 > 车场主语言 > zh_CN
 * $t('$#{{(主相机)}}', parkId);
 *
 * //使用i18n原生方法翻译数据
 *
 * //根据默认语种进行翻译
 * i18n.__('(主相机)')
 * i18n.__('Hello %s', 'Keytop') //带占位符%s
 * i18n.__('Hello {{0}}', ['Keytop']) //带占位符{0}
 * i18n.__('Hello {{name}}', { name: 'Keytop' }) //带属性占位符{name}
 *
 * //指定语种进行翻译
 * i18n.__({ phrase: 'Hello %s', locale: 'en_US' }, 'Keytop1')
 * i18n.__({ phrase: 'Hello {{0}}', locale: 'en_US' }, ['Keytop1'])
 * i18n.__({ phrase: 'Hello {{name}}', locale: 'en_US' }, { name: 'Keytop1' })
 * ```
 *
 * @see [i18n](https://www.npmjs.com/package/i18n)
 */
exports.i18n = null;
var config = Config_1.IocConfigProvider.getGlobalConfig();
function init() {
    return __awaiter(this, void 0, void 0, function () {
        var I18n, catalog, error_1;
        var _this = this;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    if ((config === null || config === void 0 ? void 0 : config.enabled) !== true)
                        return [2 /*return*/];
                    //检测插件
                    try {
                        I18n = require('i18n').I18n;
                        exports.i18n = new I18n();
                    }
                    catch (error) { }
                    if (!exports.i18n)
                        return [2 /*return*/];
                    _a.label = 1;
                case 1:
                    _a.trys.push([1, 3, , 4]);
                    return [4 /*yield*/, configure_i18n()];
                case 2:
                    _a.sent();
                    catalog = exports.i18n.getCatalog();
                    mslib_1.logger.info("i18n\u521D\u59CB\u5316\u6210\u529F,\u8BED\u79CD:" + Reflect.ownKeys(catalog).join('、'));
                    return [3 /*break*/, 4];
                case 3:
                    error_1 = _a.sent();
                    mslib_1.logger.error('i18n初始化失败', error_1);
                    return [3 /*break*/, 4];
                case 4:
                    //定时刷新语言包
                    setInterval(function () { return __awaiter(_this, void 0, void 0, function () {
                        var catalog, error_2;
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0:
                                    _a.trys.push([0, 2, , 3]);
                                    return [4 /*yield*/, configure_i18n()];
                                case 1:
                                    _a.sent();
                                    catalog = exports.i18n.getCatalog();
                                    mslib_1.logger.info("i18n\u5B9A\u65F6\u5237\u65B0\u8BED\u8A00\u5305\u6210\u529F,\u8BED\u79CD:" + Reflect.ownKeys(catalog).join('、'));
                                    return [3 /*break*/, 3];
                                case 2:
                                    error_2 = _a.sent();
                                    mslib_1.logger.error('i18n定时刷新语言包失败', error_2);
                                    return [3 /*break*/, 3];
                                case 3: return [2 /*return*/];
                            }
                        });
                    }); }, Contants_1.IS_PROD ? 1000 * 60 * 10 : 1000 * 60 * 5);
                    return [2 /*return*/];
            }
        });
    });
}
exports.init = init;
function configure_i18n() {
    return __awaiter(this, void 0, void 0, function () {
        var pack;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    pack = null;
                    if (!Contants_1.default.IS_PARK) return [3 /*break*/, 2];
                    return [4 /*yield*/, getLanguagePackForPark()];
                case 1:
                    pack = _a.sent();
                    return [3 /*break*/, 4];
                case 2: return [4 /*yield*/, getLanguagePackForCloud()];
                case 3:
                    pack = _a.sent();
                    _a.label = 4;
                case 4:
                    exports.i18n.configure({
                        locales: Reflect.ownKeys(pack),
                        //不存在的语种默认按照中文翻译
                        fallbacks: { '*': 'zh_CN' },
                        staticCatalog: pack,
                        logDebugFn: function (msg) {
                            mslib_1.logger.debug(msg);
                        },
                        logWarnFn: function (msg) {
                            if (!Contants_1.IS_PROD)
                                mslib_1.logger.warn(msg);
                        },
                        logErrorFn: function (msg) {
                            mslib_1.logger.error(msg);
                        },
                        missingKeyFn: function (locale, value) {
                            return value;
                        },
                    });
                    return [2 /*return*/];
            }
        });
    });
}
/**
 * 语言包
 */
var LanguagePack = /** @class */ (function () {
    function LanguagePack() {
    }
    return LanguagePack;
}());
/**
 * 云端获取语言包
 */
function getLanguagePackForCloud() {
    return __awaiter(this, void 0, void 0, function () {
        var pack, keyValues, _loop_1, key;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    pack = new LanguagePack();
                    return [4 /*yield*/, Redis_1.redisClient.hgetall('translation_1102011')];
                case 1:
                    keyValues = _a.sent();
                    _loop_1 = function (key) {
                        try {
                            var current_lang_1 = {};
                            JSON.parse(keyValues[key]).forEach(function (s) {
                                current_lang_1[s.key] = s.value;
                            });
                            pack[key] = current_lang_1;
                        }
                        catch (error) {
                            mslib_1.logger.error("\u52A0\u8F7D\u4E91\u7AEFredis\u8BED\u8A00\u5305\u5931\u8D25,\u8BED\u79CD:" + key, error);
                        }
                    };
                    for (key in keyValues) {
                        _loop_1(key);
                    }
                    return [2 /*return*/, pack];
            }
        });
    });
}
/**
 * 场端获取语言包
 */
function getLanguagePackForPark() {
    return __awaiter(this, void 0, void 0, function () {
        var pack, fields, lang_fields, _loop_2, _i, lang_fields_1, field;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    pack = new LanguagePack();
                    return [4 /*yield*/, Redis_1.redisClient.hkeys('t_realtime_data')];
                case 1:
                    fields = _a.sent();
                    lang_fields = fields.filter(function (s) { return s.startsWith("translation_1102011"); });
                    _loop_2 = function (field) {
                        var _a, lang, current_lang, json;
                        return __generator(this, function (_b) {
                            switch (_b.label) {
                                case 0:
                                    _a = field.split(':'), lang = _a[1];
                                    current_lang = lang.substring(0, lang.lastIndexOf('_'));
                                    if (!pack[current_lang])
                                        pack[current_lang] = {};
                                    return [4 /*yield*/, Redis_1.redisClient.hget('t_realtime_data', field)];
                                case 1:
                                    json = _b.sent();
                                    JSON.parse(json).forEach(function (s) {
                                        pack[current_lang][s.key] = s.value;
                                    });
                                    return [2 /*return*/];
                            }
                        });
                    };
                    _i = 0, lang_fields_1 = lang_fields;
                    _a.label = 2;
                case 2:
                    if (!(_i < lang_fields_1.length)) return [3 /*break*/, 5];
                    field = lang_fields_1[_i];
                    return [5 /*yield**/, _loop_2(field)];
                case 3:
                    _a.sent();
                    _a.label = 4;
                case 4:
                    _i++;
                    return [3 /*break*/, 2];
                case 5: return [2 /*return*/, pack];
            }
        });
    });
}
var $regExp = /\$#{{(.+?)\}}/g;
/**
 * 翻译数据，只翻译值为`$#{{xxx}}`的字符串
 *
 * @param data 要翻译的数据，可以是任意对象
 * @param lang 目标语种
 */
function $translate(data, lang) {
    if (!exports.i18n)
        return data;
    if (typeof data === 'object') {
        for (var key in data) {
            if (typeof data[key] === 'object') {
                $translate(data[key], lang);
            }
            else {
                if (typeof data[key] === 'string' && $regExp.test(data[key])) {
                    data[key] = data[key].replace($regExp, function (s) {
                        return lang ? exports.i18n.__({ phrase: s.substring(4, s.length - 2), locale: lang }) : exports.i18n.__(s.substring(4, s.length - 2));
                    });
                }
            }
        }
        return data;
    }
    else {
        if (typeof data === 'string' && $regExp.test(data)) {
            return data.replace($regExp, function (s) {
                return lang ? exports.i18n.__({ phrase: s.substring(4, s.length - 2), locale: lang }) : exports.i18n.__(s.substring(4, s.length - 2));
            });
        }
        else {
            return data;
        }
    }
}
exports.$translate = $translate;
/**
 * 翻译数据
 *
 * @param data 要翻译的数据，可以是任意对象
 * @param lang 目标语种
 */
function translate(data, lang) {
    if (!exports.i18n)
        return data;
    if (typeof data === 'object') {
        for (var key in data) {
            if (typeof data[key] === 'object') {
                translate(data[key], lang);
            }
            else {
                if (typeof data[key] === 'string') {
                    data[key] = lang ? exports.i18n.__({ phrase: data[key], locale: lang }) : exports.i18n.__(data[key]);
                }
            }
        }
        return data;
    }
    else {
        if (typeof data === 'string') {
            return lang ? exports.i18n.__({ phrase: data, locale: lang }) : exports.i18n.__(data);
        }
        else {
            return data;
        }
    }
}
exports.translate = translate;
/**
 * 从请求头获取语种
 */
function getLangFromHeader() {
    var _a;
    var lang = null;
    var headers = mslib_1.Context.getRequestHeaders();
    for (var key in headers) {
        if (key.toLocaleLowerCase() === 'accept-language') {
            lang = (_a = headers[key]) === null || _a === void 0 ? void 0 : _a.replace('-', '_');
        }
    }
    return lang;
}
exports.getLangFromHeader = getLangFromHeader;
/**
 * 获取车场主语言
 *
 * 场端{@link IS_PARK}从sqlite取, 非场端从redis取
 */
function getParkLang(parkId) {
    var _a;
    return __awaiter(this, void 0, void 0, function () {
        var lang, knexInstance, configs;
        return __generator(this, function (_b) {
            switch (_b.label) {
                case 0:
                    if (!!Contants_1.default.IS_PARK) return [3 /*break*/, 1];
                    return [2 /*return*/, Redis_1.redisClient === null || Redis_1.redisClient === void 0 ? void 0 : Redis_1.redisClient.get("lang-{{" + parkId + "}}")];
                case 1:
                    lang = void 0;
                    knexInstance = require('knex')({
                        client: 'sqlite3',
                        connection: {
                            filename: "/home/keytop/data/lotconfig.db"
                        }
                    });
                    return [4 /*yield*/, knexInstance('t_config').where({ session: 'charge', name: 'countryAndLanguage' })];
                case 2:
                    configs = _b.sent();
                    if (configs && configs.length > 0 && configs[0].value)
                        lang = (_a = configs[0]) === null || _a === void 0 ? void 0 : _a.value;
                    return [2 /*return*/, lang];
            }
        });
    });
}
exports.getParkLang = getParkLang;
/**
 * 获取语种
 *
 * 优先级：请求头 > 车场主语言 {@link getParkLang} > zh_CN
 */
function getLang(parkId) {
    return __awaiter(this, void 0, void 0, function () {
        var lang, error_3;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    lang = getLangFromHeader();
                    if (!!lang) return [3 /*break*/, 4];
                    if (!(Contants_1.IS_PARK && parkId)) return [3 /*break*/, 4];
                    _a.label = 1;
                case 1:
                    _a.trys.push([1, 3, , 4]);
                    return [4 /*yield*/, getParkLang(parkId)];
                case 2:
                    lang = _a.sent();
                    if (!Contants_1.IS_PROD)
                        mslib_1.logger.info("\u8BFB\u53D6\u8F66\u573A\u4E3B\u8BED\u8A00\u6210\u529F," + (lang || '未设置'));
                    return [3 /*break*/, 4];
                case 3:
                    error_3 = _a.sent();
                    mslib_1.logger.error(error_3);
                    return [3 /*break*/, 4];
                case 4: return [2 /*return*/, lang || exports.DEFAULT_LANG];
            }
        });
    });
}
exports.getLang = getLang;
/**
 * 翻译数据
 *
 * 语种优先级：请求头 > 车场主语言 {@link getParkLang} > zh_CN
 * @param data 要翻译的数据，可以是任意对象
 * @param parkId 车场id, 用来获取车场主语言
 */
function t(data, parkId) {
    return __awaiter(this, void 0, void 0, function () {
        var lang, error_4;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    if (!exports.i18n || !data)
                        return [2 /*return*/, data];
                    _a.label = 1;
                case 1:
                    _a.trys.push([1, 3, , 4]);
                    return [4 /*yield*/, getLang(parkId)];
                case 2:
                    lang = _a.sent();
                    return [2 /*return*/, translate(data, lang)];
                case 3:
                    error_4 = _a.sent();
                    mslib_1.logger.error(error_4);
                    return [2 /*return*/, data];
                case 4: return [2 /*return*/];
            }
        });
    });
}
exports.t = t;
/**
 * 翻译数据, 只翻译值为`$#{{xxx}}`的字符串
 *
 * 语种优先级：请求头 > 车场主语言 {@link getParkLang} > zh_CN
 * @param data 要翻译的数据，可以是任意对象
 * @param parkId 车场id, 用来获取车场主语言
 */
function $t(data, parkId) {
    return __awaiter(this, void 0, void 0, function () {
        var lang, error_5;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    if (!exports.i18n || !data)
                        return [2 /*return*/, data];
                    _a.label = 1;
                case 1:
                    _a.trys.push([1, 3, , 4]);
                    return [4 /*yield*/, getLang(parkId)];
                case 2:
                    lang = _a.sent();
                    return [2 /*return*/, $translate(data, lang)];
                case 3:
                    error_5 = _a.sent();
                    mslib_1.logger.error(error_5);
                    return [2 /*return*/, data];
                case 4: return [2 /*return*/];
            }
        });
    });
}
exports.$t = $t;
//# sourceMappingURL=Global.js.map