From 1b7ab489088867f24c778d9fbee116368b46a3ca Mon Sep 17 00:00:00 2001 From: Ale Mostajo Date: Sun, 5 Feb 2023 01:57:17 -0600 Subject: [PATCH] #97 Working generate pot command --- composer.json | 3 +- src/Base/BaseCommand.php | 44 +++++++++ src/GenerateCommand.php | 12 +-- src/Traits/GeneratePotTrait.php | 167 ++++++++++---------------------- tests/cases/GeneratePotTest.php | 16 +-- 5 files changed, 104 insertions(+), 138 deletions(-) diff --git a/composer.json b/composer.json index c259a6b..2430b18 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,8 @@ "require": { "php": ">=5.4.0", "10quality/ayuco": "^1.0", - "nikic/php-parser": "^4.2" + "nikic/php-parser": "^4.2", + "10quality/gettext-wp-scanner": "dev-master" }, "require-dev": { "phpunit/phpunit": "9.*" diff --git a/src/Base/BaseCommand.php b/src/Base/BaseCommand.php index 1c8a723..9c2532c 100644 --- a/src/Base/BaseCommand.php +++ b/src/Base/BaseCommand.php @@ -242,4 +242,48 @@ public function getMainClassPath() { return $this->rootPath.'/app/Main.php'; } + /** + * Returns the value of an argument (by index). + * @since 1.1.17 + * + * @param array $args + * @param int $index + * @param mixed $default + */ + protected function getArgsValue($args, $index, $default = null) + { + return !isset($args[$index]) || empty($args[$index]) ? $default : $args[$index]; + } + /** + * Returns path to /app folder. + * @since 1.1.17 + * + * @return string + */ + public function getAppPath() + { + return $this->rootPath.'/app/'; + } + /** + * Returns path to /app folder. + * @since 1.1.17 + * + * @return string + */ + public function getViewsPath() + { + return str_replace('app\Config/../../', '', + str_replace('app/Config/../../', '', $this->config['paths']['views']) + ); + } + /** + * Returns path to /app folder. + * @since 1.1.17 + * + * @return string + */ + public function getAssetsPath() + { + return $this->rootPath.'/assets/'; + } } diff --git a/src/GenerateCommand.php b/src/GenerateCommand.php index 95fb8af..272ecb3 100644 --- a/src/GenerateCommand.php +++ b/src/GenerateCommand.php @@ -14,7 +14,7 @@ * @copyright 10Quality * @license MIT * @package WPMVC\Commands - * @version 1.1.2 + * @version 1.1.17 */ class GenerateCommand extends Command { @@ -32,7 +32,7 @@ class GenerateCommand extends Command * @since 1.0.0 * @var string */ - protected $description = 'Generates files, like the language Pot file [in-progress, has bugs].'; + protected $description = 'Generates POT, PO and MO files.'; /** * Calls to command action. @@ -43,15 +43,11 @@ class GenerateCommand extends Command public function call($args = []) { if (count($args) == 0 || empty($args[2])) - throw new NoticeException('Command "'.$this->key.'": Expecting a file to generate (pot).'); - + throw new NoticeException('Command "'.$this->key.'": Expecting something to generate (pot).'); $object = explode(':', $args[2]); - switch ($object[0]) { case 'pot': - $textdomain = !isset($args[3]) || empty($args[3]) ? null : $args[3]; - $lang = !isset($args[4]) || empty($args[4]) ? 'en' : $args[4]; - $this->generatePot($textdomain, $lang); + $this->generatePot($this->getArgsValue($args, 3, 'en')); break; } } diff --git a/src/Traits/GeneratePotTrait.php b/src/Traits/GeneratePotTrait.php index aed0e52..fdcab9b 100644 --- a/src/Traits/GeneratePotTrait.php +++ b/src/Traits/GeneratePotTrait.php @@ -3,9 +3,11 @@ namespace WPMVC\Commands\Traits; use Exception; -use RecursiveDirectoryIterator; -use RecursiveIteratorIterator; use Ayuco\Exceptions\NoticeException; +use Gettext\Translations; +use Gettext\Generator\PoGenerator; +use TenQuality\Gettext\Scanner\WPJsScanner; +use TenQuality\Gettext\Scanner\WPPhpScanner; /** * Generates POT file. @@ -14,7 +16,7 @@ * @copyright 10Quality * @license MIT * @package WPMVC\Commands - * @version 1.1.8 + * @version 1.1.17 */ trait GeneratePotTrait { @@ -22,51 +24,61 @@ trait GeneratePotTrait * Generate pot file. * @since 1.1.0 * - * @param string $textdomain Domain name. - * @param string $lang Pot default language. + * @param string $lang Pot default language. */ - protected function generatePot($textdomain = null, $lang = 'en') + protected function generatePot($lang = 'en') { try { - // Search project - if (empty($textdomain)) - $textdomain = $this->config['localize']['textdomain']; - $pot = $this->getPotHeader($lang, $textdomain); - $lang_regex = '/_[_enx]\([|\s][\\\'\"][\s\S]+?(?=[\\\'|\"]'.$textdomain.'[\\\'|\"])/'; - $string_regex = '/[\\\'|\"]([^\\\'|\"]+)[\\\'|\"]/'; - // App folder - $dir = new RecursiveDirectoryIterator($this->config['paths']['base'], RecursiveDirectoryIterator::SKIP_DOTS); - foreach (new RecursiveIteratorIterator($dir, RecursiveIteratorIterator::SELF_FIRST) as $filename => $item) { - if($item->isDir()) - continue; - $content = file_get_contents($filename); - preg_match_all($lang_regex, $content, $matches ); - if (empty($matches)) - continue; - foreach ($matches[0] as $match) { - $this->evalPotMatch($pot, $match, $string_regex); - } + $domain = $this->config['localize']['textdomain']; + $translations = Translations::create($domain, $lang); + // Prepare headers + $translations->getHeaders()->set('Project-Id-Version', $this->config['namespace']); + $translations->getHeaders()->set('POT-Creation-Date', date('Y-m-d H:i:s')); + $translations->getHeaders()->set('MIME-Version', $this->config['version']); + $translations->getHeaders()->set('Content-Type', 'text/plain; charset=UTF-8'); + $translations->getHeaders()->set('Last-Translator', $this->config['author']); + $translations->getHeaders()->set('X-Generator', 'WordPress MVC Commands 1.1'); + // Php files + $scanner = new WPPhpScanner( + Translations::create($domain) + ); + foreach (glob($this->rootPath.'*.php') as $file) { + $scanner->scanFile($file); } - // Views folder - $dir = new RecursiveDirectoryIterator($this->config['paths']['views'], RecursiveDirectoryIterator::SKIP_DOTS); - foreach (new RecursiveIteratorIterator($dir, RecursiveIteratorIterator::SELF_FIRST) as $filename => $item) { - if($item->isDir()) - continue; - $content = file_get_contents($filename); - preg_match_all($lang_regex, $content, $matches ); - if (empty($matches)) - continue; - foreach ($matches[0] as $match) { - $this->evalPotMatch($pot, $match, $string_regex); - } + foreach (glob($this->getAppPath().'*.php') as $file) { + $scanner->scanFile($file); } - // Write pot file - $filename = $this->config['localize']['path'].$textdomain.'.pot'; + foreach (glob($this->getAppPath().'**/*.php') as $file) { + $scanner->scanFile($file); + } + foreach (glob($this->getViewsPath().'*.php') as $file) { + $scanner->scanFile($file); + } + foreach (glob($this->getViewsPath().'**/*.php') as $file) { + $scanner->scanFile($file); + } + $scannedTranslations = $scanner->getTranslations(); + if (array_key_exists($domain, $scannedTranslations)) + $translations = $translations->mergeWith($scannedTranslations[$domain]); + // Js files + $scanner = new WPJsScanner( + Translations::create($domain) + ); + foreach (glob($this->getAssetsPath().'js/*.js') as $file) { + $scanner->scanFile($file); + } + foreach (glob($this->getAssetsPath().'js/**/*.js') as $file) { + $scanner->scanFile($file); + } + $scannedTranslations = $scanner->getTranslations(); + if (array_key_exists($domain, $scannedTranslations)) + $translations = $translations->mergeWith($scannedTranslations[$domain]); + // Prepare if (!is_dir($this->config['localize']['path'])) mkdir($this->config['localize']['path'], 0777, true); - if (file_exists($filename)) - unlink($filename); - file_put_contents($filename,implode("\n", $pot)); + // Write pot file + $generator = new PoGenerator(); + $generator->generateFile($translations, $this->config['localize']['path'].$domain.'.pot'); // Print end $this->_print('POT file generated!'); $this->_lineBreak(); @@ -75,77 +87,4 @@ protected function generatePot($textdomain = null, $lang = 'en') throw new NoticeException('Command "'.$this->key.'": Fatal error ocurred.'); } } - /** - * Returns POT basic header. - * @since 1.1.0 - * - * @param string $lang Pot default language. - * @param string $textdomain - * - * @return array - */ - private function getPotHeader($lang, $textdomain) - { - return [ - '# Copyright (C) '.date('Y').' 10 Quality ', - 'msgid ""', - 'msgstr ""', - '"Project-Id-Version: '.$textdomain.'\n"', - '"POT-Creation-Date: '.date('Y-m-d H:i:s').'\n"', - '"PO-Creation-Date: '.date('Y-m-d H:i:s').'\n"', - '"MIME-Version: 1.0\n"', - '"Content-Type: text/plain; charset=UTF-8\n"', - '"Content-Transfer-Encoding: 8bit\n"', - '"X-Generator: WordPress MVC Commands 1.1.0\n"', - '"Language: '.$lang.'\n"', - ]; - } - /** - * Appends a new text translation line to a po file. - * @since 1.1.0 - * - * @param array &$po Po or Pot file. - * @param string $text Text to append. - * @param string $translation Text translation append. - */ - private function appendPotText(&$po, $text, $translation = '') - { - if (!in_array($text, $po)) { - $po[] = ''; - $po[] = 'msgid "'.$text.'"'; - $po[] = 'msgstr "'.$translation.'"'; - } - } - /** - * Evaluates match and appends string to Po/Pot file. - * @since 1.1.0 - * - * @param array &$po Po or Pot file. - * @param string $match String match. - * @param string $string_regex String regex rule. - */ - private function evalPotMatch(&$po, &$match, &$string_regex) - { - if (strpos($match, '_n') !== false) { - preg_match_all($string_regex, $match, $strings ); - for ($i = 0; $i < count($strings[1]); $i++) { - $this->appendPotText($po, $this->parsePotString($strings[1][$i])); - } - } else { - preg_match($string_regex, $match, $strings ); - $this->appendPotText($po, $this->parsePotString($strings[1])); - } - } - /** - * Returns parsed pot string. - * @since 1.1.0 - * - * @param string $string - * - * @return string - */ - private function parsePotString($string) - { - return str_replace('"', '\"', $string); - } } \ No newline at end of file diff --git a/tests/cases/GeneratePotTest.php b/tests/cases/GeneratePotTest.php index 48a09ad..4dd3c49 100644 --- a/tests/cases/GeneratePotTest.php +++ b/tests/cases/GeneratePotTest.php @@ -42,7 +42,7 @@ public function setUp(): void * Test resulting message. * @group pot */ - public function testResultMessage() + public function testGeneration() { // Prepare $filename = FRAMEWORK_PATH.'/environment/assets/lang/my-app.pot'; @@ -52,18 +52,4 @@ public function testResultMessage() $this->assertEquals('POT file generated!', $execution); $this->assertFileExists($filename); } - /** - * Test resulting message. - * @group pot - */ - public function testMultidomainGeneration() - { - // Prepare - $filename = FRAMEWORK_PATH.'/environment/assets/lang/other-domain.pot'; - // Execure - $execution = exec('php '.WPMVC_AYUCO.' generate pot other-domain'); - // Assert - $this->assertEquals('POT file generated!', $execution); - $this->assertFileExists($filename); - } } \ No newline at end of file