Depuis PHP 5.3, l’extension intl fournit déjà cette négociation
Un routage multilingue maison, chargé de déterminer la langue à servir à un visiteur n’ayant exprimé aucune préférence explicite via un cookie ou une URL, se heurte souvent à la tentation d’analyser lui-même l’en-tête HTTP Accept-Language envoyé par le navigateur. Cet en-tête suit pourtant une syntaxe non triviale, avec des poids de préférence optionnels notés q=, comme fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7, où l’ordre d’apparition seul ne suffit pas à déterminer la véritable priorité voulue par le visiteur.
L’extension intl de PHP, disponible de longue date dans l’écosystème PHP moderne, fournit une méthode statique dédiée exactement à ce besoin : Locale::acceptFromHttp( string $header ): string|null. Elle prend en entrée la valeur brute de l’en-tête et retourne la meilleure locale correspondante selon les règles de négociation de contenu, sans qu’il soit nécessaire d’écrire soi-même un analyseur de cet en-tête.
Un routage qui respecte réellement les préférences du visiteur

Utilisée en amont d’un mécanisme de redirection ou de sélection de langue par défaut, cette méthode permet de proposer une langue cohérente avec les préférences réellement configurées dans le navigateur du visiteur, plutôt qu’une langue devinée uniquement depuis sa position géographique déduite de son adresse IP :
$en_tete = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '';
$locale_preferee = Locale::acceptFromHttp( $en_tete );
if ( $locale_preferee ) {
$langue_courte = Locale::getPrimaryLanguage( $locale_preferee );
error_log( 'Langue négociée : ' . $langue_courte );
}
La méthode Locale::getPrimaryLanguage(), elle aussi fournie par l’extension intl, extrait ensuite le code de langue court à partir de la locale complète retournée, une opération complémentaire souvent nécessaire pour comparer le résultat à une liste de langues gérées par le site.
Toujours confronter le résultat aux langues réellement disponibles
Un piège fréquent consiste à rediriger directement le visiteur vers la langue retournée par Locale::acceptFromHttp(), sans vérifier au préalable que cette langue fait bien partie de celles réellement gérées par le site. La méthode ne connaît rien de la configuration du site : elle se contente de parser l’en-tête et de retourner la meilleure correspondance théorique, quitte à proposer une langue que le site ne prend jamais en charge.
$langues_disponibles = array( 'fr', 'en', 'de' );
$locale_preferee = Locale::acceptFromHttp( $en_tete );
$langue_courte = $locale_preferee ? Locale::getPrimaryLanguage( $locale_preferee ) : '';
$langue_finale = in_array( $langue_courte, $langues_disponibles, true )
? $langue_courte
: 'fr'; // langue de repli du site
Cette étape de confrontation avec la liste réelle des langues disponibles reste indispensable : sans elle, un visiteur dont le navigateur est configuré en polonais, langue non gérée par le site, se verrait proposer une valeur de retour inattendue plutôt que la langue de repli prévue par l’éditeur du site.
Une négociation de langue qui ignore ce que le site sait réellement servir n’est pas une négociation, c’est une supposition habillée d’une API élégante.
Quand cette approche perd de son intérêt
Sur un site où la langue est systématiquement déterminée par un choix explicite du visiteur, mémorisé ensuite dans un cookie ou reflété dans la structure de l’URL, la négociation automatique par en-tête ne devrait intervenir qu’une seule fois, à la toute première visite, avant qu’un choix explicite ne prenne définitivement le dessus. Réévaluer cet en-tête à chaque requête, y compris pour un visiteur ayant déjà exprimé un choix de langue explicite, produirait un comportement erratique où le site changerait de langue au gré des variations de configuration du navigateur, un résultat contraire à ce qu’attend un visiteur ayant déjà fait un choix conscient.
Conclusion
Parser soi-même un en-tête Accept-Language revient à réécrire, souvent de façon incomplète, une négociation de contenu déjà correctement implémentée dans l’extension intl de PHP. Locale::acceptFromHttp() évite cette réinvention, à condition de toujours confronter son résultat à la liste réelle des langues effectivement gérées par le site avant de l’utiliser pour une redirection.