|
/** |
|
* Gettext Scanner Script for Twig Projects |
|
* v1.3 |
|
* |
|
* Developed by Luís Silva |
|
* https://github.com/luism-s |
|
*/ |
|
|
|
/** |
|
* Purpose: |
|
* Scan Twig and PHP files in the given directories for gettext function calls and output a POT file for translation. |
|
* |
|
* Description: |
|
* While working with Wordpress using the Twig template engine, one might find easier to use gettext |
|
* functions in .twig files for string translation. To simplify the scanning of .twig files for those same functions, this |
|
* script was built to parse .twig files, wrap occurrences of gettext function calls in php tags and |
|
* output the result as a .php file and from that generate a POT file. |
|
* It also scans PHP files as well. |
|
* |
|
* Context: https://github.com/timber/timber/issues/1465 |
|
* |
|
* Usage: `gulp pot` |
|
* |
|
* Logic: |
|
* - Iterates over all given .twig files |
|
* - Search and replace for gettext functions in Twig files and wraps them around PHP tags |
|
* - Outputs each file as .php into a cache folder |
|
* - Scan all .php files for gettext functions using 'gulp-wp-pot' (cache included) |
|
* - Generate .pot file |
|
* |
|
* Dependencies: |
|
* `npm install gulp gulp-if del gulp-wp-pot gulp-replace gulp-rename` |
|
* |
|
* Warning: |
|
* This script has only ben tested in the context of Wordpress theme development using Timber. |
|
* |
|
* TODO: |
|
* Cover `translate_nooped_plural` function. |
|
*/ |
|
const gulp = require('gulp'); |
|
const gulpif = require('gulp-if'); |
|
const del = require('del'); |
|
const wpPot = require('gulp-wp-pot'); |
|
const replace = require('gulp-replace'); |
|
const rename = require('gulp-rename'); |
|
|
|
/** |
|
* Configuration Options |
|
* |
|
* All paths are as if this script is |
|
* located in the root of the theme and all the Twig |
|
* files are located under /views |
|
*/ |
|
const config = { |
|
"text_domain" : "theme-test", // Replace with your domain |
|
"twig_files" : "views/**/*.twig", // Twig Files |
|
"php_files" : "**/*.php", // PHP Files |
|
"cacheFolder" : "views/cache", // Cache Folder |
|
"destFolder" : "languages", // Folder where .pot file will be saved |
|
"keepCache" : true // Delete cache files after script finishes |
|
}; |
|
|
|
|
|
/** |
|
* __ |
|
* _e |
|
* _x |
|
* _xn |
|
* _ex |
|
* _n_noop |
|
* _nx_noop |
|
* translate -> Match __, _e, _x and so on |
|
* \( -> Match ( |
|
* \s*? -> Match empty space 0 or infinite times, as few times as possible (ungreedy) |
|
* ['"] -> Match ' or " |
|
* .+? -> Match any character, 1 to infinite times, as few times as possible (ungreedy) |
|
* , -> Match , |
|
* .+? -> Match any character, 1 to infinite times, as few times as possible (ungreedy) |
|
* \) -> Match ) |
|
*/ |
|
const gettext_regex = { |
|
|
|
// _e( "text", "domain" ) |
|
// __( "text", "domain" ) |
|
// translate( "text", "domain" ) |
|
// esc_attr__( "text", "domain" ) |
|
// esc_attr_e( "text", "domain" ) |
|
// esc_html__( "text", "domain" ) |
|
// esc_html_e( "text", "domain" ) |
|
simple: /(__|_e|translate|esc_attr__|esc_attr_e|esc_html__|esc_html_e)\(\s*?['"].+?['"]\s*?,\s*?['"].+?['"]\s*?\)/g, |
|
|
|
// _n( "single", "plural", number, "domain" ) |
|
plural: /_n\(\s*?['"].*?['"]\s*?,\s*?['"].*?['"]\s*?,\s*?.+?\s*?,\s*?['"].+?['"]\s*?\)/g, |
|
|
|
// _x( "text", "context", "domain" ) |
|
// _ex( "text", "context", "domain" ) |
|
// esc_attr_x( "text", "context", "domain" ) |
|
// esc_html_x( "text", "context", "domain" ) |
|
// _nx( "single", "plural", "number", "context", "domain" ) |
|
disambiguation: /(_x|_ex|_nx|esc_attr_x|esc_html_x)\(\s*?['"].+?['"]\s*?,\s*?['"].+?['"]\s*?,\s*?['"].+?['"]\s*?\)/g, |
|
|
|
// _n_noop( "singular", "plural", "domain" ) |
|
// _nx_noop( "singular", "plural", "context", "domain" ) |
|
noop: /(_n_noop|_nx_noop)\((\s*?['"].+?['"]\s*?),(\s*?['"]\w+?['"]\s*?,){0,1}\s*?['"].+?['"]\s*?\)/g, |
|
}; |
|
|
|
/** |
|
* Main Task |
|
*/ |
|
gulp.task('pot', gulp.series(['compile-twigs', 'generate-pot'])); |
|
|
|
/** |
|
* Generate POT file from all .php files in the theme, |
|
* including the cache folder. |
|
*/ |
|
gulp.task('generate-pot', () => { |
|
const output = gulp.src(config.php_files) |
|
.pipe(wpPot({ |
|
domain: config.text_domain |
|
})) |
|
.pipe(gulp.dest(`${config.destFolder}/${config.text_domain}.pot`)) |
|
.pipe(gulpif(!config.keepCache, del.bind(null, [config.cacheFolder], { force: true }))); |
|
return output; |
|
}); |
|
|
|
/** |
|
* Fake Twig Gettext Compiler |
|
* |
|
* Searches and replaces all occurences of __('string', 'domain'), _e('string', 'domain') and so on, |
|
* with <?php __('string', 'domain'); ?> or <?php _e('string', 'domain'); ?> and saves the content |
|
* in a .php file with the same name in the cache folder. |
|
* |
|
* Functions supported: |
|
* |
|
* Simple: __(), _e(), translate() |
|
* Plural: _n() |
|
* Disambiguation: _x(), _ex(), _nx() |
|
* Noop: _n_loop(), _nx_noop() |
|
*/ |
|
gulp.task('compile-twigs', () => { |
|
del.bind(null, [config.cacheFolder], {force: true}) |
|
// Iterate over .twig files |
|
const output = gulp.src(config.twig_files) |
|
// Search for Gettext function calls and wrap them around PHP tags. |
|
.pipe(replace(gettext_regex.simple, match => `<?php ${match}; ?>`)) |
|
.pipe(replace(gettext_regex.plural, match => `<?php ${match}; ?>`)) |
|
.pipe(replace(gettext_regex.disambiguation, match => `<?php ${match}; ?>`)) |
|
.pipe(replace(gettext_regex.noop, match => `<?php ${match}; ?>`)) |
|
// Rename file with .php extension |
|
.pipe(rename({ |
|
extname: '.php', |
|
})) |
|
// Output the result to the cache folder as a .php file. |
|
.pipe(gulp.dest(config.cacheFolder)); |
|
|
|
return output; |
|
}); |