Botbuilder-samples: Need sample that demonstrates localization

Created on 30 Jan 2019  路  5Comments  路  Source: microsoft/BotBuilder-Samples

Problem
The way the samples have been written does not lend them easily to localization; using hard-coded strings, etc should be avoided as it results in a bot that cannot be used across multiple (human) languages.

Solution
There needs to be a sample that demonstrates how bots can be built allowing for localization.

Alternatives
Existing samples could be reworked to replace hard-coded strings & enable localization. However, this may make them too complicated/bloated for people who will not need multilingual bots.

[enhancement]

4.4 P1

Most helpful comment

Thanks for your response. Localization is not (and should not be) limited to using Translator API. A developer of a localized bot is likely to build it in the local language from scratch. Samples should not hardcode strings and should demonstrate good software internationalization principles. Thanks for your consideration of the enhancement in future releases. This would greatly improve the development of localized as well as internationalized bots.

All 5 comments

V3 supported something similar to what you're asking for.

V3 Node sample that incorporates localization

V3 C# sample that incorporates localization

Here's a simplified example implementation of these (still hard-coded, but separate for each language):

// bot/locale/en/index.js
{
    "welcome_title": "Welcome to the Contoso Flowers",
    "welcome_subtitle": "These are the flowers you are looking for!",
    "contoso_flowers": "Contoso Flowers",
    "main_options_order_flowers": "Order flowers",
    "main_options_talk_to_support": "Talk to support",
    "main_options_settings": "Settings",
    "help": "Help",
    "thank_you": "Support will contact you shortly. Have a nice day :)"
}

However, in V4, localization has been removed and more or less replaced with the Translator API.

V4 Node sample that incorporates Translator API

V4 C# sample that incorporates Translator API

Here's a simplified example implementation of these (not hard-coded at all):

const ENGLISH_LANGUAGE = 'en';
const SPANISH_LANGUAGE = 'es';
const DEFAULT_LANGUAGE = ENGLISH_LANGUAGE;
...
 turnContext.onSendActivities(async (context, activities, next) => {
        // Translate messages sent to the user to user language
        const userLanguage = await this.languagePreferenceProperty.get(turnContext, DEFAULT_LANGUAGE);
        const shouldTranslate = userLanguage !== DEFAULT_LANGUAGE;

        if (shouldTranslate) {
            for (const activity of activities) {
                activity.text = await this.translate(activity.text, userLanguage);
            }
         }
         await next();
});

There are also experimental V4 Node and C# samples that use a combination of the Translator API and LUIS (they're a bit too complex for a copy/paste example).

Do these match what you're looking for, or are you hoping for something else?

Thanks for your response. Localization is not (and should not be) limited to using Translator API. A developer of a localized bot is likely to build it in the local language from scratch. Samples should not hardcode strings and should demonstrate good software internationalization principles. Thanks for your consideration of the enhancement in future releases. This would greatly improve the development of localized as well as internationalized bots.

@msolhab Agreed!

I know this isn't quite what you're looking for either, but for the sake of providing additional, current examples, @Zerryth pointed out that the Virtual Assistant sample also offers another way of using LUIS for localization.

LUIS files

Deploying Virtual Assistant with Language Support

I've solved my localization needs with a custom function.

npm install adaptive-expressions botbuilder-lg

I'm using:

"adaptive-expressions": "^4.9.0",
"botbuilder-lg": "^4.8.0-preview",

main.lg:

# TEMPLATE_NAME
- ${x.localize("response")}

# OBJECT
- ```
    {
        "key": "${x.localize("response")}"
    }
    ```

en-us-templates.lg:

# response
- The response.

fr-fr-templates.lg:

# response
- La r茅ponse.

The following is adapted from my own code and not directly tested:

import { EvaluateExpressionDelegate, Expression, ExpressionEvaluator, ExpressionFunctions, MemoryInterface, ReturnType } from 'adaptive-expressions'
import { Templates } from 'botbuilder-lg'

const supportedLocales = ['en-us', 'fr-fr']
const templates: { [languageKey: string]: Templates } = {}

// 'x' for your namespace (e.g. company name).
const localizationFunctionName = 'x.localize'
const localizationDelegate = new ExpressionEvaluator(
    localizationFunctionName,
    // This is mostly copied and then modified from `ExpressionFunctions.apply`.
    ((expression: Expression, state: MemoryInterface, options: any): { value: any; error: string } => {
        let value: any
        let error: string
        let args: any[]
        ({ args, error } = ExpressionFunctions.evaluateChildren(expression, state, options, ExpressionFunctions.verifyString))
        if (!error) {
            try {
                const [templateName] = args
                const locale = state.getValue('locale')
                // Passing the state as the scope happens to work even though it's not guaranteed with the types.
                value = templates[locale].evaluate(templateName, state)
            } catch (e) {
                console.error(`[${localizationFunctionName}] Error evaluating with args: ${args}`)
                error = e.message
            }
        }

        return { value, error }
    }) as EvaluateExpressionDelegate,
    ReturnType.String,
    ExpressionFunctions.validateString)

Expression.functions.set(localizationDelegate.type, localizationDelegate)

for (const key of supportedLocales) {
    const path = `./templates/${key}-templates.lg`
    templates[key] = Templates.parseFile(path)
}

const mainTemplate = Templates.parseFile('./main.lg')

function handleRequest(locale: string) {
    const templateResult = mainTemplate.evaluate('TEMPLATE_NAME', { locale })
    // TODO Use the generated result.
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

EricDahlvang picture EricDahlvang  路  9Comments

clearab picture clearab  路  4Comments

pesarkhobeee picture pesarkhobeee  路  9Comments

Batta32 picture Batta32  路  9Comments

daveRendon picture daveRendon  路  6Comments