La mejor manera de determinar la configuración regional del usuario dentro del navegador

203

Tengo un sitio web (Flash) localizado en una docena de idiomas y quiero definir automáticamente un valor predeterminado según la configuración del navegador del usuario para minimizar los pasos para acceder al contenido.

Para su información, no puedo usar scripts de servidor debido a restricciones de proxy, por lo que supongo que JavaScript o ActionScript serían apropiados para resolver el problema.

Preguntas:

  1. ¿Cuál sería el mejor método para 'adivinar' la configuración regional del usuario?

  2. ¿Existe alguna clase / función simple que pueda ayudarme (sin paquetes complejos de localización)? Especialmente para desglosar todos los idiomas posibles en un número menor (las traducciones que tengo) de una manera inteligente.

  3. ¿Hasta qué punto puedo confiar en tal solución?

  4. ¿Alguna otra solución o sugerencia?

Theo.T
fuente
La única forma en que un navegador puede compartir metadatos sobre su usuario y la solicitud es a través de URL y encabezados. Tome Firefox y eche un vistazo a los encabezados que se envían cuando se realiza una solicitud. Es bastante interesante examinar los encabezados típicos de solicitud y respuesta.
mP.

Respuestas:

188

La forma correcta es mirar el encabezado HTTP Accept-Language enviado al servidor. Contiene la lista ordenada y ponderada de idiomas que el usuario ha configurado para que su navegador prefiera.

Lamentablemente, este encabezado no está disponible para leer dentro de JavaScript; todo lo que obtienes es navigator.language, que te dice qué versión localizada del navegador web se instaló. Esto no es necesariamente lo mismo que los idiomas preferidos del usuario. En IE, en cambio, obtienes systemLanguage(idioma instalado del sistema operativo), browserLanguage(igual que language) y userLanguage(región del sistema operativo configurada por el usuario), que son igualmente inútiles.

Si tuviera que elegir entre esas propiedades, olfatearía userLanguageprimero, retrocediendo languagey solo después de eso (si no coincidían con ningún idioma disponible) mirando browserLanguagey finalmente systemLanguage.

Si puede colocar un script del lado del servidor en otro lugar en la red que simplemente lea el encabezado Accept-Language y lo escupe de nuevo como un archivo JavaScript con el valor del encabezado en la cadena, por ejemplo:

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

entonces podría incluir un <script src> apuntando a ese servicio externo en el HTML, y usar JavaScript para analizar el encabezado del idioma. Sin embargo, no conozco ningún código de biblioteca existente para hacer esto, ya que el análisis de Accept-Language casi siempre se realiza en el lado del servidor.

Lo que sea que termines haciendo, ciertamente necesitas una anulación del usuario porque siempre adivinará mal para algunas personas. A menudo es más fácil poner la configuración de idioma en la URL (por ejemplo, http: //www.example.com/en/site vs http: //www.example.com/de/site), y dejar que el usuario haga clic enlaces entre los dos. En ocasiones, desea una única URL para las dos versiones de idioma, en cuyo caso debe almacenar la configuración en las cookies, pero esto puede confundir a los agentes del usuario con la no compatibilidad con cookies y motores de búsqueda.

bobince
fuente
11
De MDN developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/… "El encabezado HTTP Accept-Language en cada solicitud HTTP del navegador del usuario usa el mismo valor para la propiedad navigator.languages, excepto para el extra campo qvalues ​​(valores de calidad) (p. ej. en-US; q = 0.8) ".
S Meaden
3
Actualización: ahora (2020) hay una función experimental compatible con todos los navegadores modernos que devuelve una variedad de preferencias de idioma: navigator.languages //["en-US", "zh-CN", "ja-JP"]Esto debería funcionar en al menos el 95% de los navegadores en 2020.
Cornelius Roemer
1
navigator.languages, de acuerdo con MDN y caniuse.com , ahora está disponible en todos los principales navegadores: pruebe el pequeño paquete de idiomas de navegador (~ 200 bytes) para el enfoque más moderno y compatible con versiones anteriores.
mindplay.dk
84

En Chrome y Firefox 32+, navigator.languages ​​contiene una variedad de configuraciones regionales en orden de preferencia del usuario, y es más preciso que navigator.language, sin embargo, para que sea compatible con versiones anteriores (probado Chrome / IE / Firefox / Safari), luego use esta:

function getLang()
{
 if (navigator.languages != undefined) 
 return navigator.languages[0]; 
 else 
 return navigator.language;
}
Fiach Reid
fuente
2
Esto no funciona para IE9 e IE10. Para ellos, debe examinar navigator.browserLanguage en su lugar.
user393274
2
OneLiner:function getLang(){ return ( navigator.language || navigator.languages[0] ); }
JorgeGarza
44
@ChStark ¿No debería ser así return navigator.languages[0] || navigator.language;?
James_
23
Además, la correcta "de una sola línea" sería el siguiente: return (navigator.languages && navigator.languages.length) ? navigator.languages[0] : navigator.language;. De lo contrario, obtendrá una excepción si navigator.languagesno está definida o está vacía.
Max Truxa
Para una versión aún más compactaconst getLang = () => navigator.language || navigator.browserLanguage || ( navigator.languages || [ "en" ] ) [ 0 ]
João Miguel Brandão
41

Este artículo sugiere las siguientes propiedades del objeto navegador del navegador :

  • navigator.language (Netscape - Localización del navegador)
  • navigator.browserLanguage (Específico de IE - Idioma localizado del navegador)
  • navigator.systemLanguage (Específico de IE - Sistema operativo Windows - Idioma localizado)
  • navigator.userLanguage

Conviértalos en una función de JavaScript y debería poder adivinar el idioma correcto, en la mayoría de las circunstancias. Asegúrese de degradar con gracia, así que tenga un div que contenga sus enlaces de elección de idioma, de modo que si no hay javascript o el método no funciona, el usuario aún puede decidir. Si funciona, solo oculta el div.

El único problema al hacer esto en el lado del cliente es que usted entrega todos los idiomas al cliente o tiene que esperar hasta que el script se haya ejecutado y detecte el idioma antes de solicitar la versión correcta. Quizás servir la versión de idioma más popular como predeterminada irritaría a la menor cantidad de personas.

Editar: respaldaría la sugerencia de cookies de Ivan, pero asegúrese de que el usuario siempre pueda cambiar el idioma más tarde; no todos prefieren el idioma predeterminado de su navegador.

Phil H
fuente
Gracias Phil por tus sugerencias. Con respecto al artículo, tiene 6 años ... ¿no está seguro de que podamos confiar en él?
Theo.T el
1
Sospecho que todos los navegadores modernos son compatibles con navigator.language. Mi navegador (FF3 en Ubuntu 8.10) informa 'en-GB'. Si alguien sigue usando IE6, alrededor del 20% de las personas, entonces vale la pena permitir eso. IE6 apareció hace 8 años.
Phil H
IE 8 no es compatible con navigator.language. Quizás IE 9 lo hará?
spig
36

Combinando las múltiples formas en que los navegadores están utilizando para almacenar el idioma del usuario, obtiene esta función:

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

Primero verificamos la navigator.languagesmatriz para su primer elemento.
Entonces obtenemos uno navigator.userLanguageo navigator.language.
Si esto falla, lo conseguimos navigator.browserLanguage.
Finalmente, lo configuramos 'en'si todo lo demás falla.


Y aquí está el sexy one-liner:

const getNavigatorLanguage = () => (navigator.languages && navigator.languages.length) ? navigator.languages[0] : navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en';
Zenoo
fuente
aparentemente también hay algo como navigator.userLanguage(para IE). Podrías agregar eso para completarlo :)
pors
¿Por qué no simplemente navigator.languages[0] || navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en'?
América
@Curse Porque navigator.languagespuede serundefined
Zenoo
@Zenoo ¿Sabes en qué navegadores?
América
(navigator.languages || [])[0] || navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en'
Steve Bennett
10

Hay una diferencia entre los idiomas preferidos del usuario y la configuración regional del sistema / navegador.

Un usuario puede configurar los idiomas preferidos en el navegador, y estos se usarán para navigator.language(s), y se usarán cuando solicite recursos de un servidor, para solicitar contenido de acuerdo con una lista de prioridades de idioma.

Sin embargo, la configuración regional del navegador decidirá cómo representar el número, la fecha, la hora y la moneda. Es probable que esta configuración sea el idioma de mayor clasificación, pero no hay garantía. En Mac y Linux, el sistema decide la configuración regional independientemente de las preferencias de idioma del usuario. En Windows se puede elegir entre los idiomas en la lista de preferidos en Chrome.

Al usar Intl ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl ), los desarrolladores pueden anular / configurar la configuración regional que se usará para representar estas cosas, pero hay elementos que no se puede anular, como el <input type="date">formato.

Para extraer correctamente este idioma, la única forma que he encontrado es:

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

( Intl.NumberFormat().resolvedOptions().localetambién parece funcionar)

Esto creará una nueva instancia de NumberFormat para la configuración regional predeterminada y luego volverá a leer la configuración regional de esas opciones resueltas.

Patrik Kullman - Neovici
fuente
5

Investigué un poco sobre esto y he resumido mis hallazgos hasta ahora en la tabla a continuación

ingrese la descripción de la imagen aquí

Por lo tanto, la solución recomendada es escribir un script del lado del servidor para analizar el Accept-Languageencabezado y pasarlo al cliente para configurar el idioma del sitio web. Es extraño por qué el servidor sería necesario para detectar la preferencia de idioma del cliente, pero así es como es ahora. Hay otros hacks disponibles para detectar el idioma, pero leer el Accept-Languageencabezado es la solución recomendada según mi entendimiento.

Abhishek V
fuente
2

También puede intentar obtener el idioma del documento que podría ser su primer puerto de escala, luego recurrir a otros medios, ya que a menudo las personas querrán que su idioma JS coincida con el idioma del documento.

HTML5:

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

Legado:

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

Ninguna fuente real es necesariamente 100% confiable ya que las personas simplemente pueden poner el idioma equivocado.

Hay bibliotecas de detección de idioma que pueden permitirle determinar el idioma por contenido.

jgmjgm
fuente
1

Usé todas las respuestas y creé una solución de línea única:

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

console.log(getLanguage());
Caio Santos
fuente