# General Translation Knowledge Base: Bonnes pratiques pour le sélecteur de langue : UX, SEO et accessibilité
URL: https://generaltranslation.com/fr/kb/language-switcher.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: Affichez chaque langue sous son propre nom, comme Deutsch ou 日本語, et bannissez les drapeaux, qui représentent des pays. Faites pointer chaque option vers la même page dans cette langue grâce à un lien explorable par les robots, mémorisez le choix dans un cookie et ne redirigez jamais automatiquement une URL localisée.
Category: Internationalisation
Last updated: 2026-10-20
Authors: Kevin Wu, Jackie Chen
Published: 2026-10-20

La personne qui a le plus besoin de votre sélecteur de langue est justement celle qui ne comprend pas la page sur laquelle elle est arrivée. Toutes les recommandations qui suivent découlent donc d’une seule règle : le sélecteur doit être compréhensible pour quelqu’un qui ne lit pas votre langue par défaut.

## Qu&#39;est-ce qu&#39;un bon sélecteur de langue ?

### 1. Désigner chaque langue par son propre nom

Sur une page en anglais, un lecteur japonais cherche 日本語, et non « Japanese », tout comme un lecteur allemand cherche « Deutsch ». Les [recommandations du W3C sur les menus de langues](https://www.w3.org/International/questions/qa-navigation-select) préconisent d’écrire « français » plutôt que « French ». Ces noms qu’une langue se donne à elle-même sont appelés endonymes, et l’API JavaScript [`Intl.DisplayNames`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames) les génère à partir du code de langue :

```js
const locales = ['en', 'fr', 'de', 'ja', 'ar', 'pt-BR', 'zh-Hant'];

for (const code of locales) {
  // Afficher le nom de chaque langue dans cette même langue (son endonyme)
  const own = new Intl.DisplayNames([code], { type: 'language' }).of(code);
  // Le même nom en anglais, à titre de comparaison
  const english = new Intl.DisplayNames(['en'], { type: 'language' }).of(code);
  console.log(`${code}: ${own} (${english})`);
}
```

Résultat sous Node.js 24 (ICU 78.3, CLDR 48.0) :

```text
en: English (English)
fr: français (French)
de: Deutsch (German)
ja: 日本語 (Japanese)
ar: العربية (Arabic)
pt-BR: português (Brasil) (Brazilian Portuguese)
zh-Hant: 繁體中文 (Traditional Chinese)
```

Le français et le portugais ne prennent pas de majuscule aux noms de langues en milieu de phrase : CLDR renvoie donc &quot;français&quot;. Dans un menu, où chaque nom apparaît seul, mettez une majuscule à la première lettre. N&#39;ajoutez une région que si vous proposez deux variantes d&#39;une même langue, par exemple &quot;Português (Brasil)&quot; à côté de &quot;Português (Portugal)&quot;.

### 2. N&#39;utilisez pas de drapeaux pour les langues

Les [bonnes pratiques du W3C pour la déclaration des langues](https://www.w3.org/TR/i18n-html-tech-lang/) sont sans ambiguïté : « N&#39;utilisez pas d&#39;icônes de drapeaux pour indiquer les langues. » Avec cette [justification](https://www.w3.org/International/questions/qa-link-lang) : « Les drapeaux représentent des pays, pas des langues. » Une même langue est parlée dans de nombreux pays (l&#39;espagnol en Espagne, au Mexique et en Argentine), un pays peut compter plusieurs langues officielles (la Suisse), et un drapeau peut véhiculer des connotations nationales mal perçues par d&#39;autres locuteurs de la même langue. Un drapeau a sa place dans un sélecteur de pays ou de boutique, où le choix porte sur la région ; associez-le alors aux noms des langues qui y sont disponibles.

### 3. Placez-le là où les utilisateurs regardent, avec un déclencheur reconnaissable

Le W3C [recommande](https://www.w3.org/International/questions/qa-navigation-select) de placer le contrôle « en haut de la page ou à proximité » et, comme un libellé textuel est spécifique à une langue, de l’accompagner d’une image reconnaissable. Aucun symbole n’est encore universellement reconnu, mais le W3C constate que les icônes de globe gagnent en popularité. Une icône de globe placée à côté du nom de la langue actuelle convient aux lecteurs de toutes les langues. De nombreux sites reprennent le sélecteur dans le pied de page comme second point d’entrée, mais le pied de page ne doit pas en être le seul.

### 4. Basculer vers la même page, pas vers la page d&#39;accueil

Une personne qui consulte votre page de tarifs en anglais et passe au français s&#39;attend à arriver sur la page de tarifs en français. La renvoyer vers la page d&#39;accueil française lui fait perdre le fil et l&#39;oblige à naviguer de nouveau, dans une langue qu&#39;elle vient peut-être tout juste de pouvoir lire. Faites pointer chaque option vers l&#39;équivalent traduit de l&#39;URL actuelle et, si une page n&#39;est pas encore traduite, renvoyez vers la page parente traduite la plus proche en le signalant.

### 5. Utilisez des liens explorables avec `hreflang` et `lang`

En règle générale, Google ne peut [explorer un lien que s&#39;il s&#39;agit d&#39;un élément `<a>` doté d&#39;un attribut `href`](https://developers.google.com/search/docs/crawling-indexing/links-crawlable), et il demande aux sites multilingues d&#39;[ajouter des liens hypertextes vers les autres versions linguistiques](https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites) afin que les utilisateurs puissent choisir celle qui leur convient d&#39;un simple clic. Un `<select>` dont le gestionnaire d&#39;événement `change` modifie `window.location` n&#39;est pas un lien : les robots d&#39;exploration n&#39;ont donc rien à suivre.

Ajoutez deux attributs à chaque lien. L&#39;attribut `hreflang` sur `<a>` [indique la langue de la page cible](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/a) ; il ne déclenche aucun comportement particulier dans le navigateur et ne doit pas être confondu avec les annotations `<link rel="alternate" hreflang>` lues par les moteurs de recherche (voir [Qu&#39;est-ce que hreflang ?](/kb/what-is-hreflang)). L&#39;attribut `lang` indique la langue du texte du lien, ce qui permet à un lecteur d&#39;écran de prononcer « Deutsch » selon les règles de l&#39;allemand. Le critère [Langue d&#39;un passage](https://www.w3.org/WAI/WCAG22/Understanding/language-of-parts.html) des WCAG cite d&#39;ailleurs en exemple les liens de langue libellés dans leur propre langue. Il souligne toutefois une limite : lorsqu&#39;une technologie d&#39;assistance annonce un lien uniquement par son nom accessible, par exemple dans la liste des liens de la page, elle ne change pas de prononciation.

### 6. Mémoriser le choix explicite

Dès qu&#39;un utilisateur choisit une langue, enregistrez ce choix dans un cookie ou dans son compte, puis réutilisez-le lors de ses visites suivantes : pour déterminer la destination à partir d&#39;une racine neutre comme `/`, et pour afficher la langue sélectionnée dans le sélecteur. Le cookie ne doit pas remplacer une URL localisée que l&#39;utilisateur a ouverte. Le W3C [recommande](https://www.w3.org/International/questions/qa-accept-lang-locales) de « stocker les résultats dans une base de données ou un cookie pour les visites ultérieures », et [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Accept-Language) précise qu&#39;un serveur « ne devrait jamais remplacer un choix de langue explicite de l&#39;utilisateur ».

### 7. Ne changez pas de langue automatiquement à chaque visite

Rediriger les visiteurs selon la langue de leur navigateur à chaque requête piège les voyageurs, les personnes qui utilisent un ordinateur partagé et toute personne ayant ouvert un lien dans une langue précise. Servez-vous de la préférence du navigateur uniquement pour afficher une suggestion que l&#39;on peut ignorer (« Diese Seite gibt es auch auf Deutsch ») et laissez l&#39;utilisateur décider. [Routage selon les paramètres régionaux et SEO](/kb/locale-routing-seo) explique quel signal doit l&#39;emporter et le seul cas où une redirection est sans risque.

### 8. Garantir l&#39;accessibilité au clavier et aux lecteurs d&#39;écran

Une simple liste de liens, ou un `<select>` natif, fonctionne d&#39;emblée avec le clavier et les technologies d&#39;assistance. Si vous créez une liste déroulante, suivez l&#39;[approche « divulgation »](https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/) de WAI-ARIA : un `<button>` affiche ou masque la liste, les touches Entrée et Espace l&#39;ouvrent et la ferment, et `aria-expanded` indique son état. Donnez au contrôle un nom accessible dans la langue de la page (`aria-label="Sprache"` sur une page en allemand) et signalez la langue active avec `aria-current="page"`.

## Comment créer un sélecteur de langue ?

### HTML simple

Ce menu applique les huit bonnes pratiques : des endonymes, une icône de globe plutôt que des drapeaux, des liens vers la même page, `hreflang` et `lang` sur chaque lien, un bouton de divulgation et un cookie pour mémoriser le choix explicite de l&#39;utilisateur.

```html title="On /de/pricing"
<nav aria-label="Sprache">
  <button type="button" aria-expanded="false" aria-controls="language-menu">
    <svg aria-hidden="true" width="16" height="16"><!-- icône globe --></svg>
    Deutsch
  </button>
  <ul id="language-menu" hidden>
    <li><a href="/en/pricing" hreflang="en" lang="en">English</a></li>
    <li><a href="/fr/pricing" hreflang="fr" lang="fr">Français</a></li>
    <li><a href="/de/pricing" hreflang="de" lang="de" aria-current="page">Deutsch</a></li>
    <li><a href="/ja/pricing" hreflang="ja" lang="ja">日本語</a></li>
  </ul>
</nav>
```

```js title="switcher.js"
const button = document.querySelector('[aria-controls="language-menu"]');
const menu = document.getElementById('language-menu');

// Ouvre et ferme le menu (Entrée et Espace activent nativement un <button>)
button.addEventListener('click', () => {
  const open = button.getAttribute('aria-expanded') === 'true';
  button.setAttribute('aria-expanded', String(!open));
  menu.hidden = open;
});

// Échap referme le menu et redonne le focus à son bouton.
button.closest('nav').addEventListener('keydown', (event) => {
  if (event.key === 'Escape' && !menu.hidden) {
    menu.hidden = true;
    button.setAttribute('aria-expanded', 'false');
    button.focus();
  }
});

// Mémorise le choix explicite pour les visites suivantes
menu.addEventListener('click', (event) => {
  const link = event.target.closest('a[hreflang]');
  if (link) {
    document.cookie = `locale=${link.hreflang}; path=/; max-age=31536000; samesite=lax`;
  }
});
```

### React

Ce composant utilise de simples liens. Transmettez le chemin actuel, la chaîne de requête et le fragment via `currentHref`, ainsi que le paramètre régional actuel. Il suppose que chaque paramètre régional dispose d&#39;un préfixe d&#39;URL, que chaque page existe dans tous les paramètres régionaux listés et que les slugs sont identiques d&#39;une langue à l&#39;autre. En cas de slugs traduits ou de pages manquantes, résolvez chaque destination à partir de vos données de routage ou de CMS plutôt que de remplacer un préfixe.

```jsx title="LanguageSwitcher.jsx"
const LOCALES = ['en', 'fr', 'de', 'ja'];

// Conserve le chemin, la barre oblique finale, la chaîne de requête et le fragment lors du changement de paramètre régional.
function hrefForLocale(currentHref, locale) {
  const url = new URL(currentHref, 'https://example.invalid');
  const trailingSlash = url.pathname.endsWith('/');
  const segments = url.pathname.split('/').filter(Boolean);
  if (LOCALES.includes(segments[0])) segments.shift();
  url.pathname = `/${[locale, ...segments].join('/')}${trailingSlash ? '/' : ''}`;
  return `${url.pathname}${url.search}${url.hash}`;
}

// Nom de la langue dans cette même langue, avec une majuscule initiale pour l'affichage dans un menu
function endonym(locale) {
  const name = new Intl.DisplayNames([locale], { type: 'language' }).of(locale);
  return name.charAt(0).toLocaleUpperCase(locale) + name.slice(1);
}

function rememberChoice(locale) {
  document.cookie = `locale=${locale}; path=/; max-age=31536000; samesite=lax`;
}

export function LanguageSwitcher({ currentHref, currentLocale, label }) {
  return (
    <nav aria-label={label}>
      <ul>
        {LOCALES.map((locale) => (
          <li key={locale}>
            <a
              href={hrefForLocale(currentHref, locale)}
              hrefLang={locale}
              lang={locale}
              aria-current={locale === currentLocale ? 'page' : undefined}
              onClick={() => rememberChoice(locale)}
            >
              {endonym(locale)}
            </a>
          </li>
        ))}
      </ul>
    </nav>
  );
}
```

Avec `currentHref="/fr/pricing/?plan=pro#faq"`, `currentLocale="fr"` et `label="Langue"`, le lien allemand pointe vers `/de/pricing/?plan=pro#faq`, tandis que le lien français porte l&#39;attribut `aria-current="page"`. Ne conservez les paramètres de requête et les fragments que s&#39;ils ont la même signification sur la page de destination. Si les identifiants d&#39;ancre sont traduits, résolvez également le fragment équivalent.

### Avec General Translation

Pour les pages Next.js publiques, le composant [`<Link>`](/docs/react/nextjs/link) de GT génère des liens adaptés au paramètre régional. Avec `prefixDefaultLocale: true`, ces liens pointent vers `/en/pricing` et `/de/pricing`. Cet exemple part du principe que les pages de tarifs en anglais et en allemand sont publiées. Transmettez le paramètre régional actuel ainsi qu&#39;un libellé de navigation localisé :

```tsx
import Link from 'gt-next/link';

export function PricingLanguages({ currentLocale, label }: { currentLocale: string; label: string }) {
  return (
    <nav aria-label={label}>
      <Link href="/pricing" locale="en" hrefLang="en" lang="en" aria-current={currentLocale === 'en' ? 'page' : undefined}>English</Link>
      {' · '}
      <Link href="/pricing" locale="de" hrefLang="de" lang="de" aria-current={currentLocale === 'de' ? 'page' : undefined}>Deutsch</Link>
    </nav>
  );
}
```

Localisez le libellé de navigation de la page courante. Pour un contrôle natif compact, par exemple au sein d&#39;une application authentifiée, utilisez le sélecteur de paramètre régional :

[`<LocaleSelector>`](/docs/react/reference/components/locale-selector), disponible dans `gt-react`, `gt-next` et le package expérimental `gt-tanstack-start`, affiche un `<select>` natif listant les paramètres régionaux configurés, affiche le nom de chacun dans sa propre langue et enregistre le choix dans un cookie. Les attributs standard de `<select>` sont transmis, vous pouvez donc passer un `aria-label` traduit avec [`useGT`](/docs/react/reference/hooks/use-gt) :

```tsx
'use client';
import { LocaleSelector, useGT } from 'gt-next';

export function Header() {
  const gt = useGT();
  return <LocaleSelector aria-label={gt('Language')} />;
}
```

Pour les pages publiques, utilisez les liens ci-dessus afin d&#39;offrir une navigation explorable par les robots d&#39;indexation, et déclarez les variantes localisées hreflang dans l&#39;en-tête de la page, comme l&#39;explique [le SEO multilingue avec Next.js](/kb/multilingual-nextjs-seo). Pour un design personnalisé, [`useLocaleSelector`](/docs/react/reference/hooks/use-locale-selector) renvoie le paramètre régional actif, la liste des paramètres régionaux et `setLocale`. Avec Vue, créez un sélecteur de langue à l&#39;aide de [`useLocale`](/docs/vue/reference/composables/use-locale) et de [`useSetLocale`](/docs/vue/reference/composables/use-set-locale), en suivant le [guide des paramètres régionaux pour Vue](/docs/vue/guides/managing-locales#switcher).

## Points clés

* Libellez les options avec des endonymes tels que Français et 日本語 ; `Intl.DisplayNames` les génère, en minuscules pour le français et le portugais.
* Utilisez une icône de globe plutôt que des drapeaux : le W3C recommande de « ne pas utiliser d&#39;icônes de drapeau pour indiquer les langues ».
* Proposez des liens vers la même page dans chaque langue sous forme de simples liens `<a href>` dotés des attributs `hreflang` et `lang`, afin que les robots d&#39;indexation puissent les suivre et que les lecteurs d&#39;écran prononcent correctement chaque nom.
* Enregistrez le choix explicite de l&#39;utilisateur et ne le redirigez jamais hors d&#39;une URL localisée en fonction de la langue du navigateur.
* Le composant [`<LocaleSelector>`](/docs/react/reference/components/locale-selector) de General Translation affiche un `<select>` natif dont les libellés sont rédigés dans la langue de chaque option, et enregistre le choix dans un cookie ; ajoutez de simples liens pour les robots d&#39;indexation.

## Related questions

- [Comment détecter la langue du navigateur d’un utilisateur ?](https://generaltranslation.com/fr/kb/detect-user-language.mdx): Lisez la liste ordonnée des langues du navigateur (navigator.languages en JavaScript ou l’en-tête Accept-Language côté serveur), triée par valeur q, puis mettez-la en correspondance avec vos paramètres régionaux pris en charge, en prévoyant une solution de secours. Safari et la navigation privée de Chrome n’indiquent qu’une seule langue, et la géolocalisation par IP révèle l’emplacement, pas la langue.
- [Redirections linguistiques et SEO : URL, cookie ou Accept-Language ?](https://generaltranslation.com/fr/kb/locale-routing-seo.mdx): Laissez l’URL déterminer la langue de chaque page que vous souhaitez faire indexer, car Googlebot n’envoie aucun en-tête Accept-Language et explore principalement depuis des adresses américaines. Ne vous servez du choix enregistré dans un cookie, puis d’Accept-Language, que pour décider vers où redirige une racine neutre comme /, avec une redirection temporaire 302 ou 307.
- [Qu’est-ce que hreflang et comment le configurer ?](https://generaltranslation.com/fr/kb/what-is-hreflang.mdx): Hreflang indique à Google quelles URL correspondent aux versions linguistiques ou régionales d’une même page, afin qu’il affiche la bonne dans les résultats de recherche. Ajoutez-le à l’aide de balises link HTML, d’en-têtes HTTP Link ou d’un plan de site, veillez à ce que chaque lien soit réciproque et utilisez des codes valides comme en-GB, et non en-UK.
- [Comment rendre un site web multilingue ?](https://generaltranslation.com/fr/kb/make-website-multilingual.mdx): Choisissez où stocker les traductions (dans un proxy, un plugin de CMS, un constructeur de sites ou votre propre code), puis attribuez à chaque langue sa propre URL, comme le recommande Google. Traduisez les pages entières ainsi que les titres et les méta-descriptions, reliez les versions avec hreflang et proposez un sélecteur de langue plutôt que de rediriger automatiquement les visiteurs.

## Previous and next questions

- Previous question: [Quelle est la meilleure bibliothèque d’i18n pour une application React ?](https://generaltranslation.com/fr/kb/best-react-i18n-library.mdx)
- Next question: [Comment détecter la langue du navigateur d’un utilisateur ?](https://generaltranslation.com/fr/kb/detect-user-language.mdx)

## Sitemap

See the [Knowledge Base sitemap](https://generaltranslation.com/fr/kb/sitemap.md) for every article.
