Melhor maneira de determinar a localidade do usuário no navegador

203

Eu tenho um site (Flash) localizado em uma dúzia de idiomas e desejo definir automaticamente um valor padrão, dependendo das configurações do navegador do usuário, para minimizar as etapas de acesso ao conteúdo.

Para sua informação, não posso usar scripts de servidor devido a restrições de proxy, por isso acho que o JavaScript ou o ActionScript seriam apropriados para resolver o problema.

Questões:

  1. Qual seria o melhor método para 'adivinhar' a localidade do usuário?

  2. Existem classes / funções simples existentes que poderiam me ajudar (sem pacotes de localização complexos)? Especialmente para dividir todos os idiomas possíveis em um número menor (as traduções que tenho) de maneira inteligente.

  3. Até que ponto posso confiar nessa solução?

  4. Alguma outra solução alternativa ou sugestão?

Theo.T
fonte
A única maneira de um navegador compartilhar metadados sobre seu usuário e a solicitação é por meio de URLs e cabeçalhos. Pegue o Firefox e dê uma olhada nos cabeçalhos enviados quando uma solicitação é feita. É bastante interessante examinar cabeçalhos de solicitação e resposta típicos.
mP.

Respostas:

188

A maneira correta é examinar o cabeçalho HTTP Accept-Language enviado ao servidor. Ele contém a lista ordenada e ponderada de idiomas para os quais o usuário configurou seu navegador para preferir.

Infelizmente este cabeçalho não está disponível para leitura dentro do JavaScript; tudo o que você obtém é o navigator.languageque informa qual versão localizada do navegador da web foi instalada. Isso não é necessariamente o mesmo que o idioma preferido do usuário. No IE, você obtém systemLanguage(idioma instalado do SO), browserLanguage(o mesmo que language) e userLanguage(região do SO configurada pelo usuário), que são igualmente inúteis.

Se eu tivesse que escolher entre essas propriedades, cheiraria userLanguageprimeiro, voltando ae languagesomente depois disso (se elas não correspondessem a nenhum idioma disponível) olhando browserLanguagee finalmente systemLanguage.

Se você pode colocar um script do lado do servidor em outro lugar na rede que simplesmente lê o cabeçalho Accept-Language e o cospe novamente como um arquivo JavaScript com o valor do cabeçalho na string, por exemplo:

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

você pode incluir um <script src> apontando para esse serviço externo no HTML e usar JavaScript para analisar o cabeçalho do idioma. Porém, não conheço nenhum código de biblioteca existente para fazer isso, pois a análise do Accept-Language é quase sempre feita no lado do servidor.

O que quer que você acabe fazendo, certamente precisará de uma substituição de usuário, porque sempre achará errado para algumas pessoas. Geralmente, é mais fácil colocar a configuração de idioma no URL (por exemplo, http: //www.example.com/en/site vs http: //www.example.com/de/site) e deixar o usuário clicar em links entre os dois. Às vezes, você deseja um único URL para as duas versões de idioma; nesse caso, você deve armazenar a configuração em cookies, mas isso pode confundir os agentes do usuário sem suporte para cookies e mecanismos de pesquisa.

bobince
fonte
11
Do MDN developer.mozilla.org/pt-BR/docs/Web/API/NavigatorLanguage/… "O cabeçalho HTTP do idioma de aceitação em todas as solicitações HTTP do navegador do usuário usa o mesmo valor para a propriedade navigator.languages, exceto as informações extras. campo qvalues ​​(valores de qualidade) (por exemplo, en-US; q = 0,8). "
S Meaden
3
Atualização: Existe agora (2020) um recurso experimental suportado por todos os navegadores modernos que retorna uma variedade de preferências de idioma: navigator.languages //["en-US", "zh-CN", "ja-JP"]isso deve funcionar em pelo menos 95% dos navegadores em 2020.
Cornelius Roemer
1
navigator.languages, de acordo com o MDN e o caniuse.com , agora está disponível em todos os principais navegadores - tente o pequeno pacote de idiomas de navegador (~ 200 bytes) para obter a abordagem mais moderna e compatível com versões anteriores.
mindplay.dk 18/03
84

No Chrome e Firefox 32+, o navigator.languages ​​contém uma variedade de localidades na ordem de preferência do usuário e é mais preciso que o navigator.language, no entanto, para torná-lo compatível com versões anteriores (Testado Chrome / IE / Firefox / Safari), use isto:

function getLang()
{
 if (navigator.languages != undefined) 
 return navigator.languages[0]; 
 else 
 return navigator.language;
}
Fiach Reid
fonte
2
Isso não funciona para o IE9 e IE10. Para eles, você deve examinar navigator.browserLanguage.
user393274
2
OneLiner:function getLang(){ return ( navigator.language || navigator.languages[0] ); }
JorgeGarza
4
@ChStark Não deveria ser return navigator.languages[0] || navigator.language;?
James_
23
Além disso, a correta "one-liner" ficaria assim: return (navigator.languages && navigator.languages.length) ? navigator.languages[0] : navigator.language;. Caso contrário, você receberá uma exceção se navigator.languagesestiver indefinida ou vazia.
Max Truxa
Para uma versão ainda mais compactaconst getLang = () => navigator.language || navigator.browserLanguage || ( navigator.languages || [ "en" ] ) [ 0 ]
João Miguel Brandão
41

Este artigo sugere as seguintes propriedades do objeto de navegador do navegador :

  • navigator.language (Netscape - Localização do navegador)
  • navigator.browserLanguage (específico do IE - idioma localizado no navegador)
  • navigator.systemLanguage (Específico do IE - SO Windows - Idioma localizado)
  • navigator.userLanguage

Coloque-os em uma função javascript e você poderá adivinhar o idioma correto, na maioria das circunstâncias. Certifique-se de degradar normalmente, para ter uma div contendo os links de escolha de idioma, para que, se não houver javascript ou o método não funcione, o usuário ainda possa decidir. Se funcionar, apenas oculte o div.

O único problema ao fazer isso no lado do cliente é que você atende todos os idiomas ao cliente ou precisa aguardar até que o script seja executado e detectado o idioma antes de solicitar a versão correta. Talvez servir como padrão a versão mais popular do idioma irrite o menor número de pessoas.

Editar: Gostaria da segunda sugestão de cookie de Ivan, mas verifique se o usuário sempre pode alterar o idioma mais tarde; nem todos preferem o idioma padrão do navegador.

Phil H
fonte
Obrigado Phil por suas sugestões. Em relação ao artigo, ele tem 6 anos ... não tem certeza se podemos confiar nele?
23410 Theo.T
1
Suspeito que todos os navegadores modernos suportem navigator.language. Meu navegador (FF3 no Ubuntu 8.10) reporta 'en-GB'. Se alguém ainda estiver usando o IE6 - cerca de 20% das pessoas -, vale a pena permitir isso. O IE6 apareceu há 8 anos.
Phil H
O IE 8 não suporta navigator.language. Talvez o IE 9 seja?
Spig
36

Combinando as várias maneiras pelas quais os navegadores estão usando para armazenar o idioma do usuário, você obtém esta função:

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

Primeiro, verificamos o navigator.languagesarray para seu primeiro elemento.
Então temos um navigator.userLanguageou outro navigator.language.
Se isso falhar, nós obtemos navigator.browserLanguage.
Por fim, definimos como 'en'se tudo falhar.


E aqui está a frase sexy:

const getNavigatorLanguage = () => (navigator.languages && navigator.languages.length) ? navigator.languages[0] : navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en';
Zenoo
fonte
aparentemente, também há algo como navigator.userLanguage(para o IE). Você pode adicionar isso para torná-lo completo :)
pors
Por que não simplesmente navigator.languages[0] || navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en'?
Emerica
@Curse Porque navigator.languagespode serundefined
Zenoo 13/09/19
@Zenoo Você sabe em quais navegadores?
Emerica
(navigator.languages || [])[0] || navigator.userLanguage || navigator.language || navigator.browserLanguage || 'en'
Steve Bennett
10

Há uma diferença entre os idiomas preferenciais do usuário e a localidade do sistema / navegador.

Um usuário pode configurar os idiomas preferidos no navegador e eles serão usados navigator.language(s)e solicitados a recursos de um servidor para solicitar conteúdo de acordo com uma lista de prioridades de idioma.

No entanto, a localidade do navegador decidirá como renderizar número, data, hora e moeda. Essa configuração é provavelmente o idioma de classificação mais alto, mas não há garantia. No Mac e Linux, o código do idioma é decidido pelo sistema, independentemente das preferências de idioma do usuário. No Windows pode ser eleito entre os idiomas na lista preferida no Chrome.

Usando o Intl ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl ), os desenvolvedores podem substituir / definir o código do idioma a ser usado para renderizar essas coisas, mas existem elementos que não pode ser substituído, como o <input type="date">formato.

Para extrair corretamente esse idioma, a única maneira que encontrei é:

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

( Intl.NumberFormat().resolvedOptions().localetambém parece funcionar)

Isso criará uma nova instância NumberFormat para o código do idioma padrão e, em seguida, lerá novamente o código do idioma dessas opções resolvidas.

Patrik Kullman - Neovici
fonte
5

Pesquisei um pouco sobre isso e resumi minhas descobertas até agora na tabela abaixo

insira a descrição da imagem aqui

Portanto, a solução recomendada é escrever um script do lado do servidor para analisar o Accept-Languagecabeçalho e passá-lo ao cliente para definir o idioma do site. É estranho que o motivo pelo qual o servidor seja necessário para detectar a preferência de idioma do cliente, mas é assim que é agora. Existem outros hacks disponíveis para detectar o idioma, mas ler o Accept-Languagecabeçalho é a solução recomendada pelo meu entendimento.

Abhishek V
fonte
2

Você também pode tentar obter o idioma do documento, caso essa seja sua primeira porta de escala e, em seguida, recorrer a outros meios, já que as pessoas desejam que o idioma JS corresponda ao idioma do documento.

HTML5:

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

Legado:

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

Nenhuma fonte real é necessariamente 100% confiável, pois as pessoas podem simplesmente colocar no idioma errado.

Existem bibliotecas de detecção de idioma que podem permitir que você determine o idioma pelo conteúdo.

jgmjgm
fonte
1

Usei todas as respostas e criei uma solução de linha ú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
fonte