UNPKG

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
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 }; });