diff --git a/README.md b/README.md index 7f688c7..29e8428 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ with the following options: - Language: `Twig` - List of extensions: `*.twig` - Invocation: - - Parser command: `/vendor/bin/twig-gettext-extractor --sort-output --force-po -o %o %C %K -L PHP --files %F` (replace `` with absolute path to your project) + - Parser command: `/vendor/bin/twig-gettext-extractor --files %F -- --sort-output --force-po -o %o %C %K -L PHP` (replace `` with absolute path to your project) - An item in keyword list: `-k%k` - An item in input file list: `%f` - Source code charset: `--from-code=%c` diff --git a/Twig/Gettext/Extractor.php b/Twig/Gettext/Extractor.php index e5247d9..13aacbe 100644 --- a/Twig/Gettext/Extractor.php +++ b/Twig/Gettext/Extractor.php @@ -38,7 +38,6 @@ class Extractor public function __construct(\Twig_Environment $environment) { $this->environment = $environment; - $this->reset(); } /** @@ -57,6 +56,9 @@ protected function reset() public function addTemplate($path) { $this->environment->loadTemplate($path); + if ($this->environment->isDebug()) { + fprintf(STDERR, $path . PHP_EOL); + } } public function addGettextParameter($parameter) @@ -71,11 +73,15 @@ public function setGettextParameters(array $parameters) public function extract() { - $command = $this->executable ?: 'xgettext'; + $command = $this->executable; $command .= ' ' . implode(' ', $this->parameters); $command .= ' ' . $this->environment->getCache() . '/*/*.php'; $error = 0; + if ($this->environment->isDebug()) { + fprintf(STDERR, $command . PHP_EOL); + } + $output = system($command, $error); if (0 !== $error) { throw new \RuntimeException(sprintf( @@ -85,13 +91,13 @@ public function extract() $output )); } - - $this->reset(); } public function __destruct() { $filesystem = new Filesystem(); - $filesystem->remove($this->environment->getCache()); + if (! $this->environment->isDebug()) { + $filesystem->remove($this->environment->getCache()); + } } } diff --git a/composer.json b/composer.json index 61428d5..3d9e40f 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,8 @@ "symfony/filesystem": "^4.0", "symfony/translation": "^4.0", "symfony/form": "^4.0", - "symfony/asset": "^4.0" + "symfony/asset": "^4.0", + "symfony/console": "^4.0" }, "require-dev": { "symfony/config": "^4.0", diff --git a/twig-gettext-extractor b/twig-gettext-extractor index d45aed5..6fed9bf 100755 --- a/twig-gettext-extractor +++ b/twig-gettext-extractor @@ -14,6 +14,7 @@ * Extracts translations from twig templates. * * @author Саша Стаменковић + * @author Raphaël Droz */ if (file_exists($a = __DIR__ . '/../../autoload.php')) { @@ -22,9 +23,46 @@ if (file_exists($a = __DIR__ . '/../../autoload.php')) { require_once __DIR__ . '/vendor/autoload.php'; } -$twig = new Twig_Environment(new Twig\Gettext\Loader\Filesystem(DIRECTORY_SEPARATOR), [ - 'cache' => implode(DIRECTORY_SEPARATOR, [sys_get_temp_dir(), 'cache', uniqid()]), - 'auto_reload' => true, +use Symfony\Component\Console\Input\ArgvInput; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputOption; + + +// You can add more extensions here, or via command line with the --functions and --filter options +$input = new ArgvInput($argv, new InputDefinition([ + new InputOption('exec', null, InputOption::VALUE_REQUIRED, 'xgettext binary', 'xgettext'), + new InputOption('files', null, InputOption::VALUE_REQUIRED, 'template files'), + new InputOption('dir', null, InputOption::VALUE_REQUIRED, 'template directory', '.'), + new InputOption('functions', null, InputOption::VALUE_REQUIRED, 'custom Twig extensions to load'), + new InputOption('filters', null, InputOption::VALUE_REQUIRED, 'custom Twig filter to support'), + new InputOption('require', null, InputOption::VALUE_REQUIRED, 'Additional PHP file to require'), + new InputOption('debug', 'd', InputOption::VALUE_NONE), + new InputArgument('gettext_parameters', InputArgument::IS_ARRAY, 'Additional xgettext parameters', []) +])); + +// Twig Loaders options +$loaders = new Twig_Loader_Chain(); + +if ($input->getOption('dir')) { + $directory_loader = new \Twig_Loader_Filesystem( explode(',', $input->getOption('dir')) ); + $loaders->addLoader($directory_loader); +} +if ($input->getOption('files')) { + $files = []; + foreach(explode(',', $input->getOption('files')) as $f) { + if (file_exists($f)) { + $files[$f] = file_get_contents($f); + } + } + $loaders->addLoader(new Twig_Loader_Array($files)); +} + +// Loader initialized => Initialize Twig Environment +$cachedir = implode(DIRECTORY_SEPARATOR, [sys_get_temp_dir(), 'cache', uniqid()]); +$twig = new Twig_Environment($loaders, [ + 'cache' => $cachedir, + 'auto_reload' => true ]); $twig->addExtension(new Twig_Extensions_Extension_I18n()); $twig->addExtension(new Symfony\Bridge\Twig\Extension\TranslationExtension( @@ -38,43 +76,39 @@ $twig->addExtension(new Symfony\Bridge\Twig\Extension\AssetExtension( new Symfony\Component\Asset\Packages() )); -// You can add more extensions here, or via command line with the --functions and --filter options - -array_shift($_SERVER['argv']); - -$setFunctions = false; -$setFilters = false; -$addTemplate = false; -$setExecutable = false; +if ($input->getOption('debug')) { + $twig->enableDebug(); +} +if ($input->getOption('functions')) { + foreach (explode(',', $input->getOption('functions')) as $functionName) { + $twig->addFunction(new \Twig_SimpleFunction($functionName, true)); + } +} +if ($input->getOption('filters')) { + foreach (explode(',', $input->getOption('filters')) as $filterName) { + $twig->addFilter(new \Twig_SimpleFilter($filterName, function($e) { return ""; })); + } +} +// Twig Environment is up => initialize extractor $extractor = new Twig\Gettext\Extractor($twig); +$extractor->setGettextParameters($input->getArgument('gettext_parameters')); +$extractor->setExecutable($input->getOption('exec')); -foreach ($_SERVER['argv'] as $arg) { - if ('--files' === $arg) { - $addTemplate = true; - } else if ($addTemplate) { - $extractor->addTemplate(getcwd() . DIRECTORY_SEPARATOR . $arg); - } else if ('--exec' === $arg) { - $setExecutable = true; - } else if ($setExecutable) { - $extractor->setExecutable($arg); - $setExecutable = false; - } else if ('--functions' === $arg) { - $setFunctions = true; - } else if ($setFunctions) { - foreach (explode(',', $arg) as $functionName) { - $twig->addFunction(new \Twig_SimpleFunction($functionName, true)); - } - $setFunctions = false; - } else if ('--filters' === $arg) { - $setFilters = true; - } else if ($setFilters) { - foreach (explode(',', $arg) as $filterName) { - $twig->addFilter(new \Twig_SimpleFilter($filterName, true)); - } - $setFilters = false; - } else { - $extractor->addGettextParameter($arg); +if ($input->getOption('require')) { + require_once($input->getOption('require')); +} + +// compile +if ($input->getOption('files')) { + if ($input->getOption('files') == 'stdin') { + $files = explode("\n", trim(file_get_contents('php://stdin'))); + } + else { + $files = explode(',', $input->getOption('files')); + } + foreach($files as $f) { + $extractor->addTemplate($f); } } diff --git a/wp-timber-bridge.php b/wp-timber-bridge.php new file mode 100644 index 0000000..3869b22 --- /dev/null +++ b/wp-timber-bridge.php @@ -0,0 +1,16 @@ + +// Bridge between Twig-Gettext-Extractor and WordPress/Timber: +// find templates/ -type f -name '*twig' | TIMBER_DIR=/path/to/wp/plugins/timber-library twig-gettext-extractor --require wp-timber-bridge.php --files stdin -- -o - + +function add_action() { } +include_once(getenv('TIMBER_DIR') . '/lib/Twig_Function.php'); +include_once(getenv('TIMBER_DIR') . '/lib/Twig.php'); +$x = new \Timber\Twig(); +$x->add_timber_functions($twig); + +foreach(['__','_e','_n','_x','_ex','_nx','esc_attr__','esc_attr_e','esc_attr_x','esc_html__','esc_html_e','esc_html_x','_n_noop','_nx_noop','translate_nooped_plural'] as $a) { + $extractor->addGettextParameter('-k' . $a); +} +$extractor->addGettextParameter('-L'); +$extractor->addGettextParameter('PHP');