Skip to content

Développer un bot multilingue (i18n)

La page Bot multilingue de la documentation utilisateur présente les bases de l’internationalisation (i18n) pour construire des bots avec Tock : pré-requis, Locale, etc.

Cette page vient compléter cette documentation avec des éléments propres au développement.

Pré-requis

Pour activer l’internationalisation dans Tock, programmatiquement ou pas, voir Bot multilingue.

Principes

Le code ne change pas une fois l’internationalisation activée. Par exemple :

     send("Arrival at {0}", time)

est un code valide que le module soit activé ou non.

Par contre, à l’exécution, le comportement diffère significativement.

Si l’internationalisation est activée, les opérations suivantes vont être effectuées :

  1. Une clé va être générée à partir du texte passé en paramètre, en fonction du namespace (l’organisation du créateur du bot) et de la story dans laquelle est demandé ce libellé. Dans le cas ci-dessus, cela devrait ressembler à app_arrivals_Arrival at {0}app est le namespace et arrivals l’intention principale de la story.

  2. Tock vérifie ensuite si cette clé est déjà présente en base.
    • Si c’est le cas, il utilise le libellé présent en base pour la langue demandée afin de trouver la traduction la plus appropriée (le connecteur ou le type d’interface peuvent également être pris en compte)
    • Sinon, une clé est créée en base avec le libellé par défaut (“Arrival at {0}” dans notre exemple) utilisée pour la langue courante
      • Si le texte passé en paramètre est un objet I18nLabelValue dont le champ defaultI18n contient une valeur pour la langue courante, celle-ci sera utilisée
  3. Il est ensuite possible de consulter et de modifier ce libellé dans l’interface d’administration :

Internationalisation

Format des messages

Le format supporté est celui du support i18n de java, en particulier celui de la classe MessageFormat en java. Cela inclut le support de ChoiceFormat :

    send("There {0,choice,0#are no files|1#is one file|1<are {0,number,integer} files}.", 2)  

Par ailleurs, Tock met à disposition une extension by pour les dates qui permet d’indiquer un format dans les paramètres :

    send("Departure at {0}", departureDateTime by timeFormat) 

Locale utilisateur

Voir Bot multilingue.

Points d’attention

Le module d’internationalisation de Tock est efficace, mais certaines pratiques, pourtant intuitives en Kotlin, sont à bannir sous peine de mauvaises surprises.

Par exemple, ce code fonctionne parfaitement bien avec le module i18n désactivé.

    send("There are $nb files") //DANGER!! 

mais pose problème si il est activé. En effet, un nouveau libellé sera créé pour chaque valeur différente de la variable nb !

Si il est nécessaire d’envoyer des réponses “à ne pas traduire”, utilisez les méthodes BotBus.sendRaw, BotBus.endRaw ou String.raw

    send("There are $nb files".raw) //CORRECT 
    send("There are {0} files", nb) //FORMAT A SUIVRE 
  • Le risque de collision entre deux libellés est faible puisque l’intention principale de la story fait partie de la clé. Si vous souhaitez cependant éviter tout risque, vous pouvez utiliser la méthode i18nKey :
    send(i18nKey("my_unique_key", "There are {0} files", nb)) 

Spécification de plusieurs localisations

Il est possible de définir des valeurs par défaut pour plusieurs localisations dans le code d’un bot :

    send(i18nKey("departure", "Departure at {0}", setOf(I18nLocalizedLabel(Locale.FRENCH, textChat, "Départ à {0}")), nb))

Par défaut, ces valeurs par défaut ne seront utilisées que lorsque la clé est utilisée pour la première fois. Pour écraser les valeurs existantes (y compris celles définies via TOCK Studio) lorsque la localisation par défaut est changée, mettez la valeur de configuration tock_i18n_reset_value_on_default_change à true (soit en variable d’environnement, soit en propriété système).

Tester l’internationalisation

Un exemple de dispositif de test est disponible dans le code source du bot d’exemple Il est nécessaire d’étendre l’extension de test pour ensuite indiquer la correspondance des libellés à tester.

Il ne reste plus qu’à indiquer la locale souhaitée :


    @Test
    fun `search story asks for departure date WHEN there is a destination and an origin but no departure date in context`() {
        ext.newRequest("Recherche", search, locale = Locale.FRENCH) {
            destination = lille
            origin = paris

            run()

            firstAnswer.assertText("Quand souhaitez-vous partir?")
        }
    }