diff --git a/web-next/app/[locale]/log-out/route.ts b/web-next/app/[locale]/log-out/route.ts index 2bdf192..dca2379 100644 --- a/web-next/app/[locale]/log-out/route.ts +++ b/web-next/app/[locale]/log-out/route.ts @@ -18,5 +18,6 @@ export async function GET(_request: Request, { params }: { params: Promise<{ loc const session = await getSession() session.destroy() + // La raíz de idioma es canónica CON barra (/es/); el resto de rutas sin barra. return new NextResponse(null, { status: 303, headers: { Location: `/${loc}/` } }) } diff --git a/web-next/app/[locale]/login/LoginForm.tsx b/web-next/app/[locale]/login/LoginForm.tsx index 0378039..1efc234 100644 --- a/web-next/app/[locale]/login/LoginForm.tsx +++ b/web-next/app/[locale]/login/LoginForm.tsx @@ -38,7 +38,7 @@ export function LoginForm() { // Navegación completa (no del lado cliente): fuerza que el servidor // re-renderice el layout/cabecera con la sesión nueva. Con router.push // el layout persiste y la cabecera seguía mostrando "Conectar". - window.location.assign(`/${locale}${data.needsSelection ? '/select-account/' : '/my-account/'}`) + window.location.assign(`/${locale}${data.needsSelection ? '/select-account' : '/my-account'}`) return } else { const key = (ERROR_KEYS as readonly string[]).includes(data.error ?? '') ? data.error! : 'genericError' diff --git a/web-next/app/[locale]/select-account/SelectAccountForm.tsx b/web-next/app/[locale]/select-account/SelectAccountForm.tsx index 535b5b0..0eb5ea1 100644 --- a/web-next/app/[locale]/select-account/SelectAccountForm.tsx +++ b/web-next/app/[locale]/select-account/SelectAccountForm.tsx @@ -28,7 +28,7 @@ export function SelectAccountForm({ accounts }: { accounts: GameAccount[] }) { }) const data: { success?: boolean } = await res.json() // Navegación completa: re-renderiza el layout/cabecera con la cuenta ya elegida. - if (data.success) window.location.assign(`/${locale}/my-account/`) + if (data.success) window.location.assign(`/${locale}/my-account`) else { setError(t('error')) setBusy(null) diff --git a/web-next/components/SiteHeader.tsx b/web-next/components/SiteHeader.tsx index b6a7fe6..d14ee71 100644 --- a/web-next/components/SiteHeader.tsx +++ b/web-next/components/SiteHeader.tsx @@ -118,7 +118,7 @@ export function SiteHeader({ MI CUENTA

- DESCONECTAR + DESCONECTAR

diff --git a/web-next/middleware.ts b/web-next/middleware.ts index 9a6d201..3a81c69 100644 --- a/web-next/middleware.ts +++ b/web-next/middleware.ts @@ -1,7 +1,31 @@ import createMiddleware from 'next-intl/middleware' +import { NextResponse, type NextRequest } from 'next/server' import { routing } from './i18n/routing' -export default createMiddleware(routing) +const intlMiddleware = createMiddleware(routing) + +// Raíces de idioma: «/es», «/en». Estas SÍ llevan barra final; el resto NO. +const LOCALE_ROOTS = new Set(routing.locales.map((l) => `/${l}`)) + +export default function middleware(request: NextRequest) { + const { pathname } = request.nextUrl + + // 1) Raíz de idioma sin barra → con barra: /es → /es/ + if (LOCALE_ROOTS.has(pathname)) { + const url = new URL(request.url) + url.pathname = `${pathname}/` + return NextResponse.redirect(url) + } + + // 2) Sub-ruta con barra final → sin barra (la raíz /es/ se conserva): /es/x/ → /es/x + if (pathname.length > 1 && pathname.endsWith('/') && !LOCALE_ROOTS.has(pathname.slice(0, -1))) { + const url = new URL(request.url) + url.pathname = pathname.replace(/\/+$/, '') + return NextResponse.redirect(url) + } + + return intlMiddleware(request) +} export const config = { // Aplica a todo salvo /api, estáticos de Next e ipas con extensión. diff --git a/web-next/next.config.ts b/web-next/next.config.ts index 72ff0e1..7f87dfe 100644 --- a/web-next/next.config.ts +++ b/web-next/next.config.ts @@ -4,8 +4,10 @@ import createNextIntlPlugin from 'next-intl/plugin' const withNextIntl = createNextIntlPlugin('./i18n/request.ts') const nextConfig: NextConfig = { - // URLs con barra final (/es/ en vez de /es), como el sitio original. - trailingSlash: true, + // Barra final SOLO en la raíz de idioma (/es/, /en/); el resto de rutas SIN + // barra (/es/content-creators). Desactivamos el auto-redirect de Next: la + // normalización la hace el middleware con lógica estricta de pathname. + skipTrailingSlashRedirect: true, } export default withNextIntl(nextConfig)