import { Controller } from './Controller/Controller'; import { combineOptions } from './Controller/State/initState'; import { JioTranslateOptions, JioTranslatePlugin, DevCredentials, TFnType, DefaultParamType, TranslationKey, } from './types'; function createJioTranslate(options: JioTranslateOptions) { const controller = Controller({ options, }); if (controller.isDev()) { // override existing data in DevMode controller.invalidate(); } // restarts jiotranslate while applying callback function withRestart(callback: () => void) { const wasRunning = controller.isRunning(); wasRunning && controller.stop(); callback(); // invalidate cache when jiotranslate configuration is updated/plugin added in DevMode controller.isDev() && controller.invalidate(); wasRunning && controller.run(); } const self = Object.freeze({ /** * Listen to jiotranslate events. */ on: controller.on, /** * Listen for specific namespaces changes. * * ``` * const sub = jiotranslate.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. */ setEmitterActive: controller.setEmitterActive, /** * @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 jiotranslate is running, loads required data. */ addActiveNs: controller.addActiveNs, /** * Remove namespace(s) from active namespaces. * * jiotranslate 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, /** * Returns records needed for instance to be `loaded` */ getRequiredRecords: controller.getRequiredRecords, /** * @return `true` if jiotranslate is loading initial data (triggered by `run`). */ isInitialLoading: controller.isInitialLoading, /** * @param ns optional list of namespaces that you are interested in * @return `true` if jiotranslate 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 jiotranslate is fetching some translations. */ isFetching: controller.isFetching, /** * @return `true` if jiotranslate 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 jiotranslate is running, wraps result to be identifiable in the DOM. */ t: controller.t, /** * Highlight keys that match selection. */ highlight: controller.highlight, /** * Find positions of keys in the DOM. */ findPositions: controller.findPositions, /** * @return current jiotranslate options. */ getInitialOptions: controller.getInitialOptions, /** * jiotranslate is in dev mode if `DevTools` plugin is used and `apiKey` + `apiUrl` are specified. * @return `true` if jiotranslate is in dev mode. */ isDev: controller.isDev, /** * Wraps translation if there is `Observer` plugin */ wrap: controller.wrap, /** * Unwrap translation */ unwrap: controller.unwrap, /** * Override creadentials passed on initialization. * * When called in running state, jiotranslate stops and runs again. */ overrideCredentials(credentials: DevCredentials) { withRestart(() => controller.overrideCredentials(credentials)); }, /** * Add jiotranslate plugin after initialization. * * When called in running state, jiotranslate stops and runs again. */ addPlugin(plugin: JioTranslatePlugin | undefined) { if (plugin) { withRestart(() => controller.addPlugin(self, plugin)); } }, /** * Updates options after instance creation. Extends existing options, * so it only changes the fields, that are listed. * * When called in running state, jiotranslate stops and runs again. */ updateOptions(options?: JioTranslateOptions) { if (options) { withRestart(() => controller.init(options)); } }, }); return self; } export type JioTranslateInstance = Omit< ReturnType, 't' > & { // enabling generics (when inferred they are lost) t: TFnType; }; export type JioTranslateChainer = { /** * Add plugin, plugins are applied when `init` method is called. */ use: (plugin: JioTranslatePlugin | undefined) => JioTranslateChainer; /** * Update default options before jiotranslate is initialized. */ updateDefaults: (options: JioTranslateOptions) => JioTranslateChainer; /** * Initialize jiotranslate options and apply plugins * @returns jiotranslate instance */ init(options?: JioTranslateOptions): JioTranslateInstance; }; /** * jiotranslate chainable constructor. * * Usage: * ``` * const jiotranslate = JioTranslate().use(...).init(...) * ``` */ export const JioTranslateCore = (): JioTranslateChainer => { const state = { plugins: [] as (JioTranslatePlugin | undefined)[], options: {} as JioTranslateOptions, }; const jiotranslateChain = Object.freeze({ use(plugin: JioTranslatePlugin | undefined) { state.plugins.push(plugin); return jiotranslateChain; }, updateDefaults(options: JioTranslateOptions) { state.options = combineOptions(state.options, options); return jiotranslateChain; }, init(options?: JioTranslateOptions) { const jiotranslate = createJioTranslate( combineOptions(state.options, options) ); state.plugins.forEach(jiotranslate.addPlugin); return jiotranslate; }, }); return jiotranslateChain; };