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.
117 lines (116 loc) • 4.38 kB
JavaScript
import { joinURL, parseURL, withQuery } from "ufo";
import { isPrefixExceptDefaultStrategy, isNoPrefixStrategy } from "nuxt-i18n-micro-core";
import { unref, useRoute, useRuntimeConfig, watch, onUnmounted, ref, useNuxtApp } from "#imports";
import { findAllowedLocalesForRoute } from "../utils/route-utils.js";
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 { defaultLocale, strategy, canonicalQueryWhitelist, routeLocales } = useRuntimeConfig().public.i18nConfig;
const { $getLocales, $getLocale } = useNuxtApp();
if (!$getLocale || !$getLocales) return;
const route = useRoute();
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 localizedPath2 = defaultLocale === loc.code && isPrefixExceptDefaultStrategy(strategy) ? canonicalPath : joinURL(loc.code, canonicalPath);
const href = joinURL(unref(baseUrl), localizedPath2);
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];
}
if (import.meta.client) {
const route = useRoute();
const stop = watch(
() => route.fullPath,
() => updateMeta(),
{ immediate: true }
);
onUnmounted(() => stop());
} else {
updateMeta();
}
return metaObject;
};