From defa52c0ed16282a330c6f3d4837c69fa60c637a Mon Sep 17 00:00:00 2001 From: Demian Katz <demian.katz@villanova.edu> Date: Mon, 22 Feb 2016 14:49:53 -0500 Subject: [PATCH] Added CLI tool for building language strings from templates. --- module/VuFindConsole/Module.php | 2 + .../Controller/LanguageController.php | 106 +++++++++++++++++- 2 files changed, 104 insertions(+), 4 deletions(-) diff --git a/module/VuFindConsole/Module.php b/module/VuFindConsole/Module.php index ddc1ecc4dff..403783eaac3 100644 --- a/module/VuFindConsole/Module.php +++ b/module/VuFindConsole/Module.php @@ -86,6 +86,8 @@ class Module implements \Zend\ModuleManager\Feature\ConsoleUsageProviderInterfac 'harvest merge-marc' => 'MARC merge tool', 'import import-xsl' => 'XSLT importer', 'import webcrawl' => 'Web crawler', + 'language addusingtemplate' => 'Build new language strings from ' + . 'existing ones using a template', 'language copystring' => 'Copy one language string to another', 'language delete' => 'Remove a language string from all files', 'language normalize' => 'Normalize a directory of language files', diff --git a/module/VuFindConsole/src/VuFindConsole/Controller/LanguageController.php b/module/VuFindConsole/src/VuFindConsole/Controller/LanguageController.php index 0471d70095e..25b9a8916cb 100644 --- a/module/VuFindConsole/src/VuFindConsole/Controller/LanguageController.php +++ b/module/VuFindConsole/src/VuFindConsole/Controller/LanguageController.php @@ -105,6 +105,101 @@ class LanguageController extends AbstractBase return $this->getSuccessResponse(); } + /** + * Assemble a new language string by combining existing ones using a + * template. + * + * @return \Zend\Console\Response + */ + public function addusingtemplateAction() + { + // Display help message if parameters missing: + $argv = $this->consoleOpts->getRemainingArgs(); + if (!isset($argv[1])) { + Console::writeLine( + "Usage: {$_SERVER['argv'][0]} [target] [template]" + ); + Console::writeLine( + "\ttarget - the target key to add " + . "(may include 'textdomain::' prefix)\n" + . "\ttemplate - the template to build the string, using ||string||" + . " to import existing strings" + ); + return $this->getFailureResponse(); + } + + // Make sure a valid target has been specified: + list($targetDomain, $targetKey) = $this->extractTextDomain($argv[0]); + if (!($targetDir = $this->getLangDir($targetDomain, true))) { + return $this->getFailureResponse(); + } + + // Extract required source values from template: + $template = $argv[1]; + preg_match_all('/\|\|[^|]+\|\|/', $template, $matches); + $lookups = []; + foreach ($matches[0] as $current) { + $key = trim($current, '|'); + list($sourceDomain, $sourceKey) = $this->extractTextDomain($key); + $lookups[$sourceDomain][$current] = [ + 'key' => $sourceKey, + 'translations' => [] + ]; + } + + // Look up translations of all references in template: + $reader = new ExtendedIniReader(); + foreach ($lookups as $domain => & $tokens) { + $sourceDir = $this->getLangDir($domain, false); + if (!$sourceDir) { + return $this->getFailureResponse(); + } + $sourceCallback = function ($full) use ( + $domain, & $tokens, $reader + ) { + $strings = $reader->getTextDomain($full, false); + foreach ($tokens as & $current) { + $sourceKey = $current['key']; + if (isset($strings[$sourceKey])) { + $current['translations'][basename($full)] + = $strings[$sourceKey]; + } + } + }; + $this->processDirectory($sourceDir, $sourceCallback, false); + } + + // Fill in template, write results: + $normalizer = new ExtendedIniNormalizer(); + $targetCallback = function ($full) use ( + $template, $targetKey, $normalizer, $lookups + ) { + $lang = basename($full); + $in = $out = []; + foreach ($lookups as $domain => $tokens) { + foreach ($tokens as $token => $details) { + if (isset($details['translations'][$lang])) { + $in[] = $token; + $out[] = $details['translations'][$lang]; + } else { + Console::writeLine( + 'Skipping; no match for token: ' . $token + ); + return; + } + } + } + $fHandle = fopen($full, "a"); + fputs( + $fHandle, + "\n$targetKey = \"" . str_replace($in, $out, $template) . "\"\n" + ); + fclose($fHandle); + $normalizer->normalizeFile($full); + }; + $this->processDirectory($targetDir, $targetCallback); + } + /** * Delete a language string to another * @@ -242,17 +337,20 @@ class LanguageController extends AbstractBase /** * Process a language directory. * - * @param object $dir Directory object from dir() to process - * @param Callable $callback Function to run on all .ini files in $dir + * @param object $dir Directory object from dir() to process + * @param Callable $callback Function to run on all .ini files in $dir + * @param bool $showStatus Should we display status messages? * * @return void */ - protected function processDirectory($dir, $callback) + protected function processDirectory($dir, $callback, $showStatus = true) { while ($file = $dir->read()) { // Only process .ini files, and ignore native.ini special case file: if (substr($file, -4) == '.ini' && $file !== 'native.ini') { - Console::writeLine("Processing $file..."); + if ($showStatus) { + Console::writeLine("Processing $file..."); + } $callback($dir->path . '/' . $file); } } -- GitLab