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
JavaScript
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?.();
});
});