Enlaces entre páginas localizadas

Manteniendo a los usuarios en su idioma seleccionado

Problema

Cuando los códigos de idioma forman parte de la URL, crear enlaces internos se vuelve complejo. Un enlace simple como <a href="/about"> es incorrecto, ya que rompe la ruta localizada, enviando a un usuario desde /fr/contact a /about en lugar de /fr/about. Esto saca al usuario del idioma que había seleccionado.

Solución

Crear un componente personalizado que envuelva el componente Link de Next.js. Este nuevo componente utilizará el hook useParams para obtener el idioma actual de la URL y automáticamente lo añadirá como prefijo a cualquier href que reciba, asegurando que todos los enlaces internos estén correctamente localizados.

Pasos

Crea un nuevo archivo app/components/LocalizedLink.tsx. Este debe ser un componente de cliente para poder usar el hook useParams.

// app/components/LocalizedLink.tsx
'use client';

import Link from 'next/link';
import { useParams } from 'next/navigation';
import type { ComponentProps } from 'react';

type LinkProps = ComponentProps<typeof Link>;

export default function LocalizedLink({ href, ...rest }: LinkProps) {
  const params = useParams();
  const lang = params.lang as string;

  let localizedHref = href;

  // Check if href is a string and needs prefixing
  if (typeof href === 'string' && href.startsWith('/')) {
    localizedHref = `/${lang}${href}`;
  } else if (
    typeof href === 'object' &&
    href !== null &&
    href.pathname?.startsWith('/')
  ) {
    // Re-create the object with a prefixed pathname
    localizedHref = {
      ...href,
      pathname: `/${lang}${href.pathname}`,
    };
  }
  // Absolute URLs or other cases are passed through

  return <Link href={localizedHref} {...rest} />;
}

Este componente importa las props estándar de Link. Comprueba si href es una cadena de texto (como /about) o un objeto (como { pathname: '/about' }) e inteligentemente añade como prefijo el lang actual (por ejemplo, es) a este.

2. Usa el componente en tus páginas

Ahora, en tus páginas, importa LocalizedLink en lugar del estándar next/link. Puedes usarlo exactamente como usarías el componente Link normal, pero sin preocuparte por el prefijo de idioma.

// app/[lang]/page.tsx
import LocalizedLink from '@/app/components/LocalizedLink';

export default function Home({ params }: { params: { lang: string } }) {
  return (
    <div>
      <h1>Home page</h1>
      <p>Current language: {params.lang}</p>
      
      <nav>
        <ul>
          <li>
            {/* This will render as /en/about or /es/about, etc. */}
            <LocalizedLink href="/about">About page</LocalizedLink>
          </li>
          <li>
            {/* This also works */}
            <LocalizedLink href={{ pathname: '/contact' }}>
              Contact page
            </LocalizedLink>
          </li>
        </ul>
      </nav>
    </div>
  );
}

Usar <LocalizedLink href="/about"> ahora renderiza correctamente un enlace a /{current_lang}/about, manteniendo al usuario dentro del idioma seleccionado mientras navega por tu sitio.