Skip to content

Commit 2eafdeb

Browse files
author
Raphaël Droz
committed
symfony-console arguments handling + WordPress Timber bridge
* This commit uses symfony-console for manage arguments specific to Twig-Gettext-Extractor which used to be broken. * The $input is also passed to the extractor for possible futur use (eg: handling --debug) * Better Twig loaded. Twig Environment use a ChainLoader which is initialized according to file/paths passed to the command line. * It's possible to add a template directory the Twig-way and compile for one (or multiple templates). * The list of Twig templates to compile can now be passed through stdin, using --files stdin * Twig_SimpleFilter is fixed. true is not an accepted value anymore. Empty value callback avoid the cryptic Twig error: `Function 1() does not exist` * A --require flag is added to add custom PHP code before compilation. * Using the above, a brigde with WordPress+Timber is added. It loads Timber Twig extensions and add a couple of WordPress specific parameters to xgettext. * integrate umpirsky#53 (debugging)
1 parent da881c1 commit 2eafdeb

File tree

5 files changed

+113
-50
lines changed

5 files changed

+113
-50
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ with the following options:
7272
- Language: `Twig`
7373
- List of extensions: `*.twig`
7474
- Invocation:
75-
- Parser command: `<project>/vendor/bin/twig-gettext-extractor --sort-output --force-po -o %o %C %K -L PHP --files %F` (replace `<project>` with absolute path to your project)
75+
- Parser command: `<project>/vendor/bin/twig-gettext-extractor --files %F -- --sort-output --force-po -o %o %C %K -L PHP` (replace `<project>` with absolute path to your project)
7676
- An item in keyword list: `-k%k`
7777
- An item in input file list: `%f`
7878
- Source code charset: `--from-code=%c`

Twig/Gettext/Extractor.php

+18-6
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,18 @@ class Extractor
3232
*/
3333
protected $parameters;
3434

35+
/**
36+
* @var `Symfony\Component\Console\Input\ArgvInput
37+
*/
38+
protected $input;
39+
3540

3641
private $executable;
3742

38-
public function __construct(\Twig_Environment $environment)
43+
public function __construct(\Twig_Environment $environment, $input = null)
3944
{
4045
$this->environment = $environment;
41-
$this->reset();
46+
$this->input = $input;
4247
}
4348

4449
/**
@@ -57,6 +62,9 @@ protected function reset()
5762
public function addTemplate($path)
5863
{
5964
$this->environment->loadTemplate($path);
65+
if ($this->environment->isDebug()) {
66+
fprintf(STDERR, $path . PHP_EOL);
67+
}
6068
}
6169

6270
public function addGettextParameter($parameter)
@@ -71,11 +79,15 @@ public function setGettextParameters(array $parameters)
7179

7280
public function extract()
7381
{
74-
$command = $this->executable ?: 'xgettext';
82+
$command = $this->executable;
7583
$command .= ' ' . implode(' ', $this->parameters);
7684
$command .= ' ' . $this->environment->getCache() . '/*/*.php';
7785

7886
$error = 0;
87+
if ($this->environment->isDebug()) {
88+
fprintf(STDERR, $command . PHP_EOL);
89+
}
90+
7991
$output = system($command, $error);
8092
if (0 !== $error) {
8193
throw new \RuntimeException(sprintf(
@@ -85,13 +97,13 @@ public function extract()
8597
$output
8698
));
8799
}
88-
89-
$this->reset();
90100
}
91101

92102
public function __destruct()
93103
{
94104
$filesystem = new Filesystem();
95-
$filesystem->remove($this->environment->getCache());
105+
if (! $this->environment->isDebug()) {
106+
$filesystem->remove($this->environment->getCache());
107+
}
96108
}
97109
}

composer.json

+7-6
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@
1313
"php": "^7.1",
1414
"twig/twig": "^2.0",
1515
"twig/extensions": "~1.0",
16-
"symfony/twig-bridge": "^4.0",
17-
"symfony/routing": "^4.0",
18-
"symfony/filesystem": "^4.0",
19-
"symfony/translation": "^4.0",
20-
"symfony/form": "^4.0",
21-
"symfony/asset": "^4.0"
16+
"symfony/twig-bridge": "~3.0|~4.0",
17+
"symfony/routing": "~3.0|~4.0",
18+
"symfony/filesystem": "~3.0|~4.0",
19+
"symfony/translation": "~3.0|~4.0",
20+
"symfony/form": "~3.0|~4.0",
21+
"symfony/asset": "~2.8|~3.0|~4.0",
22+
"symfony/console": "^4.1"
2223
},
2324
"require-dev": {
2425
"symfony/config": "^4.0",

twig-gettext-extractor

+71-37
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* Extracts translations from twig templates.
1515
*
1616
* @author Саша Стаменковић <[email protected]>
17+
* @author Raphaël Droz <[email protected]>
1718
*/
1819

1920
if (file_exists($a = __DIR__ . '/../../autoload.php')) {
@@ -22,9 +23,46 @@ if (file_exists($a = __DIR__ . '/../../autoload.php')) {
2223
require_once __DIR__ . '/vendor/autoload.php';
2324
}
2425

25-
$twig = new Twig_Environment(new Twig\Gettext\Loader\Filesystem(DIRECTORY_SEPARATOR), [
26-
'cache' => implode(DIRECTORY_SEPARATOR, [sys_get_temp_dir(), 'cache', uniqid()]),
27-
'auto_reload' => true,
26+
use Symfony\Component\Console\Input\ArgvInput;
27+
use Symfony\Component\Console\Input\InputDefinition;
28+
use Symfony\Component\Console\Input\InputArgument;
29+
use Symfony\Component\Console\Input\InputOption;
30+
31+
32+
// You can add more extensions here, or via command line with the --functions and --filter options
33+
$input = new ArgvInput($argv, new InputDefinition([
34+
new InputOption('exec', null, InputOption::VALUE_REQUIRED, 'xgettext binary', 'xgettext'),
35+
new InputOption('files', null, InputOption::VALUE_REQUIRED, 'template files'),
36+
new InputOption('dir', null, InputOption::VALUE_REQUIRED, 'template directory', '.'),
37+
new InputOption('functions', null, InputOption::VALUE_REQUIRED, 'custom Twig extensions to load'),
38+
new InputOption('filters', null, InputOption::VALUE_REQUIRED, 'custom Twig filter to support'),
39+
new InputOption('require', null, InputOption::VALUE_REQUIRED, 'Additional PHP file to require'),
40+
new InputOption('debug', 'd', InputOption::VALUE_NONE),
41+
new InputArgument('gettext_parameters', InputArgument::IS_ARRAY, 'Additional xgettext parameters', [])
42+
]));
43+
44+
// Twig Loaders options
45+
$loaders = new Twig_Loader_Chain();
46+
47+
if ($input->getOption('dir')) {
48+
$directory_loader = new \Twig_Loader_Filesystem( explode(',', $input->getOption('dir')) );
49+
$loaders->addLoader($directory_loader);
50+
}
51+
if ($input->getOption('files')) {
52+
$files = [];
53+
foreach(explode(',', $input->getOption('files')) as $f) {
54+
if (file_exists($f)) {
55+
$files[$f] = file_get_contents($f);
56+
}
57+
}
58+
$loaders->addLoader(new Twig_Loader_Array($files));
59+
}
60+
61+
// Loader initialized => Initialize Twig Environment
62+
$cachedir = implode(DIRECTORY_SEPARATOR, [sys_get_temp_dir(), 'cache', uniqid()]);
63+
$twig = new Twig_Environment($loaders, [
64+
'cache' => $cachedir,
65+
'auto_reload' => true
2866
]);
2967
$twig->addExtension(new Twig_Extensions_Extension_I18n());
3068
$twig->addExtension(new Symfony\Bridge\Twig\Extension\TranslationExtension(
@@ -38,43 +76,39 @@ $twig->addExtension(new Symfony\Bridge\Twig\Extension\AssetExtension(
3876
new Symfony\Component\Asset\Packages()
3977
));
4078

41-
// You can add more extensions here, or via command line with the --functions and --filter options
42-
43-
array_shift($_SERVER['argv']);
79+
if ($input->getOption('debug')) {
80+
$twig->enableDebug();
81+
}
82+
if ($input->getOption('functions')) {
83+
foreach (explode(',', $input->getOption('functions')) as $functionName) {
84+
$twig->addFunction(new \Twig_SimpleFunction($functionName, true));
85+
}
86+
}
87+
if ($input->getOption('filters')) {
88+
foreach (explode(',', $input->getOption('filters')) as $filterName) {
89+
$twig->addFilter(new \Twig_SimpleFilter($filterName, function($e) { return ""; }));
90+
}
91+
}
4492

45-
$setFunctions = false;
46-
$setFilters = false;
47-
$addTemplate = false;
48-
$setExecutable = false;
93+
// Twig Environment is up => initialize extractor
94+
$extractor = new Twig\Gettext\Extractor($twig, $input);
95+
$extractor->setGettextParameters($input->getArgument('gettext_parameters'));
96+
$extractor->setExecutable($input->getOption('exec'));
4997

50-
$extractor = new Twig\Gettext\Extractor($twig);
98+
if ($input->getOption('require')) {
99+
require_once($input->getOption('require'));
100+
}
51101

52-
foreach ($_SERVER['argv'] as $arg) {
53-
if ('--files' === $arg) {
54-
$addTemplate = true;
55-
} else if ($addTemplate) {
56-
$extractor->addTemplate(getcwd() . DIRECTORY_SEPARATOR . $arg);
57-
} else if ('--exec' === $arg) {
58-
$setExecutable = true;
59-
} else if ($setExecutable) {
60-
$extractor->setExecutable($arg);
61-
$setExecutable = false;
62-
} else if ('--functions' === $arg) {
63-
$setFunctions = true;
64-
} else if ($setFunctions) {
65-
foreach (explode(',', $arg) as $functionName) {
66-
$twig->addFunction(new \Twig_SimpleFunction($functionName, true));
67-
}
68-
$setFunctions = false;
69-
} else if ('--filters' === $arg) {
70-
$setFilters = true;
71-
} else if ($setFilters) {
72-
foreach (explode(',', $arg) as $filterName) {
73-
$twig->addFilter(new \Twig_SimpleFilter($filterName, true));
74-
}
75-
$setFilters = false;
76-
} else {
77-
$extractor->addGettextParameter($arg);
102+
// compile
103+
if ($input->getOption('files')) {
104+
if ($input->getOption('files') == 'stdin') {
105+
$files = explode("\n", trim(file_get_contents('php://stdin')));
106+
}
107+
else {
108+
$files = explode(',', $input->getOption('files'));
109+
}
110+
foreach($files as $f) {
111+
$extractor->addTemplate($f);
78112
}
79113
}
80114

wp-timber-bridge.php

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
// (c) 2018 Raphaël Droz <[email protected]>
3+
// Bridge between Twig-Gettext-Extractor and WordPress/Timber:
4+
// 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 -
5+
6+
function add_action() { }
7+
include_once(getenv('TIMBER_DIR') . '/lib/Twig_Function.php');
8+
include_once(getenv('TIMBER_DIR') . '/lib/Twig.php');
9+
$x = new \Timber\Twig();
10+
$x->add_timber_functions($twig);
11+
12+
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) {
13+
$extractor->addGettextParameter('-k' . $a);
14+
}
15+
$extractor->addGettextParameter('-L');
16+
$extractor->addGettextParameter('PHP');

0 commit comments

Comments
 (0)