nuxt-i18n-micro
Version:
Nuxt I18n Micro is a lightweight, high-performance internationalization module for Nuxt, designed to handle multi-language support with minimal overhead, fast build times, and efficient runtime performance.
231 lines (230 loc) • 9.26 kB
JavaScript
import { useTranslationHelper, interpolate, isNoPrefixStrategy, RouteService, FormatService } from "nuxt-i18n-micro-core";
import { useRouter, useCookie, useState, unref, navigateTo, defineNuxtPlugin, useRuntimeConfig } from "#imports";
import { plural } from "#build/i18n.plural.mjs";
const i18nHelper = useTranslationHelper();
const isDev = process.env.NODE_ENV !== "production";
export default defineNuxtPlugin(async (nuxtApp) => {
const config = useRuntimeConfig();
const i18nConfig = config.public.i18nConfig;
const apiBaseUrl = i18nConfig.apiBaseUrl ?? "_locales";
const router = useRouter();
const runtimeConfig = useRuntimeConfig();
let hashLocaleDefault = null;
let noPrefixDefault = null;
if (i18nConfig.hashMode) {
hashLocaleDefault = await nuxtApp.runWithContext(() => useCookie("hash-locale").value);
}
if (isNoPrefixStrategy(i18nConfig.strategy)) {
noPrefixDefault = await nuxtApp.runWithContext(() => useCookie("no-prefix-locale").value);
}
const routeService = new RouteService(
i18nConfig,
router,
hashLocaleDefault,
noPrefixDefault,
(to, options) => navigateTo(to, options),
(name, value) => {
nuxtApp.runWithContext(() => {
return useCookie(name).value = value;
});
}
);
const translationService = new FormatService();
const i18nRouteParams = useState("i18n-route-params", () => ({}));
nuxtApp.hook("page:start", () => {
i18nRouteParams.value = null;
});
const loadTranslationsIfNeeded = async (locale, routeName, path) => {
try {
if (!i18nHelper.hasPageTranslation(locale, routeName)) {
let fRouteName = routeName;
if (i18nConfig.routesLocaleLinks && fRouteName && i18nConfig.routesLocaleLinks[fRouteName]) {
const newRouteName = i18nConfig.routesLocaleLinks[fRouteName];
if (newRouteName) {
fRouteName = newRouteName;
}
}
if (!fRouteName || fRouteName === "") {
console.warn(`[nuxt-i18n-next] The page name is missing in the path: ${path}. Please ensure that definePageMeta({ name: 'pageName' }) is set.`);
return;
}
const url = `/${apiBaseUrl}/${fRouteName}/${locale}/data.json`.replace(/\/{2,}/g, "/");
const data = await $fetch(url, {
baseURL: runtimeConfig.app.baseURL,
params: {
v: i18nConfig.dateBuild
}
});
await i18nHelper.loadPageTranslations(locale, routeName, data ?? {});
}
} catch (_error) {
}
};
async function loadGlobalTranslations(to) {
let locale = routeService.getCurrentLocale(to);
if (i18nConfig.hashMode) {
locale = await nuxtApp.runWithContext(() => {
return useCookie("hash-locale", { default: () => locale }).value;
});
}
if (isNoPrefixStrategy(i18nConfig.strategy)) {
locale = await nuxtApp.runWithContext(() => {
return useCookie("no-prefix-locale", { default: () => locale }).value;
});
}
if (!i18nHelper.hasGeneralTranslation(locale)) {
const url = `/${apiBaseUrl}/general/${locale}/data.json`.replace(/\/{2,}/g, "/");
const data = await $fetch(url, {
baseURL: runtimeConfig.app.baseURL,
params: {
v: i18nConfig.dateBuild
}
});
await i18nHelper.loadTranslations(locale, data ?? {});
}
if (!i18nConfig.disablePageLocales) {
const locale2 = routeService.getCurrentLocale(to);
const routeName = routeService.getRouteName(to, locale2);
await loadTranslationsIfNeeded(locale2, routeName, to.fullPath);
}
}
router.beforeEach(async (to, from, next) => {
if (to.path !== from.path || isNoPrefixStrategy(i18nConfig.strategy)) {
await loadGlobalTranslations(to);
}
if (next) {
next();
}
});
await loadGlobalTranslations(router.currentRoute.value);
const provideData = {
i18n: void 0,
__micro: true,
getLocale: (route) => routeService.getCurrentLocale(route),
getLocaleName: () => routeService.getCurrentName(routeService.getCurrentRoute()),
defaultLocale: () => i18nConfig.defaultLocale,
getLocales: () => i18nConfig.locales || [],
getRouteName: (route, locale) => {
const selectedLocale = locale ?? routeService.getCurrentLocale();
const selectedRoute = route ?? routeService.getCurrentRoute();
return routeService.getRouteName(selectedRoute, selectedLocale);
},
t: (key, params, defaultValue, route) => {
if (!key) return "";
route = route ?? routeService.getCurrentRoute();
const locale = routeService.getCurrentLocale();
const routeName = routeService.getRouteName(route, locale);
let value = i18nHelper.getTranslation(locale, routeName, key);
if (!value) {
if (isDev && import.meta.client) {
console.warn(`Not found '${key}' key in '${locale}' locale messages.`);
}
value = defaultValue === void 0 ? key : defaultValue;
}
return typeof value === "string" && params ? interpolate(value, params) : value;
},
ts: (key, params, defaultValue, route) => {
const value = provideData.t(key, params, defaultValue, route);
return value?.toString() ?? defaultValue ?? key;
},
_t: (route) => {
return (key, params, defaultValue) => {
return provideData.t(key, params, defaultValue, route);
};
},
_ts: (route) => {
return (key, params, defaultValue) => {
return provideData.ts(key, params, defaultValue, route);
};
},
tc: (key, params, defaultValue) => {
const currentLocale = routeService.getCurrentLocale();
const { count, ..._params } = typeof params === "number" ? { count: params } : params;
if (count === void 0) return defaultValue ?? key;
return plural(key, Number.parseInt(count.toString()), _params, currentLocale, provideData.t) ?? defaultValue ?? key;
},
tn: (value, options) => {
const currentLocale = routeService.getCurrentLocale();
return translationService.formatNumber(value, currentLocale, options);
},
td: (value, options) => {
const currentLocale = routeService.getCurrentLocale();
return translationService.formatDate(value, currentLocale, options);
},
tdr: (value, options) => {
const currentLocale = routeService.getCurrentLocale();
return translationService.formatRelativeTime(value, currentLocale, options);
},
has: (key, route) => {
route = route ?? routeService.getCurrentRoute();
const locale = routeService.getCurrentLocale();
const routeName = routeService.getRouteName(route, locale);
return !!i18nHelper.getTranslation(locale, routeName, key);
},
mergeTranslations: (newTranslations) => {
const route = routeService.getCurrentRoute();
const locale = routeService.getCurrentLocale(route);
const routeName = routeService.getRouteName(route, locale);
i18nHelper.mergeTranslation(locale, routeName, newTranslations);
},
mergeGlobalTranslations: (newTranslations) => {
const locale = routeService.getCurrentLocale();
i18nHelper.mergeGlobalTranslation(locale, newTranslations, true);
},
switchLocaleRoute: (toLocale) => {
const route = routeService.getCurrentRoute();
const fromLocale = routeService.getCurrentLocale(route);
return routeService.switchLocaleRoute(fromLocale, toLocale, route, unref(i18nRouteParams.value));
},
clearCache: () => {
i18nHelper.clearCache();
},
switchLocalePath: (toLocale) => {
const route = routeService.getCurrentRoute();
const fromLocale = routeService.getCurrentLocale(route);
const localeRoute = routeService.switchLocaleRoute(fromLocale, toLocale, route, unref(i18nRouteParams.value));
if (typeof localeRoute === "string") {
return localeRoute;
}
if ("fullPath" in localeRoute && localeRoute.fullPath) {
return localeRoute.fullPath;
}
if ("name" in localeRoute && localeRoute.name) {
if (router.hasRoute(localeRoute.name)) {
return router.resolve(localeRoute).fullPath;
}
}
return "";
},
switchLocale: (toLocale) => {
return routeService.switchLocaleLogic(toLocale, unref(i18nRouteParams.value));
},
switchRoute: (route, toLocale) => {
return routeService.switchLocaleLogic(toLocale ?? routeService.getCurrentLocale(), unref(i18nRouteParams.value), route);
},
localeRoute: (to, locale) => {
return routeService.resolveLocalizedRoute(to, locale);
},
localePath: (to, locale) => {
const localeRoute = routeService.resolveLocalizedRoute(to, locale);
if (typeof localeRoute === "string") {
return localeRoute;
}
if ("fullPath" in localeRoute) {
return localeRoute.fullPath;
}
return "";
},
setI18nRouteParams: (value) => {
i18nRouteParams.value = value;
return i18nRouteParams.value;
}
};
const $provideData = Object.fromEntries(
Object.entries(provideData).map(([key, value]) => [`$${key}`, value])
);
provideData.i18n = { ...provideData, ...$provideData };
return {
provide: provideData
};
});