UNPKG

vue-i18n-bridge

Version:
1,238 lines (1,227 loc) 47.2 kB
/*! * vue-i18n-bridge v9.2.0-beta.6 * (c) 2021 kazuya kawaguchi * Released under the MIT License. */ import { getGlobalThis, format, makeSymbol, isPlainObject, isArray, hasOwn, isObject, isBoolean, isString, isRegExp, isFunction, assign, isNumber, warn, isEmptyObject } from '@intlify/shared'; import { CoreWarnCodes, createCompileError, CompileErrorCodes, DEFAULT_LOCALE, createCoreContext, updateFallbackLocale, clearDateTimeFormat, clearNumberFormat, setAdditionalMeta, NOT_REOSLVED, isTranslateFallbackWarn, isTranslateMissingWarn, parseTranslateArgs, translate, MISSING_RESOLVE_VALUE, parseDateTimeArgs, datetime, parseNumberArgs, number, fallbackWithLocaleChain, registerMessageResolver, resolveValue, registerLocaleFallbacker, setDevToolsHook } from '@intlify/core-base'; import { ref, getCurrentInstance, computed, watch, onBeforeMount, onUnmounted } from '@vue/composition-api'; /** * Vue I18n Version * * @remarks * Semver format. Same format as the package.json `version` field. * * @VueI18nGeneral */ const VERSION = '9.2.0-beta.6'; /** * This is only called in esm-bundler builds. * istanbul-ignore-next */ function initFeatureFlags() { let needWarn = false; if (typeof __VUE_I18N_FULL_INSTALL__ !== 'boolean') { needWarn = true; getGlobalThis().__VUE_I18N_FULL_INSTALL__ = true; } if (typeof __VUE_I18N_LEGACY_API__ !== 'boolean') { needWarn = true; getGlobalThis().__VUE_I18N_LEGACY_API__ = true; } if (typeof __INTLIFY_PROD_DEVTOOLS__ !== 'boolean') { getGlobalThis().__INTLIFY_PROD_DEVTOOLS__ = false; } if ((process.env.NODE_ENV !== 'production') && needWarn) { console.warn(`You are running the esm-bundler build of vue-i18n. It is recommended to ` + `configure your bundler to explicitly replace feature flag globals ` + `with boolean literals to get proper tree-shaking in the final bundle.`); } } let code$1 = CoreWarnCodes.__EXTEND_POINT__; const inc$1 = () => code$1++; const I18nWarnCodes = { FALLBACK_TO_ROOT: code$1, NOT_SUPPORTED_PRESERVE: inc$1(), NOT_SUPPORTED_FORMATTER: inc$1(), NOT_SUPPORTED_PRESERVE_DIRECTIVE: inc$1(), NOT_SUPPORTED_GET_CHOICE_INDEX: inc$1(), COMPONENT_NAME_LEGACY_COMPATIBLE: inc$1(), NOT_FOUND_PARENT_SCOPE: inc$1(), NOT_SUPPORT_MULTI_I18N_INSTANCE: inc$1() // 14 }; const warnMessages = { [I18nWarnCodes.FALLBACK_TO_ROOT]: `Fall back to {type} '{key}' with root locale.`, [I18nWarnCodes.NOT_SUPPORTED_PRESERVE]: `Not supported 'preserve'.`, [I18nWarnCodes.NOT_SUPPORTED_FORMATTER]: `Not supported 'formatter'.`, [I18nWarnCodes.NOT_SUPPORTED_PRESERVE_DIRECTIVE]: `Not supported 'preserveDirectiveContent'.`, [I18nWarnCodes.NOT_SUPPORTED_GET_CHOICE_INDEX]: `Not supported 'getChoiceIndex'.`, [I18nWarnCodes.COMPONENT_NAME_LEGACY_COMPATIBLE]: `Component name legacy compatible: '{name}' -> 'i18n'`, [I18nWarnCodes.NOT_FOUND_PARENT_SCOPE]: `Not found parent scope. use the global scope.`, [I18nWarnCodes.NOT_SUPPORT_MULTI_I18N_INSTANCE]: `Not support multi i18n instance.` }; function getWarnMessage(code, ...args) { return format(warnMessages[code], ...args); } let code = CompileErrorCodes.__EXTEND_POINT__; const inc = () => code++; const I18nErrorCodes = { // composer module errors UNEXPECTED_RETURN_TYPE: code, // legacy module errors INVALID_ARGUMENT: inc(), // i18n module errors MUST_BE_CALL_SETUP_TOP: inc(), NOT_INSLALLED: inc(), NOT_AVAILABLE_IN_LEGACY_MODE: inc(), // directive module errors REQUIRED_VALUE: inc(), INVALID_VALUE: inc(), // vue-devtools errors CANNOT_SETUP_VUE_DEVTOOLS_PLUGIN: inc(), NOT_INSLALLED_WITH_PROVIDE: inc(), // unexpected error UNEXPECTED_ERROR: inc(), // not compatible legacy vue-i18n constructor NOT_COMPATIBLE_LEGACY_VUE_I18N: inc(), // bridge support vue 2.x only BRIDGE_SUPPORT_VUE_2_ONLY: inc(), // for enhancement __EXTEND_POINT__: inc() // 27 }; function createI18nError(code, ...args) { return createCompileError(code, null, (process.env.NODE_ENV !== 'production') ? { messages: errorMessages, args } : undefined); } const errorMessages = { [I18nErrorCodes.UNEXPECTED_RETURN_TYPE]: 'Unexpected return type in composer', [I18nErrorCodes.INVALID_ARGUMENT]: 'Invalid argument', [I18nErrorCodes.MUST_BE_CALL_SETUP_TOP]: 'Must be called at the top of a `setup` function', [I18nErrorCodes.NOT_INSLALLED]: 'Need to install with `app.use` function', [I18nErrorCodes.UNEXPECTED_ERROR]: 'Unexpected error', [I18nErrorCodes.NOT_AVAILABLE_IN_LEGACY_MODE]: 'Not available in legacy mode', [I18nErrorCodes.REQUIRED_VALUE]: `Required in value: {0}`, [I18nErrorCodes.INVALID_VALUE]: `Invalid value`, [I18nErrorCodes.CANNOT_SETUP_VUE_DEVTOOLS_PLUGIN]: `Cannot setup vue-devtools plugin`, [I18nErrorCodes.NOT_INSLALLED_WITH_PROVIDE]: 'Need to install with `provide` function', [I18nErrorCodes.NOT_COMPATIBLE_LEGACY_VUE_I18N]: 'Not compatible legacy VueI18n.', [I18nErrorCodes.BRIDGE_SUPPORT_VUE_2_ONLY]: 'vue-i18n-bridge support Vue 2.x only' }; const SetPluralRulesSymbol = makeSymbol('__setPluralRules'); makeSymbol('__intlifyMeta'); const LegacyInstanceSymbol = /* #__PURE__*/ makeSymbol('__legacyVueI18n'); /* eslint-disable @typescript-eslint/no-explicit-any */ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types function isLegacyVueI18n(VueI18n) { if (VueI18n == null || VueI18n.version == null) { return false; } return (Number(VueI18n.version.split('.')[0]) || -1) >= 8; } /** * Transform flat json in obj to normal json in obj */ function handleFlatJson(obj) { // check obj if (!isObject(obj)) { return obj; } for (const key in obj) { // check key if (!hasOwn(obj, key)) { continue; } // handle for normal json if (!key.includes('.')) { // recursive process value if value is also a object if (isObject(obj[key])) { handleFlatJson(obj[key]); } } // handle for flat json, transform to normal json else { // go to the last object const subKeys = key.split('.'); const lastIndex = subKeys.length - 1; let currentObj = obj; for (let i = 0; i < lastIndex; i++) { if (!(subKeys[i] in currentObj)) { currentObj[subKeys[i]] = {}; } currentObj = currentObj[subKeys[i]]; } // update last object value, delete old property currentObj[subKeys[lastIndex]] = obj[key]; delete obj[key]; // recursive process value if value is also a object if (isObject(currentObj[subKeys[lastIndex]])) { handleFlatJson(currentObj[subKeys[lastIndex]]); } } } return obj; } function getLocaleMessages(locale, options) { const { messages, __i18n, messageResolver, flatJson } = options; // prettier-ignore const ret = isPlainObject(messages) ? messages : isArray(__i18n) ? {} : { [locale]: {} }; // merge locale messages of i18n custom block if (isArray(__i18n)) { __i18n.forEach(({ locale, resource }) => { if (locale) { ret[locale] = ret[locale] || {}; deepCopy(resource, ret[locale]); } else { deepCopy(resource, ret); } }); } // handle messages for flat json if (messageResolver == null && flatJson) { for (const key in ret) { if (hasOwn(ret, key)) { handleFlatJson(ret[key]); } } } return ret; } const isNotObjectOrIsArray = (val) => !isObject(val) || isArray(val); // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types function deepCopy(src, des) { // src and des should both be objects, and non of then can be a array if (isNotObjectOrIsArray(src) || isNotObjectOrIsArray(des)) { throw createI18nError(I18nErrorCodes.INVALID_VALUE); } for (const key in src) { if (hasOwn(src, key)) { if (isNotObjectOrIsArray(src[key]) || isNotObjectOrIsArray(des[key])) { // replace with src[key] when: // src[key] or des[key] is not a object, or // src[key] or des[key] is a array des[key] = src[key]; } else { // src[key] and des[key] are both object, merge them deepCopy(src[key], des[key]); } } } } /* eslint-enable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */ const DEVTOOLS_META = '__INTLIFY_META__'; let composerID = 0; function defineCoreMissingHandler(missing) { return ((ctx, locale, key, type) => { return missing(locale, key, getCurrentInstance() || undefined, type); }); } // for Intlify DevTools const getMetaInfo = () => { const instance = getCurrentInstance(); return instance && instance.type[DEVTOOLS_META] // eslint-disable-line @typescript-eslint/no-explicit-any ? { [DEVTOOLS_META]: instance.type[DEVTOOLS_META] } // eslint-disable-line @typescript-eslint/no-explicit-any : null; }; /** * Create composer interface factory * * @internal */ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types function createComposer(options = {}, VueI18nLegacy) { const { __root } = options; const _isGlobal = __root === undefined; let _inheritLocale = isBoolean(options.inheritLocale) ? options.inheritLocale : true; const _locale = ref( // prettier-ignore __root && _inheritLocale ? __root.locale.value : isString(options.locale) ? options.locale : DEFAULT_LOCALE); const _fallbackLocale = ref( // prettier-ignore __root && _inheritLocale ? __root.fallbackLocale.value : isString(options.fallbackLocale) || isArray(options.fallbackLocale) || isPlainObject(options.fallbackLocale) || options.fallbackLocale === false ? options.fallbackLocale : _locale.value); const _messages = ref(getLocaleMessages(_locale.value, options)); // prettier-ignore const _datetimeFormats = ref(isPlainObject(options.datetimeFormats) ? options.datetimeFormats : { [_locale.value]: {} }) ; // prettier-ignore const _numberFormats = ref(isPlainObject(options.numberFormats) ? options.numberFormats : { [_locale.value]: {} }) ; // warning suppress options // prettier-ignore let _missingWarn = __root ? __root.missingWarn : isBoolean(options.missingWarn) || isRegExp(options.missingWarn) ? options.missingWarn : true; // prettier-ignore let _fallbackWarn = __root ? __root.fallbackWarn : isBoolean(options.fallbackWarn) || isRegExp(options.fallbackWarn) ? options.fallbackWarn : true; // prettier-ignore let _fallbackRoot = __root ? __root.fallbackRoot : isBoolean(options.fallbackRoot) ? options.fallbackRoot : true; // configure fall back to root let _fallbackFormat = !!options.fallbackFormat; // runtime missing let _missing = isFunction(options.missing) ? options.missing : null; let _runtimeMissing = isFunction(options.missing) ? defineCoreMissingHandler(options.missing) : null; // postTranslation handler let _postTranslation = isFunction(options.postTranslation) ? options.postTranslation : null; let _warnHtmlMessage = isBoolean(options.warnHtmlMessage) ? options.warnHtmlMessage : true; let _escapeParameter = !!options.escapeParameter; // custom linked modifiers // prettier-ignore const _modifiers = __root ? __root.modifiers : isPlainObject(options.modifiers) ? options.modifiers : {}; // pluralRules let _pluralRules = options.pluralRules || (__root && __root.pluralRules); // for bridge let __legacy; { if (!isLegacyVueI18n(VueI18nLegacy)) { createI18nError(I18nErrorCodes.NOT_COMPATIBLE_LEGACY_VUE_I18N); } const legacyOptions = { locale: _locale.value, fallbackLocale: _fallbackLocale.value, messages: _messages.value, dateTimeFormats: _datetimeFormats.value, numberFormats: _numberFormats.value, modifiers: _modifiers, missing: _missing, fallbackRoot: _fallbackRoot, postTranslation: _postTranslation, pluralizationRules: _pluralRules, escapeParameterHtml: _escapeParameter, sync: _inheritLocale, silentFallbackWarn: isBoolean(_fallbackWarn) ? !_fallbackWarn : _fallbackWarn, silentTranslationWarn: isBoolean(_missingWarn) ? !_missingWarn : _missingWarn, formatFallbackMessages: isBoolean(_fallbackFormat) ? !_fallbackFormat : _fallbackFormat, warnHtmlInMessage: isBoolean(_warnHtmlMessage) ? _warnHtmlMessage ? 'warn' : 'off' : 'off' }; __legacy = new VueI18nLegacy(legacyOptions); } // runtime context // eslint-disable-next-line prefer-const let _context; function getCoreContext() { const ctxOptions = { version: VERSION, locale: _locale.value, fallbackLocale: _fallbackLocale.value, messages: _messages.value, modifiers: _modifiers, pluralRules: _pluralRules, missing: _runtimeMissing === null ? undefined : _runtimeMissing, missingWarn: _missingWarn, fallbackWarn: _fallbackWarn, fallbackFormat: _fallbackFormat, unresolving: true, postTranslation: _postTranslation === null ? undefined : _postTranslation, warnHtmlMessage: _warnHtmlMessage, escapeParameter: _escapeParameter, messageResolver: options.messageResolver, __meta: { framework: 'vue' } }; { ctxOptions.datetimeFormats = _datetimeFormats.value; ctxOptions.numberFormats = _numberFormats.value; ctxOptions.__datetimeFormatters = isPlainObject(_context) ? _context.__datetimeFormatters : undefined; ctxOptions.__numberFormatters = isPlainObject(_context) ? _context.__numberFormatters : undefined; } return createCoreContext(ctxOptions); } _context = getCoreContext(); updateFallbackLocale(_context, _locale.value, _fallbackLocale.value); // track reactivity function trackReactivityValues() { return [ _locale.value, _fallbackLocale.value, _messages.value, _datetimeFormats.value, _numberFormats.value ] ; } // locale const locale = computed({ get: () => _locale.value, set: val => { _locale.value = val; { if (__legacy) { __legacy.locale = val; } } _context.locale = _locale.value; } }); // fallbackLocale const fallbackLocale = computed({ get: () => _fallbackLocale.value, set: val => { _fallbackLocale.value = val; { if (__legacy) { __legacy.fallbackLocale = val; } } _context.fallbackLocale = _fallbackLocale.value; updateFallbackLocale(_context, _locale.value, val); } }); // messages const messages = computed(() => _messages.value); // datetimeFormats const datetimeFormats = /* #__PURE__*/ computed(() => _datetimeFormats.value); // numberFormats const numberFormats = /* #__PURE__*/ computed(() => _numberFormats.value); // getPostTranslationHandler function getPostTranslationHandler() { return isFunction(_postTranslation) ? _postTranslation : null; } // setPostTranslationHandler function setPostTranslationHandler(handler) { _postTranslation = handler; _context.postTranslation = handler; } // getMissingHandler function getMissingHandler() { return _missing; } // setMissingHandler function setMissingHandler(handler) { if (handler !== null) { _runtimeMissing = defineCoreMissingHandler(handler); } _missing = handler; _context.missing = _runtimeMissing; } function isResolvedTranslateMessage(type, arg // eslint-disable-line @typescript-eslint/no-explicit-any ) { return type !== 'translate' || !arg.resolvedMessage; } function wrapWithDeps(fn, argumentParser, warnType, fallbackSuccess, fallbackFail, successCondition) { trackReactivityValues(); // track reactive dependency // NOTE: experimental !! let ret; if ((process.env.NODE_ENV !== 'production') || __INTLIFY_PROD_DEVTOOLS__) { try { setAdditionalMeta(getMetaInfo()); ret = fn(_context); } finally { setAdditionalMeta(null); } } else { ret = fn(_context); } if (isNumber(ret) && ret === NOT_REOSLVED) { const [key, arg2] = argumentParser(); if ((process.env.NODE_ENV !== 'production') && __root && isString(key) && isResolvedTranslateMessage(warnType, arg2)) { if (_fallbackRoot && (isTranslateFallbackWarn(_fallbackWarn, key) || isTranslateMissingWarn(_missingWarn, key))) { warn(getWarnMessage(I18nWarnCodes.FALLBACK_TO_ROOT, { key, type: warnType })); } } return __root && _fallbackRoot ? fallbackSuccess(__root) : fallbackFail(key); } else if (successCondition(ret)) { return ret; } else { /* istanbul ignore next */ throw createI18nError(I18nErrorCodes.UNEXPECTED_RETURN_TYPE); } } // t function t(...args) { return wrapWithDeps(context => Reflect.apply(translate, null, [context, ...args]), () => parseTranslateArgs(...args), 'translate', root => Reflect.apply(root.t, root, [...args]), key => key, val => isString(val)); } // rt function rt(...args) { const [arg1, arg2, arg3] = args; if (arg3 && !isObject(arg3)) { throw createI18nError(I18nErrorCodes.INVALID_ARGUMENT); } return t(...[arg1, arg2, assign({ resolvedMessage: true }, arg3 || {})]); } // d function d(...args) { return wrapWithDeps(context => Reflect.apply(datetime, null, [context, ...args]), () => parseDateTimeArgs(...args), 'datetime format', root => Reflect.apply(root.d, root, [...args]), () => MISSING_RESOLVE_VALUE, val => isString(val)); } // n function n(...args) { return wrapWithDeps(context => Reflect.apply(number, null, [context, ...args]), () => parseNumberArgs(...args), 'number format', root => Reflect.apply(root.n, root, [...args]), () => MISSING_RESOLVE_VALUE, val => isString(val)); } function setPluralRules(rules) { _pluralRules = rules; _context.pluralRules = _pluralRules; } // te function te(key, locale) { const targetLocale = isString(locale) ? locale : _locale.value; const message = getLocaleMessage(targetLocale); return _context.messageResolver(message, key) !== null; } function resolveMessages(key) { let messages = null; const locales = fallbackWithLocaleChain(_context, _fallbackLocale.value, _locale.value); for (let i = 0; i < locales.length; i++) { const targetLocaleMessages = _messages.value[locales[i]] || {}; const messageValue = _context.messageResolver(targetLocaleMessages, key); if (messageValue != null) { messages = messageValue; break; } } return messages; } // tm function tm(key) { const messages = resolveMessages(key); // prettier-ignore return messages != null ? messages : __root ? __root.tm(key) || {} : {}; } // getLocaleMessage function getLocaleMessage(locale) { return (_messages.value[locale] || {}); } // setLocaleMessage function setLocaleMessage(locale, message) { _messages.value[locale] = message; { __legacy && __legacy.setLocaleMessage(locale, message); } _context.messages = _messages.value; } // mergeLocaleMessage function mergeLocaleMessage(locale, message) { _messages.value[locale] = _messages.value[locale] || {}; { __legacy && __legacy.mergeLocaleMessage(locale, message); } deepCopy(message, _messages.value[locale]); _context.messages = _messages.value; } // getDateTimeFormat function getDateTimeFormat(locale) { return _datetimeFormats.value[locale] || {}; } // setDateTimeFormat function setDateTimeFormat(locale, format) { _datetimeFormats.value[locale] = format; { __legacy && __legacy.setDateTimeFormat(locale, format); } _context.datetimeFormats = _datetimeFormats.value; clearDateTimeFormat(_context, locale, format); } // mergeDateTimeFormat function mergeDateTimeFormat(locale, format) { _datetimeFormats.value[locale] = assign(_datetimeFormats.value[locale] || {}, format); { __legacy && __legacy.mergeDateTimeFormat(locale, format); } _context.datetimeFormats = _datetimeFormats.value; clearDateTimeFormat(_context, locale, format); } // getNumberFormat function getNumberFormat(locale) { return _numberFormats.value[locale] || {}; } // setNumberFormat function setNumberFormat(locale, format) { _numberFormats.value[locale] = format; { __legacy && __legacy.setNumberFormat(locale, format); } _context.numberFormats = _numberFormats.value; clearNumberFormat(_context, locale, format); } // mergeNumberFormat function mergeNumberFormat(locale, format) { _numberFormats.value[locale] = assign(_numberFormats.value[locale] || {}, format); { __legacy && __legacy.mergeNumberFormat(locale, format); } _context.numberFormats = _numberFormats.value; clearNumberFormat(_context, locale, format); } // for debug composerID++; // watch root locale & fallbackLocale if (__root) { watch(__root.locale, (val) => { if (_inheritLocale) { _locale.value = val; { if (__legacy) { __legacy.locale = val; } } _context.locale = val; updateFallbackLocale(_context, _locale.value, _fallbackLocale.value); } }); watch(__root.fallbackLocale, (val) => { if (_inheritLocale) { _fallbackLocale.value = val; { if (__legacy) { __legacy.fallbackLocale = val; } } _context.fallbackLocale = val; updateFallbackLocale(_context, _locale.value, _fallbackLocale.value); } }); } // define basic composition API! const composer = { id: composerID, locale, fallbackLocale, get inheritLocale() { return _inheritLocale; }, set inheritLocale(val) { _inheritLocale = val; { if (__legacy) { __legacy._sync = val; } } if (val && __root) { _locale.value = __root.locale.value; _fallbackLocale.value = __root.fallbackLocale.value; { if (__legacy) { __legacy.locale = __root.locale.value; __legacy.fallbackLocale = __root.fallbackLocale.value; } } updateFallbackLocale(_context, _locale.value, _fallbackLocale.value); } }, get availableLocales() { return Object.keys(_messages.value).sort(); }, messages, get modifiers() { return _modifiers; }, get pluralRules() { return _pluralRules || {}; }, get isGlobal() { return _isGlobal; }, get missingWarn() { return _missingWarn; }, set missingWarn(val) { _missingWarn = val; _context.missingWarn = _missingWarn; }, get fallbackWarn() { return _fallbackWarn; }, set fallbackWarn(val) { _fallbackWarn = val; _context.fallbackWarn = _fallbackWarn; }, get fallbackRoot() { return _fallbackRoot; }, set fallbackRoot(val) { _fallbackRoot = val; }, get fallbackFormat() { return _fallbackFormat; }, set fallbackFormat(val) { _fallbackFormat = val; _context.fallbackFormat = _fallbackFormat; }, get warnHtmlMessage() { return _warnHtmlMessage; }, set warnHtmlMessage(val) { _warnHtmlMessage = val; _context.warnHtmlMessage = val; }, get escapeParameter() { return _escapeParameter; }, set escapeParameter(val) { _escapeParameter = val; _context.escapeParameter = val; }, t, getLocaleMessage, setLocaleMessage, mergeLocaleMessage, getPostTranslationHandler, setPostTranslationHandler, getMissingHandler, setMissingHandler, [SetPluralRulesSymbol]: setPluralRules }; { composer.datetimeFormats = datetimeFormats; composer.numberFormats = numberFormats; composer.rt = rt; composer.te = te; composer.tm = tm; composer.d = d; composer.n = n; composer.getDateTimeFormat = getDateTimeFormat; composer.setDateTimeFormat = setDateTimeFormat; composer.mergeDateTimeFormat = mergeDateTimeFormat; composer.getNumberFormat = getNumberFormat; composer.setNumberFormat = setNumberFormat; composer.mergeNumberFormat = mergeNumberFormat; } { composer[LegacyInstanceSymbol] = __legacy; } return composer; } /* eslint-enable @typescript-eslint/no-explicit-any */ /** * Port from vue-i18n@v8.x * This mixin is used when we use vue-i18n-bridge */ function defineMixin(i18n, VueI18n // eslint-disable-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types ) { return { beforeCreate() { const options = this.$options; // eslint-disable-line @typescript-eslint/no-explicit-any if (options.__VUE18N__INSTANCE__) { return; } options.i18n = options.i18n || (options.__i18n ? {} : null); this._i18nBridgeRoot = i18n; if (i18n.mode === 'composition') { this._i18n = i18n; return; } if (options.i18n) { if (options.i18n instanceof VueI18n) { // init locale messages via custom blocks if (options.__i18n) { try { const localeMessages = options.i18n && options.i18n.messages ? options.i18n.messages : {}; options.__i18n.forEach(resource => deepCopy(localeMessages, JSON.parse(resource))); Object.keys(localeMessages).forEach((locale) => { options.i18n.mergeLocaleMessage(locale, localeMessages[locale]); }); } catch (e) { if ((process.env.NODE_ENV !== 'production')) { console.error(`Cannot parse locale messages via custom blocks.`, e); } } } this._i18n = options.i18n; this._i18nWatcher = this._i18n.watchI18nData(); } else if (isPlainObject(options.i18n)) { const rootI18n = this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n ? this.$root.$i18n : null; // component local i18n if (rootI18n) { options.i18n.root = this.$root; options.i18n.formatter = rootI18n.formatter; options.i18n.fallbackLocale = rootI18n.fallbackLocale; options.i18n.formatFallbackMessages = rootI18n.formatFallbackMessages; options.i18n.silentTranslationWarn = rootI18n.silentTranslationWarn; options.i18n.silentFallbackWarn = rootI18n.silentFallbackWarn; options.i18n.pluralizationRules = rootI18n.pluralizationRules; options.i18n.preserveDirectiveContent = rootI18n.preserveDirectiveContent; } // init locale messages via custom blocks if (options.__i18n) { try { const localeMessages = options.i18n && options.i18n.messages ? options.i18n.messages : {}; options.__i18n.forEach(resource => deepCopy(localeMessages, JSON.parse(resource))); options.i18n.messages = localeMessages; } catch (e) { if ((process.env.NODE_ENV !== 'production')) { warn(`Cannot parse locale messages via custom blocks.`, e); } } } const { sharedMessages } = options.i18n; if (sharedMessages && isPlainObject(sharedMessages)) { deepCopy(options.i18n.messages, sharedMessages); } this._i18n = new VueI18n(options.i18n); this._i18nWatcher = this._i18n.watchI18nData(); if (options.i18n.sync === undefined || !!options.i18n.sync) { this._localeWatcher = this.$i18n.watchLocale(); } if (rootI18n) { rootI18n.onComponentInstanceCreated(this._i18n); } } else { if ((process.env.NODE_ENV !== 'production')) { warn(`Cannot be interpreted 'i18n' option.`); } } } else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) { // root i18n this._i18n = this.$root.$i18n; } else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) { // parent i18n this._i18n = options.parent.$i18n; } }, beforeMount() { const options = this.$options; // eslint-disable-line @typescript-eslint/no-explicit-any if (options.__VUE18N__INSTANCE__) { return; } options.i18n = options.i18n || (options.__i18n ? {} : null); if (options.i18n) { if (options.i18n instanceof VueI18n) { // init locale messages via custom blocks this._i18n.subscribeDataChanging(this); this._subscribing = true; } else if (isPlainObject(options.i18n)) { this._i18n.subscribeDataChanging(this); this._subscribing = true; } else { if ((process.env.NODE_ENV !== 'production')) { warn(`Cannot be interpreted 'i18n' option.`); } } } else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) { this._i18n.subscribeDataChanging(this); this._subscribing = true; } else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) { this._i18n.subscribeDataChanging(this); this._subscribing = true; } }, beforeDestroy() { const options = this.$options; // eslint-disable-line @typescript-eslint/no-explicit-any if (options.__VUE18N__INSTANCE__) { return; } if (this._i18nBridgeRoot) { delete this._i18nBridgeRoot; return; } if (i18n.mode === 'composition') { delete this._i18n; return; } if (!this._i18n) { return; } const self = this; // eslint-disable-line @typescript-eslint/no-explicit-any this.$nextTick(() => { if (self._subscribing) { self._i18n.unsubscribeDataChanging(self); delete self._subscribing; } if (self._i18nWatcher) { self._i18nWatcher(); self._i18n.destroyVM(); delete self._i18nWatcher; } if (self._localeWatcher) { self._localeWatcher(); delete self._localeWatcher; } }); } }; } // for bridge let _legacyVueI18n = null; // eslint-disable-line @typescript-eslint/no-explicit-any let _legacyI18n = null; // eslint-disable-line @typescript-eslint/no-explicit-any /** * Injection key for {@link useI18n} * * @remarks * The global injection key for I18n instances with `useI18n`. this injection key is used in Web Components. * Specify the i18n instance created by {@link createI18n} together with `provide` function. * * @VueI18nGeneral */ const I18nInjectionKey = /* #__PURE__*/ makeSymbol('global-vue-i18n'); // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types function createI18n(options = {}, VueI18nLegacy) { if (_legacyI18n) { (process.env.NODE_ENV !== 'production') && warn(getWarnMessage(I18nWarnCodes.NOT_SUPPORT_MULTI_I18N_INSTANCE)); return _legacyI18n; } { _legacyVueI18n = VueI18nLegacy; } // prettier-ignore const __legacyMode = __VUE_I18N_LEGACY_API__ && isBoolean(options.legacy) ? options.legacy : __VUE_I18N_LEGACY_API__; !!options.globalInjection; const __instances = new Map(); const __global = createGlobal(options, __legacyMode, VueI18nLegacy); makeSymbol((process.env.NODE_ENV !== 'production') ? 'vue-i18n' : ''); function __getInstance(component) { return __instances.get(component) || null; } function __setInstance(component, instance) { __instances.set(component, instance); } function __deleteInstance(component) { __instances.delete(component); } { // extend legacy VueI18n instance const i18n = __global[LegacyInstanceSymbol]; // eslint-disable-line @typescript-eslint/no-explicit-any Object.defineProperty(i18n, 'global', { get() { return __global; } }); Object.defineProperty(i18n, 'mode', { get() { return __legacyMode ? 'legacy' : 'composition'; } }); Object.defineProperty(i18n, '__instances', { get() { return __instances; } }); Object.defineProperty(i18n, 'install', { // eslint-disable-next-line @typescript-eslint/no-explicit-any value: (Vue) => { const version = (Vue && Vue.version && Number(Vue.version.split('.')[0])) || -1; if (version !== 2) { throw createI18nError(I18nErrorCodes.BRIDGE_SUPPORT_VUE_2_ONLY); } Vue.mixin(defineMixin(i18n, _legacyVueI18n)); } }); const methodMap = { __getInstance, __setInstance, __deleteInstance }; Object.keys(methodMap).forEach(key => Object.defineProperty(i18n, key, { value: methodMap[key] }) // eslint-disable-line @typescript-eslint/no-explicit-any ); _legacyI18n = i18n; return i18n; } } // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types function useI18n(options = {}) { const instance = getCurrentInstance(); if (instance == null) { throw createI18nError(I18nErrorCodes.MUST_BE_CALL_SETUP_TOP); } { if (_legacyVueI18n == null || _legacyI18n == null) { throw createI18nError(I18nErrorCodes.NOT_INSLALLED); } } const i18n = getI18nInstance(instance); const global = getGlobalComposer(i18n); const componentOptions = getComponentOptions(instance); const scope = getScope(options, componentOptions); if (scope === 'global') { adjustI18nResources(global, options, componentOptions); return global; } if (scope === 'parent') { let composer = getComposer(i18n, instance); if (composer == null) { if ((process.env.NODE_ENV !== 'production')) { warn(getWarnMessage(I18nWarnCodes.NOT_FOUND_PARENT_SCOPE)); } composer = global; } return composer; } // scope 'local' case if (i18n.mode === 'legacy') { throw createI18nError(I18nErrorCodes.NOT_AVAILABLE_IN_LEGACY_MODE); } const i18nInternal = i18n; let composer = i18nInternal.__getInstance(instance); if (composer == null) { const composerOptions = assign({}, options); if ('__i18n' in componentOptions) { composerOptions.__i18n = componentOptions.__i18n; } if (global) { composerOptions.__root = global; } composer = createComposer(composerOptions, _legacyVueI18n); setupLifeCycle(i18nInternal, instance, composer); i18nInternal.__setInstance(instance, composer); } return composer; } function createGlobal(options, legacyMode, VueI18nLegacy // eslint-disable-line @typescript-eslint/no-explicit-any ) { { if (!isLegacyVueI18n(VueI18nLegacy)) { throw createI18nError(I18nErrorCodes.NOT_COMPATIBLE_LEGACY_VUE_I18N); } return createComposer(options, VueI18nLegacy); } } function getI18nInstance(instance) { { const vm = instance.proxy; /* istanbul ignore if */ if (vm == null) { throw createI18nError(I18nErrorCodes.UNEXPECTED_ERROR); } const i18n = vm._i18nBridgeRoot; // eslint-disable-line @typescript-eslint/no-explicit-any /* istanbul ignore if */ if (!i18n) { throw createI18nError(I18nErrorCodes.NOT_INSLALLED); } return i18n; } } // eslint-disable-next-line @typescript-eslint/no-explicit-any function getComponentOptions(instance) { return instance.proxy.$options; } // eslint-disable-next-line @typescript-eslint/no-explicit-any function getScope(options, componentOptions) { // prettier-ignore return isEmptyObject(options) ? ('__i18n' in componentOptions) ? 'local' : 'global' : !options.useScope ? 'local' : options.useScope; } function getGlobalComposer(i18n) { // prettier-ignore return i18n.global; } function adjustI18nResources(global, options, componentOptions // eslint-disable-line @typescript-eslint/no-explicit-any ) { let messages = isObject(options.messages) ? options.messages : {}; if ('__i18nGlobal' in componentOptions) { messages = getLocaleMessages(global.locale.value, { messages, __i18n: componentOptions.__i18nGlobal }); } // merge locale messages const locales = Object.keys(messages); if (locales.length) { locales.forEach(locale => { global.mergeLocaleMessage(locale, messages[locale]); }); } { // merge datetime formats if (isObject(options.datetimeFormats)) { const locales = Object.keys(options.datetimeFormats); if (locales.length) { locales.forEach(locale => { global.mergeDateTimeFormat(locale, options.datetimeFormats[locale]); }); } } // merge number formats if (isObject(options.numberFormats)) { const locales = Object.keys(options.numberFormats); if (locales.length) { locales.forEach(locale => { global.mergeNumberFormat(locale, options.numberFormats[locale]); }); } } } } function getComposer(i18n, target) { let composer = null; const root = target.root; let current = target.parent; while (current != null) { const i18nInternal = i18n; if (i18n.mode === 'composition') { composer = i18nInternal.__getInstance(current); } else { if (__VUE_I18N_LEGACY_API__) { const vueI18n = i18nInternal.__getInstance(current); if (vueI18n != null) { composer = vueI18n .__composer; } } } if (composer != null) { break; } if (root === current) { break; } current = current.parent; } return composer; } function setupLifeCycle(i18n, target, composer) { { // assign legacy VueI18n instance to Vue2 instance // eslint-disable-next-line @typescript-eslint/no-explicit-any const vm = target.proxy; if (vm == null) { throw createI18nError(I18nErrorCodes.UNEXPECTED_ERROR); } // eslint-disable-next-line @typescript-eslint/no-explicit-any const _i18n = composer[LegacyInstanceSymbol]; if (_i18n === i18n) { throw createI18nError(I18nErrorCodes.UNEXPECTED_ERROR); } vm._i18n = _i18n; vm._i18n_bridge = true; vm._i18nWatcher = vm._i18n.watchI18nData(); if (vm._i18n._sync) { vm._localeWatcher = vm._i18n.watchLocale(); } let subscribing = false; onBeforeMount(() => { vm._i18n.subscribeDataChanging(vm); subscribing = true; }, target); onUnmounted(() => { if (subscribing) { vm._i18n.unsubscribeDataChanging(vm); subscribing = false; } if (vm._i18nWatcher) { vm._i18nWatcher(); vm._i18n.destroyVM(); delete vm._i18nWatcher; } if (vm._localeWatcher) { vm._localeWatcher(); delete vm._localeWatcher; } delete vm._i18n_bridge; delete vm._i18n; }, target); } } // register message resolver at vue-i18n registerMessageResolver(resolveValue); // register fallback locale at vue-i18n registerLocaleFallbacker(fallbackWithLocaleChain); { initFeatureFlags(); } // NOTE: experimental !! if ((process.env.NODE_ENV !== 'production') || __INTLIFY_PROD_DEVTOOLS__) { const target = getGlobalThis(); target.__INTLIFY__ = true; setDevToolsHook(target.__INTLIFY_DEVTOOLS_GLOBAL_HOOK__); } if ((process.env.NODE_ENV !== 'production')) ; export { I18nInjectionKey, VERSION, createI18n, useI18n };