Reaching a wider audience with your skills — multi-locale

Tom Berwick
Alexa Skills Dev
Published in
4 min readApr 28, 2020
Photo by NASA on Unsplash

As with any app or software, making your product available to as many of your potential customers as possible is paramount and one of the ways Alexa skills support this is via locales.

First off I will preface this with the fact that, as long as your skill is set to be available anywhere Amazon distributes skills, someone can download it provided their device settings are set to a locale your skill supports.

This last bit is key. Basically it means that if you develop a skill in English(UK), anyone who has their device set to that language can get hold of it. It doesn’t matter if they’re actually based in the UK or in Germany, they would be able to access your skill. However, the likelihood is that most people in Germany would have their devices set to support the German locale.

So how do we go about supporting multiple languages?

I’m going to show you a simple solution here. I’m not saying it’s the best solution, and others may have much better ideas. But this is one that works for me.

First things first, how do we know the user’s locale?

Good question, I’m glad you asked. To do that we’re going to make a little utility function that accepts the handlerInput as a parameter and returns the locale. We could go a step further and call this within a requestInterceptor and store it in the sessionAttributes.

function getLocale(handlerInput) {
return handlerInput.requestEnvelope.request.locale;
}
const requestInterceptor = {
async process(handlerInput) {
const {attributesManager} = handlerInput;
const sessionAttributes = attributesManager.getSessionAttributes();
sessionAttributes.locale = getLocale(handlerInput);
attributesManager.setSessionAttributes(sessionAttributes);
}
}

Now have the user’s locale, the trick is to make use of it in our intentHandlers. The locale property can only be one of a set number of values . The next step, is how to change the response to a different language depending on the locale. As I mentioned previously there are a number of ways to approach this and I’ll provide a couple of similar, but slightly different solutions. They both begin with a top level object that will contain the various responses. But where they differ is in their organisation. You could for instance have the top level keys as the “intent” and they contain nested properties for the different languages… like so:

const responses = {"launchRequest":{
"en-GB":"Hi and welcome to my skill. ",
"de-DE":"Hallo und willkommen."
}
}
const LaunchRequestHandler = (handlerInput) => {
const {attributesManager, responseBuilder} = handlerInput;
const sessionAttributes = attributesManager.getSessionAttributes()
return responseBuilder.speak(responses.launchRequest[sessionAttributes.locale]).getResponse();
}

Alternatively, you could use the language as the top level keys, like so:

const responses = {"en-Gb":{
launchRequest: "hello, and welcome. "
},"de-DE":{
launchRequest:"Hallo, und willkommen. "}
}

Both very similar, but personally I prefer the second version, keeping the languages separate. To make things easier of course you can (And probably should) split these into their own files (each file just duplicating the intents as above):

const responses = {"en-Gb": require('./en-gb'),"de-DE": require('./de-de')
}

Again this will work well for simple skills, but what if we want to do a bit more logic? For instance my Last Flight of the Icarus skill has conditional responses based upon user slot values, so how would we manage something like that? Plus the same intent is triggered in the different chapters but has different responses. This is where separating by language is a bit more logical in my opinion. You could still keep your logic that chooses what “response” should fire in your intents, but use more nested objects or constants to access specific keys.

For instance in the case of a story you might inspect the handlerInput and grab an ID from a slot value, and use some other data to determine whether they are opening a door in chapter one, or in chapter two for example. Therefore your language structure might look as follows:

//Sample en-GB file
module.exports = {
"one": { //This is the chapter
"door":"You open the door."
} ,
"two":{
"door":"The door is locked"
}
}

You’d set-up your “responses” object similar to above requiring these files and access them like so in your intent handlers:

const DoorIntentHandler = (handlerInput) => {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === "IntentRequest"&& (handlerInput.requestEnvelope.request.intent.name === "DoorIntent" )},handle(handlerInput) {const {attributesManager,responseBuilder} = handlerInput;const sessionAttributes = attributesManager.getSessionAttributes();
const locale = sessionAttributes.locale;
const chapter = sessionAttributes.chapter; //Would be 'one' or 'two' depending on how you saved your story progress.
const speechText = responses[locale][chapter];return responseBuilder.speak(speechText).getResponse()}}

Obviously as your skill gets more complex you might have to add more logic to your intentHandlers. But you could build a response from multiple “keys” in your language file.

It’s not actually that hard.

The reality is, from a technical point of view it’s not actually that difficult to get hold of a users locale in order to support it. The difficult part is coming up with a good organised structure that supports what you are trying to build, and in the example above I believe we do a good job of separating out the speech text itself from any logic that decides what should be returned. This hopefully keep things nice and clean and allows you to update the text without worrying about breaking your skill.

It is obviously a much different matter to actually get all the translations you need to support every locale Alexa supports. That’s the hard part. But hopefully this post will have helped someone work out how to do it.

If you’d like to see more tips or examples, please let me know in the comments below, or request to join my Facebook group and ask there. Happy to help if I can.

--

--

Tom Berwick
Alexa Skills Dev

Mobile App, game and full stack developer. Constantly trying to learn new things and dabble in growth hacking