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.

99 lines (98 loc) 4.55 kB
import { isNoPrefixStrategy, isPrefixStrategy } from "@i18n-micro/core"; import { defineNuxtPlugin, useRuntimeConfig, useRoute, useRouter, navigateTo, createError } from "#imports"; import { findAllowedLocalesForRoute } from "../utils/route-utils.js"; import { joinURL, withQuery } from "ufo"; function resolvePathWithParams(path, params) { let resolvedPath = path; for (const key in params) { const value = params[key]; if (value) { const stringValue = String(value); resolvedPath = resolvedPath.replace(`:${key}()`, stringValue).replace(`:${key}`, stringValue); } } return resolvedPath; } export default defineNuxtPlugin(async (nuxtApp) => { const config = useRuntimeConfig(); const i18nConfig = config.public.i18nConfig; const { routeLocales, globalLocaleRoutes } = useRuntimeConfig().public.i18nConfig; const route = useRoute(); const router = useRouter(); const checkGlobalLocaleRoutes = (to) => { if (!globalLocaleRoutes || typeof globalLocaleRoutes !== "object" || Object.keys(globalLocaleRoutes).length === 0) { return false; } const locales = i18nConfig.locales?.map((l) => l.code) || []; const defaultLocale = i18nConfig.defaultLocale || "en"; const pathSegments = to.path.split("/").filter(Boolean); const firstSegment = pathSegments[0]; const pathWithoutLocale = firstSegment && locales.includes(firstSegment) ? "/" + pathSegments.slice(1).join("/") : to.path; const routeName = (typeof to.name === "string" ? to.name : "").replace("localized-", "").replace(new RegExp(`-(${locales.join("|")})$`), ""); const routeRules = globalLocaleRoutes[pathWithoutLocale] || globalLocaleRoutes[routeName]; if (routeRules && typeof routeRules === "object") { const localeToUse = firstSegment && locales.includes(firstSegment) ? firstSegment : defaultLocale; const customPathSegment = localeToUse ? routeRules[localeToUse] : void 0; if (customPathSegment) { const resolvedCustomPath = resolvePathWithParams(customPathSegment, to.params); const localizedPath = firstSegment && locales.includes(firstSegment) ? joinURL(`/${firstSegment}`, resolvedCustomPath) : resolvedCustomPath; if (decodeURI(to.path) !== decodeURI(localizedPath)) { const finalUrl = withQuery(localizedPath, to.query); navigateTo(finalUrl, { redirectCode: 301, external: true }); return true; } } else if (firstSegment && locales.includes(firstSegment)) { throw createError({ statusCode: 404, statusMessage: "Page Not Found" }); } } return false; }; const checkRouteLocales = (to) => { const allowedLocales = findAllowedLocalesForRoute(to, routeLocales); if (!allowedLocales || allowedLocales.length === 0) return; const pathSegments = to.path.split("/").filter(Boolean); const firstSegment = pathSegments[0]; const allLocales = i18nConfig.locales?.map((l) => l.code) || []; if (firstSegment && allLocales.includes(firstSegment) && !allowedLocales.includes(firstSegment)) { throw createError({ statusCode: 404, statusMessage: "Page Not Found" }); } }; const handleRedirect = async (to) => { const currentLocale = nuxtApp.$getLocale(to); const name = to.name?.toString(); let defaultRouteName = name?.toString().replace("localized-", "").replace(new RegExp(`-${currentLocale}$`), ""); if (!to.params.locale) { if (router.hasRoute(`localized-${name}-${currentLocale}`)) { defaultRouteName = `localized-${name}-${currentLocale}`; } else { defaultRouteName = `localized-${name}`; } if (!router.hasRoute(defaultRouteName)) return; const newParams = { ...to.params }; if (!isNoPrefixStrategy(i18nConfig.strategy)) { newParams.locale = i18nConfig.defaultLocale; } return navigateTo({ name: defaultRouteName, params: newParams }, { redirectCode: 301, external: true }); } }; if (import.meta.server) { if (checkGlobalLocaleRoutes(route)) return; checkRouteLocales(route); if (isPrefixStrategy(i18nConfig.strategy) || isNoPrefixStrategy(i18nConfig.strategy)) { await handleRedirect(route); } } router.beforeEach(async (to, from, next) => { if (checkGlobalLocaleRoutes(to)) return; if (from.path !== to.path) { checkRouteLocales(to); } if (isPrefixStrategy(i18nConfig.strategy) || isNoPrefixStrategy(i18nConfig.strategy)) { await handleRedirect(to); } next?.(); }); });