From 9df18c18dd10b7cc0838aa0f41be5a4524c6e51f Mon Sep 17 00:00:00 2001 From: Sebastien Marinier Date: Fri, 16 Aug 2024 12:12:02 +0200 Subject: [PATCH 1/5] feature: add translationtool command options (-h, -v), add check-files action Signed-off-by: Sebastien Marinier --- .../translationtool/src/translationtool.php | 143 ++++++++++++++++-- 1 file changed, 131 insertions(+), 12 deletions(-) diff --git a/translations/translationtool/src/translationtool.php b/translations/translationtool/src/translationtool.php index 42513563..87257fde 100644 --- a/translations/translationtool/src/translationtool.php +++ b/translations/translationtool/src/translationtool.php @@ -30,10 +30,12 @@ class TranslatableApp { private $fakeLocaleFile; private $ignoreFiles; private $translationsPath; + private $tool; - public function __construct($appPath, $translationsPath) { + public function __construct($appPath, $translationsPath, $tool) { $this->appPath = $appPath; $this->translationsPath = $translationsPath; + $this->tool = $tool; $this->ignoreFiles = []; $this->fakeAppInfoFile = $this->appPath . '/specialAppInfoFakeDummyForL10nScript.php'; @@ -59,7 +61,7 @@ public function __construct($appPath, $translationsPath) { print_r($this->ignoreFiles); } - public function createPotFile() { + public function createOrCheckPotFile(bool $checkFiles=false) { $pathToPotFile = $this->translationsPath . '/templates/' . $this->name . '.pot'; // Gather required data @@ -95,7 +97,26 @@ public function createPotFile() { $joinexisting = '--join-existing'; } - exec('xgettext ' . $output . ' ' . $joinexisting . ' ' . $keywords . ' ' . $language . ' ' . escapeshellarg($entry) . ' ' . $additionalArguments); + $extractAll = $tmpfname = $skipErrors = ''; + if ($checkFiles) { + $extractAll = '--extract-all'; + + // modify output + $tmpfname = tempnam(sys_get_temp_dir(), 'checkpot'); + $output = '--output=' . $tmpfname; + // extract-all generates a recurrent warning + $skipErrors = "2>/dev/null"; + } + + $xgetCmd = 'xgettext ' . $output . ' ' . $joinexisting . ' ' . $keywords . ' ' . $language . ' ' . escapeshellarg($entry) . ' ' . $additionalArguments . ' ' . $extractAll . ' ' . $skipErrors; + $this->tool->log($xgetCmd); + exec($xgetCmd); + + // checking files + if ($checkFiles) { + $this->checkMissingTranslations($entry, $tmpfname); + unlink($tmpfname); + } } // Don't forget to remove the temporary file @@ -104,6 +125,34 @@ public function createPotFile() { $this->deleteFakeFileForLocale(); } + private function checkMissingTranslations(string $entry, string $tmpfname) { + $translations = Gettext\Translations::fromPoFile($tmpfname); + $first=true; + foreach($translations as $translation) { + if (preg_match_all('/(^|[^a-zA-Z_]+)(t\([^\)]*\))/', $translation->getOriginal(), $matches)) { + $suspects = []; + foreach($matches[2] as $miss) { + if (preg_match('/["\']'.$this->name.'["\']/', $miss )) { + $suspects[] = $miss; + } + } + if (empty($suspects)) { + continue; + } + if ($first) { + echo '** Warning : Check potentially missing translations sentences : ' . $this->name . ' ' . $entry . PHP_EOL; + $first = false; + } + if ($translation->hasReferences()) { + echo '> Starting at line ' . $translation->getReferences()[0][1] . PHP_EOL; + } + foreach($suspects as $suspect) { + echo ' -> ' . $suspect . PHP_EOL; + } + } + } + } + public function createNextcloudFiles() { foreach ($this->findLanguages() as $language) { $poFile = $this->translationsPath . '/' . $language . '/' . $this->name . '.po'; @@ -464,6 +513,7 @@ private function deleteFakeFileForLocale() { class TranslationTool { private $translationPath; private $appPaths; + private $verbose = 0; public function __construct(){ $this->translationPath = getcwd() . '/translationfiles'; @@ -474,6 +524,10 @@ public function __construct(){ } } + public function setVerbose(int $verbose) { + $this->verbose = $verbose; + } + public function checkEnvironment() { // Check if the version of xgettext is at least 0.18.3 $output = []; @@ -482,6 +536,8 @@ public function checkEnvironment() { // we assume the first line looks like this 'xgettext (GNU gettext-tools) 0.19.3' $version = trim(substr($output[0], 29)); + $this->log("xgettext version : ". $version); + if (version_compare($version, '0.18.3', '<')) { echo 'Minimum expected version of xgettext is 0.18.3. Detected: ' . $version . '".' . PHP_EOL; return false; @@ -503,18 +559,30 @@ public function createPotFiles() { // iterate over all apps foreach ($this->appPaths as $appPath) { - $app = new TranslatableApp($appPath, $this->translationPath); - $app->createPotFile(); + $this->log('Application path: ' . $appPath); + $app = new TranslatableApp($appPath, $this->translationPath, $this); + $app->createOrCheckPotFile(); } } public function convertPoFiles() { foreach ($this->appPaths as $appPath) { - $app = new TranslatableApp($appPath, $this->translationPath); + $this->log('Application path: ' . $appPath); + $app = new TranslatableApp($appPath, $this->translationPath, $this); $app->createNextcloudFiles(); } } + public function checkFiles() { + + // iterate over all apps + foreach ($this->appPaths as $appPath) { + $this->log('Application path: ' . $appPath); + $app = new TranslatableApp($appPath, $this->translationPath, $this); + $app->createOrCheckPotFile(true); + } + } + private function findApps($path){ $directoryectoryContent = scandir($path); foreach ($directoryectoryContent as $entry) { @@ -539,7 +607,6 @@ private function findApps($path){ } } - private function rrmdir($path) { if (!is_dir($path)) { return; @@ -561,18 +628,68 @@ private function rrmdir($path) { rmdir($path); } + + public function log(string $message) { + if ($this->verbose == 0) { + return; + } + echo " > " . $message . PHP_EOL; + } +} + +// arguments handle +$task = ''; +$usage = false; +$verbose = 0; +$returnValue = true; + +$index = 0; +foreach ($argv as $arg) { + $index++; + if ($index == 1) { + $TOOLNAME = $arg; + continue; + } + switch($arg) { + case '-h': + case '--help': + $usage = true; + break; + case '-v': + case '--verbose': + $verbose++; + break; + case 'create-pot-files': + case 'convert-po-files': + case 'check-files': + $task = $arg; + break; + default: + echo "Unknown command parameter : " . $arg . PHP_EOL; + $usage = true; + $returnValue = false; + break; + } } // read the command line arguments -if(count($argv) < 2) { +if(empty($task) && !$usage) { echo 'Missing arguments' . PHP_EOL; - echo 'call "' . $argv[0] . ' $task [$appName]' . PHP_EOL; - echo '$task: create-pot-files || convert-po-files' . PHP_EOL; - return false; + $usage = true; + $returnValue = false; +} + +if ($usage) { + echo 'call "' . $TOOLNAME . ' $task [$appName]' . PHP_EOL; + echo '$task: create-pot-files || convert-po-files || check-files' . PHP_EOL; + echo "Options:". PHP_EOL; + echo " -v, --verbose Verbose mode". PHP_EOL; + echo " -h, --help Display command usage". PHP_EOL; + return $returnValue; } -$task = $argv[1]; $tool = new TranslationTool(); +$tool->setVerbose($verbose); if (!$tool->checkEnvironment()) { return false; } @@ -581,6 +698,8 @@ private function rrmdir($path) { $tool->createPotFiles(); } elseif ($task === 'convert-po-files') { $tool->convertPoFiles(); +} elseif ($task === 'check-files') { + $tool->checkFiles(); } else { echo 'Unknown task: "' . $task . '".' . PHP_EOL; return false; From c5ac41efa11e61ac00b2cf31149847a90575215b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marinier?= Date: Sat, 17 Aug 2024 10:49:55 +0200 Subject: [PATCH 2/5] Update translations/translationtool/src/translationtool.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Joas Schilling <213943+nickvergessen@users.noreply.github.com> Signed-off-by: Sébastien Marinier --- translations/translationtool/src/translationtool.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/translations/translationtool/src/translationtool.php b/translations/translationtool/src/translationtool.php index 87257fde..e5a6aa4c 100644 --- a/translations/translationtool/src/translationtool.php +++ b/translations/translationtool/src/translationtool.php @@ -140,7 +140,7 @@ private function checkMissingTranslations(string $entry, string $tmpfname) { continue; } if ($first) { - echo '** Warning : Check potentially missing translations sentences : ' . $this->name . ' ' . $entry . PHP_EOL; + echo '** Warning: Check potentially missing translations sentences: ' . $this->name . ' ' . $entry . PHP_EOL; $first = false; } if ($translation->hasReferences()) { From 04d275824632fb97d74e043fb60c2897a299a298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marinier?= Date: Sat, 17 Aug 2024 10:50:14 +0200 Subject: [PATCH 3/5] Update translations/translationtool/src/translationtool.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Joas Schilling <213943+nickvergessen@users.noreply.github.com> Signed-off-by: Sébastien Marinier --- translations/translationtool/src/translationtool.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/translations/translationtool/src/translationtool.php b/translations/translationtool/src/translationtool.php index e5a6aa4c..20c2d715 100644 --- a/translations/translationtool/src/translationtool.php +++ b/translations/translationtool/src/translationtool.php @@ -680,8 +680,10 @@ public function log(string $message) { } if ($usage) { - echo 'call "' . $TOOLNAME . ' $task [$appName]' . PHP_EOL; - echo '$task: create-pot-files || convert-po-files || check-files' . PHP_EOL; + echo 'Usage:' . PHP_EOL; + echo ' ' . $TOOLNAME . ' []' . PHP_EOL; + echo 'Arguments:' . PHP_EOL; + echo ' task: One of: create-pot-files, convert-po-files, check-files' . PHP_EOL; echo "Options:". PHP_EOL; echo " -v, --verbose Verbose mode". PHP_EOL; echo " -h, --help Display command usage". PHP_EOL; From e15271da90065af6a6d9f603a7abc90a180f433f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marinier?= Date: Sat, 17 Aug 2024 10:51:17 +0200 Subject: [PATCH 4/5] Update translations/translationtool/src/translationtool.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Joas Schilling <213943+nickvergessen@users.noreply.github.com> Signed-off-by: Sébastien Marinier --- translations/translationtool/src/translationtool.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/translations/translationtool/src/translationtool.php b/translations/translationtool/src/translationtool.php index 20c2d715..15f1b113 100644 --- a/translations/translationtool/src/translationtool.php +++ b/translations/translationtool/src/translationtool.php @@ -536,7 +536,7 @@ public function checkEnvironment() { // we assume the first line looks like this 'xgettext (GNU gettext-tools) 0.19.3' $version = trim(substr($output[0], 29)); - $this->log("xgettext version : ". $version); + $this->log("xgettext version: ". $version); if (version_compare($version, '0.18.3', '<')) { echo 'Minimum expected version of xgettext is 0.18.3. Detected: ' . $version . '".' . PHP_EOL; From 57fbb093d579e26d5ffc01398c4260160c4e2648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marinier?= Date: Sat, 17 Aug 2024 10:51:32 +0200 Subject: [PATCH 5/5] Update translations/translationtool/src/translationtool.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Joas Schilling <213943+nickvergessen@users.noreply.github.com> Signed-off-by: Sébastien Marinier --- translations/translationtool/src/translationtool.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/translations/translationtool/src/translationtool.php b/translations/translationtool/src/translationtool.php index 15f1b113..398448ee 100644 --- a/translations/translationtool/src/translationtool.php +++ b/translations/translationtool/src/translationtool.php @@ -61,7 +61,7 @@ public function __construct($appPath, $translationsPath, $tool) { print_r($this->ignoreFiles); } - public function createOrCheckPotFile(bool $checkFiles=false) { + public function createOrCheckPotFile(bool $checkFiles = false) { $pathToPotFile = $this->translationsPath . '/templates/' . $this->name . '.pot'; // Gather required data