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

Reflejar diseños 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 debe 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 la aplicación se sienta poco pulida.

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

Solución

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

Este enfoque crea diseños independientes de la dirección que funcionan correctamente tanto para idiomas LTR como RTL sin duplicar estilos ni agregar lógica compleja.

Pasos

1. Crear una función auxiliar 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, siendo 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 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 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 según 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 actualmente 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 asignan automáticamente a propiedades físicas según el modo de escritura y la 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 de manera más eficiente en diferentes modos de escritura. Estas propiedades se invierten automáticamente en contextos RTL sin estilos adicionales ni media queries.

4. Usar propiedades lógicas para el posicionamiento

Para elementos posicionados de forma absoluta o relativa, reemplaza left y right con inset-inline-start y 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 garantizan que los elementos posicionados aparezcan en el lado correcto para la dirección de texto actual.

5. Aplicar alineación de texto lógica

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 del 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 de manera apropiada tanto para idiomas LTR como RTL.