import { addLeadingSlash, normalizeHrefInRuntime, removeBase, useLocation, usePage, useSite, useVersion, } from '@rspress/core/runtime'; function replaceLang( rawUrl: string, lang: { current: string; target: string; default: string; }, version: { current: string; default: string; }, cleanUrls: boolean, isPageNotFound: boolean, ) { let url = removeBase(rawUrl); // rspress.rs/builder + switch to en -> rspress.rs/builder/en/index.html if (!url || isPageNotFound) { url = '/'; } url = normalizeHrefInRuntime(url); let versionPart = ''; let langPart = ''; let purePathPart = ''; const parts = url.split('/').filter(Boolean); if (version.current && version.current !== version.default) { versionPart = parts.shift() || ''; } // Should we remove the lang part? // The answer is as follows: if (lang.target !== lang.default) { langPart = lang.target; if (lang.current !== lang.default) { parts.shift(); } } else { parts.shift(); } purePathPart = parts.join('/') || ''; if ((versionPart || langPart) && !purePathPart) { purePathPart = cleanUrls ? 'index' : 'index.html'; } return addLeadingSlash( [versionPart, langPart, purePathPart].filter(Boolean).join('/'), ); } export function useLangsMenu() { const { page } = usePage(); const { site } = useSite(); const currentVersion = useVersion(); const { pathname, search } = useLocation(); const defaultLang = site.lang || ''; const defaultVersion = site.multiVersion.default || ''; const localeLanguages = Object.values( site.locales || site.themeConfig.locales || {}, ); const cleanUrls = site.route?.cleanUrls || false; const hasMultiLanguage = localeLanguages.length > 1; const { lang: currentLang, pageType } = page; const translationMenuData = hasMultiLanguage ? { items: localeLanguages.map(item => { return { text: item?.label, link: replaceLang( pathname + search, { current: currentLang, target: item.lang, default: defaultLang, }, { current: currentVersion, default: defaultVersion, }, cleanUrls, pageType === '404', ), lang: item.lang, rel: 'alternate', }; }), activeValue: localeLanguages.find(item => currentLang === item.lang) ?.label, } : { items: [] }; return translationMenuData; } function replaceVersion( rawUrl: string, version: { current: string; target: string; default: string; }, cleanUrls: boolean, isPageNotFound: boolean, ) { let url = removeBase(rawUrl); // rspress.rs/builder + switch to en -> rspress.rs/builder/en/index.html if (!url || isPageNotFound) { url = normalizeHrefInRuntime('/'); } let versionPart = ''; const parts = url.split('/').filter(Boolean); if (version.target !== version.default) { versionPart = version.target; if (version.current !== version.default) { parts.shift(); } } else { parts.shift(); } let restPart = parts.join('/') || ''; if (versionPart && !restPart) { restPart = cleanUrls ? 'index' : 'index.html'; } return addLeadingSlash([versionPart, restPart].filter(Boolean).join('/')); } export function useVersionsMenu() { const { page } = usePage(); const { site } = useSite(); const currentVersion = useVersion(); const { pathname } = useLocation(); const cleanUrls = site.route?.cleanUrls || false; const defaultVersion = site.multiVersion.default || ''; const versions = site.multiVersion.versions || []; const versionsMenuData = { items: versions.map(version => ({ text: version, link: replaceVersion( pathname, { current: currentVersion, target: version, default: defaultVersion, }, cleanUrls, page.pageType === '404', ), })), text: currentVersion, activeValue: currentVersion, }; return versionsMenuData; }