Comment prendre en charge les langues de droite à gauche (RTL) dans Next.js (Pages Router) v16
Mise en miroir des mises en page pour l'arabe et l'hébreu
Problème
La plupart des mises en page web supposent un flux de texte de gauche à droite. Les menus de navigation s'ancrent à gauche, le contenu se lit de gauche à droite, et l'espacement est appliqué avec des propriétés comme margin-left ou padding-right. Lorsqu'une application est traduite en arabe ou en hébreu, ces langues se lisent de droite à gauche, et toute la mise en page visuelle devrait être inversée en conséquence. Sans cette inversion, les utilisateurs font face à une interface désorientante où la hiérarchie visuelle contredit leur sens naturel de lecture, rendant la navigation confuse et donnant à l'application un aspect non soigné.
Le défi va au-delà de l'alignement du texte. Les propriétés CSS physiques comme left, right, margin-left, et padding-right sont liées à des positions fixes sur l'écran plutôt qu'au flux du contenu. Lorsque la direction du texte change, ces propriétés restent ancrées aux mêmes bords physiques, empêchant la mise en page de s'adapter naturellement.
Solution
Définir l'attribut de direction du texte du document pour correspondre à la locale actuelle, permettant aux navigateurs d'inverser automatiquement le flux de mise en page pour les langues RTL. Remplacer les propriétés CSS physiques par des propriétés logiques qui font référence au flux de contenu plutôt qu'à la position sur l'écran. Les propriétés logiques comme margin-inline-start et padding-inline-end se mappent automatiquement au bord physique correct en fonction de la direction du texte, permettant aux mises en page de s'inverser sans code supplémentaire ou style conditionnel.
Cette approche crée des mises en page indépendantes de la direction qui fonctionnent correctement pour les langues LTR et RTL sans dupliquer les styles ou ajouter une logique complexe.
Étapes
1. Créer un helper pour déterminer la direction du texte à partir de la locale
Les propriétés logiques s'adaptent en fonction de la direction du texte, avec margin-inline-start équivalent à margin-left dans les contextes LTR et margin-right dans les contextes RTL. Construisez une fonction utilitaire qui associe les locales à leur direction de texte.
export function getDirection(locale: string): "ltr" | "rtl" {
const rtlLocales = ["ar", "he", "fa", "ur"];
return rtlLocales.includes(locale) ? "rtl" : "ltr";
}
Cette fonction identifie les langues RTL et renvoie la valeur de direction appropriée pour une utilisation dans HTML et CSS.
2. Définir l'attribut de direction du document
Les classes Document personnalisées peuvent remplacer la méthode render pour personnaliser l'élément HTML avec des attributs comme lang et dir. Créez un Document personnalisé pour définir l'attribut dir sur l'élément HTML racine en fonction de la locale actuelle.
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;
Le routeur Next.js fournit la locale active via la propriété locale. Le document lit la locale à partir des données de routage Next.js et applique la direction correspondante à l'élément HTML, activant ainsi la prise en charge RTL au niveau du navigateur.
3. Remplacer les propriétés CSS physiques par des équivalents logiques
Les propriétés logiques comme margin-inline-start, padding-inline-start, et leurs formes abrégées margin-inline et padding-inline se mappent automatiquement aux propriétés physiques en fonction du mode d'écriture et de la direction. Mettez à jour les styles de vos composants pour utiliser des propriétés relatives au flux.
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;
}
Les propriétés logiques pour margin, padding et inset facilitent et rendent plus efficace le positionnement des éléments à travers les différents modes d'écriture. Ces propriétés s'inversent automatiquement dans les contextes RTL sans nécessiter de styles supplémentaires ou de media queries.
4. Utiliser des propriétés logiques pour le positionnement
Pour les éléments positionnés de manière absolue ou relative, remplacez left et right par inset-inline-start et 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 propriété width est remplacée par inline-size et height par block-size dans la méthodologie des propriétés logiques. Ces propriétés garantissent que les éléments positionnés apparaissent du bon côté pour la direction de texte actuelle.
5. Appliquer l'alignement logique du texte
Remplacez text-align: left et text-align: right par text-align: start et text-align: end.
.content {
text-align: start;
}
.metadata {
text-align: end;
margin-inline-start: auto;
}
Les propriétés logiques font référence aux bords d'une boîte en relation avec le flux du contenu plutôt qu'aux dimensions physiques de la fenêtre d'affichage. Les valeurs d'alignement de texte start et end s'adaptent automatiquement à la direction du texte, alignant le contenu de manière appropriée pour les langues LTR et RTL.