Starting today, developers can use the Alexa Skills Kit (ASK) to build skills for customers in the Kingdom of Saudi Arabia (KSA) and the United Arab Emirates (UAE) using the new Arabic (SA) 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 Arabic language model. This tutorial will show you how you can add support for the Arabic (SA) model for your existing skills. It will also show you how you can use ASK to enable Alexa to respond based on locales.
You will learn:
1. Navigate to your existing skill on the Amazon Developer Portal.
2. Click on the language drop down on the top right of the screen and select the last option: “Language Settings.” In this example, the skill already has language models for English and other languages.
3. Follow the steps below to complete the Language Settings screen:
Select “Arabic (SA)”
4. Now provide the interaction model for the Arabic (SA) version. You can do this by copying the interaction model from English version of our skill, and localizing the sample utterances and slot values and synonyms. In this example, we’re starting from English (US). Switch to the English version by clicking on the language dropdown in the skill builder, and choose English (US).
5. Click on JSON Editor on the left side bar. This displays the complete interaction model for the skill in JSON format.
6. Select and copy all of the JSON in the code window.
7. Switch back to Arabic (SA) using the language dropdown.
8. Click on JSON Editor again, and paste the JSON into the code window, replacing the existing JSON.
9. Localize all sample utterances, slot values, and slot synonyms.
10. Click on the Save Model button.
11. Click on the Build Model button.
We now have the language model built for Arabic (SA). You now need to translate the invocation name, the sample utterances, the slot values, and the synonyms.
You also must localize the skill metadata, including skill name, description, keywords and the icons, should they contain localized content, such as text or currency symbols. Skills metadata are available in the “Distribution” tab of the Alexa Developer Console.
In a typical development workflow, you will probably build the skill voice interaction model JSON document programmatically, based on different files you have with sample utterances and slot values.
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 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 Arabic (SA), you need to customize the responses your skill returns for the different locales that you support. 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 least, you need to translate to Arabic the strings the skill is sending to Alexa to render with the voice of Alexa. You can also use this technique to use different strings for different variation of English. For instance, you may want to greet your customers with “G’day” in Australia, “Hello” in Canada and the UK, “Namaste,” in India, "Hi" in the US, “Bonjour” in France, and “Bon matin” in Quebec. 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, 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. In this example, I am using i18next in conjunction with an interceptor. To learn more about how this works, read this post: How to Localize your Alexa Skills
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);
};
},
};
All my strings follow this structure:
const enData = {
translation: {
SKILL_NAME: 'Space Facts',
GET_FACT_MESSAGE: 'Here\'s your fact: ',
HELP_MESSAGE: 'You can say tell me a space fact, or, you can say exit... What can I help you with?',
HELP_REPROMPT: 'What can I help you with?',
FALLBACK_MESSAGE: 'The Space Facts skill can\'t help you with that. It can help you discover facts about space if you say tell me a space fact. What can I help you with?',
FALLBACK_REPROMPT: 'What can I help you with?',
ERROR_MESSAGE: 'Sorry, an error occurred.',
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 translated them to Arabic also changing the object name from “enData” to “arData” to reflect the new language.
const arData = {
translation: {
SKILL_NAME: 'حقائق عن الفضاء',
GET_FACT_MESSAGE: 'معلومة اليوم هي',
HELP_MESSAGE: 'أحكي لي معلومة عن الفضاء أو تقدر تقول خلاص للخروج من اللعبة. كيف ممكن أساعدك؟',
HELP_REPROMPT: 'كيف أقدر أساعدك؟',
FALLBACK_MESSAGE: 'حقائق عن الفضاء ما تقدر تجاوب على سؤالك. لكن ممكن تساعدك تكتشف معلومات جديدة لو قولت خبريني عن الفضاء',
FALLBACK_REPROMPT: 'كيف أقدر أساعدك؟',
ERROR_MESSAGE: 'أعتذر، حدث خطأ',
STOP_MESSAGE: 'مع السلامة',
FACTS:
[
'عدد أيام السنة على عطارد هو 88 يوم فقط.',
'على الرغم من كون كوكب الزهرة بعيد عن الشمس، إلا أنه يعاني من درجات حرارة أعلى من تلك على عطارد.',
'على سطح المريخ، تظهر الشمس حوالي نصف الحجم الذي نراه من سطح الأرض.',
'كوكب المشتري لديه أقصر يوم بين جميع الكواكب.',
'يكاد يكون شكل الشمس كرة مثالية.',
],
},
};
When initializing the i18next service during step 0 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.
const languageStrings = {
'de-DE': deData,
'en': enData,
'en-US': enusData,
'es': esData,
'es-ES': esesData,
'pt-BR': ptData,
'ar-SA': arData,
};
Here we added “ar-SA” to the end of our list and referenced the object we just translated.
Using our interceptor in combination with the i18next library both showed in step 0 we can easily reference strings by their IDs and automatically answering 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 "AMAZON.HelpIntent" just uses the "t" function saved in our request atributes referencing the ressource ID.
handle(handlerInput) {
const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
return handlerInput.responseBuilder
.speak(requestAttributes.t('HELP_MESSAGE'))
.reprompt(requestAttributes.t('HELP_REPROMPT'))
.getResponse();
}
That’s all that it takes to update your skill for Arabic customers. We are excited to have Alexa available in Arabic (SA) later this year, and we can't wait to see what you will build. This space facts skill localized to Arabic (SA) is available for everyone to try out.
Check out our documentation to learn more about how you can use ASK to create multi-language Alexa skills.
Check out the following training resources, tutorials, and code samples to start building Alexa skills: