Seu widget de suporte deveria ler o idioma da página, não o do navegador

Product

Até esta semana, o widget de chat do Kookee não sabia em que idioma estava. Um site podia passar um locale, e o widget o repassava à API, mas os botões e o “How can we help?” do Início ficavam em inglês, a menos que o site traduzisse cada um por conta própria, e alguns textos, como as mensagens de erro, não tinham tradução possível.

Um nível abaixo era pior. A API comparava as tags de idioma como texto puro, então um site brasileiro que passava pt-BR para um projeto com a central de ajuda escrita em pt não encontrava correspondência e recebia de volta o idioma padrão.

O widget só parecia multilíngue se o site fizesse metade do trabalho e escrevesse a tag exatamente certa. Refiz a forma como ele escolhe o idioma e o que faz com ele. A mudança saiu hoje, e estas são as regras que adotei.

O Início do widget em russo, cumprimentando o visitante pelo nome, com um anúncio que só existe em inglês e três links

1. Primeiro decide a página, depois o navegador

A maioria dos widgets lê navigator.language, o idioma do navegador do visitante. É o sinal óbvio e geralmente o errado, porque descreve o computador do visitante, não a página que ele está lendo. Um desenvolvedor alemão num site de documentação em inglês receberia um widget em alemão numa página em inglês, oferecendo artigos que depois buscaria em inglês de qualquer forma.

A página já diz em que idioma está: <html lang>. A maioria dos frameworks e CMSs define esse atributo, e ele é uma decisão do dono do site, não um palpite. Por isso o widget lê esse valor primeiro. O navegador só tem voz quando a página não declara nada, e só para um idioma que o widget de fato traz. Sem nenhum dos dois, ele usa o idioma padrão do projeto.

Um site ainda pode passar por cima de tudo isso com data-locale, ou locale no React. E quando o seletor de idioma do site muda o <html lang> sem recarregar a página, o widget percebe e acompanha.

2. Uma tag de idioma é uma família, não um texto

pt-BR, pt, PT-br e pt_BR querem dizer português, e um widget que roda nos sites dos outros precisa aceitar todas essas formas. A forma com sublinhado vem de servidores que escrevem locales no estilo POSIX. Algumas tags trazem mais que uma região, como ca-ES-valencia.

Trato isso em dois lugares. O widget limpa a tag antes de enviar qualquer coisa: põe na forma canônica, mantém o idioma e a região e descarta tudo o que nem é tag de idioma, porque uma requisição recusada pela API deixaria o visitante com um widget quebrado. Depois o servidor compara a tag com os idiomas do projeto: primeiro a correspondência exata, depois o idioma base, depois alguns códigos antigos, como nb e nn para norueguês e iw para hebraico.

Uma tag que não corresponde a nada continua sendo o que é. Ela não vira, sem aviso, outro idioma. Segue o mesmo caminho de uma tradução que falta.

3. Seus textos recorrem ao seu idioma; os do widget, ao inglês

Um widget mostra dois tipos de texto, e cada um precisa de um idioma de reserva diferente.

Seu conteúdo (artigos de ajuda, coleções, novidades no Início) recorre ao idioma padrão do projeto. Um artigo em inglês numa página em francês não é o ideal, mas é melhor que uma aba Ajuda vazia, e era o que a API do Kookee já fazia quando faltava uma tradução.

O texto do próprio widget recorre ao inglês. O widget traz cinco idiomas, e num sexto os botões ficam em inglês até você passar suas próprias palavras com labels.

Então uma página em alemão, num projeto com artigos em alemão, mostra artigos em alemão com botões em inglês. Fui e voltei nessa decisão e acabei mantendo. Uma tela misturada é honesta sobre o que existe. Esconder um artigo porque o widget não tem a palavra alemã para “Back” seria pior.

A tela do Início no começo deste post mostra as duas regras ao mesmo tempo. O texto do widget e a saudação que a página passou no código estão em russo, e o anúncio, escrito só em inglês, aparece em inglês.

Esse trabalho revelou dois bugs mais antigos no mesmo lugar. Uma lista podia mostrar o mesmo artigo duas vezes, uma em cada idioma, e um idioma sem categorias traduzidas fazia a aba Ajuda perder todas as coleções. Os dois foram corrigidos: uma lista agora tem uma versão de cada artigo, e as categorias recorrem ao idioma padrão como todo o resto.

4. Responda no idioma em que o visitante escreve

Tudo o que vem acima é um palpite sobre o visitante. A mensagem dele não é. Se alguém escreve em espanhol numa página que se diz em inglês, quer a resposta em espanhol.

Por isso o assistente agora responde no idioma da última mensagem do visitante e só recorre ao idioma do widget quando a mensagem não resolve a questão, como num “hi” ou no nome de um produto. Ele continua buscando seus artigos em qualquer idioma em que existam e os cita como estão.

O chat do widget em espanhol: uma pergunta sobre faturas, as buscas do assistente e a resposta em espanhol, com um artigo de ajuda em inglês como fonte

5. Trocar o idioma não deveria custar a conversa

Numa single-page app, o visitante pode trocar de idioma sem recarregar a página. Quando isso acontece, Início e Ajuda recarregam no novo idioma e a conversa fica onde estava.

Um artigo aberto nesse momento fecha e volta para a aba dele. Ele foi buscado no idioma antigo, e o endereço pode mudar de um idioma para outro, então recarregá-lo no lugar não é confiável. Voltar um passo é um preço pequeno, e a conversa fica intacta.

Sites cujo seletor de idioma não mexe no <html lang> podem chamar KookeeChat.setLocale('fr').

6. Mande os textos junto com o widget

Eu podia ter servido as traduções pela API, um idioma por requisição. O script ficaria menor, mas cada página abriria mostrando inglês por um instante, até os textos carregarem, e uma cópia antiga do widget quebraria no dia em que eu renomeasse uma chave.

Por isso os cinco idiomas estão dentro do arquivo. Isso custou cerca de 7 KB com gzip: o script passou de 149,0 para 156,2 KB. Adicionar um sexto idioma é um arquivo e uma versão nova, e labels cobre o que vier nesse meio-tempo.

O que deixei de fora

Um seletor de idioma dentro do widget. Seu site já tem um seletor de idioma, e um segundo no canto da página, mais cedo ou mais tarde, vai discordar dele. O widget segue o seu.

Textos traduzidos no painel. O título, a saudação, as sugestões e os links da aba Personalizar são salvos em um idioma só. Um site em vários idiomas pode deixá-los vazios, para valerem os textos padrão já traduzidos, ou defini-los por página no código, onde eles têm prioridade sobre os valores salvos:

HTML
<script async src="https://kookee.dev/chat/latest.js"
  data-api-key="YOUR_API_KEY"
  data-locale="es"
  data-greeting="¿En qué podemos ayudarte?"></script>

Mais de cinco idiomas. Cada texto novo no widget precisa de tradução em todos os idiomas que ele traz, e prefiro ter cinco que consigo conferir a trinta que não consigo.

Como ativar

A tag de script recebe a atualização sem nenhuma mudança no seu site. No React, atualize para @kookee/react 1.12.0 e @kookee/sdk 1.12.0. Se sua página define <html lang>, o widget já segue esse idioma.

Uma mudança de comportamento: um site que não define idioma agora recebe o que a página declara. Para manter o widget em inglês, seja qual for o idioma da página, defina data-locale="en". A aba Instalação da página Widget do site tem um campo Idioma que escreve isso para você.

O campo Idioma da aba Instalação, aberto: Automático (página ou navegador), English, Русский, Español, Français e Português

Mostre o widget no idioma dos seus visitantes cobre todas as opções, e Controle o widget de chat com JavaScript traz o setLocale(). O portal hospedado ganhou idiomas próprios depois, como conto em Uma central de ajuda multilíngue sem páginas vazias.