vue-i18n-lite
Version:
A super lightweight and minimal plugin that introduces internationalization into your Vue.js app with a simple API
193 lines (185 loc) • 5.26 kB
JavaScript
/*!
* vue-i18n-lite v1.0.2
* (c) 2021 Erik Pham
* @license MIT
*/
;
Object.defineProperty(exports, '__esModule', { value: true });
var vue = require('vue');
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;