Reputation: 71
We're setting ourselves up to do internationalization/localization in our Angular 2 app, and I'd like to be able to write some scripts that will do various tasks, such as generating translation source files, building and/or serving the application with the translations from a particular language.
Rather than writing the scripts in the package.json file, I'd like to be able to capture the scripts in separate files in a scripts/directory and the scripts in the package.json file would just point to those.
For example, I'd like to take something like this in package.json
:
"scripts": {
//other irrelevant scripts
"generateXLF": "ng-xi18n --i18nFormat=xlf --outFile=./src/locale/baseFile/messages.xlf",
//other irrelevant scripts
},
And instead have something like this:
"scripts": {
//other irrelevant scripts
"generateXLF": "node ./build/scripts/locale/generateXLF.js"
//other irrelevant scripts
},
Or instead of something like this:
"scripts": {
//other irrelevant scripts
"serveLocale": : "./node_modules/.bin/ngc --i18nFile=./src/locale/languages/($someLocaleIPassIn)/messages.($someLocaleIPassIn).xlf --locale=($someLocaleIPassIn) --i18nFormat=xlf",
//other irrelevant scripts
},
And instead have this:
"scripts": {
//other irrelevant scripts
"serveLocale": : "node ./build/scripts/locale/serveLocale.js $someLocaleIPassIn"
//other irrelevant scripts
},
Basically I need to do the following:
Currently I'm part of the way there. For example in my generateXLF.js
file I'm currently just trying to run ng serve
, with no parameters or flags, like so:
var ngServe = require('@angular/cli/commands/serve');
new ngServe.default();
but I keep getting this error:
C:\Projects\MyProject\StyleGuide\node_modules\@angular\cli\ember-cli\lib\models\command.js:77
this.isWithinProject = this.project.isEmberCLIProject();
^
TypeError: Cannot read property 'isEmberCLIProject' of undefined
at Class.init (C:\Projects\MyProject\StyleGuide\node_modules\@angular\cli\ember-cli\lib\models\command.js:77:40)
at Class.superWrapper [as init] (C:\Projects\MyProject\StyleGuide\node_modules\core-object\lib\assign-properties.js:34:20)
at Class.CoreObject (C:\Projects\MyProject\StyleGuide\node_modules\core-object\core-object.js:9:15)
at Class (C:\Projects\MyProject\StyleGuide\node_modules\core-object\core-object.js:21:5)
at Class (C:\Projects\MyProject\StyleGuide\node_modules\core-object\core-object.js:21:5)
at C:\Projects\MyProject\StyleGuide\build\scripts\locale\generateXLF.js:32:5
at Object.<anonymous> (C:\Projects\MyProject\StyleGuide\build\scripts\locale\generateXLF.js:37:3)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
Process finished with exit code 1
ng serve
works just fine when I run it from the CLI but not when I try to run it from a script. I'm guessing somehow I need to set the script file up to know where my .angular-cli.json
file and my package.json
file is, and to do things with the information in those files to make ng serve
run correctly from a script file. But I may be totally wrong about why it's failing.
TLDR: How do I successfully run Angular CLI scripts, with flags, from a script file? How to pick up parameters that I've passed?
Upvotes: 3
Views: 6532
Reputation: 71
Ended up figuring it out. Here is my script, compileInLocale.js
:
#! /usr/bin/env node
const angularCli = require('@angular/cli');
const fileSystem = require('fs');
const chalk = require('chalk');
var command = process.argv.slice(2, 3).toString();
var locale = process.argv.slice(3, 4).toString();
console.log(chalk.bgBlueBright.bold('Attempting to execute ' + __filename + ' with command "' +
command + '" and locale "' + locale + '".\n'));
makeArguments(command, locale);
/**
* @name makeArguments
* @description Create the array of arguments to send to the Angular CLI
* @param {String} commandToRun the ng command we want to run, such as 'serve' or 'build'
* @param {String} specifiedLocale the locale that the developer specified when they called
* the script. For example, the string 'es' from the following command line
* entry: 'npm run serveInLocale es'
* @returns {void} Nothing.
*/
function makeArguments(commandToRun, specifiedLocale) {
var localeFile = './src/locale/languages/' + specifiedLocale + '/messages.' + specifiedLocale + '.xlf';
if (fileSystem.existsSync(localeFile)) {
/*
@TODO: add in logic to build the base translation file, then compare the contents of the
@TODO <source> tags in the translation file to the <source> tags in the file we are trying
@TODO to serve to see if it is up-to-date.
*/
var argArray = [
commandToRun,
'--aot',
'--i18nFile=' + localeFile,
'--locale=' + specifiedLocale,
'--i18nFormat=xlf'
];
console.log(chalk.bgGreen.bold('Preparing to ' + commandToRun + ' file ' + localeFile + '.\n'));
serveInSpecifiedLocale(argArray);
}
else {
console.log(chalk.bgRed.bold('Cannot ' + commandToRun + ' file ' + localeFile + '. File does not exist!\n'));
}
}
/**
* @name serveInSpecifiedLocale
* @description Send an object to the Angular CLI containing our arguments array, and other
* properties that Angular CLI needs to execute our command.
* @param {Array} argArray the array of arguments we want to give to the CLI
* @returns {void} Nothing.
*/
function serveInSpecifiedLocale(argArray) {
/*
@TODO: move this to its own file. We will have more scripts in the
@TODO future which need to send arguments to the Angular CLI.
*/
angularCli({
cliArgs: argArray,
inputStream: process.stdin,
outputStream: process.stdout
});
}
Run it with a command such as this:
npm run buildInLocale es
or this:
npm run serveInLocale fr
In package.json
have something like this:
"serveInLocale": "node ./build/scripts/locale/compileInLocale.js serve",
"buildInLocale": "node ./build/scripts/locale/compileInLocale.js build"
Depending on whether you typed buildInLocale
or serveInLocale
, the script will be hit with either serve
or build
as an argument, followed by the locale as another argument, and if we have a file for that locale, the script works.
Sidenote: I ended up doing a bunch of work to figure this out for no reason. It's pointless because the native tool in Angular 2 to do internationalization (the i18n attribute) doesn't have a means to support translations when 2-way binding is involved, so we are going to end up using something like ngx-translate
instead. I still wanted to post my solution though in case someone else needs to write a script to let them run scripts that would normally be ran from the CLI.
Upvotes: 3