Meilleure façon de déterminer les paramètres régionaux de l'utilisateur dans le navigateur

203

J'ai un site Web (Flash) localisé dans une douzaine de langues et je veux définir automatiquement une valeur par défaut en fonction des paramètres du navigateur de l'utilisateur afin de minimiser les étapes pour accéder au contenu.

Pour info, je ne peux pas utiliser de scripts serveur en raison de restrictions de proxy, donc je suppose que JavaScript ou ActionScript serait approprié pour résoudre le problème.

Des questions:

  1. Quelle serait la meilleure méthode pour «deviner» les paramètres régionaux de l'utilisateur?

  2. Existe-t-il des classes / fonctions simples existantes qui pourraient m'aider (pas de bundles de localisation complexes)? Spécialement pour décomposer toutes les langues possibles en un plus petit nombre (les traductions que j'ai) de manière intelligente.

  3. Jusqu'à quel point puis-je faire confiance à une telle solution?

  4. D'autres solutions ou suggestions?

Theo.T
la source
Le seul moyen pour un navigateur de partager des métadonnées sur son utilisateur et la demande est via des URL et des en-têtes. Saisissez Firefox et jetez un œil aux en-têtes envoyés lorsqu'une demande est faite. Il est très intéressant d'examiner les en-têtes de demande et de réponse typiques.
mP.

Réponses:

188

La bonne façon est de regarder l'en - tête HTTP Accept-Language envoyé au serveur. Il contient la liste ordonnée et pondérée des langues que l'utilisateur a configuré pour préférer son navigateur.

Malheureusement, cet en-tête n'est pas disponible pour la lecture à l'intérieur de JavaScript; tout ce que vous obtenez est navigator.language, qui vous indique quelle version localisée du navigateur Web a été installée. Ce n'est pas nécessairement la même chose que la ou les langues préférées de l'utilisateur. Sur IE, vous obtenez à la place systemLanguage(langue installée du système d'exploitation), browserLanguage(identique à language) et userLanguage(région du système d'exploitation configurée par l'utilisateur), qui sont tous également inutiles.

Si je devais choisir entre ces propriétés, je reniflerais d' userLanguageabord, en retombant languageet seulement après cela (si celles-ci ne correspondaient à aucune langue disponible) en regardant browserLanguageet enfin systemLanguage.

Si vous pouvez mettre un script côté serveur ailleurs sur le net qui lit simplement l'en-tête Accept-Language et le recrache sous forme de fichier JavaScript avec la valeur d'en-tête dans la chaîne, par exemple:

var acceptLanguage= 'en-gb,en;q=0.7,de;q=0.3';

vous pouvez alors inclure un <script src> pointant vers ce service externe dans le HTML et utiliser JavaScript pour analyser l'en-tête de la langue. Cependant, je ne connais aucun code de bibliothèque existant, car l'analyse en langage accepté est presque toujours effectuée côté serveur.

Quoi que vous finissiez par faire, vous aurez certainement besoin d'un remplacement par l'utilisateur car il devinera toujours mauvais pour certaines personnes. Il est souvent plus facile de mettre le paramètre de langue dans l'URL (par exemple, http: //www.example.com/en/site vs http: //www.example.com/de/site) et de laisser l'utilisateur cliquer liens entre les deux. Parfois, vous voulez une URL unique pour les deux versions linguistiques, auquel cas vous devez stocker le paramètre dans les cookies, mais cela peut confondre les agents utilisateurs sans prise en charge des cookies et des moteurs de recherche.

bobince
la source
11
From MDN developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/… "L'en-tête HTTP Accept-Language dans chaque requête HTTP du navigateur de l'utilisateur utilise la même valeur pour la propriété navigator.languages, sauf pour le supplément champ qvalues ​​(valeurs de qualité) (par exemple en-US; q = 0,8). "
S Meaden
3
Mise à jour: Il existe maintenant (2020) une fonctionnalité expérimentale prise en charge par tous les navigateurs modernes qui renvoie un éventail de préférences linguistiques: navigator.languages //["en-US", "zh-CN", "ja-JP"]cela devrait fonctionner sur au moins 95% des navigateurs en 2020.
Cornelius Roemer
1
navigator.languages, selon MDN et caniuse.com , est maintenant disponible dans tous les principaux navigateurs - essayez le minuscule (~ 200 octets) package de langues de navigateur pour l'approche la plus moderne et rétrocompatible.
mindplay.dk
84

Sur Chrome et Firefox 32+, navigator.languages ​​contient un tableau de paramètres régionaux par ordre de préférence de l'utilisateur et est plus précis que navigator.language, mais pour le rendre rétrocompatible (Testé Chrome / IE / Firefox / Safari), puis utilisez ce:

function getLang()
{
 if (navigator.languages != undefined) 
 return navigator.languages[0]; 
 else 
 return navigator.language;
}
Fiach Reid
la source
2
Cela ne fonctionne pas pour IE9 et IE10. Pour eux, vous devez plutôt examiner navigator.browserLanguage.
user393274
2
OneLiner:function getLang(){ return ( navigator.language || navigator.languages[0] ); }
JorgeGarza
4
@ChStark ne devrait-il pas en être ainsi return navigator.languages[0] || navigator.language;?
James_
23
En outre, le bon « one-liner » ressemblerait à ceci: return (navigator.languages && navigator.languages.length) ? navigator.languages[0] : navigator.language;. Sinon, vous obtenez une exception si elle navigator.languagesn'est pas définie ou vide.
Max Truxa
Pour une version encore plus compacteconst getLang = () => navigator.language || navigator.browserLanguage || ( navigator.languages || [ "en" ] ) [ 0 ]
João Miguel Brandão
41

Cet article suggère les propriétés suivantes de l' objet navigateur du navigateur :

  • navigator.language (Netscape - Localisation du navigateur)
  • navigator.browserLanguage (spécifique à IE - Langue localisée du navigateur)
  • navigator.systemLanguage (Spécifique à IE - Système d'exploitation Windows - Langue localisée)
  • navigator.userLanguage

Roulez-les dans une fonction javascript et vous devriez pouvoir deviner la bonne langue, dans la plupart des cas. Assurez-vous de vous dégrader gracieusement, alors ayez une div contenant vos liens de choix de langue, afin que s'il n'y a pas de javascript ou que la méthode ne fonctionne pas, l'utilisateur puisse toujours décider. Si cela fonctionne, cachez simplement le div.

Le seul problème avec cela du côté client est que soit vous fournissez toutes les langues au client, soit vous devez attendre que le script soit exécuté et détecté la langue avant de demander la bonne version. Peut-être que servir la version linguistique la plus populaire par défaut irriterait le moins de gens.

Edit: je seconderais la suggestion de cookie d'Ivan, mais assurez-vous que l'utilisateur peut toujours changer la langue plus tard; tout le monde ne préfère pas la langue par défaut de son navigateur.

Phil H
la source
Merci Phil pour vos suggestions. Concernant l'article, il a 6 ans ... pas sûr qu'on puisse s'y fier?
Theo.T
1
Je soupçonne que les navigateurs modernes prennent tous en charge navigator.language. Mon navigateur (FF3 sur Ubuntu 8.10) signale 'en-GB'. Si quelqu'un utilise encore IE6 - environ 20% des gens - alors cela vaut la peine de le permettre. IE6 est apparu il y a 8 ans.
Phil H
IE 8 ne prend pas en charge navigator.language. Peut-être que IE 9 le fera?
broche
36

En combinant les multiples façons dont les navigateurs utilisent pour stocker la langue de l'utilisateur, vous obtenez cette fonction:

const getNavigatorLanguage = () => {
  if (navigator.languages && navigator.languages.length) {
    return navigator.languages[0];
  } else {
    return navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en';
  }
}

Nous vérifions d'abord le navigator.languagestableau pour son premier élément.
Ensuite, nous obtenons soit navigator.userLanguageou navigator.language.
Si cela échoue, nous obtenons navigator.browserLanguage.
Enfin, nous l'avons défini 'en'si tout le reste a échoué.


Et voici le one-liner sexy:

const getNavigatorLanguage = () => (navigator.languages && navigator.languages.length) ? navigator.languages[0] : navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en';
Zenoo
la source
il y a apparemment aussi quelque chose comme navigator.userLanguage(pour IE). Vous pouvez ajouter cela pour le compléter :)
pors
Pourquoi pas simplement navigator.languages[0] || navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en'?
Emerica
@Curse Parce que navigator.languagespeut êtreundefined
Zenoo
@Zenoo Savez-vous sur quels navigateurs?
Emerica
(navigator.languages || [])[0] || navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en'
Steve Bennett
10

Il y a une différence entre les langues préférées de l'utilisateur et les paramètres régionaux du système / navigateur.

Un utilisateur peut configurer les langues préférées dans le navigateur, et celles-ci seront utilisées navigator.language(s)et utilisées lors de la demande de ressources d'un serveur, pour demander du contenu en fonction d'une liste de priorités linguistiques.

Cependant, les paramètres régionaux du navigateur décideront de la façon de rendre le nombre, la date, l'heure et la devise. Ce paramètre est probablement la langue la mieux classée, mais il n'y a aucune garantie. Sur Mac et Linux, les paramètres régionaux sont décidés par le système indépendamment des préférences de langue de l'utilisateur. Sur Windows, il peut être choisi parmi les langues de la liste préférée sur Chrome.

En utilisant Intl ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl ), les développeurs peuvent remplacer / définir les paramètres régionaux à utiliser pour rendre ces choses, mais il y a des éléments qui ne peut pas être remplacé, comme le <input type="date">format.

Pour extraire correctement cette langue, le seul moyen que j'ai trouvé est:

(new Intl.NumberFormat()).resolvedOptions().locale

( Intl.NumberFormat().resolvedOptions().localesemble également fonctionner)

Cela créera une nouvelle instance de NumberFormat pour les paramètres régionaux par défaut, puis relira les paramètres régionaux de ces options résolues.

Patrik Kullman - Neovici
la source
5

J'ai fait un peu de recherche à ce sujet et j'ai résumé mes résultats jusqu'à présent dans le tableau ci-dessous

entrez la description de l'image ici

La solution recommandée consiste donc à écrire un script côté serveur pour analyser l'en- Accept-Languagetête et le transmettre au client pour définir la langue du site Web. Il est étrange que la raison pour laquelle le serveur soit nécessaire pour détecter la préférence de langue du client, mais c'est comme ça à partir de maintenant.Il existe d'autres hacks différents pour détecter la langue, mais la lecture de l'en- Accept-Languagetête est la solution recommandée selon ma compréhension.

Abhishek V
la source
2

Vous pouvez également essayer d'obtenir la langue du document qui devrait être votre premier port d'escale, puis revenir à d'autres moyens car les gens voudront souvent que leur langue JS corresponde à la langue du document.

HTML5:

document.querySelector('html').getAttribute('lang')

Héritage:

document.querySelector('meta[http-equiv=content-language]').getAttribute('content')

Aucune véritable source n'est nécessairement fiable à 100%, car les gens peuvent simplement mettre dans la mauvaise langue.

Il existe des bibliothèques de détection de langue qui peuvent vous permettre de déterminer la langue en fonction de son contenu.

jgmjgm
la source
1

J'ai utilisé toutes les réponses et créé une solution sur une seule ligne:

const getLanguage = () => navigator.userLanguage || (navigator.languages && navigator.languages.length && navigator.languages[0]) || navigator.language || navigator.browserLanguage || navigator.systemLanguage || 'en';

console.log(getLanguage());
Caio Santos
la source