/* * grunt-wp-i18n * https://github.com/cedaro/grunt-wp-i18n * * Copyright (c) 2014 Cedaro, LLC * Licensed under the MIT license. */ 'use strict'; module.exports = function( grunt ) { var _ = require( 'underscore' ), gettext = require( 'gettext-parser' ), path = require( 'path' ), pkg = require( '../package.json' ), util = require( './lib/util' ).init( grunt ), localConfig = util.getLocalConfig(), wp = require( './lib/wordpress' ).init( grunt), msgMerge = require( './lib/msgmerge' ).init( grunt ), async = require( 'async' ); // Mix no-conflict string functions into the Underscore namespace. _.str = require( 'underscore.string' ); _.mixin( _.str.exports() ); /** * Generate a POT file for translating strings. * * php-cli should be in the system path to run this task. * * @link http://develop.svn.wordpress.org/trunk/tools/i18n/ */ grunt.registerMultiTask( 'makepot', 'Generate a POT file for translating strings.', function() { var done = this.async(), defaultI18nToolsPath = path.resolve( __dirname, '../vendor/wp-i18n-tools/' ), gruntBase = process.cwd(), cmdArgs, o, originalPot; o = this.options({ cwd: process.cwd(), domainPath: '', exclude: [], include: [], i18nToolsPath: defaultI18nToolsPath, mainFile: '', potComments: '', potFilename: '', potHeaders: {}, processPot: null, type: 'wp-plugin', updateTimestamp: true, updatePoFiles: false }); // Set the current working directory. o.cwd = path.resolve( process.cwd(), o.cwd ); grunt.file.setBase( o.cwd ); // Attempt to discover the main project file. if ( '' === o.mainFile ) { o.mainFile = wp.getMainFile( o.type ); } // Use Domain Path header if the domain path hasn't been set. if ( '' === o.domainPath ) { o.domainPath = wp.getHeader( 'Domain Path', o.mainFile ); } // Use the Text Domain header or project folder name // for the pot file if it hasn't been set. if ( '' === o.potFilename ) { o.potFilename = wp.getHeader( 'Text Domain', o.mainFile ) + '.pot' || wp.slugify() + '.pot'; } o.domainPath = _.ltrim( o.domainPath, [ '/', '\\' ] ); o.i18nToolsPath = localConfig.i18nToolsPath || o.i18nToolsPath; o.potFile = path.join( o.cwd, o.domainPath, o.potFilename ); // Make sure the makepot.php script exists. o.makepotScript = path.join( o.i18nToolsPath, 'makepot.php' ); if ( ! grunt.file.exists( o.makepotScript ) ) { grunt.fatal( 'makepot.php could not be found in ' + o.i18nToolsPath ); } // Create the domain path directory if it doesn't exist. grunt.file.mkdir( path.resolve( o.cwd, o.domainPath ) ); // Reset the working directory. grunt.file.setBase( gruntBase ); // Exclude the node_modules directory by default. o.exclude.push( 'node_modules/.*' ); // o.include.push('views/.*'); // Build the list of CLI args. cmdArgs = [ o.makepotScript, o.type, o.cwd, o.potFile ]; if ( defaultI18nToolsPath === o.i18nToolsPath ) { // Use the custom CLI script that extends makepot.php. o.makepotScript = path.join( o.i18nToolsPath, 'grunt-makepot.php' ); // Only add custom CLI args if using the bundled tools. cmdArgs[0] = o.makepotScript; cmdArgs.push( o.mainFile.split( '.' ).shift() ); cmdArgs.push( o.exclude.join( ',' ) ); cmdArgs.push( o.include.join( ',' ) ); } // Parse the existing POT file to compare for changes. if ( ! o.updateTimestamp && grunt.file.exists( o.potFile ) ) { originalPot = gettext.po.parse( grunt.file.read( o.potFile ) ); } grunt.util.spawn({ cmd: 'php', args: cmdArgs, opts: { stdio: 'inherit' } }, function( error, result, code ) { var matches, pattern, pot, poFiles; if ( 0 === code && grunt.file.exists( o.potFile ) ) { pot = grunt.file.read( o.potFile ); // Update the comments header. pattern = /# /; if ( '' === o.potComments && ( matches = pot.match( pattern ) ) ) { o.potComments = matches[1]; } o.potComments = '# ' + o.potComments.replace( /\n(# )?/g, '\n# ' ).replace( '{year}', new Date().getFullYear() ); pot = pot.replace( pattern, o.potComments ); // Remove duplicate entries from the POT file. pot = gettext.po.parse( pot ); // Merge custom headers. pot.headers['x-generator'] = 'grunt-wp-i18n ' + pkg.version; pot = util.mergeHeaders( pot, o.potHeaders ); // Allow the POT file to be modified with a callback. if ( _.isFunction( o.processPot ) ) { pot = o.processPot.call( undefined, pot, o ); } // Determine if the creation date is the only thing that changed. if ( ! o.updateTimestamp && ! _.isUndefined( originalPot ) ) { pot = util.comparePotFiles( originalPot, pot ) ? originalPot : pot; } // Fix headers. pot = gettext.po.compile( pot ).toString(); pot = util.fixHeaders( pot ); // Save the POT file. grunt.file.write( o.potFile, pot ); grunt.log.ok( 'POT file saved to ' + path.relative( process.cwd(), o.potFile ) ); // Maybe update .po files if ( o.updatePoFiles ) { poFiles = msgMerge.searchPoFiles( o.potFile, o.type ); async.eachSeries( poFiles, function( poFile, done ) { msgMerge.msgMerge( o.potFile, poFile, done ); }, done ); } else { done( error, result ); } } else { done( error, result ); } }); }); };