Oracle Cloud Infrastructure Documentation

Localization

You can design your skills and digital assistants for users whose native language is not English. While the Natural Language Processing (NLP) engine works in English, you can still design skills to interact with users in other languages by using a combination of a translation service, special translation components, and resource bundles.

Translation Services

To enable skills to interact with users in a non-English language, you need to first set up a translation service in Oracle Digital Assistant. You can use either Microsoft Translator or the Google Translation API.

When a user enters a non-English request or response, the skill uses the translation service to convert this input to English. Once it’s translated, the Natural Language Processing (NLP) engine can resolve it to an intent and match the entities. The skill can then respond to the user by using the translation service to translate the labels and prompts or by referencing language-specific strings in resource bundles.

For skills that have a training corpus in a non-English language, the translation service is also used at design time. When you train such a non-English skill, it creates English versions of the example utterances and custom entity values to be used in the training model (though these translations are not shown in the skill designer).

Register a Translation Service in Oracle Digital Assistant

  1. Click icon to open the side menu to open the side menu and select Settings > Translation Service.
  2. Click + Service.
  3. Enter the URL and Authorization token for the Microsoft Translator service or the Google Translation API in the Translation Services dialog.
Refer to the documentation for Microsoft Translator and Google Translation API to find out how to get the URL and access token.
Note

To use the Google Translation API, you need to generate the API Key. You create this key from the GCP Console (APIs & services > Credentials). To find out more, see the Google Cloud Platform Documentation.

Add a Translation Service to Your Skill

  1. If you haven't done so already, register a translation service in Oracle Digital Assistant.
  2. Click icon to open the side menu to open the side menu, select Development > Skills, and select your skill.
  3. In the skill's left navbar, click the Settings(an image of the left navbar's Settings icon) icon and select the General tab.
  4. Navigate to the Translation Service dropdown and select your translation service.

Predominant Language

If you have set up a translation service for a skill, Oracle Digital Assistant automatically assigns a predominant language for that skill, based on the language of the skill's example utterances.

You can find what predominant language has been assigned for a skill by clicking the Settings(an image of the left navbar's Settings icon) icon in the skill's left navbar, selecting the General tab, and checking the value of the Predominant Language property.

Make sure that all of your intent example utterances, entities, and dialog response text are in the predominant language.

If you are designing the skill to support multiple languages, the predominant language must be English.

The predominant language of the digital assistant is determined by the predominant language of the first skill that you add to the digital assistant. Any other skills that you add to the digital assistant must have the same predominant language.

If the first skill that you add has no predominant language (because no translation service has been specified in the skill), the digital assistant's predominant language is set to English. In this case, you can either add skills that have English as the predominant language (or which have no predominant language set).

Translation Approaches

To develop skills that converse in non-English languages, you can use one of these approaches:

  • Create non-English single-language skills where you:
    • Prepare the training corpus in the target language of the skill.

    If you use this approach but need to support multiple languages, you simply create separate skills for each language.

    When you develop non-English digital assistants, you populate them with such single-language skills (where all of the skills in a given digital assistant have the same predominant language).

  • Create multi-language skills where you:
    • Prepare the training corpus in English.
    • Enhance the skill's dialog flow to manage the translation of the user input and the skill's responses.
    • Optionally (but preferably), create resource bundles for one or more languages for the skill's labels, prompts, and messages. This is desirable because it allows you to control the wording of the skill's responses.
    Note

    Though skills can be multilingual, digital assistants only support a single language. If you need a skill to converse in multiple languages, you can expose the skill itself directly to the channel rather than through a digital assistant.

Non-English Single-Language Skills

To develop a skill for a single non-English language, you:

  1. If you haven't already done so, add a translation service to your skill.

  2. Create the utterances for your skill in the target language of the skill (instead of in English):
    1. Click icon to open the side menu to open the side menu, select Development > Skills, and open your skill.
    2. In the left navigation for the skill, click This is an image of the Intent icon.
    3. Select an intent.
    4. In the Examples text field, type the utterance and press Enter.
    5. Repeat the previous two sub-steps for each intent.
  3. For any custom entities in your skill, make sure the values are in the skill's predominant language.

    You can add and edit custom entities by clicking An image of the Entities icon in the left navigation of the skill.

    If you don't provide custom entity values in the predominant language, the skill won't be able to properly process user input that contains any values that need to be matched by a custom entity.

  4. In the skill, update all of the configuration messages and prompts to use the predominant language:

    To access these messages and prompts:

    • In the left navigation for the skill, click The Settings icon in the left navbar.

    The messages and prompts are located on the Configuration and Digital Assistant tabs.

There are a couple of other things to keep in mind:
  • You can’t translate the names of the built-in entities.

  • When you set up your skill this way, the language processing framework detects non-English input and then translates it into English (the language of the training model) behind the scenes. After evaluating the input, it determines the appropriate response and translates it back to the target language.

    This can impact translation costs because it requires more calls to the translation service than a skill where the training corpus is already in the English.

Multi-Language Skills with Auto-Translation

You can enable your skill to automatically detect the user’s language and communicate in that language.

To set this up, you need to update the dialog flow to handle translation. Since the NLP engine can only recognize English, you need to set up the flow to:

  • Detect the user's language.
  • Translate the user input so that it can be resolved by the System.Intent component.

You can handle translation of user input using either of the following strategies:

  • Opt-in: You individually set the translate property to true for each component that you want to have translated.
  • Opt-out: You set the autoTranslate context variable to true so that input for each component is translated by default. If there is a component for which you don't want translation, you set its translate property to false.

Opt-In Translation

Here are the steps if you want to individually specify which components to translate :

  1. If you haven't already done so, add a translation service to your skill.
  2. Make sure that the autoTranslate context variable is not set (or set to false).
  3. Above the state for the System.Intent component, add the System.DetectLanguage component:
      detect:
        component: "System.DetectLanguage"
        transitions: {}
  4. In the System.Intent component, set the translate property to true.
      intent:
        component: "System.Intent"
        properties:
          variable: "iResult"
          translate: true
  5. For all other input components, also set the translate property property to true.
Example: Multi-Language Skill with Auto-Translation (Opt-In)
metadata:
  platformVersion: "1.0"
main: true
name: "AutoTranslatePizzaJoe"
parameters:
  age: 18
context:
  variables:
    size: "PizzaSize"
    type: "PizzaType"
    crust: "PizzaCrust"
    iResult: "nlpresult" 
states:
  detect:
    component: "System.DetectLanguage"
    transitions: {}
  intent:
    component: "System.Intent"
    properties:
      variable: "iResult" 
      translate: true
  ShowMenu:
    component: "System.CommonResponse"
    properties:
      processUserMessage: true
      translate: true
      metadata:
        responseItems:
          - type: "text"
            text: "Hello ${profile.firstName}, this is our menu today:"
            ...
  ...  

Opt-Out Translation

Here are the steps if you want to use auto-translation by default (and individually specify components to not translate) :

  1. If you haven't already done so, add a translation service to your skill.
  2. Add autoTranslate: "boolean" as a variable to the context node.
    context:
      variables:
        ...
        autoTranslate: "boolean"
  3. Within the states node, above your System.Intent component, add a System.SetVariable component. Then set the variable property to use the autoTranslate context variable and set the value property to true.
      setAutoTranslate:
        component: "System.SetVariable"
        properties:
          variable: "autoTranslate"
          value: true
        transitions: {}
  4. For the next state, add the System.DetectLanguage component:
      detect:
        component: "System.DetectLanguage"
        transitions: {}
  5. For any components that you don't want auto-translated, see the translate property to false, e.g.:
      done:
        component: "System.Output"
        properties:
          text: "${rb('OnTheWay','${size.value}','${type.value}')}"
          translate: false
        transitions:
          return: "done"
Example: Multi-Language Skill with Auto-Translation (Opt-Out)
metadata:
  platformVersion: "1.0"
main: true
name: "AutoTranslatePizzaJoe"
parameters:
  age: 18
context:
  variables:
    size: "PizzaSize"
    type: "PizzaType"
    crust: "PizzaCrust"
    iResult: "nlpresult"
    autoTranslate: "boolean" 
states:
  setAutoTranslate:
    component: "System.SetVariable"
    properties:
      variable: "autoTranslate"
      value: true
    transitions: {}
  detect:
    component: "System.DetectLanguage"
    transitions: {}
  intent:
    component: "System.Intent"
    properties:
      variable: "iResult" 

Manipulate Input Before Translation

If you want to be able to manipulate input text before sending it to the translation service, you can use the System.TranslateInput component. For example, you might want to process user input to remove some personal data before sending it to the translation service.

In the following snippet, the sourceString variable holds the text to be translated. (This input, for example, may have been gathered by a System.Text component and processed by another component.) After the System.TranslateInput completes its processing, the English translation is stored in the translatedString variable.
context:
  variables:
    autoTranslate: "boolean" 
    translatedString: "string"
    sourceString: "string"    
   ...
states:
   ...
  translateInputString:
    component: "System.TranslateInput"
    properties:
      source: "sourceString"
      variable: "translatedString"
    transitions: {}

Resource Bundles

When you want to control the wording for your skill’s responses (instead of relying on the text provided by the translation service), use resource bundles. You can provide resources bundles for as many languages and dialects as you need.

Create a Resource Bundle

You define a single bundle for each skill that’s made up of various keys that identify the output text that needs to be translated.

To create a resource bundle:
  1. Click Resource Bundle in the left navbar (This is an image of the left navbar Resource Bundle icon.).

  2. Click the User-Defined tab.
  3. Click Add Bundle.

    By default, the language for your first key is English.

  4. Enter the key and the and its text. For example, for the user prompt How old are you?, you might enter HowOld in the Key field and then How old are you? in the Text field.

  5. Click Create Entry.

  6. To add a foreign language version of the string, click Add Language.
  7. Complete the Create Entry dialog:
    • Language—Add an IETF BCP 47 language tag like fr for French or de for German.

    • Text—The output string. For example, for a French translation (fr) of the HowOld key, you’d add a string like quel âge avez-vous ?

      Note

      You can also use more specific locales (such as en-US), but they are not useful in most cases. For example, if you are using a translation service (via the System.DetectLanguage component) to detect the language, only a two-letter code will be returned.

      If the skill can’t match the input language with a language tag defined in the bundle, it defaults to a less-specific tag (if one is available). If none of the entries match the browser’s language, the skill uses the default entry, English. See Resource Bundle Entry Resolution for details.

  8. If you want to translate other strings, click Add Key to create another entry in the resource bundle.

  9. Reference the resource bundle in the in the dialog flow. You can define the entity prompts as a resource bundle.

Note

Custom entities can't be translated with resource bundles. Instead, you can add translations as synonyms in the value list for the custom entities.

Create Entry for Conversation Name

At some points within a conversation, such as when the skill is trying to determine what flow the user wants to follow, the skill may present a dialog that refers to one more intents. In these cases, the skill refers to the intents by their conversation names, for which keys and default entries are generated in the resource bundle.

To provide a translation for a conversation name:

  1. Click Resource Bundle in the left navbar (This is an image of the left navbar Resource Bundle icon.).

  2. Click the Intents tab on the Resource Bundles page.



  3. Select the intent

  4. Click Add Language.

  5. Complete the Create Entry dialog:
    • Language—Add an IETF BCP 47 language tag like fr for French, de for German, or en-US for U.S. English.

    • Text—The output string. For example, for a French translation (fr) of the HowOld key, you’d add a string like quel âge avez-vous ?

Note

If the intent for which you want to change the conversation name doesn't appear in the list, click This is an image of the Intent icon. to go back to the Intents page, select the intent, and edit its Conversation Name field. When you return the Resource Bundles page, it should then appear under the Intents tab.

Reference Resource Bundles in the Dialog Flow

To set the output for a built-in component, you reference the resource bundle context variable and message key.

In the following OBotML snippet for a pizza skill, the resource bundle is declared as the variable, rb, in the context section. Further down, value expressions define the text property for the System.Output components reference the rb variable and the keys, WhatType and OnTheWay. The first outputs a simple string and the other uses dynamic values.
context:
  variables:
    rb: "resourcebundle"
...

pizzaType:
  component: "System.Output"
  properties:
    text: "${rb('WhatType')}" # rb refers to the variable, WhatType is the key to the message in the resource bundle.
  transitions: {}
...

done:
  component: "System.Output"
  properties:
    text: "${rb('OnTheWay','${size.value}','${type.value}')}" # size.value and type.value are the arguments for the 'OnTheWay' message code.
  transitions:
    return: "done"
For simple messages, you can also reference resource bundles using dot notation (${rb.WhatType}).

Tip:

To test your resource bundles using the tester, set your browser to another language.

Resource Bundles and Auto-Translation

When you are using resource bundles, you still use a translation service so that users can provide input in their native language. However, you will not want components that use resource bundles to be automatically translated.

Here are the general steps for setting up a skill to translate user input while using resource bundles for the skill's responses:

  1. If you haven't already done so, add a translation service to your skill.
  2. Use the System.DetectLanguage component to determine the language of the user's input.
  3. Apply resource bundles to handle the skill's responses to the user.
  4. For any components that reference resource bundles, make sure that auto-translation is turned off. You can handle this either by:
    • Using the "opt-in" approach:
      1. Set the autoTranslate context variable to false (or don't set it at all).
      2. Set the translate property to true for System.Intent, System.Text, and other input components.
    • Using the "opt-out" approach:
      1. Set the autoTranslate context variable to true .
      2. Override autoTranslate for each component that uses resource bundles (such as System.Output and System.CommonResponse components) by setting the translate property for those components false.

      One disadvantage of this approach is that it might be harder to notice where you have inadvertently set up auto-translation for a component that should be using resource bundles instead.

If your skill uses resource bundles for some components but relies on auto-translation for other components, you can:

  • Set the autoTranslate context variable to true.
  • Set the translate property to false for each component that uses a resource bundle.
Example: Translation with Resource Bundles

The following dialog flow sample code shows the relevant part of the dialog flow for a skill that it accepts a user's non-English input, translates the input into English for intent resolution, and responds in the user's language using text from resource bundles.

The autotranslate context variable is not set, so components are not automatically translated by default. However, the translate property is set to true for the System.Intent component so that user input is automatically translated.

metadata:
  platformVersion: "1.0"
main: true
name: "PizzaJoe"
parameters:
  age: 18
context:
  variables:
    size: "PizzaSize"
    type: "PizzaType"
    crust: "PizzaCrust"
    iResult: "nlpresult"
    rb: "resourcebundle"
    
states:
   # add DetectLanguage component
  detect:
    component: "System.DetectLanguage"
    transitions: {}
   
  intent:
    component: "System.Intent"
    properties:
      variable: "iResult"
      translate: true 
    transitions:
      actions:
        OrderPizza: "resolvesize"
        CancelPizza: "cancelorder"
        unresolvedIntent: "unresolved"
  ...

  pizzaType:
    component: "System.Output"
    properties:
      text: "${rb('WhatType')}" 
    transitions: {}
  ...

In this sample:

  • It is assumed that a translation service is enabled for the skill.
  • The rb context variable is accompanied by another variable called translated.
  • The System.DetectLanguage is set. This sets the value of profile.languageTag to the two-letter code of the detected language. This value also takes precedence over the value of profile.locale.
  • Because both the System.DetectLanguage and System.TranslateInput components are positioned before the System.Intent component, they enable the initial user input to be translated into English before it can be used by the System.Intent component and resolved to one of the intents.
Note

You can also detect the language from the messenger client via the profile.locale variable (and not use the System.DetectLanguage component). However, this approach requires users to initially invoke the skill in English (like “Hello, PizzaJoe!”).

Resource Bundle Entry Resolution

The resource bundle that gets applied depends on the value stored for the two location-specific user context variables, profile.languageTag and profile.locale. If both variables are set, profile.languageTag takes precedence.

profile.languageTag is set to the language of the user's input by the System.DetectLanguage component, if you have that component in your dialog flow. The value of profile.languageTag takes the form of a two-character language code (e.g. en for English).

profile.locale is set by the messenging client. The value of profile.locale can take the form of language-country-variant (e.g. en-AU-sydney), language-country (e.g. en-AU), or language (e.g. en).

When resolving which language to use, Oracle Digital Assistant first searches for an exact match. If it doesn't find one, it incrementally broadens its search until it succeeds. If it still can't find a match, it returns the default language, which is English (en).

For example, if the value of ${profile.locale} is en-AU-sydney (and profile.languageTag isn't set), Oracle Digital Assistant does the following to find the best language match:
  1. Searches the bundle by the language-country-variant criteria (en-AU-sydney).

  2. If it can’t find that, it searches the bundle by language and country (en-AU).

  3. Failing that, it broadens its search for language (en).

How Do I Translate Custom Component Responses?

There are three methods for returning translated content from your custom components:
  1. Store s data object sent from a custom component in a context variable. You can then reference this variable in the built-in user interface components like System.Output, System.Text, or System.CommonResponse.
  2. Save string messages in a context variable, and then pass the name of the context variable as an input parameter to system components like System.Output, System.List, System.CommonResponse, or System.TranslateOutput.
  3. Translate the custom component output in the component itself and then directly write the response to the messenger client (thus avoiding the system components altogether).

Option 1: Storing Data in a Context Variable

Custom components that query backend services might return data in a complex format like an object or an array of objects. If this data requires translation:
  1. Save the data in a context variable in your dialog flow.

    To write data from a data object to a context variable, add the following code to your custom component:
    conversation.variable('dialogVar', dataObject);
    conversation.transition();
    done();
    
    For this particular line of code to work, you need to add a corresponding context variable to your dialog flow definition named dialogVar that’s a string type :
    dialogVar: "string"

    Tip:

    As a best practice, pass the name of the context variable that the custom component should write to as a input parameter to the custom component. This way, you ensure that the context parameter really exists when accessing it.
  2. Include the translate: true property in an output component definition, or use the System.TranslateOutput component to translate it to the user’s language.

    The system components can’t translate a data object as a whole, so if you need to translate data objects stored in a context variable, then you need to reference the context variable along with the name of the data object attribute that’s displayed to user and gets translated by an output component. In the following example, the context variable is dialogVar. The data object that’s passed from the custom component to this context variable is {product: "an apple", type: "fruit", origin: "Spain" }. To display and translate this object, you’d reference it a System.Output component and enable its translation:
    printProduct:
      component: "System.Output"
      properties:
        text: "The product in your cart is a ${dialogVar.value.type}. It is
               ${dialogVar.value.product} from ${dialogVar.value.origin}"
        translate: true
    
    If a translation service is enabled for the skill, then this message gets translated to the user’s language. The custom component also passes the translated content of the data object.

Option 2: Saving Messages in a Context Variable

In this approach, you can pass the name of the context variable that holds the component response as an input parameter to the custom component. This ensures that custom components are not dependent on a specific OBotML implementation code and remain reusable.

The following OBotML sample references a custom component in the initializeReceipt state and passes the name of the context variable (receipt) that holds the component response and purchaseId as input parameters.
initializeReceipt:
  component: "sample.receipt.dataresponse"
  properties:
    dataVariable: "receipt"
    purchaseid: "${purchaseId.value}

printReceipt:
  component: "System.Output"
  properties:
    text:"${receipt.value}"
    translate: true
 ...
The custom code for accessing these input parameters is as follows:
...
invoke: (conversation, done) => {
  var responseVariable = conversation.properties().dataVariable;
  var purchaseId = conversation.properties().purchaseId;
  ...
  var message = queryRemoteServiceForReceipt(purchaseId);
  ...
  conversation.variable(responseVariable, message);
  conversation.transition(); 
  done();
}
To display messages in the detected user language, you can either use the System.TranslateOutput component or set the translate property on an output component like System.CommonResponse or System.Output, as shown in the printReceipt state:If a custom component returns a message that’s not in English and therefore requires processing by the Natural Language Processing (NLP) engine, then you’d position the System.TranslateInput component before the System.Intent in the dialog flow. This allows the System.Intent component to process the English version of the message.
translateMessage:
  component: "System.TranslateInput"
  properties:
    source: "variable_populated_by_custom_component"
    variable: "translationStringVar"
getIntent:
  component: "System.Intent"
  properties:
    variable: "iResult"
    sourceVariable: "translationStringVar"
...

Option 3: Sending Responses Directly to the User

In some cases, custom components can be self-contained: they don’t send a message directly to a message channel or save data to a context variable. These custom components return responses directly to the user because they use the conversation.reply helper method.
Note

Responses that are directly sent to a user can’t be translated by a translation service. In this case, you'd need to code the translations into the custom component
There are two ways to translate the skill responses that are sent directly from a custom component:
  1. In the custom component code, call a translation service before the message can be sent. Use this approach when the message does not originate from the custom component, but is queried from a remote backend. In this case, auto-translation converts the strings to the language expected by the skill.
  2. Use message bundles to provide translated responses for the languages you that want the skill to support. Message bundles can use placeholders in the translated strings in which the custom component inserts the data value at runtime. Message bundles in custom components are a viable option if the custom component queries data from a remote service.
    To detect the preferred language in the custom component, you can either pass the locale as an input parameter to the component or access the profile.locale and profile.languageTag variables as shown in the following example:
    //detect user locale. If not set, define a default
    var locale = conversation.variable('profile.locale')?
                 conversation.variable('profile.locale') : 'en';
    //when profile languageTag is set, use it. If not, use profile.locale
    var languageTag = conversation.variable('profile.langageTag')?
                      conversation.variable('profile.langageTag') : locale;