From 62d0bf507d063fd737d2e67cfd8bf0f589221517 Mon Sep 17 00:00:00 2001 From: Craig Walls Date: Sun, 12 Apr 2020 17:43:22 -0600 Subject: [PATCH] Add i18n to ASK CLI 2.0.x template --- lambda/index.js | 50 +++++++++++++++++++++++++++++++++------ lambda/languageStrings.js | 20 ++++++++++++++++ lambda/package.json | 3 ++- 3 files changed, 65 insertions(+), 8 deletions(-) create mode 100644 lambda/languageStrings.js diff --git a/lambda/index.js b/lambda/index.js index 04be554..70e3003 100644 --- a/lambda/index.js +++ b/lambda/index.js @@ -2,13 +2,15 @@ // Please visit https://alexa.design/cookbook for additional examples on implementing slots, dialog management, // session persistence, api calls, and more. const Alexa = require('ask-sdk-core'); +const i18n = require('i18next'); +const languageStrings = require('./languageStrings'); const LaunchRequestHandler = { canHandle(handlerInput) { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest'; }, handle(handlerInput) { - const speakOutput = 'Welcome, you can say Hello or Help. Which would you like to try?'; + const speakOutput = handlerInput.t('WELCOME_MSG'); return handlerInput.responseBuilder .speak(speakOutput) .reprompt(speakOutput) @@ -21,8 +23,8 @@ const HelloWorldIntentHandler = { && Alexa.getIntentName(handlerInput.requestEnvelope) === 'HelloWorldIntent'; }, handle(handlerInput) { - const speakOutput = 'Hello World!'; - return handlerInput.responseBuilder + const speakOutput = handlerInput.t('HELLO_MSG'); + return handlerInput.responseBuilder .speak(speakOutput) //.reprompt('add a reprompt if you want to keep the session open for the user to respond') .getResponse(); @@ -34,7 +36,7 @@ const HelpIntentHandler = { && Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.HelpIntent'; }, handle(handlerInput) { - const speakOutput = 'You can say hello to me! How can I help?'; + const speakOutput = handlerInput.t('HELP_MSG'); return handlerInput.responseBuilder .speak(speakOutput) @@ -49,12 +51,31 @@ const CancelAndStopIntentHandler = { || Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.StopIntent'); }, handle(handlerInput) { - const speakOutput = 'Goodbye!'; + const speakOutput = handlerInput.t('GOODBYE_MSG'); return handlerInput.responseBuilder .speak(speakOutput) .getResponse(); } }; + +// FallbackIntent triggers when a customer says something that doesn’t map to any intents in your skill +// It must also be defined in the language model (if the locale supports it) +// This handler can be safely added but will be ingnored in locales that do not support it yet +const FallbackIntentHandler = { + canHandle(handlerInput) { + return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' + && Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.FallbackIntent'; + }, + handle(handlerInput) { + const speakOutput = handlerInput.t('FALLBACK_MSG'); + + return handlerInput.responseBuilder + .speak(speakOutput) + .reprompt(speakOutput) + .getResponse(); + } +}; + const SessionEndedRequestHandler = { canHandle(handlerInput) { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'SessionEndedRequest'; @@ -75,7 +96,7 @@ const IntentReflectorHandler = { }, handle(handlerInput) { const intentName = Alexa.getIntentName(handlerInput.requestEnvelope); - const speakOutput = `You just triggered ${intentName}`; + const speakOutput = handlerInput.t('REFLECTOR_MSG', {intentName: intentName}); return handlerInput.responseBuilder .speak(speakOutput) @@ -93,7 +114,7 @@ const ErrorHandler = { }, handle(handlerInput, error) { console.log(`~~~~ Error handled: ${error.stack}`); - const speakOutput = `Sorry, I had trouble doing what you asked. Please try again.`; + const speakOutput = handlerInput.t('ERROR_MSG'); return handlerInput.responseBuilder .speak(speakOutput) @@ -102,6 +123,17 @@ const ErrorHandler = { } }; +const LocalisationRequestInterceptor = { + process(handlerInput) { + i18n.init({ + lng: Alexa.getLocale(handlerInput.requestEnvelope), + resources: languageStrings + }).then((t) => { + handlerInput.t = (...args) => t(...args); + }); + } +}; + // The SkillBuilder acts as the entry point for your skill, routing all request and response // payloads to the handlers above. Make sure any new handlers or interceptors you've // defined are included below. The order matters - they're processed top to bottom. @@ -111,10 +143,14 @@ exports.handler = Alexa.SkillBuilders.custom() HelloWorldIntentHandler, HelpIntentHandler, CancelAndStopIntentHandler, + FallbackIntentHandler, SessionEndedRequestHandler, IntentReflectorHandler, // make sure IntentReflectorHandler is last so it doesn't override your custom intent handlers ) .addErrorHandlers( ErrorHandler, ) + .addRequestInterceptors( + LocalisationRequestInterceptor + ) .lambda(); diff --git a/lambda/languageStrings.js b/lambda/languageStrings.js new file mode 100644 index 0000000..6910e1d --- /dev/null +++ b/lambda/languageStrings.js @@ -0,0 +1,20 @@ +/* * + * We create a language strings object containing all of our strings. + * The keys for each string will then be referenced in our code, e.g. handlerInput.t('WELCOME_MSG'). + * The localisation interceptor in index.js will automatically choose the strings + * that match the request's locale. + * */ + +module.exports = { + en: { + translation: { + WELCOME_MSG: 'Welcome, you can say Hello or Help. Which would you like to try?', + HELLO_MSG: 'Hello World!', + 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.' + } + } +} diff --git a/lambda/package.json b/lambda/package.json index 3a323d9..421256a 100644 --- a/lambda/package.json +++ b/lambda/package.json @@ -11,6 +11,7 @@ "dependencies": { "ask-sdk-core": "^2.6.0", "ask-sdk-model": "^1.18.0", - "aws-sdk": "^2.326.0" + "aws-sdk": "^2.326.0", + "i18next": "^15.0.5" } }