Cómo soportar idiomas de derecha a izquierda (RTL) en Next.js (Pages Router) v16

Espejar layouts para árabe y hebreo

Problema

La mayoría de los diseños web asumen un flujo de texto de izquierda a derecha. Los menús de navegación se anclan a la izquierda, el contenido se lee de izquierda a derecha, y el espaciado se aplica con propiedades como margin-left o padding-right. Cuando una aplicación se traduce al árabe o hebreo, estos idiomas se leen de derecha a izquierda, y todo el diseño visual debería reflejarse para coincidir. Sin este reflejo, los usuarios experimentan una interfaz desorientadora donde la jerarquía visual contradice su dirección natural de lectura, haciendo que la navegación sea confusa y que la aplicación parezca poco pulida.

El desafío va más allá de la alineación del texto. Las propiedades físicas de CSS como left, right, margin-left y padding-right están vinculadas a posiciones fijas de la pantalla en lugar del flujo del contenido. Cuando cambia la dirección del texto, estas propiedades permanecen ancladas a los mismos bordes físicos, impidiendo que el diseño se adapte naturalmente.

Solución

Establecer el atributo de dirección de texto del documento para que coincida con la configuración regional actual, permitiendo a los navegadores invertir automáticamente el flujo del diseño para idiomas RTL. Reemplazar las propiedades físicas de CSS con propiedades lógicas que hacen referencia al flujo del contenido en lugar de la posición en la pantalla. Propiedades lógicas como margin-inline-start y padding-inline-end se mapean automáticamente al borde físico correcto basado en la dirección del texto, permitiendo que los diseños se reflejen sin código adicional o estilos condicionales.

Este enfoque crea diseños agnósticos a la dirección que funcionan correctamente tanto para idiomas LTR como RTL sin duplicar estilos o añadir lógica compleja.

Pasos

1. Crear un helper para determinar la dirección del texto desde la configuración regional

Las propiedades lógicas se adaptan según la dirección del texto, con margin-inline-start equivalente a margin-left en contextos LTR y margin-right en contextos RTL. Construye una función de utilidad que mapee las configuraciones regionales a su dirección de texto.

export function getDirection(locale: string): "ltr" | "rtl" {
  const rtlLocales = ["ar", "he", "fa", "ur"];
  return rtlLocales.includes(locale) ? "rtl" : "ltr";
}

Esta función identifica los idiomas RTL y devuelve el valor de dirección apropiado para usar en HTML y CSS.

2. Establecer el atributo de dirección del documento

Las clases de Document personalizadas pueden sobrescribir el método render para personalizar el elemento HTML con atributos como lang y dir. Crea un Document personalizado para establecer el atributo dir en el elemento HTML raíz basado en la configuración regional actual.

import Document, {
  Html,
  Head,
  Main,
  NextScript,
  DocumentContext,
} from "next/document";
import { getDirection } from "../utils/direction";

class MyDocument extends Document {
  static async getInitialProps(ctx: DocumentContext) {
    const initialProps = await Document.getInitialProps(ctx);
    return initialProps;
  }

  render() {
    const locale = this.props.__NEXT_DATA__.locale || "en";
    const dir = getDirection(locale);

    return (
      <Html lang={locale} dir={dir}>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;

El router de Next.js proporciona la configuración regional activa a través de la propiedad locale. El documento lee la configuración regional de los datos de enrutamiento de Next.js y aplica la dirección correspondiente al elemento HTML, habilitando el soporte RTL a nivel del navegador.

3. Reemplazar propiedades CSS físicas con equivalentes lógicos

Las propiedades lógicas como margin-inline-start, padding-inline-start, y sus formas abreviadas margin-inline y padding-inline se mapean automáticamente a propiedades físicas basadas en el modo de escritura y dirección. Actualiza los estilos de tus componentes para usar propiedades relativas al flujo.

export default function Navigation() {
  return (
    <nav className="nav">
      <ul className="nav-list">
        <li className="nav-item">Home</li>
        <li className="nav-item">About</li>
        <li className="nav-item">Contact</li>
      </ul>
    </nav>
  );
}
.nav {
  padding-inline: 1rem;
  border-inline-start: 4px solid blue;
}

.nav-list {
  display: flex;
  gap: 1rem;
  margin-block: 0;
  padding-inline-start: 0;
}

.nav-item {
  margin-inline-end: 1.5rem;
}

Las propiedades lógicas para margin, padding e inset facilitan el posicionamiento de elementos y lo hacen más eficiente en diferentes modos de escritura. Estas propiedades se invierten automáticamente en contextos RTL sin necesidad de estilos adicionales o media queries.

4. Utiliza propiedades lógicas para el posicionamiento

Para elementos posicionados absoluta o relativamente, reemplaza left y right con inset-inline-start e inset-inline-end.

export default function Sidebar() {
  return (
    <aside className="sidebar">
      <button className="close-button">×</button>
      <p>Sidebar content</p>
    </aside>
  );
}
.sidebar {
  position: fixed;
  inset-inline-start: 0;
  inset-block-start: 0;
  inline-size: 250px;
  block-size: 100vh;
  padding-inline: 1rem;
}

.close-button {
  position: absolute;
  inset-inline-end: 0.5rem;
  inset-block-start: 0.5rem;
}

La propiedad width se reemplaza por inline-size y height por block-size en la metodología de propiedades lógicas. Estas propiedades aseguran que los elementos posicionados aparezcan en el lado correcto para la dirección de texto actual.

5. Aplica alineación lógica de texto

Reemplaza text-align: left y text-align: right con text-align: start y text-align: end.

.content {
  text-align: start;
}

.metadata {
  text-align: end;
  margin-inline-start: auto;
}

Las propiedades lógicas se refieren a los bordes de una caja en relación con el flujo de contenido en lugar de las dimensiones físicas del viewport. Los valores de alineación de texto start y end se adaptan automáticamente a la dirección del texto, alineando el contenido apropiadamente tanto para idiomas LTR como RTL.