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 de produit en anglais et passe à l'espagnol, elle souhaite voir cette même page de produit en espagnol, et non être redirigée vers la page d'accueil. Ne pas respecter cette attente crée des frictions et oblige les utilisateurs à revenir là où ils étaient, dégradant ainsi l'expérience et les incitant potentiellement à abandonner complètement la tâche.
De nombreuses implémentations de sélecteurs de langue échouent car elles traitent la sélection de la 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 renvoyer vers des destinations fixes, perdant ainsi le contexte de l'utilisateur dans le processus.
Solution
Construire un sélecteur de langue qui lit le chemin et les paramètres de requête de la route actuelle à partir du routeur, puis génère des liens pour chaque langue prise en charge qui préservent ces informations de routage tout en ne modifiant que la locale. En transmettant le chemin 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 router fournit les propriétés pathname, asPath, query, locale et locales qui contiennent toutes les informations nécessaires pour construire des liens adaptés aux locales.
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 un 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 actuelle de locale identifie la langue active et applique un style distinct pour la différencier des alternatives disponibles.
3. Ajouter des libellés 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 donne accès aux fonctions de formatage pour traduire les libellés de l'interface utilisateur. Les attributs aria-label et aria-current améliorent l'accessibilité pour les utilisateurs de lecteurs d'écran.