Comment créer un composant de sélecteur de langue dans Next.js (Pages Router) v16
Changer de langue tout en restant sur la même page
Problème
Les utilisateurs s'attendent à ce que les sélecteurs de langue préservent leur emplacement actuel. Lorsqu'une personne consulte une page produit en anglais et passe à l'espagnol, elle souhaite voir cette même page produit en espagnol, et non être redirigée vers la page d'accueil. Rompre cette attente crée des frictions et oblige les utilisateurs à revenir là où ils étaient, dégradant l'expérience et les poussant potentiellement à abandonner complètement leur tâche.
De nombreuses implémentations de sélecteurs de langue échouent car elles traitent la sélection de langue comme une simple navigation plutôt que comme une transformation de la vue actuelle. Sans accès aux informations de routage de la page actuelle, un sélecteur ne peut que créer des liens vers des destinations fixes, perdant ainsi le contexte de l'utilisateur.
Solution
Créez un sélecteur de langue qui lit le pathname et les paramètres de requête de la route actuelle depuis le routeur, puis génère des liens pour chaque langue prise en charge qui préservent ces informations de routage tout en changeant uniquement la locale. En passant le pathname et la requête à l'API de navigation avec la locale cible, le sélecteur garantit que les utilisateurs restent sur la page équivalente dans la nouvelle langue.
Étapes
1. Créer un composant de sélecteur de langue qui lit la route actuelle
L'objet routeur fournit les propriétés pathname, asPath, query, locale et locales qui contiennent toutes les informations nécessaires pour créer des liens tenant compte de la locale.
import { useRouter } from "next/router";
import Link from "next/link";
export default function LanguageSwitcher() {
const router = useRouter();
const { locale, locales, pathname, asPath, query } = router;
return (
<nav>
{locales?.map((loc) => (
<Link key={loc} href={{ pathname, query }} as={asPath} locale={loc}>
{loc.toUpperCase()}
</Link>
))}
</nav>
);
}
Le composant Link accepte une prop locale pour passer à une locale différente de celle actuellement active. Passer pathname et query comme objet à href préserve toutes les informations de routage, y compris les valeurs de requête des routes dynamiques.
2. Styliser la locale active pour fournir un retour visuel
Mettez en évidence la langue actuelle afin que les utilisateurs sachent quelle locale ils consultent.
import { useRouter } from "next/router";
import Link from "next/link";
export default function LanguageSwitcher() {
const router = useRouter();
const { locale, locales, pathname, asPath, query } = router;
return (
<nav>
{locales?.map((loc) => {
const isActive = loc === locale;
return (
<Link
key={loc}
href={{ pathname, query }}
as={asPath}
locale={loc}
style={{
fontWeight: isActive ? "bold" : "normal",
textDecoration: isActive ? "none" : "underline",
marginRight: "1rem",
}}
>
{loc.toUpperCase()}
</Link>
);
})}
</nav>
);
}
La comparaison de chaque locale avec la valeur locale actuelle identifie la langue active et applique un style distinct pour la différencier des alternatives disponibles.
3. Ajouter des labels accessibles avec react-intl
Remplacez les codes de locale par des noms de langues lisibles pour une meilleure utilisabilité.
import { useRouter } from "next/router";
import { useIntl } from "react-intl";
import Link from "next/link";
const localeNames: Record<string, string> = {
en: "English",
es: "Español",
fr: "Français",
de: "Deutsch",
};
export default function LanguageSwitcher() {
const router = useRouter();
const intl = useIntl();
const { locale, locales, pathname, asPath, query } = router;
return (
<nav
aria-label={intl.formatMessage({
id: "languageSwitcher.label",
defaultMessage: "Select language",
})}
>
{locales?.map((loc) => {
const isActive = loc === locale;
return (
<Link
key={loc}
href={{ pathname, query }}
as={asPath}
locale={loc}
aria-current={isActive ? "true" : undefined}
style={{
fontWeight: isActive ? "bold" : "normal",
textDecoration: isActive ? "none" : "underline",
marginRight: "1rem",
}}
>
{localeNames[loc] || loc}
</Link>
);
})}
</nav>
);
}
Le hook useIntl fournit un accès aux fonctions de formatage pour traduire les labels de l'interface utilisateur. Les attributs aria-label et aria-current améliorent l'accessibilité pour les utilisateurs de lecteurs d'écran.