Localizing Spoken Responses

In Chapter 1, Alexa, Hello, as we began work on the Star Port 75 Travel skill, we added a LocalisationRequestInterceptor object in index.js and registered it with the skill builder. As a reminder, here’s what LocalisationRequestInterceptor looks like:

 const​ LocalisationRequestInterceptor = {
  process(handlerInput) {
  i18n.init({
  lng: Alexa.getLocale(handlerInput.requestEnvelope),
  resources: languageStrings
  }).then((t) => {
  handlerInput.t = (...args) => t(...args);
  });
  }
 };

The ASK SDK gives us the option of registering one or more request intercepters in the skill. Such interceptors may inspect and modify the handlerInput object before giving it to a request handler. In this case, the LocalisationRequestInterceptor initializes the i18next module with the locale from the request and the source of the strings that will be spoken in responses. Then, LocalisationRequestInterceptor adds a new t() function to the handlerInput that will lookup localized string values.

We’ve been using that t() function throughout this book to fetch response messages by name from lambda/languageStrings.js. Up to this point, however, there hasn’t been much benefit in this mechanism. Had we simply hard-coded those strings in each intent handler and dispensed with the i18next module, languageStrings.js, and the interceptor, our code would’ve been much simpler.

But now that we’re ready to support additional languages in our skill, keeping response text separate from the intent handlers is about to pay off.

You’ll recall that the languageStrings.js file defines a map object where the top-level keys are two-character language codes. Currently, we only support English, so the only top-level key is en. Within the en entry is a map of English strings that are returned by the skill’s intent handlers. As a reminder, here’s what it looks like:

 module.exports = {
  en: {
  translation: {
  WELCOME_MSG:
 '<speak>'​ +
 '<p><audio src="https://starport75.dev/audio/SP75.mp3"/> '​ +
 'Welcome to Star Port 75 Travel, your source for '​ +
 '<audio src="soundbank://soundlibrary/scifi/'​ +
 'amzn_sfx_scifi_small_zoom_flyby_01"/> '​ +
 'out-of-this world adventures.</p> '​ +
 '<p>Where do you want to blast off to?</p> '​ +
 '</speak>'​,
  WELCOME_MSG_PERSONAL:
 'Welcome back to Star Port 75 Travel, {{givenName}}! '​ +
 'How can I help you?'​,
  HELLO_MSG: ​'Have a stellar day!'​,
  SCHEDULED_MSG: ​"You're all set. Enjoy your trip to {{destination}}!"​,
  DATE_VALIDATION_ERROR:
 'Star Port Seventy Five specializes in space travel, '​ +
 'not time travel. Please specify a return date that is '​ +
 'after the departure date.'​,
  LINK_MSG:
 "You'll need to link the Star Port "​ +
 "75 Travel skill with your Google Calendar so "​ +
 "that I can schedule your trip. I've added a "​ +
 "card in the Alexa app to help you with that."​,
  HELP_MSG: ​'You can say hello to me! How can I help?'​,
  GOODBYE_MSG: ​'Goodbye!'​,
  REFLECTOR_MSG: ​'You just triggered {{intentName}}'​,
  FALLBACK_MSG: ​'Sorry, I don​​'​​t know about that. Please try again.'​,
  ERROR_MSG:
 'Sorry, I had trouble doing what you asked. Please try again.'
  }
 }

In order to add Spanish or any other language to our skill’s responses, we must duplicate the en entry. The new entry’s key should be changed to es, the two-letter language code for Spanish. And, its contents should be translated to Spanish. After such a translation, the es entry in languageStrings.js will look like this:

 module.exports = {
  en: {
  ...
  },
  es: {
  translation: {
  WELCOME_MSG:
 '<speak>'​ +
 '<p><audio src="https://starport75.dev/audio/SP75.mp3"/> '​ +
 'Bienvenido a Star Port 75 Travel, su fuente de '​ +
 '<audio src="soundbank://soundlibrary/scifi/'​ +
 'amzn_sfx_scifi_small_zoom_flyby_01"/> '​ +
 'aventuras fuera de este mundo.</p> '​ +
 '<p>¿A dónde quieres volar?</p> '​ +
 '</speak>'​,
  WELCOME_MSG_PERSONAL:
 '¡Bienvenido de nuevo a Star Port 75 Travel, {{givenName}}! '​+
 '¿Como puedo ayudarte?'​,
  HELLO_MSG: ​'¡Que tengas un día estelar!'​,
 
  SCHEDULED_MSG:
 'Estás listo. ¡Disfruta tu viaje a {{destination}}!'​,
  DATE_VALIDATION_ERROR:
 'Star Port Seventy Five se especializa en viajes espaciales, '​ +
 'no en viajes en el tiempo. Especifique una fecha de regreso '​ +
 'posterior a la fecha de salida.'​,
  ACCOUNT_LINKING_MSG:
 "Tendrá que vincular la habilidad de viaje Star Port 75 "​ +
 "con su Google Calendar para que pueda programar su viaje. "​ +
 "Agregué una tarjeta en la aplicación Alexa para ayudarte "​ +
 "con eso."​,
  HELP_MSG: ​'¡Puedes saludarme! ¿Cómo puedo ayudar?'​,
  GOODBYE_MSG: ​'¡Adiós!'​,
  REFLECTOR_MSG: ​'Acabas de activar {{intentName}}'​,
  FALLBACK_MSG: ​'Lo siento, no sé sobre eso. Inténtalo de nuevo.'​,
  ERROR_MSG:
 'Lo siento, tuve problemas para hacer lo que me pediste. '​ +
 'Inténtalo de nuevo.'
  }
 }

As you can see, the es and en properties are quite similar. The key difference is that the entries in en are in English, while those in es are in Spanish. If later we decide to support another language, all we’ll need to do is copy and paste either the en or es block and change the key to the appropriate language code and translate the string values.

In some cases, you may want to define a region-specific response. In that case, you can define the region-specific language strings in languageStrings.js using the full locale definition instead of the two-letter language abbreviation. For example, suppose that you wanted to have Alexa say something unique as a goodbye statement for English-speaking users in the United Kingdom. To do that, you would add this entry to languageStrings.js:

 "en-GB"​: {
  translation: {
  GOODBYE_MSG: ​'Cheerio!'
  }
 },

Notice that only the unique region-specific string had to be defined. The i18next library will fallback to the broader language strings when no region specific string is provided.

With the response strings translated to Spanish (along with an English variation for the United Kingdom), let’s test our new bilingual skill.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset