Localize APL Templates Efficiently

Skills and their APL documents usually create multimodal voice experiences for Alexa users that reside in different locales that have their own languages, habits, cultural conventions, and regulations.

Translation of displayed information on screen is just one of many things that you might need to consider for localization in your APL projects. The following list shows some of the things you should consider to localize your templates efficiently:

  • Display text needs to be translated into the respective language that the user speaks.
  • Media assets like images, audio files and video might have spoken or displayed text encoded in their source so that you might need to create localized variations for these media files. In APL, the localization challenge often is to provide a localized URL string to the respective file.
  • Direction of layout can either be left-to-right or right-to-left depending on the language setting of a user’s device. Layout direction often goes beyond just changing component alignment. It might also require you to reposition, rearrange, and resize visual components.
  • Formatting of numbers, dates, time, and units can vary based on the locale a user is in.
  • In some instances, an APL template can also adapt to certain cultural preferences, conventions, and regulations by including or excluding a visual feature, or changing functional and display behavior of components.

The simplest way to achieve localization is to provide dedicated APL templates for each locale and language. Since this creates a lot of redundant and potentially inconsistent template code, your APL project artifacts are less efficient to maintain.

In general, you can optimize localization in your APL templates by extracting their locally affected parts, and then separating them from content and features that are globally shared across all locales. It is best to design your templates to support localization right from the start even when your APL project is not intended to expand to new locales anytime soon. With that being said, avoid hard coding localized content, such as text, into your APL templates.

Localize APL resources

The most common task when you localize an APL template is to provide translated text strings to the template so that information is displayed in the user’s language. This can happen in the following ways:

Translated strings are hard coded into the APL template

This should be the least preferred way to localize an APL template, because it would require you to replicate the template entirely to provide a new version for each user locale.

Translated strings in the data source

Translated strings are provided by the skill through the APL template’s data source. This is useful when strings contain dynamic content or strings are linked to a data entity as part of the data source. For example, a data source contains a list of products with their localized product titles and descriptions. Making translated strings — in particular longer text strings — part of the data source has its limits, due to the byte size limit that exists for skill responses.

Below is an example of how a skill would return a RenderDocument directive that contains localized text strings in the data source.

return {
    type: 'Alexa.Presentation.APL.RenderDocument',
    token: 'myToken',
    document: {
        type: 'APL',
        version: '2022.1',
        mainTemplate: {
            parameters: [ "localizedStrings" ],
            items: [
                {
                    type: "Text",
                    text: "${localizedStrings.welcome}"
                }
            ]
        }
    },
    datasources: {
        localizedStrings: {
            welcome: 'Welcome to APL'
        }
    }
}

Translated strings as APL resource strings

Translated strings are provided as APL resource strings in the APL document that is returned from the Alexa skill — For details, see APL Resources. Technically, this approach is comparable to putting localized strings into the data source as the skill still* hard codes* them into its RenderDocument directive response. The best reason why you would follow this approach is to overwrite certain resource strings that already exist in an imported APL package, such as to replace static with dynamic information.

In this case, a skill would return a RenderDocument directive with string resources in the APL document:

return {
    type: 'Alexa.Presentation.APL.RenderDocument',
    token: 'myToken',
    document: {
        type: 'APL',
        version: '2022.1',
        resources: [
            {
                strings: {
                    welcome: "Welcome to APL."
                }
            }
        ],
        mainTemplate: {
            items: [
                {
                    type: "Text",
                    text: "${@welcome}"
                }
            ]
        }
    }
}

Translated strings in an APL resource package

Translated strings are provided as APL resource strings in an APL package that is imported into an APL document. For more details, see APL Resources and APL Packages. This is a best practice approach to providing globally static strings to your APL document, but it has one major challenge to solve to qualify as an effective strategy for localization. When you import localized resources from an APL package, the package must contain translated string resources for each individual language unless the package is dedicated to a specific locale. You can use the lang environment variable inside a conditional resource block expression to resolve a string value according to the current user locale. The APL resource package would appear similar to the following code example.

{
  "type": "APL",
  "version": "2022.1",
  "resources": [
    {
      "strings": {
        "welcome": "Welcome"
      }
    },
    {
      "when": "${environment.lang == 'de-DE'}",
      "strings": {
        "welcome": "Willkommen"
      }
    },
    {
      "when": "${environment.lang == 'es-ES'}",
      "strings": {
        "welcome": "Bienvenido"
      }
    }
  ]
}

Translated strings in a locale-specific APL resource package

Translated strings are provided as APL resource strings in an APL package that is dedicated to a specific locale. This approach resolves the problem of containing translated strings for all locales in a single APL package and selecting them dynamically based on the current user locale. Instead, your skill hard codes the import path to a localized APL package into the RenderDocument directive response depending on the current locale that is known to the skill when it is invoked by the user. Constructing import source URLs can only be done on the skill code side, because APL templates do not allow for dynamic expressions on this property.

return {
    type: 'Alexa.Presentation.APL.RenderDocument',
    token: 'myToken',
    document: {
        type: 'APL',
        version: '2022.1',
        import: [
            {
                name: "my-local-strings",
                source: 'https://path.to/my/local-strings-for-' + locale + '.json',
                version: '1.0'
            }
        ],
        mainTemplate: {
            items: [
                {
                    type: "Text",
                    text: "${@welcome}"
                }
            ]
        }
    }
}

Resource strings cannot just contain display text, but also URLs of media assets, such as images and videos that you might want to localize. Moreover, APL resources also cannot just hold strings, but support other resource types, such as colors, dimensions, numbers, and Booleans that you can use to add dynamic APL components. These components visual appearance and functional behavior depend upon such a localized resource value. For example, display of an APL Image or background color of an APL Frame can dynamically be set in your APL template based on a localized resource variable.

Localize Styles

Sometimes, you need to customize layouts and styles based on a user locale. The most common example is layout direction that is already covered as an APL document setting and can conveniently be set globally. However, you might have more specific needs to reposition or resize APL components, rearrange them, or customize their appearance in any other way.

One simple approach is to replicate an APL component and use its when property to only inflate and render the component that is dedicated to a specific user locale. However, keep in mind that this can be considered inefficient template design.

{
    "type": "Text",
    "when": "${environment.lang == 'en-US'}",
    "color": "green",
    "text": "${@welcome}"
 },
 {
    "type": "Text",
    "when": "${environment.lang != 'en-US'}",
    "color": "red",
    "text": "${@welcome}"
}

Instead, use localized APL resources, such as dimensions, Booleans, colors, easing functions, etc. to make individual APL component properties dependent upon the current user locale.

{
    "type": "Text",
    "color": "${@localizedColorResource}",
    "text": "${@welcome}"
}

Use localized APL style definitions by making use of style evaluation if you want to make a combined set of styled component properties depend upon the current user locale. You can also put localized style property values in a resource and have the style reference that resource.

{
  "type": "APL",
  "version": "2022.1",
  "styles": {
    "WelcomeTextStyle": {
      "values": [
        {
          "color": "green",
          "fontSize": "@welcomeTextSize"
        },
        {
          "when": "${environment.lang != 'en-US'}",
          "color": "red",
          "fontWeight": 200
        }
      ]
    }
  },
  "mainTemplate": {
    "items": [
      {
        "type": "Text",
        "style": "WelcomeTextStyle",
        "text": "${@welcome}"
      }
    ]
  }
}

To avoid having style definitions for all locales in your APL template, you can follow the same approach as discussed for Translated strings in a locale-specific APL resource package, and make the style definition part of an APL package that is dedicated to providing only localized assets, such as resource strings, styles, and layouts. In this case, the skill hard codes the localized APL package URL path into the RenderDocument directive response.

return {
    type: 'Alexa.Presentation.APL.RenderDocument',
    token: 'myToken',
    document: {
        type: 'APL',
        version: '2022.1',
        import: [
            {
                name: "my-local-assets",
                source: 'https://path.to/my/local-assets-for-' + locale + '.json',
                version: '1.0'
            }
        ],
        mainTemplate: {
            items: [
                {
                    type: "Text",
                    style: "WelcomeTextStyle",
                    text: "${@welcome}"
                }
            ]
        }
    }
}

Localize Layouts

If you want to apply localized change to an entire component structure that goes beyond just stylistic appearance, APL layouts is the best way to achieve your goal. Extract the locally affected component construct from your APL template design, and then define it as an APL layout. For details, see APL layouts on the APL technical documentation pages. Your first option is to overwrite an entire APL layout definition that is imported from another APL package that you provide to your APL template. For example, you create an APL package with default assets, such as layouts, styles, and resources. You import a second APL package with localized assets in which you selectively overwrite a layout by providing a localized version of it with the same layout name. Your skill code would construct the RenderDocument directive that looks like the following code example:

return {
    type: 'Alexa.Presentation.APL.RenderDocument',
    token: 'myToken',
    document: {
        type: 'APL',
        version: '2022.1',
        import: [
            {
                name: "my-global-assets",
                source: 'https://path.to/my/global-assets.json',
                version: '1.0'
            }
            {
                name: "my-local-assets",
                source: 'https://path.to/my/local-assets-for-' + locale + '.json',
                version: '1.0'
            }
        ],
        mainTemplate: {
            items: [
                {
                    type: "MyWeatherInfoLayout"
                }
            ]
        }
    }
}

Both APL packages have a layout MyWeatherInfoLayout. The localized version of the second APL package overwrites the one from the first APL package so that the APL template renders the layout in accordance to the local user needs.

{
  "type": "APL",
  "version": "2022.1",
  "layouts": {
    "MyWeatherInfoLayout": {
      "items": [
        ...
      ]
    }
  }
}

APL layouts tend to contain complex composites that are not affected by local needs entirely. In some cases, you just want to extend a global layout definition to apply a minor change without needing to replicate and overwrite the entire layout in your localized APL package. If you identify such a need, you would extract the affected part of a layout to define as its own, localizable layout, and then nest it inside the global layout that you don’t wish to replicate and overwrite entirely. You might break up MyWeatherInfoLayout into individual parts that can be localized selectively as shown in the following example.

{
    "type": "APL",
    "version": "2022.1",
    "layouts": {
      "MyTemperatureForecastLayout": {
        ...
      }  
      "MyForecastPanelLayout": {
        "items": [
            ...,
            {
              "type": "MyTemperatureForecastLayout"
            },
            ...
        ]
      }  
      "MyWeatherInfoLayout": {
        "items": [
          ...,
          {
            "type": "MyForecastPanelLayout"
          },
          ...
        ]
      }
    }
}

A localized APL package can choose to localize just one specific part of the entire layout by overwriting either MyForecastPanelLayout or MyTemperatureForecastLayout. That reduces the amount of code you replicate if you want to overwrite it for localization.

Localize functional behavior

APL templates implement functional features for users to interact with UI elements, such as buttons, slider bars, and scroll views by using APL commands. For details, see APL commands on the APL technical documentation pages. As with any other APL component, individual commands and command groups can change their behavior dynamically based on certain conditions, such as the current user locale. This enables you to change UI behavior for different user locales.

{
    "type": "TouchWrapper",
    "onPress": [
        {
            "type": "WelcomeShowUS",
            "when": "${environment.lang == 'en-US'}"
        },
        {
            "type": "WelcomeShowROW",
            "when": "${environment.lang != 'en-US'}"
        }
    ]
}

You can also use localized APL commands to apply specific localized needs to APL components that cannot be otherwise achieved by using APL resources, styles, or conditional property value assignments. For example, a translated string to display in an APL Text component contains a dynamic data source value, such as a product title. Depending on the language, the product title might reside in different places within the sentence. You can perform dynamic string concatenation by using APL commands with an APL components onMount event handler.

{
  "type": "APL",
  "version": "2022.1",
  "commands": {
    "ConstructSelectText": {
      "parameters": [
        {
          "name": "productCategory"
        }
      ],
      "commands": {
        "type": "SetValue",
        "property": "text",
        "value": "Please select from ${productCategory}"
      }
    }
  },
  "mainTemplate": {
    "parameters": [
      "myData"
    ],
    "items": [
      {
        "type": "Text",
        "text": "${@pleaseWait}",
        "onMount": {
          "type": "ConstructSelectText",
          "productCategory": "${myData.productCategory}"
        }
      }
    ]
  }
}

The user-defined ConstructSelectText encapsulates the logic to construct the text that says, “Please select from ${productCategory}”. In other languages like German, the dynamic value for ${productCategory} is embedded into the sentence differently. To reflect this need, the localized APL package for the German user locale would overwrite the ConstructSelectText command as shown in the following code example.

"ConstructSelectText": {
    "parameters": [
        {
            "name": "productCategory"
        }
    ],
    "commands": {
        "type": "SetValue",
        "property": "text",
        "value": "Bitte wählen Sie ${productCategory} aus."
    }
}