Today we announced that developers now can use the Alexa Skills Kit (ASK) to build skills for Hindi speaking customers in India using the new Hindi (IN) language model.
If you are new to skill development, check out this detailed walkthrough to get started. If you’re an experienced Alexa developer, you can enhance your existing skill by extending it to support the new Hindi language model. This tutorial will show you how you can add support for the Hindi (IN) model for your existing skills. It will also show you how you can use ASK to enable Alexa to respond based on locales.
In this tutorial, we will be localizing the Space Facts Skill. By the end of this tutorial, you will understand
1. Navigate to your existing skill on the Amazon Developer Portal.
2. Click on the language drop down on the top left of the screen and select the last option: “Language Settings.”
3. Click on “Add new language”
4. Select “Hindi (IN)”
5. Click on Save at the top of the screen. Once your settings are saved, click on the Build tab.You will now have Hindi language as an option in the language dropdown menu.
6. Now provide the interaction model for the Hindi (IN) version. You can do this by copying the interaction model from one of the English versions of our skill, and translating the sample utterances, invocation name, slot values and synonyms.
While translating the invocation name, sample utterances, slot values and synonyms, use Devanagari script for Hindi words and Latin script for English words.For example, consider our space facts skill. There are many ways a user can ask the skill to give a fact.
मुझे एक fact बताओ
मुझे अंतरिक्ष के बारे में एक fact बताओ
मुझे space के बारे में एक fact बताओ
मुझे अंतरिक्ष के बारे में ज्ञान बताओ
For the invocation name, I will use 'अंतरिक्ष facts'
Notice how we used a mix of Devanagari script for Hindi Words and Latin script for English words. The same holds true for your invocation name, slot values and prompts. For a list of Hindi conventions, follow our Hindi conventions document.
7. We now have the language model built for Hindi. Click on the Save Model and the Build Model button.
If your interaction model uses any built-in slot types, you may need to make changes to ensure that the types are supported in the HI-IN locale. See the Slot Type Reference for a list of slot types for each supported locale.
Once you have finished translating your interaction model for Hindi (IN), you need to customize the responses your skill returns for the different locales that you support. You can do this by updating your Lambda Function.
Now that your skill is ready to support multiple regions, you may want to update your Lambda function to ensure that your skill provides responses translated or tailored to each supported region.
At the least, you need to translate to Hindi the strings the skill is sending to Alexa to render with the voice of Alexa. One rule of thumb while writing out your responses in Hindi is to follow colloquial Hindi (Ex: The Hindi you hear in Radio, Bollywood movies) instead of Pure Hindi.
You can use any localization library to help you to match strings to locale. In this article I’m using an example I made with the ASK SDK v2 for Node.js, which you can replicate.
To facilitate localizing your skills, you should use one of the internationalization libraries available for the language of your choosing or write your own. For this example, I am using the i18next library.
If you are developing locally with the ASK Command-Line Interface (CLI), simply install them as you would install any other npm module using:
npm i —save i18next i18next-sprintf-postprocessor
If you are developing using Alexa Hosted Skills, navigate to the Code tab and add the packages to your package.json file. Save and Deploy your Lambda function.
{
"name": "hello-world",
"version": "0.9.0",
"description": "alexa utility for quickly building skills",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Amazon Alexa",
"license": "ISC",
"dependencies": {
"ask-sdk-core": "^2.0.7",
"ask-sdk-model": "^1.4.1",
"aws-sdk": "^2.326.0",
"i18next": "^11.8.0",
"i18next-sprintf-postprocessor": "^0.2.2"
}
}
Once the i18next library has been installed, I will add a Request Interceptor. The interceptor is executed each time a request is received immediately before the control is handed to the relevant intent handler, which in this case can be GetNewFactIntentHandler, HelpIntentHandler, etc. The LocalizationInterceptor intercepts the request, gets the locale of the user and then returns the string from the language's specific array (which we will see in the later steps).
const i18n = require('i18next');
const sprintf = require('i18next-sprintf-postprocessor');
const LocalizationInterceptor = {
process(handlerInput) {
// Gets the locale from the request and initializes i18next.
const localizationClient = i18n.use(sprintf).init({
lng: handlerInput.requestEnvelope.request.locale,
resources: languageStrings,
});
// Creates a localize function to support arguments.
localizationClient.localize = function localize() {
// gets arguments through and passes them to
// i18next using sprintf to replace string placeholders
// with arguments.
const args = arguments;
const values = [];
for (let i = 1; i < args.length; i += 1) {
values.push(args[i]);
}
const value = i18n.t(args[0], {
returnObjects: true,
postProcess: 'sprintf',
sprintf: values,
});
// If an array is used then a random value is selected
if (Array.isArray(value)) {
return value[Math.floor(Math.random() * value.length)];
}
return value;
};
// this gets the request attributes and save the localize function inside
// it to be used in a handler by calling requestAttributes.t(STRING_ID, [args...])
const attributes = handlerInput.attributesManager.getRequestAttributes();
attributes.t = function translate(...args) {
return localizationClient.localize(...args);
};
},
};
Once we have defined the LocalizationInterceptor, I will register it with the addRequestInterceptors method as shown below
const skillBuilder = Alexa.SkillBuilders.custom();
exports.handler = skillBuilder
.addRequestHandlers(
GetNewFactIntentHandler,
HelpIntentHandler,
CancelAndStopIntentHandler,
SessionEndedRequestHandler
)
.addRequestInterceptors(LocalizationInterceptor)
.addErrorHandlers(ErrorHandler)
.lambda();
Once the localization interceptor is in place, create arrays for different languages. Assuming you already support the English model, place all of your strings inside an object. This will allow you to localize easily to other languages.
const enData = {
translation: {
SKILL_NAME: 'Space Facts',
GET_FACT_MESSAGE: 'Here\'s your cool fact: ',
HELP_MESSAGE: 'You can say tell me a fact, or, you can say exit... What can I help you with?',
HELP_REPROMPT: 'What can I help you with?',
ERROR_MESSAGE: 'Sorry, I can\'t understand the command. Please say again.',
STOP_MESSAGE: 'Goodbye!',
FACTS:
[
'A year on Mercury is just 88 days long.',
'Despite being farther from the Sun, Venus experiences higher temperatures than Mercury.',
'On Mars, the Sun appears about half the size as it does on Earth.',
'Jupiter has the shortest day of all the planets.',
'The Sun is an almost perfect sphere.'
],
},
};
I’m taking the English string as a base for my translations. The “enData” object contains all the strings used by my skill in the English language. Our interceptor coupled with i18next supports both single strings and arrays, which can be seen on “FACTS”.
Using the English strings as base, I created a new array and translated all strings to Hindi and appropriately named the new object as hiData.
const hiData = {
translation: {
SKILL_NAME: 'अंतरिक्ष facts',
GET_FACT_MESSAGE: 'ये लीजिए आपका fact: ',
HELP_MESSAGE: 'आप मुझे नया fact सुनाओ बोल सकते हैं या फिर exit भी बोल सकते हैं... आप क्या करना चाहेंगे?',
HELP_REPROMPT: 'मैं आपकी किस प्रकार से सहायता कर सकती हूँ?',
ERROR_MESSAGE: 'सॉरी, मैं वो समज नहीं पायी. क्या आप repeat कर सकते हैं?',
STOP_MESSAGE: 'अच्छा bye, फिर मिलते हैं',
FACTS:
[
'बुध ग्रह में एक साल में केवल अठासी दिन होते हैं',
'सूरज से दूर होने के बावजूद, Venus का तापमान Mercury से ज़्यादा होता हैं',
'Earth के तुलना से Mars में सूरज का size तक़रीबन आधा हैं',
'सारे ग्रहों में Jupiter का दिन सबसे कम हैं',
'सूरज का shape एकदम गेंद आकार में हैं'
],
},
};
When initializing the i18next service during step 2 you might have noticed a reference to “languageStrings”. This is the list of supported locales and where to find them. Every language is reference by their locale code, i18next will always search for strings in the most specific match first. If for example you have all your strings available for “en” and only a specific welcome message written for “en-AU”, then requests coming from “en-AU” would receive this single welcome message while every other string would just get served from the “en”-pool.
Here we added “hi-IN” to the end of our list and referenced the object we just translated.
const languageStrings = {
'hi-IN': hiData,
'en-US': enData
};
Using our interceptor in combination with the i18next library both showed in step 1 we can easily reference strings by their IDs and automatically answer the skill request with the right locale. The selected Strings will be rendered in the language that matches the locale of the incoming request.
This handler for the "GetNewFactIntentHandler" just uses the "t" function saved in our request attributes referencing the resource ID. Save and Deploy your Lambda function when you are done
// core functionality for facts skill
const GetNewFactIntentHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'LaunchRequest'
|| (request.type === 'IntentRequest'
&& request.intent.name === 'GetNewFactIntent');
},
handle(handlerInput) {
const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
// gets a random fact by assigning an array to the variable
// the random item from the array will be selected by the i18next library
// the i18next library is set up in the Request Interceptor
const randomFact = requestAttributes.t('FACTS');
// concatenates a standard message with the random fact
const speakOutput = requestAttributes.t('GET_FACT_MESSAGE') + randomFact;
return handlerInput.responseBuilder
.speak(speakOutput)
// Uncomment the next line if you want to keep the session open so you can
// ask for another fact without first re-opening the skill
// .reprompt(requestAttributes.t('HELP_REPROMPT'))
.withSimpleCard(requestAttributes.t('SKILL_NAME'), randomFact)
.getResponse();
},
};
That’s all that it takes to update your skill for Hindi customers. This space facts skill localized to Hindi (IN) is available for everyone to try out in NodeJS and Python. You can test out your skill using the in-built simulator tool in the Developer Console.
Alongside our Technical Evangelist (Sohan Maheshwar) and Solutions Architect (Karthik Ragubathy) you will learn how to reach new Hindi speaking customers by building new Hindi skills and updating your existing skill to the Hindi model.
We are excited to have Alexa available in Hindi soon, and we can't wait to see what you will build.