UNPKG

vue-i18n-lite

Version:

A super lightweight and minimal plugin that introduces internationalization into your Vue.js app with a simple API

196 lines (187 loc) 5.67 kB
/*! * vue-i18n-lite v1.0.2 * (c) 2021 Erik Pham * @license MIT */ var VueI18nLite = (function (exports, vue) { 'use strict'; const disallowedKeys = ['__proto__', 'prototype', 'constructor']; /** * Is object * @param value */ function isObject(value) { const type = typeof value; return value !== null && (type === 'object' || type === 'function'); } /** * Check is empty * @param obj */ function isEmpty(obj) { return !(Array.isArray(obj) ? obj.length : Object.keys(obj).length); } /** * Is valid path * @param segments */ function isValidPath(segments) { return !segments.some((segment) => disallowedKeys.indexOf(segment) !== -1); } /** * Parse path * @param path */ function parsePath(path) { const pathArray = path.split('.'); const parts = []; for (let i = 0; i < pathArray.length; i++) { let p = pathArray[i]; while (p[p.length - 1] === '\\' && pathArray[i + 1] !== undefined) { p = p.slice(0, -1) + '.'; p += pathArray[++i]; } parts.push(p); } if (!isValidPath(parts)) { return []; } return parts; } /** * Get object value by path * @param object * @param path */ function getMessage(object, path) { if (!isObject(object)) { return ''; } const paths = parsePath(path); if (paths.length === 0) { return ''; } let rawObject = Object.assign({}, object); for (let i = 0; i < paths.length; i++) { if (typeof rawObject[paths[i]] === 'string') { return rawObject[paths[i]]; } rawObject = rawObject[paths[i]]; if (rawObject === undefined || rawObject === null) { if (i !== paths.length - 1) { return ''; } break; } } return ''; } /** * Parse locale values * @param message * @param values */ function parseLocaleValues(message, values) { if (Array.isArray(values)) { const parseValues = {}; const matches = [...message.matchAll(/{(.+?)}/g)]; if (matches) { matches.forEach((match, index) => { if (values[index]) { parseValues[match[1]] = values[index]; } }); } return parseValues; } return values; } /** * Replace locale values to message * @param message * @param values */ function replaceLocaleValues(message, values) { for (const key in values) { message = message.replace(`{${key}}`, String(values[key])); } return message; } /** * Merge deep * @param target * @param source */ function mergeDeep(target, source) { Object.keys(source).forEach(key => { if (source[key] instanceof Object && key in target) { source[key] = { ...source[key], ...mergeDeep(target[key], source[key]) }; } }); return { ...(target || {}), ...source }; } const hasSymbol = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol'; const PolySymbol = (name) => hasSymbol ? Symbol(name) : '_vt_' + name; const vueI18nKey = /*#__PURE__*/ PolySymbol('i18n'); /** * Returns the i18n instance. */ function useI18n() { return vue.inject(vueI18nKey); } /** * Creates a I18n instance that can be used by a Vue app. * * @param options - {@link I18nOptions} */ function createI18n(options) { const initOptions = Object.assign({ locale: 'en', fallbackLocale: 'en', messages: {} }, options); const current = vue.ref(initOptions.locale); const locales = vue.reactive({}); Object.entries(initOptions.messages).forEach(([key, messages]) => { locales[key] = messages; }); return { t(key, option) { if (!key) { return ''; } const locale = typeof option === 'string' && option ? option : current.value; let message = getMessage(locales[locale], key) || getMessage(locales[initOptions.fallbackLocale], key); if (option && typeof option !== 'string') { const values = parseLocaleValues(message, option); if (!isEmpty(values)) { message = replaceLocaleValues(message, values); } } return message || key; }, current: vue.readonly(current), options: vue.readonly(options || {}), install(app) { const context = this; app.config.globalProperties.$t = context.t; app.provide(vueI18nKey, context); }, changeLocale(locale) { current.value = locale; }, setLocaleMessage(locale, messages) { locales[locale] = mergeDeep(vue.toRaw(locales[locale] || {}), messages); }, getLocaleMessage(locale) { return locales[locale] || {}; }, }; } /** * Super lightweight internationalization (i18n) plugin for Vue 3 * * @packageDocumentation */ exports.createI18n = createI18n; exports.useI18n = useI18n; Object.defineProperty(exports, '__esModule', { value: true }); return exports; }({}, Vue));