diff --git a/frontend/src/entry-server.tsx b/frontend/src/entry-server.tsx index 9c691ca..8deb38e 100644 --- a/frontend/src/entry-server.tsx +++ b/frontend/src/entry-server.tsx @@ -1,6 +1,6 @@ import { QueryClient, QueryClientProvider, dehydrate, skipToken } from '@tanstack/react-query' import { PassThrough } from 'node:stream' -import { renderToPipeableStream } from 'react-dom/server' +import { renderToPipeableStream, renderToStaticMarkup } from 'react-dom/server' import { HelmetProvider } from 'react-helmet-async' import { I18nextProvider } from 'react-i18next' import { createStaticHandler, createStaticRouter, @@ -9,7 +9,7 @@ import { createStaticHandler, createStaticRouter, import { AppFrame, appRoutes, resolvePageRoute } from '@/App' import { apiGet, isApiError } from '@/lib/api' import { createUII18n } from '@/lib/i18n' -import { fetchLocales, isLocaleCode, legacyLocalePath } from '@/lib/locales' +import { fetchLocales, isLocaleCode, legacyLocalePath, switchLocalePath } from '@/lib/locales' import { localesKeys, sessionKeys } from '@/lib/queryKeys' import { withRenderContext } from '@/lib/renderContext.server' @@ -171,8 +171,26 @@ export const render = async ( })) } const helmet = helmetContext.helmet! + const alternates = status === 200 && known != null + ? await Promise.all (locales.locales.map (entry => entry.code) + .filter (isLocaleCode) + .filter (code => known.route.handle?.locale == null + || known.route.handle.locale === code) + .map (async targetLocale => { + const location = { pathname: url.pathname, search: url.search, hash: '' } + const path = targetLocale === locale + ? url.pathname + url.search + : (known.route.handle?.switchLocale != null + ? await known.route.handle.switchLocale ({ + location, params: known.params, locale, targetLocale }) + : switchLocalePath (location, targetLocale)) + return + })) + : [] const head = [helmet.title, helmet.meta, helmet.link, helmet.style] .map (entry => entry.toString ()).join ('') + + renderToStaticMarkup (<>{alternates}) const dehydrated = dehydrate (client, { shouldDehydrateQuery: query => query.state.status !== 'pending' && query.meta?.clientOnly !== true