Extract translations from HTML & JS files - javascript

I have a project where I'm using Angular 1.6 and I'm using angular-translate to internationalize the project.
Angular-translate is installed, configured and working, If I add some text like:
{{'Test' | translate}}
<span translate>Test</span>
and manually add the key "Test" into the files es.json and en.json, Angular translate the keys without problems.
Now I'm trying to automatize the process of extracting all the translated keys from the HTML and JS files.
I've been digging around and found this 2 packages:
gulp-angular-translate-extract
gulp-angular-translate-extractor
My gulpfile.js has a task called "watch", this task is watching the JS & HTML files for changes. My idea is to have another task "translation" that is called within the watch task.
I tried to create the task "translation" with the 2 libraries mentioned above. I tried several configurations with those libraries but none of those libraries extracted the translations and added them into en.json & es.json.
This are small examples of what I tried:
gulp-angular-translate-extract
var angularTranslate = require('gulp-angular-translate-extract');
gulp.task('translate', function () {
return gulp.src(['./src/app/**/*.html', './src/app/**/*.js'])
.pipe(angularTranslate({
lang: ['en', 'es'],
dest: 'src/app/locale/',
suffix: '.json',
prefix: '',
}))
});
gulp-angular-translate-extractor
var extractTranslate = require('gulp-angular-translate-extractor');
gulp.task('taskName', function () {
var i18nsrc = ['./src/app/**/*.html', './src/app/**/*.js']; // your source files
var i18ndest = './src/app/locale'; //destination directory
return gulp.src(i18nsrc)
.pipe(extractTranslate({
defaultLang: 'en',
lang: ['en', 'es'],
dest: i18ndest,
prefix: '',
suffix: '.json',
safeMode: false,
stringifyOptions: true,
}))
.pipe(gulp.dest(i18ndest));
});
With the above configuration the translation task is called every time I modified an HTML or JS file, but the translation keys are not extracted, I mean the keys of the translations are not automatically added to the es.json and en.json
What am I missing here ? Am I missing some extra gulp configuration ?

Solved ! I manage to make it works using the package gulp-angular-translate-extractor
It seems the main issue there was the relative paths:
# Source paths
./src/app/**/*.html
./src/app/**/*.js
# Dest paths
./src/app/locale
I update the configuration to use the next paths and the translations are extracted without problems:
var extractTranslate = require('gulp-angular-translate-extractor');
gulp.task('translate', function () {
var i18nsrc = [path.join(conf.paths.src, '/app/**/*.html'), path.join(conf.paths.src, '/app/**/*.js')]; // your source files
var i18ndest = path.join(conf.paths.src, '/app/locale/')
return gulp.src(i18nsrc)
.pipe(extractTranslate({
defaultLang: 'en',
lang: ['en', 'es'],
dest: i18ndest,
prefix: '',
suffix: '.json',
safeMode: false,
stringifyOptions: true,
}))
.pipe(gulp.dest(i18ndest));
});
The main difference with the code of my question is that I used the next paths:
# Source paths
path.join(conf.paths.src, '/app/**/*.html')
path.join(conf.paths.src, '/app/**/*.js')
# Dest paths
path.join(conf.paths.src, './src/app/locale')
Being the variable conf.paths.src like:
conf.js
exports.paths = {
src: 'src',
dist: 'release',
devDist: 'dev-release',
tmp: '.tmp',
e2e: 'e2e'
};

Related

hash updated but the browser still loads the old cache using gulp-rev

I've been scratching head to bold due to this
I have set hash to name of all html files using gulp-rev and they are all matched in manifest file . I use gulp-rev-collector to match all updated hash as well .
I'm sure if any of content of client side file changed , I get new hashed file name after gulp
build but the Browser doesn't update and request new file , It still uses old cache file until I clean cache and hard reload .
here is simplified codes below:
gulp-rev
gulp.task('minify:html', function () {
var options = {
removeComments: true,
collapseWhitespace: true,
collapseBooleanAttributes: false,
removeEmptyAttributes: false,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
minifyJS: true,
minifyCSS: true
};
return gulp
.src([paths.src.html, '!./node_modules/**/*.html', '!./templates/**/*.html', '!./index.html',
'!./dist/**/*.html']) // views
.pipe(htmlmin(options))
.pipe(rev())
.pipe(gulp.dest('./dist'))
.pipe(rev.manifest())
.pipe(gulp.dest('./dist/rev/html'))
})
revision dist views
gulp.task('revDistViews', function () {
return gulp.src(['./dist/rev/**/*.json', './dist/views/*.html'])
.pipe( revCollector({
replaceReved: true,
}) )
.pipe( gulp.dest('./dist/views') );
})
gulp build
gulp.task('build', function (callback) {
runSequence('clean:dist', 'clean:views', 'scss', 'concat:js', 'file:include', 'copy:lib',
'copy:locales', 'copy:img', 'minify:html', 'minify:index', 'minify:scripts',
'revImages','minify:css', 'rev', 'revDistViews','revScripts', callback)
})
I can see hash changed after built in /dist folder . but the Chrome still use old Cache instead of new file
Is there any solution I could use by client side ?
Note: none of cache policy set in response header

Grunt run curl on changed file only

I'm trying to upload a file to a server on change using grunt-run and curl. I can get it to work if I hard code the file name into the actual task, but I'm trying to run it based on the file that changed...here's my grunt file so far (stripped down to the parts related to this question).
module.exports = function(grunt) {
var config = require('./config.json');
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
watch: {
less : {
files : ['front-end/less/**/*.less'],
tasks : ['newer:less','sync:css','run:deploy_less_files']
},
},
less: {
development: {
options: {
paths: ['front-end/_builds/css'],
sourceMap : true,
},
files: [{
cwd: "front-end/less",
expand : true,
src : [ '**/*.less', '!_settings.less'],
dest : "front-end/_builds/css",
ext: ".css"
}]
},
},
sync : {
target: {},
css : {
expand: true,
flatten :true,
verbose: true,
cwd : "front-end/_builds/css/",
src : "**/*.css",
dest : "target/css/"
},
},
run : {
deploy_less_files : {}
}
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-sync');
grunt.loadNpmTasks('grunt-run');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-newer');
grunt.registerTask('default', ['watch']);
grunt.event.on('watch', function(action, filepath, target) {
if (target == "less") {
grunt.config.set('run.deploy_less_files.exec','curl -u ' + config.credentials.user + ':' + config.credentials.pw + ' -T ' + filepath + ' http://localhost:8080/assets/less/');
grunt.task.run("run:deploy_less_files");
}
});
}
Here's what I am trying to do in order:
Watch all LESS files in /front-end/less
If a file changes, compile it to css and place in front-end/_builds/css directory
Sync the contents of front-end/_builds/css with my target/css directory.
Upload the file via curl to my localhost.
Ideally, I'd like to just grab the css file from either my target or the _builds directory and upload it to my localhost, but I can sort that out if I can get this part working.
Any help would be appreciated. Thanks.
See this comment in the grunt-contrib-watch github repo. Excerpts from it read:
"Don't use grunt.event.on('watch') to run your tasks."
and...
"The watch event is not intended for running tasks."
However, you can utilize the grunt.event.on('watch', ...) listener to configure the exec property.
The following gist shows how to meet your requirement:
Gruntfile.js
module.exports = function(grunt) {
var config = require('./config.json');
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
watch: {
less : {
files : ['front-end/less/**/*.less'],
tasks : ['newer:less','sync:css'/*,'run:deploy_less_files'*/]
},
// 1. Added new target to watch the directory in which the resultant
// .css files are saved. Set the `task` to `run:deploy_css_files`.
// The `nospawn` option must be set to true.
generatedCss : {
files : ['target/css/**/*'],
tasks : ['run:deploy_css_files'],
options: {
nospawn: true
}
}
},
less: {
development: {
options: {
paths: ['front-end/_builds/css'],
sourceMap : true,
},
files: [{
cwd: "front-end/less",
expand : true,
src : [ '**/*.less', '!_settings.less'],
dest : "front-end/_builds/css",
ext: ".css"
}]
},
},
sync : {
target: {},
css : {
expand: true,
flatten :true,
verbose: true,
cwd : "front-end/_builds/css/",
src : "**/*.css",
dest : "target/css/"
},
},
run : {
deploy_css_files : {// 2. Renamed target and added `exec` key. The
exec: '' // `exec` value is intentionally empty and will
} // be configured via the `watch` event listener.
}
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-sync');
grunt.loadNpmTasks('grunt-run');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-newer');
// 3. 'less' and 'sync' targets are aliased before the `watch`
// task to ensure the path defined in the `files` property of the
// `watch:generatedCss` task exists before `watch`ing.
grunt.registerTask('default', ['less', 'sync', 'watch']);
// 4. Listen for changes via the `watch:generatedCss` target only.
// Configures the `exec` property of the `run:deploy_css_files`
// target to `curl` the most recently created `.css` file.
grunt.event.on('watch', function(action, filepath, target) {
if (target === 'generatedCss') {
var cmd = 'curl -u ' + config.credentials.user + ':' +
config.credentials.pw + ' -T ' + filepath +
' http://localhost:8080/assets/less/';
grunt.config('run.deploy_css_files.exec', cmd);
}
});
}
Further explanation
Firstly, in the Gruntfile.js above, you'll notice that run:deploy_less_files alias has been omitted from your original watch.less.tasks array. Then the following changes were made:
Added a new target named generatedCss to the watch Task. Its files value specifies the path to the directory in which the resultant .css files are saved. The value in the task property array is set to run:deploy_css_files. The nospawn option is set to true.
Note As you mentioned the following in your question:
"Ideally, I'd like to just grab the css file from either my target or the _builds directory and upload it to my localhost,.."
I chose to name the target generatedCss and renamed the task to run deploy_css_files (instead of deploy_less_files) as this better reflects the actual intent.
The files that ultimately get uploaded via curl to your localhost will be from the target/css/ directory, simply because that's the directory we're watching for changes.
Replaced your original run task with the following instead:
run : {
deploy_css_files : {
exec: ''
}
}
Note The target has been renamed and the exec property added. Its value is intentionally empty as this will be configured via the watch event listener.
less and sync targets are aliased before the watch task of the default registered task. This ensures that, (when initially running grunt via your CLI), the path defined in the files property of the watch:generatedCss task exists before watching begins.
Finally, in the grunt.event.on('watch', ...) listener we listen for changes via the watch:generatedCss target only and configure the exec property of the run:deploy_css_files target to curl the most recently created .css file.
Running
When running the grunt command via your CLI any changes made to the .less files, (i.e. those residing in the /front-end/less directory), will trigger the tasks in the correct order (as per your listed points 1-4).
Caveat: I didn't actually test running the curl command, however the file path for the most recent generated .css file is assigned to the filepath variable in the grunt.event.on('watch', ...) listener, thus it can be referenced when configuring the run.deploy_css_files.exec task/target.
Note: you'll need to ensure the server supports POST requests for your curl command to succceed (i.e. it's not something like SimpleHTTPServer).

Excluding a file change in gulp but still keeping the file

The following is my simple gulp task:
gulp.src is getting script.js as input
minifies script.js and saves script.min.js
removes console.log from both script.js and script.min.js
updates script.js file and saves script.min.js
I want to simply remove console.log from a minified file (or script.min.js) not from script.js, and I am failing. I am looking for a way to run .pipe(gulpRemoveLogging... only on a minified file (i.e. script.min.js) and do not modify anything from script.js
var gulp = require("gulp"),
minify = require("gulp-minify"),
gulpRemoveLogging = require("gulp-remove-logging");
var _dist_path = "./dist/"; // relative path
// minify JS files
gulp.task("minify-js", function() {
return gulp.src(path.join(_dist_path, "/*.js"))
.pipe(minify({
ext: {
src: ".js",
min: ".min.js"
},
ignoreFiles: ["-min.js"]
}))
.pipe(gulpRemoveLogging({
namespace: ["console", "window.console"] // remove these namespaces. e.g. console.log("..."), window.console.log("...")
}))
.pipe(gulp.dest(_dist_path));
});
Solved the problem:
Added .pipe(gulpIgnore("smartsitescripts.js")) between .pipe(minify({ ... and .pipe(gulpRemoveLogging ...
var gulpIgnore = require("gulp-ignore");
...
.pipe(minify({
ext: {
src: ".js",
min: ".min.js"
},
ignoreFiles: ["-min.js"]
}))
.pipe(gulpIgnore("script.js")) // <---- this line solved the problem
.pipe(gulpRemoveLogging({
namespace: ["console", "window.console"] // remove these namespaces. e.g. console.log("..."), window.console.log("...")
}))
...
That line of code will exclude script.js from stream hence stream will contain only script.min.js.

Gulp Bundle + Browserify on multiple files

So I have asimple gulp task function which currently converts my main.jsx to a main.js file:
gulp.task("bundle", function () {
return browserify({
entries: "./app/main.jsx",
debug: true
}).transform(reactify)
.bundle()
.pipe(source("main.js"))
.pipe(gulp.dest("app/dist"))
});
I was wondering if it would be possible to put multiple bundles in this gulp.task?
My ideal outcome would be being able to do:
main.jsx to main.js
otherPage.jsx to otherPage.js
otherPage2.jsx to otherPage2.js
All in one gulp task.
I have searched onliine but cannot seem to find anything relevant, any help or advice is appreciated, thank you in advance.
If you want to create a bundle for each file you need to loop over the respective files, create a stream for each file and then merge the streams afterwards (using merge-stream):
var merge = require('merge-stream');
gulp.task("bundle", function () {
var files = [ "main", "otherPage", "otherPage2" ];
return merge(files.map(function(file) {
return browserify({
entries: "./app/" + file + ".jsx",
debug: true
}).transform(reactify)
.bundle()
.pipe(source(file + ".js"))
.pipe(gulp.dest("app/dist"))
}));
});
The above requires that you maintain a list of files manually as an array. It's also possible to write a task that bundles all .jsx files in the app directory without having to maintain an explicit array of the files. You just need the glob package to determine the array of files for you:
var merge = require('merge-stream');
var glob = require('glob');
var path = require('path');
gulp.task("bundle", function () {
var files = glob.sync('./app/*.jsx');
return merge(files.map(function(file) {
return browserify({
entries: file,
debug: true
}).transform(reactify)
.bundle()
.pipe(source(path.basename(file, '.jsx') + ".js"))
.pipe(gulp.dest("app/dist"))
}));
});

grunt-closure-tools config issue with multiple targets

I want to work with closure compiler, so I added grunt-closure-tools to my Grunt config, but my config is erroring with:
Verifying property closureCompiler.loader exists in config...ERROR
Here is the reference material for grunt-closure-tools:
https://www.npmjs.com/package/grunt-closure-tools
or
https://github.com/thanpolas/grunt-closure-tools
Here is my GruntFile.js:
module.exports = function(grunt) {
var path = require('path');
require('load-grunt-config')(grunt, {
//pkg: grunt.file.readJSON('package.json'),
configPath: path.join(process.cwd(), 'grunt'), //path to task.js files, defaults to grunt dir
init: true, //auto grunt.initConfig
data: { //data passed into config. Can use with <%= test %>
pkg: require('./package.json')
},
loadGruntTasks: { //can optionally pass options to load-grunt-tasks. If you set to false, it will disable auto loading tasks.
pattern: ['grunt-contrib-*', 'grunt-jslint', 'grunt-newer', 'imagemin-*','grunt-closure-tools'],
scope: 'devDependencies'
},
postProcess: function(config) {} //can post process config object before it gets passed to grunt
});
//require('load-grunt-tasks')(grunt);
grunt.registerTask("default", ["newer:jslint", "newer:concat", "closureCompiler:loader", "newer:sass"]);
};
I am using load-grunt-config to break up my config into multiple parts. Here is my closure.js file, mostly modeled on grunt-closure-tools github page example:
module.exports = {
options: {
compilerFile: '/usr/local/Cellar/closure-compiler/20141023/libexec/build/compiler.jar',
checkModified: true,
compilerOpts: {
create_source_map: null,
compilation_level: 'ADVANCED_OPTIMIZATIONS',
},
d32: true, // will use 'java -client -d32 -jar compiler.jar'
},
util: {
src: 'includes/javascript/util/util.js',
dest: 'includes/javascript/build/util.min.js'
},
loader: {
src : 'includes/javascript/loaders/loader.js',
dest: 'includes/javascript/build/loader.min.js'
}
};
Any help with this error is appreciated.
After some digging and no small amount of thrashing of teeth, I have managed to getting my config working. My Gruntfile.js:
module.exports = function(grunt) {
var path = require('path');
require('load-grunt-config')(grunt, {
//pkg: grunt.file.readJSON('package.json'),
configPath: path.join(process.cwd(), 'grunt'), //path to task.js files, defaults to grunt dir
init: true, //auto grunt.initConfig
data: { //data passed into config. Can use with <%= test %>
pkg: require('./package.json')
},
loadGruntTasks: { //can optionally pass options to load-grunt-tasks. If you set to false, it will disable auto loading tasks.
pattern: ['grunt-contrib-*', 'grunt-jslint', 'grunt-newer', 'imagemin-*','grunt-closure-tools'],
scope: 'devDependencies'
},
postProcess: function(config) {} //can post process config object before it gets passed to grunt
});
//require('load-grunt-tasks')(grunt);
grunt.registerTask("default", ["newer:jslint", "newer:concat", "closureCompiler:loader", "newer:sass"]);
};
and my closureCompiler.js file (shortened for clarity):
module.exports = {
options: {
compilerFile: '/usr/local/Cellar/closure-compiler/20141023/libexec/build/compiler.jar',
checkModified: true,
compilerOpts: {
// create_source_map: null
},
execOpts: {
maxBuffer: 999999 * 1024
},
TieredCompilation: true // will use 'java -server -XX:+TieredCompilation -jar compiler.jar'
},
loader: {
TEMPcompilerOpts: {
create_source_map: 'includes/javascript/build/loader.min.js.map'
},
src : 'includes/javascript/loaders/loader.js',
dest: 'includes/javascript/build/loader.min.js'
}
};
I had quite a few errors in my config:
I had to rename closure.js to closureCompiler.js so load-grunt-config could find the file. Oops, my bad.
The d32: true switch on the Closure Compiler means use 32-bit JVM, which I do not have on my system. I switched to TieredCompilation: true instead.
create_source_map: null in the options did not work for me. I found the reference in the source code of grunt-closure-tools but didn't spend the time to sort out what was wrong. Instead, I added TEMPcompilerOpts to the target config with the map file I wanted Closure to make.
I hope other benefit from my experience with this solution. From this point, I am going to use the ability of Closure Compiler to create source maps to merge my dev and prod build targets into a single target.

Categories