Skip to content

Instantly share code, notes, and snippets.

@KayLerch
Last active February 17, 2021 06:39
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save KayLerch/ae89e7dc6a55f120eea62c002a2bd434 to your computer and use it in GitHub Desktop.
Save KayLerch/ae89e7dc6a55f120eea62c002a2bd434 to your computer and use it in GitHub Desktop.
Optimized i18n request interceptor for Alexa custom skills in Node. Loads only required language assets from external files and provides some convenient functions to read them. Will also let you store localized settings represented as JSON objects in your language files.
module.exports = Object.freeze({
translation: {
welcome: 'Howdy',
images: [
{
background: 'https://image/en-US.png'
},
{
background: 'https://image/en-US2.png'
},
{
background: 'https://image/en-US3.png'
}
]
}
});
module.exports = Object.freeze({
translation: {
welcome: 'Hello',
greet: 'Hello %s',
random: {
welcome: [ 'Hello', 'Hi' ],
greet: [ 'Hello %s', 'Hi %s' ],
}
}
});
const Alexa = require('ask-sdk-core');
const LaunchRequestHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
},
handle(handlerInput) {
console.log(handlerInput.t('welcome'));
console.log(handlerInput.t2('welcome'));
console.log(handlerInput.t('random.welcome'));
console.log(handlerInput.t2('random.welcome')[1]);
console.log(handlerInput.t('greet', 'Michael'));
console.log(handlerInput.t2('greet', 'Michael'));
console.log(handlerInput.t('random.greet', 'Michael'));
console.log(handlerInput.t2('random.greet', 'Michael')[1]);
console.log(handlerInput.o('images').background);
console.log(handlerInput.o2('images')[1].background);
return handlerInput.responseBuilder.speak('Test').getResponse();
},
};
const skillBuilder = Alexa.SkillBuilders.custom();
exports.handler = skillBuilder
.addRequestHandlers(LaunchRequestHandler)
.addRequestInterceptors(require("./intercept_i18n"))
.lambda();
const i18n = require('i18next');
const sprintf = require('i18next-sprintf-postprocessor');
const merge_json = require("merge-json");
/*
1) SETUP:
required are language file (e.g. en.js or de.js) and locale file (e.g. en-US.js) both in format of:
/*
module.exports = Object.freeze({
translation: {
sayhello: [ 'hello', 'hi' ],
greet: 'Welcome %s',
saybye: 'Good bye',
images: {
logo: 'https://localized/images/us.png'
},
nice_places: [
{
name: 'Golden Gate Bridge',
city: 'San Francisco'
}, ...
],
...
}
});
2) INTEGRATE:
Alexa.SkillBuilders.custom().addRequestInterceptors(require("./path/to/this/file.js"));
3) USE:
handlerInput.t('welcome');
handlerInput.t('greet', 'Scott');
handlerInput.o('images').logo;
handlerInput.o2('nice_places')[0].name;
*/
module.exports = Object.freeze({
process(handlerInput) {
const locale = handlerInput.requestEnvelope.request.locale;
const localizationClient = i18n.use(sprintf).init({
resources: {
/* merge language and locale file where locale file is dominant and overwrites generic language assets.
e.g. you can set generic English welcome string 'hello' and specifc en-US welcome 'Howdy'. 'Howdy' will be taken */
[locale]: merge_json.merge(
require(`./strings/${locale.split("-")[0]}.js`), // e.g. en.js
require(`./strings/${locale}.js`) // e.g. en-US.js
)}, lng: locale });
localizationClient.localize = function(format, randomize, ...args) {
const settings = Object.assign({ returnObjects: true }, format ? { postProcess: 'sprintf', sprintf: args.slice(1) } : {});
const value = i18n.t(args[0], settings);
return randomize && Array.isArray(value) ? value[Math.floor(Math.random() * value.length)] : value;
};
handlerInput.t = handlerInput.attributesManager.getRequestAttributes().t = function(...args) {
return localizationClient.localize(true, true, ...args);
};
// t2 skips returning randomized string from an array of strings for a given asset. instead returns array as is
handlerInput.t2 = handlerInput.attributesManager.getRequestAttributes().t2 = function(...args) {
return localizationClient.localize(true, false, ...args);
};
// o skips string post processing and returns plain JSON object (useful if you store localized settings in your language files)
// will still pick random item if requested asset is an array
handlerInput.o = handlerInput.attributesManager.getRequestAttributes().o = function(...args) {
return localizationClient.localize(false, true, ...args);
};
// o2 skips string post processing and returns JSON object (useful if you store localized settings in your language files)
// also skips picking random item if requested asset is an array
handlerInput.o2 = handlerInput.attributesManager.getRequestAttributes().o2 = function(...args) {
return localizationClient.localize(false, false, ...args);
};
}
});
{
"name": "i18n-interceptor-sample",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Kay Lerch",
"license": "ISC",
"dependencies": {
"ask-sdk-core": "^2.0.0",
"ask-sdk-model": "^1.0.0",
"i18next": "^11.8.0",
"i18next-sprintf-postprocessor": "^0.2.2",
"merge-json": "0.1.0-b.3"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment