Votre widget de support doit lire la langue de la page, pas celle du navigateur

Product

Jusqu’à cette semaine, le widget de chat de Kookee ne savait pas dans quelle langue il était. Un site pouvait passer un paramètre locale, et le widget le transmettait à l’API, mais les boutons et le « How can we help? » de l’Accueil restaient en anglais, à moins que le site ne les traduise un par un lui-même, et certains textes, comme les messages d’erreur, n’étaient pas traduisibles du tout.

Un niveau plus bas, c’était pire. L’API comparait les codes de langue comme de simples chaînes : un site brésilien qui passait pt-BR à un projet dont le centre d’aide était rédigé en pt ne trouvait aucune correspondance et recevait la langue par défaut.

Le widget n’avait l’air multilingue que si le site faisait la moitié du travail et écrivait le code exactement comme il fallait. J’ai refait la façon dont il choisit une langue et ce qu’il en fait. C’est en ligne depuis aujourd’hui, et voici les règles que j’ai retenues.

L’Accueil du widget en russe, qui salue le visiteur par son nom, avec une annonce qui n’existe qu’en anglais et trois liens

1. La page décide d’abord, le navigateur ensuite

La plupart des widgets lisent navigator.language, la langue du navigateur du visiteur. C’est le signal évident, et le plus souvent le mauvais : il décrit l’ordinateur du visiteur, pas la page qu’il lit. Un développeur allemand sur un site de documentation en anglais obtiendrait un widget en allemand posé sur une page en anglais, qui proposerait des articles qu’il irait de toute façon chercher en anglais.

La page indique déjà sa langue : <html lang>. La plupart des frameworks et des CMS le renseignent, et c’est une décision du propriétaire du site, pas une supposition. Le widget lit donc cette valeur en premier. Le navigateur n’a son mot à dire que si la page ne déclare rien, et seulement pour une langue livrée avec le widget. Sans l’un ni l’autre, le widget prend la langue par défaut du projet.

Un site peut toujours passer outre avec data-locale, ou locale en React. Et quand son sélecteur de langue modifie <html lang> sans recharger la page, le widget s’en aperçoit et suit.

2. Un code de langue est une famille, pas une chaîne

pt-BR, pt, PT-br et pt_BR désignent tous le portugais, et un widget qui tourne sur les sites des autres doit tous les accepter. La forme avec un tiret bas vient de serveurs qui écrivent les locales à la manière POSIX. Certains codes portent plus qu’une région, comme ca-ES-valencia.

Je traite cela à deux endroits. Le widget nettoie le code avant d’envoyer quoi que ce soit : il le met sous forme canonique, garde la langue et la région, et écarte tout ce qui n’est pas un code de langue, car une requête refusée par l’API laisserait le visiteur avec un widget cassé. Le serveur compare ensuite le code aux langues du projet : d’abord une correspondance exacte, puis la langue de base, puis quelques anciens codes comme nb et nn pour le norvégien et iw pour l’hébreu.

Un code qui ne correspond à rien reste ce qu’il est. Il ne se transforme pas en douce en une autre langue. Le repli se fait comme pour une traduction manquante.

3. Vos textes se replient sur votre langue, ceux du widget sur l’anglais

Un widget affiche deux sortes de textes, et ils demandent des replis différents.

Votre contenu (articles d’aide, collections, actualités de l’Accueil) se replie sur la langue par défaut de votre projet. Un article anglais sur une page française n’est pas idéal, mais c’est mieux qu’un onglet Aide vide, et c’est déjà ce que faisait l’API de Kookee pour une traduction manquante.

Les textes propres au widget se replient sur l’anglais. Le widget est livré en cinq langues, et pour une sixième, les boutons restent en anglais jusqu’à ce que vous lui donniez vos propres textes avec labels.

Une page allemande, sur un projet qui a des articles en allemand, affiche donc des articles en allemand avec des boutons en anglais. J’ai longtemps hésité, et j’ai gardé ce choix. Un écran mixte montre honnêtement ce qui existe. Masquer un article faute d’avoir un mot allemand pour « Back » serait pire.

L’Accueil en haut de cet article montre les deux règles à la fois. Les textes du widget et le message d’accueil que la page a passé dans son code sont en russe, et l’annonce, rédigée seulement en anglais, s’affiche en anglais.

Ce travail a fait remonter deux bugs plus anciens au même endroit. Une liste pouvait afficher deux fois le même article, une fois dans chaque langue, et une langue sans catégories traduites faisait disparaître toutes les collections de l’onglet Aide. Les deux sont corrigés : une liste contient maintenant une seule version de chaque article, et les catégories se replient comme le reste.

4. Répondre dans la langue du message du visiteur

Tout ce qui précède est une supposition sur le visiteur. Son message, non. Si quelqu’un écrit en espagnol sur une page qui se dit en anglais, il veut la réponse en espagnol.

L’assistant répond donc maintenant dans la langue du dernier message du visiteur, et ne revient à la langue du widget que si le message ne permet pas de trancher, comme « hi » ou un nom de produit. Il cherche toujours vos articles dans la langue où ils existent, et les cite tels quels.

Le chat du widget en espagnol : une question sur les factures, les recherches de l’assistant et sa réponse en espagnol, avec un article d’aide en anglais comme source

5. Changer de langue ne doit pas faire perdre la conversation

Dans une application monopage, le visiteur peut changer de langue sans recharger la page. Dans ce cas, Accueil et Aide se rechargent dans la nouvelle langue, et la conversation reste où elle était.

Un article ouvert à ce moment se ferme et ramène à son onglet. Il a été chargé dans l’ancienne langue, et son adresse peut changer d’une langue à l’autre : le recharger sur place n’est pas fiable. Revenir d’un cran en arrière est un petit prix à payer, et la conversation reste intacte.

Les sites dont le sélecteur de langue ne touche pas à <html lang> peuvent appeler KookeeChat.setLocale('fr') à la place.

6. Livrer les textes avec le widget

J’aurais pu servir les traductions depuis l’API, une langue par requête. Le script serait resté plus léger, mais chaque page s’afficherait d’abord en anglais le temps que les textes se chargent, et une ancienne copie du widget casserait le jour où je renommerais une clé.

Les cinq langues sont donc dans le fichier. Cela a coûté environ 7 Ko après gzip : le script est passé de 149,0 à 156,2 Ko. Ajouter une sixième langue, c’est un fichier et une nouvelle version, et labels couvre tout ce qui reste entre les deux.

Ce que j’ai laissé de côté

Un sélecteur de langue dans le widget. Votre site a déjà un sélecteur de langue, et un second dans le coin de la page finira tôt ou tard par le contredire. Le widget suit le vôtre.

Des textes traduits dans le tableau de bord. Le titre, le message d’accueil, les suggestions et les liens de l’onglet Personnaliser sont enregistrés dans une seule langue. Un site multilingue peut les laisser vides, pour que les textes par défaut traduits s’appliquent, ou les définir page par page dans le code, où ils l’emportent sur les valeurs enregistrées :

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>

Plus de cinq langues. Chaque nouveau texte du widget doit être traduit dans toutes les langues livrées, et je préfère cinq langues que je peux vérifier à trente que je ne peux pas vérifier.

Pour l’obtenir

La balise script en profite sans aucune modification de votre site. En React, passez à @kookee/react 1.12.0 et @kookee/sdk 1.12.0. Si votre page définit <html lang>, le widget le suit déjà.

Un changement de comportement : un site qui ne définit aucune langue obtient désormais celle que déclare sa page. Pour garder le widget en anglais quoi que dise la page, définissez data-locale="en". L’onglet Installation de la page Widget du site a une liste Langue qui l’écrit pour vous.

La liste Langue de l’onglet Installation, ouverte : Auto (page ou navigateur), English, Русский, Español, Français et Português

Afficher le widget dans la langue de vos visiteurs présente toutes les options, et Piloter le widget de chat en JavaScript décrit setLocale(). Le portail hébergé a eu ses propres langues plus tard, dans Un centre d’aide multilingue sans pages vides.