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.
119 lines (118 loc) • 4.49 kB
JavaScript
import { joinURL, parseURL, withQuery } from "ufo";
import { isNoPrefixStrategy } from "@i18n-micro/core";
import { useRoute, useRuntimeConfig, useNuxtApp } from "#imports";
import { findAllowedLocalesForRoute } from "../utils/route-utils.js";
import { ref, unref } from "vue";
export const useLocaleHead = ({ addDirAttribute = true, identifierAttribute = "id", addSeoAttributes = true, baseUrl = "/" } = {}) => {
const metaObject = ref({
htmlAttrs: {},
link: [],
meta: []
});
function filterQuery(fullPath, whitelist) {
const { pathname, search } = parseURL(fullPath);
const params = new URLSearchParams(search);
const filtered = {};
for (const key of whitelist) {
if (params.has(key)) {
filtered[key] = params.get(key);
}
}
return withQuery(pathname, filtered);
}
function updateMeta() {
const route = useRoute();
if (route.matched.length === 0 || route.matched.some((record) => record.name === "custom-fallback-route")) {
metaObject.value = { htmlAttrs: {}, link: [], meta: [] };
return;
}
const { strategy, canonicalQueryWhitelist, routeLocales } = useRuntimeConfig().public.i18nConfig;
const { $getLocales, $getLocale, $switchLocalePath } = useNuxtApp();
if (!$getLocale || !$getLocales) return;
const locale = unref($getLocale());
const allLocales = unref($getLocales());
const routeName = (route.name ?? "").toString();
const currentLocale = unref($getLocales().find((loc) => loc.code === locale));
if (!currentLocale) return;
const currentRouteLocales = findAllowedLocalesForRoute(route, routeLocales);
const locales = currentRouteLocales ? allLocales.filter((loc) => currentRouteLocales.includes(loc.code)) : allLocales;
const currentIso = currentLocale.iso || locale;
const currentDir = currentLocale.dir || "auto";
let fullPath = unref(route.fullPath);
if (!fullPath.startsWith("/")) {
fullPath = `/${fullPath}`;
}
const matchedLocale = locales.find((locale2) => fullPath.startsWith(`/${locale2.code}`));
let localizedPath = fullPath;
let ogUrl;
let canonicalPath;
if (routeName.startsWith("localized-") && matchedLocale) {
localizedPath = fullPath.slice(matchedLocale.code.length + 1);
canonicalPath = filterQuery(localizedPath, canonicalQueryWhitelist ?? []);
ogUrl = joinURL(unref(baseUrl), locale, canonicalPath);
} else {
canonicalPath = filterQuery(fullPath, canonicalQueryWhitelist ?? []);
ogUrl = joinURL(unref(baseUrl), canonicalPath);
}
metaObject.value = {
htmlAttrs: {
lang: currentIso,
...addDirAttribute ? { dir: currentDir } : {}
},
link: [],
meta: []
};
if (!addSeoAttributes) return;
const alternateLocales = locales;
const ogLocaleMeta = {
[identifierAttribute]: "i18n-og",
property: "og:locale",
content: currentIso
};
const ogUrlMeta = {
[identifierAttribute]: "i18n-og-url",
property: "og:url",
content: ogUrl
};
const alternateOgLocalesMeta = alternateLocales.map((loc) => ({
[identifierAttribute]: `i18n-og-alt-${loc.iso || loc.code}`,
property: "og:locale:alternate",
content: unref(loc.iso || loc.code)
}));
const canonicalLink = {
[identifierAttribute]: "i18n-can",
rel: "canonical",
href: ogUrl
};
const alternateLinks = isNoPrefixStrategy(strategy) ? [] : alternateLocales.flatMap((loc) => {
const switchedPath = $switchLocalePath(loc.code);
if (!switchedPath) {
return [];
}
let href;
if (switchedPath.startsWith("http://") || switchedPath.startsWith("https://")) {
href = switchedPath;
} else {
href = joinURL(unref(baseUrl), switchedPath.startsWith("/") ? switchedPath : `/${switchedPath}`);
}
const links = [{
[identifierAttribute]: `i18n-alternate-${loc.code}`,
rel: "alternate",
href,
hreflang: unref(loc.code)
}];
if (loc.iso && loc.iso !== loc.code) {
links.push({
[identifierAttribute]: `i18n-alternate-${loc.iso}`,
rel: "alternate",
href,
hreflang: unref(loc.iso)
});
}
return links;
});
metaObject.value.meta = [ogLocaleMeta, ogUrlMeta, ...alternateOgLocalesMeta];
metaObject.value.link = [canonicalLink, ...alternateLinks];
}
return { metaObject, updateMeta };
};