diff options
-rw-r--r-- | core/Translation/Transifex/API.php | 140 | ||||
-rw-r--r-- | plugins/LanguagesManager/Commands/CompareKeys.php | 111 | ||||
-rw-r--r-- | plugins/LanguagesManager/Commands/CreatePull.php | 6 | ||||
-rw-r--r-- | plugins/LanguagesManager/Commands/FetchFromOTrance.php | 182 | ||||
-rw-r--r-- | plugins/LanguagesManager/Commands/FetchTranslations.php | 114 | ||||
-rw-r--r-- | plugins/LanguagesManager/Commands/Update.php | 168 | ||||
-rwxr-xr-x | plugins/LanguagesManager/Test/Integration/LanguagesManagerTest.php | 2 |
7 files changed, 360 insertions, 363 deletions
diff --git a/core/Translation/Transifex/API.php b/core/Translation/Transifex/API.php new file mode 100644 index 0000000000..935eba280b --- /dev/null +++ b/core/Translation/Transifex/API.php @@ -0,0 +1,140 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + */ +namespace Piwik\Translation\Transifex; + +use Exception; +use Piwik\Exception\AuthenticationFailedException; +use Piwik\Http; + +class API +{ + protected $apiUrl = 'https://www.transifex.com/api/2/'; + protected $username = ''; + protected $password = ''; + protected $projectSlug = ''; + + public function __construct($username, $password, $project='piwik') + { + $this->username = $username; + $this->password = $password; + $this->projectSlug = $project; + } + + /** + * Returns all resources available on Transifex project + * + * @return array + */ + public function getAvailableResources() + { + static $resources; + + if (empty($resources)) { + $apiPath = 'project/' . $this->projectSlug . '/resources'; + $resources = $this->getApiResults($apiPath); + } + + return $resources; + } + + /** + * Checks if the given resource exists in Transifex project + * + * @param string $resource + * @return bool + */ + public function resourceExists($resource) + { + $resources = $this->getAvailableResources(); + foreach ($resources as $res) { + if ($res->slug == $resource) { + return true; + } + } + return false; + } + + /** + * Returns all language codes the transifex project is available for + * + * @return array + * @throws AuthenticationFailedException + * @throws Exception + */ + public function getAvailableLanguageCodes() + { + static $languageCodes = array(); + if (empty($languageCodes)) { + $apiData = $this->getApiResults('project/' . $this->projectSlug . '/languages'); + foreach ($apiData as $languageData) { + $languageCodes[] = $languageData->language_code; + } + } + return $languageCodes; + } + + /** + * Returns statistic data for the given resource + * + * @param string $resource e.g. piwik-base, piwik-plugin-api,... + * @return array + * @throws AuthenticationFailedException + * @throws Exception + */ + public function getStatistics($resource) + { + return $this->getApiResults('project/' . $this->projectSlug . '/resource/' . $resource . '/stats/'); + } + + /** + * Return the translations for the given resource and language + * + * @param string $resource e.g. piwik-base, piwik-plugin-api,... + * @param string $language e.g. de, pt_BR, hy,... + * @param bool $raw if true plain response wil be returned (unparsed json) + * @return mixed + * @throws AuthenticationFailedException + * @throws Exception + */ + public function getTranslations($resource, $language, $raw=false) + { + if ($this->resourceExists($resource)) { + $apiPath = 'project/' . $this->projectSlug . '/resource/' . $resource . '/translation/' . $language . '/?mode=onlytranslated&file'; + return $this->getApiResults($apiPath, $raw); + } + return null; + } + + /** + * Returns response for API request with given path + * + * @param $apiPath + * @param bool $raw + * @return mixed + * @throws AuthenticationFailedException + * @throws Exception + */ + protected function getApiResults($apiPath, $raw=false) + { + $apiUrl = $this->apiUrl . $apiPath; + + $response = Http::sendHttpRequest($apiUrl, 1000, null, null, 5, false, false, true, 'GET', $this->username, $this->password); + + $httpStatus = $response['status']; + $response = $response['data']; + + if ($httpStatus == 401) { + throw new AuthenticationFailedException(); + } else if ($httpStatus != 200) { + throw new Exception('Error while getting API results', $httpStatus); + } + + return $raw ? $response : json_decode($response); + } +}
\ No newline at end of file diff --git a/plugins/LanguagesManager/Commands/CompareKeys.php b/plugins/LanguagesManager/Commands/CompareKeys.php deleted file mode 100644 index fbbe803a6e..0000000000 --- a/plugins/LanguagesManager/Commands/CompareKeys.php +++ /dev/null @@ -1,111 +0,0 @@ -<?php -/** - * Piwik - free/libre analytics platform - * - * @link http://piwik.org - * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later - * - */ - -namespace Piwik\Plugins\LanguagesManager\Commands; - -use Piwik\Container\StaticContainer; -use Piwik\Translation\Translator; -use Symfony\Component\Console\Input\ArrayInput; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Output\OutputInterface; - -/** - */ -class CompareKeys extends TranslationBase -{ - protected function configure() - { - $this->setName('translations:compare') - ->setDescription('Updates translation files') - ->addOption('username', 'u', InputOption::VALUE_OPTIONAL, 'oTrance username') - ->addOption('password', 'p', InputOption::VALUE_OPTIONAL, 'oTrance password'); - } - - protected function execute(InputInterface $input, OutputInterface $output) - { - $command = $this->getApplication()->find('translations:fetch'); - $arguments = array( - 'command' => 'translations:fetch', - '--username' => $input->getOption('username'), - '--password' => $input->getOption('password'), - '--keep-english' => true, - ); - $inputObject = new ArrayInput($arguments); - $inputObject->setInteractive($input->isInteractive()); - $command->run($inputObject, $output); - - $englishFromOTrance = FetchFromOTrance::getDownloadPath() . DIRECTORY_SEPARATOR . 'en.json'; - - if (!file_exists($englishFromOTrance)) { - $output->writeln("English file from oTrance missing. Aborting"); - return; - } - - $englishFromOTrance = json_decode(file_get_contents($englishFromOTrance), true); - - /** @var Translator $translator */ - $translator = StaticContainer::get('Piwik\Translation\Translator'); - $translator->setCurrentLanguage('en'); - $availableTranslations = $translator->getAllTranslations(); - - $categories = array_unique(array_merge(array_keys($englishFromOTrance), array_keys($availableTranslations))); - sort($categories); - - $unnecessary = $outdated = $missing = array(); - - foreach ($categories as $category) - { - if (!empty($englishFromOTrance[$category])) { - foreach ($englishFromOTrance[$category] as $key => $value) { - if (!array_key_exists($category, $availableTranslations) || !array_key_exists($key, $availableTranslations[$category])) { - $unnecessary[] = sprintf('%s_%s', $category, $key); - continue; - } else if (html_entity_decode($availableTranslations[$category][$key]) != html_entity_decode($englishFromOTrance[$category][$key])) { - $outdated[] = sprintf('%s_%s', $category, $key); - continue; - } - } - } - if (!empty($availableTranslations[$category])) { - foreach ($availableTranslations[$category] as $key => $value) { - if (!array_key_exists($category, $englishFromOTrance) || !array_key_exists($key, $englishFromOTrance[$category])) { - $missing[] = sprintf('%s_%s', $category, $key); - continue; - } - } - } - } - - $output->writeln(""); - - if (!empty($missing)) { - $output->writeln("<bg=yellow;options=bold>-- Following keys are missing on oTrance --</bg=yellow;options=bold>"); - $output->writeln(implode("\n", $missing)); - - $output->writeln(""); - } - - if (!empty($unnecessary)) { - $output->writeln("<bg=yellow;options=bold>-- Following keys might be unnecessary on oTrance --</bg=yellow;options=bold>"); - $output->writeln(implode("\n", $unnecessary)); - - $output->writeln(""); - } - - if (!empty($outdated)) { - $output->writeln("<bg=yellow;options=bold>-- Following keys are outdated on oTrance --</bg=yellow;options=bold>"); - $output->writeln(implode("\n", $outdated)); - - $output->writeln(""); - } - - $output->writeln("Finished."); - } -} diff --git a/plugins/LanguagesManager/Commands/CreatePull.php b/plugins/LanguagesManager/Commands/CreatePull.php index bf208ac332..4436a4ba38 100644 --- a/plugins/LanguagesManager/Commands/CreatePull.php +++ b/plugins/LanguagesManager/Commands/CreatePull.php @@ -23,8 +23,8 @@ class CreatePull extends TranslationBase { $this->setName('translations:createpull') ->setDescription('Updates translation files') - ->addOption('username', 'u', InputOption::VALUE_OPTIONAL, 'oTrance username') - ->addOption('password', 'p', InputOption::VALUE_OPTIONAL, 'oTrance password') + ->addOption('username', 'u', InputOption::VALUE_OPTIONAL, 'Transifex username') + ->addOption('password', 'p', InputOption::VALUE_OPTIONAL, 'Transifex password') ->addOption('plugin', 'P', InputOption::VALUE_OPTIONAL, 'optional name of plugin to update translations for'); } @@ -158,7 +158,7 @@ class CreatePull extends TranslationBase implode(', ', $languageCodesTouched) ); - shell_exec('git commit -m "language update ${pluginName} refs #3430"'); + shell_exec('git commit -m "language update ${pluginName}"'); shell_exec('git push'); shell_exec('git checkout master > /dev/null 2>&1'); diff --git a/plugins/LanguagesManager/Commands/FetchFromOTrance.php b/plugins/LanguagesManager/Commands/FetchFromOTrance.php deleted file mode 100644 index 8802209ced..0000000000 --- a/plugins/LanguagesManager/Commands/FetchFromOTrance.php +++ /dev/null @@ -1,182 +0,0 @@ -<?php -/** - * Piwik - free/libre analytics platform - * - * @link http://piwik.org - * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later - * - */ - -namespace Piwik\Plugins\LanguagesManager\Commands; - -use Piwik\Container\StaticContainer; -use Piwik\Unzip; -use Symfony\Component\Console\Helper\DialogHelper; -use Symfony\Component\Console\Helper\ProgressHelper; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Output\OutputInterface; - -/** - */ -class FetchFromOTrance extends TranslationBase -{ - const DOWNLOAD_PATH = '/oTrance'; - - protected function configure() - { - $path = StaticContainer::get('path.tmp') . self::DOWNLOAD_PATH; - - $this->setName('translations:fetch') - ->setDescription('Fetches translations files from oTrance to ' . $path) - ->addOption('username', 'u', InputOption::VALUE_OPTIONAL, 'oTrance username') - ->addOption('password', 'p', InputOption::VALUE_OPTIONAL, 'oTrance password') - ->addOption('keep-english', 'k', InputOption::VALUE_NONE, 'keep english file'); - } - - protected function execute(InputInterface $input, OutputInterface $output) - { - $output->writeln("Starting to fetch latest language pack"); - - /** @var DialogHelper $dialog */ - $dialog = $this->getHelperSet()->get('dialog'); - - $cookieFile = self::getDownloadPath() . DIRECTORY_SEPARATOR . 'cookie.txt'; - @unlink($cookieFile); - - $username = $input->getOption('username'); - $password = $input->getOption('password'); - - while (!file_exists($cookieFile)) { - if (empty($username)) { - $username = $dialog->ask($output, 'What is your oTrance username? '); - } - - if (empty($password)) { - $password = $dialog->askHiddenResponse($output, 'What is your oTrance password? '); - } - - // send login request to oTrance and save the login cookie - $curl = curl_init('http://translations.piwik.org/public/index/login'); - curl_setopt($curl, CURLOPT_POSTFIELDS, sprintf("user=%s&pass=%s&autologin=1", $username, $password)); - curl_setopt($curl, CURLOPT_COOKIEJAR, $cookieFile); - curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); - curl_exec($curl); - curl_close($curl); - - if (strpos(file_get_contents($cookieFile), 'oTranCe_autologin') !== false) { - break; - } - - $username = null; - $password = null; - @unlink($cookieFile); - $output->writeln("Invalid oTrance credentials. Please try again..."); - } - - // send request to create a new download package using the cookie file - $createNewPackage = true; - if ($input->isInteractive()) { - $createNewPackage = $dialog->askConfirmation($output, 'Shall we create a new language pack? '); - } - - if ($createNewPackage) { - - $curl = curl_init('http://translations.piwik.org/public/export/update.all'); - curl_setopt($curl, CURLOPT_COOKIEFILE, $cookieFile); - curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); - curl_exec($curl); - curl_close($curl); - } - - // request download page to search for available packages - $curl = curl_init('http://translations.piwik.org/public/downloads/'); - curl_setopt($curl, CURLOPT_COOKIEFILE, $cookieFile); - curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); - $response = curl_exec($curl); - curl_close($curl); - - preg_match_all('/language\_pack\-[0-9]{8}\-[0-9]{6}\.tar\.gz/i', $response, $matches); - - if (empty($matches[0])) { - - $output->writeln("No packages found for download. Please try again."); - return; - } - - $downloadPackage = array_shift($matches[0]); - - $continueWithPackage = true; - if ($input->isInteractive()) { - $continueWithPackage = $dialog->askConfirmation($output, "Found language pack $downloadPackage. Proceed? "); - } - - if (!$continueWithPackage) { - - $output->writeln('Aborted.'); - return; - } - - // download language pack - $packageHandle = fopen(self::getDownloadPath() . DIRECTORY_SEPARATOR . 'language_pack.tar.gz', 'w'); - $curl = curl_init('http://translations.piwik.org/public/downloads/download/file/'.$downloadPackage); - curl_setopt($curl, CURLOPT_COOKIEFILE, self::getDownloadPath() . DIRECTORY_SEPARATOR . 'cookie.txt'); - curl_setopt($curl, CURLOPT_FILE, $packageHandle); - curl_exec($curl); - curl_close($curl); - - @unlink($cookieFile); - - $output->writeln("Extracting package..."); - - $unzipper = Unzip::factory('tar.gz', self::getDownloadPath() . DIRECTORY_SEPARATOR . 'language_pack.tar.gz'); - $unzipper->extract(self::getDownloadPath()); - - if (!$input->getOption('keep-english')) { - @unlink(self::getDownloadPath() . DIRECTORY_SEPARATOR . 'en.php'); - @unlink(self::getDownloadPath() . DIRECTORY_SEPARATOR . 'en.json'); - } - @unlink(self::getDownloadPath() . DIRECTORY_SEPARATOR . 'language_pack.tar.gz'); - - $filesToConvert = _glob(self::getDownloadPath() . DIRECTORY_SEPARATOR . '*.php'); - - $output->writeln("Converting downloaded php files to json"); - - /** @var ProgressHelper $progress */ - $progress = $this->getHelperSet()->get('progress'); - - $progress->start($output, count($filesToConvert)); - foreach ($filesToConvert as $filename) { - - require_once $filename; - $basename = explode(".", basename($filename)); - $nested = array(); - foreach ($translations as $key => $value) { - list($plugin, $nkey) = explode("_", $key, 2); - $nested[$plugin][$nkey] = $value; - } - $translations = $nested; - $data = json_encode($translations, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); - $newFile = sprintf("%s/%s.json", self::getDownloadPath(), $basename[0]); - file_put_contents($newFile, $data); - @unlink($filename); - - $progress->advance(); - } - - $progress->finish(); - - $output->writeln("Finished fetching new language files from oTrance"); - } - - public static function getDownloadPath() - { - $path = StaticContainer::get('path.tmp') . self::DOWNLOAD_PATH; - - if (!is_dir($path)) { - mkdir($path); - } - - return $path; - } -} diff --git a/plugins/LanguagesManager/Commands/FetchTranslations.php b/plugins/LanguagesManager/Commands/FetchTranslations.php new file mode 100644 index 0000000000..532d1061d8 --- /dev/null +++ b/plugins/LanguagesManager/Commands/FetchTranslations.php @@ -0,0 +1,114 @@ +<?php +/** + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * + */ + +namespace Piwik\Plugins\LanguagesManager\Commands; + +use Piwik\Container\StaticContainer; +use Piwik\Plugins\LanguagesManager\API as LanguagesManagerApi; +use Piwik\Translation\Transifex\API; +use Symfony\Component\Console\Helper\ProgressHelper; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +/** + */ +class FetchTranslations extends TranslationBase +{ + const DOWNLOAD_PATH = '/transifex'; + + protected function configure() + { + $path = StaticContainer::get('path.tmp') . self::DOWNLOAD_PATH; + + $this->setName('translations:fetch') + ->setDescription('Fetches translations files from Transifex to ' . $path) + ->addOption('username', 'u', InputOption::VALUE_OPTIONAL, 'Transifex username') + ->addOption('password', 'p', InputOption::VALUE_OPTIONAL, 'Transifex password') + ->addOption('lastupdate', 'l', InputOption::VALUE_OPTIONAL, 'Last time update ran', time()-30*24*3600) + ->addOption('plugin', 'r', InputOption::VALUE_OPTIONAL, 'Plugin to update'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $username = $input->getOption('username'); + $password = $input->getOption('password'); + $plugin = $input->getOption('plugin'); + $lastUpdate = $input->getOption('lastupdate'); + + $resource = 'piwik-'. ($plugin ? 'plugin-'.strtolower($plugin) : 'base'); + + $transifexApi = new API($username, $password); + + // remove all existing translation files in download path + $files = glob($this->getDownloadPath() . DIRECTORY_SEPARATOR . '*.json'); + array_map('unlink', $files); + + if (!$transifexApi->resourceExists($resource)) { + $output->writeln("Skipping resource $resource as it doesn't exist on Transifex"); + return; + } + + $output->writeln("Fetching translations from Transifex for resource $resource"); + + $languages = $transifexApi->getAvailableLanguageCodes(); + + if (!empty($plugin)) { + $languages = array_filter($languages, function($language) { + return LanguagesManagerApi::getInstance()->isLanguageAvailable(str_replace('_', '-', strtolower($language))); + }); + } + + $availableLanguages = LanguagesManagerApi::getInstance()->getAvailableLanguageNames(); + + $languageCodes = array(); + foreach ($availableLanguages as $languageInfo) { + $languageCodes[] = $languageInfo['code']; + } + + /** @var ProgressHelper $progress */ + $progress = $this->getHelperSet()->get('progress'); + + $progress->start($output, count($languages)); + + $statistics = $transifexApi->getStatistics($resource); + + foreach ($languages as $language) { + try { + // if we have modification date given from statistics api compare it with given last update time to ignore not update resources + if (LanguagesManagerApi::getInstance()->isLanguageAvailable(str_replace('_', '-', strtolower($language))) && isset($statistics->$language)) { + $lastupdated = strtotime($statistics->$language->last_update); + if ($lastUpdate > $lastupdated) { + $progress->advance(); + continue; + } + } + + $translations = $transifexApi->getTranslations($resource, $language, true); + file_put_contents($this->getDownloadPath() . DIRECTORY_SEPARATOR . str_replace('_', '-', strtolower($language)) . '.json', $translations); + } catch (\Exception $e) { + $output->writeln("Error fetching language file $language: " . $e->getMessage()); + } + $progress->advance(); + } + + $progress->finish(); + } + + public static function getDownloadPath() + { + $path = StaticContainer::get('path.tmp') . self::DOWNLOAD_PATH; + + if (!is_dir($path)) { + mkdir($path); + } + + return $path; + } +} diff --git a/plugins/LanguagesManager/Commands/Update.php b/plugins/LanguagesManager/Commands/Update.php index 4d0c28bd76..2539ab0e77 100644 --- a/plugins/LanguagesManager/Commands/Update.php +++ b/plugins/LanguagesManager/Commands/Update.php @@ -26,26 +26,19 @@ class Update extends TranslationBase { $this->setName('translations:update') ->setDescription('Updates translation files') - ->addOption('username', 'u', InputOption::VALUE_OPTIONAL, 'oTrance username') - ->addOption('password', 'p', InputOption::VALUE_OPTIONAL, 'oTrance password') + ->addOption('force', 'f', InputOption::VALUE_NONE, 'Force update of all language files') + ->addOption('username', 'u', InputOption::VALUE_OPTIONAL, 'Transifex username') + ->addOption('password', 'p', InputOption::VALUE_OPTIONAL, 'Transifex password') ->addOption('plugin', 'P', InputOption::VALUE_OPTIONAL, 'optional name of plugin to update translations for'); } protected function execute(InputInterface $input, OutputInterface $output) { + $start = microtime(true); + /** @var DialogHelper $dialog */ $dialog = $this->getHelperSet()->get('dialog'); - $command = $this->getApplication()->find('translations:fetch'); - $arguments = array( - 'command' => 'translations:fetch', - '--username' => $input->getOption('username'), - '--password' => $input->getOption('password') - ); - $inputObject = new ArrayInput($arguments); - $inputObject->setInteractive($input->isInteractive()); - $command->run($inputObject, $output); - $languages = API::getInstance()->getAvailableLanguageNames(); $languageCodes = array(); @@ -55,79 +48,78 @@ class Update extends TranslationBase $plugin = $input->getOption('plugin'); - $files = _glob(FetchFromOTrance::getDownloadPath() . DIRECTORY_SEPARATOR . '*.json'); - - $output->writeln("Starting to import new language files"); - if (!$input->isInteractive()) { $output->writeln("(!) Non interactive mode: New languages will be skipped"); } - /** @var ProgressHelper $progress */ - $progress = $this->getHelperSet()->get('progress'); + $pluginList = array($plugin); + if (empty($plugin)) { + $pluginList = self::getPluginsInCore(); + array_unshift($pluginList, ''); + } - $progress->start($output, count($files)); + foreach ($pluginList as $plugin) { - foreach ($files as $filename) { + $output->writeln(""); - $progress->advance(); + // fetch base or specific plugin + $this->fetchTranslations($input, $output, $plugin); - $code = basename($filename, '.json'); + $files = _glob(FetchTranslations::getDownloadPath() . DIRECTORY_SEPARATOR . '*.json'); - if (!in_array($code, $languageCodes)) { + if (count($files) == 0) { + $output->writeln("No translation updates available! Skipped."); + continue; + } - if (!empty($plugin)) { + $output->writeln("Starting to import new language files"); - continue; # never create a new language for plugin only - } + /** @var ProgressHelper $progress */ + $progress = $this->getHelperSet()->get('progress'); - $createNewFile = false; - if ($input->isInteractive()) { - $createNewFile = $dialog->askConfirmation($output, "\nLanguage $code does not exist. Should it be added? ", false); - } + $progress->start($output, count($files)); - if (!$createNewFile) { + foreach ($files as $filename) { - continue; # do not create a new file for the language - } + $progress->advance(); - @touch(PIWIK_DOCUMENT_ROOT . DIRECTORY_SEPARATOR . 'lang' . DIRECTORY_SEPARATOR . $code . '.json'); - API::unsetInstance(); // unset language manager instance, so valid names are refetched - } + $code = basename($filename, '.json'); + + if (!in_array($code, $languageCodes)) { + + if (!empty($plugin)) { + continue; # never create a new language for plugin only + } + + $createNewFile = false; + if ($input->isInteractive()) { + $createNewFile = $dialog->askConfirmation($output, "\nLanguage $code does not exist. Should it be added? ", false); + } + + if (!$createNewFile) { + continue; # do not create a new file for the language + } - $command = $this->getApplication()->find('translations:set'); - $arguments = array( - 'command' => 'translations:set', - '--code' => $code, - '--file' => $filename, - '--plugin' => $plugin - ); - $inputObject = new ArrayInput($arguments); - $inputObject->setInteractive($input->isInteractive()); - $command->run($inputObject, new NullOutput()); - - // update core modules that aren't in their own repo - if (empty($plugin)) { - - foreach (self::getPluginsInCore() as $pluginName) { - - // update translation files - $command = $this->getApplication()->find('translations:set'); - $arguments = array( - 'command' => 'translations:set', - '--code' => $code, - '--file' => $filename, - '--plugin' => $pluginName - ); - $inputObject = new ArrayInput($arguments); - $inputObject->setInteractive($input->isInteractive()); - $command->run($inputObject, new NullOutput()); + @touch(PIWIK_DOCUMENT_ROOT . DIRECTORY_SEPARATOR . 'lang' . DIRECTORY_SEPARATOR . $code . '.json'); + API::unsetInstance(); // unset language manager instance, so valid names are refetched } + + $command = $this->getApplication()->find('translations:set'); + $arguments = array( + 'command' => 'translations:set', + '--code' => $code, + '--file' => $filename, + '--plugin' => $plugin + ); + $inputObject = new ArrayInput($arguments); + $inputObject->setInteractive($input->isInteractive()); + $command->run($inputObject, new NullOutput()); } + + $progress->finish(); } - $progress->finish(); - $output->writeln("Finished."); + $output->writeln("Finished in " . round(microtime(true)-$start, 3) . "s"); } /** @@ -154,7 +146,7 @@ class Update extends TranslationBase $pluginsNotInCore = array_merge($submodulePlugins, $newPlugins); $pluginsWithTranslations = glob(sprintf('%s/plugins/*/lang/en.json', PIWIK_INCLUDE_PATH)); - $pluginsWithTranslations = array_map(function($elem){ + $pluginsWithTranslations = array_map(function ($elem) { return str_replace(array(sprintf('%s/plugins/', PIWIK_INCLUDE_PATH), '/lang/en.json'), '', $elem); }, $pluginsWithTranslations); @@ -162,4 +154,48 @@ class Update extends TranslationBase return $pluginsInCore; } + + /** + * @param InputInterface $input + * @param OutputInterface $output + * @param string $plugin + * @throws \Exception + */ + protected function fetchTranslations(InputInterface $input, OutputInterface $output, $plugin) + { + + $command = $this->getApplication()->find('translations:fetch'); + $arguments = array( + 'command' => 'translations:fetch', + '--username' => $input->getOption('username'), + '--password' => $input->getOption('password'), + '--plugin' => $plugin + ); + + if ($input->getOption('force')) { + $arguments['--lastupdate'] = 1; + } else { + $lastModDate = strtotime('2015-01-04 00:00:00'); // date of inital transifex setup + try { + // try to find the language file (of given plugin) with the newest modification date in git log + $path = ($plugin ? 'plugins/' . $plugin . '/' : '') . 'lang'; + $files = explode("\n", trim(shell_exec('git ls-tree -r --name-only HEAD ' . $path))); + + foreach ($files as $file) { + $fileModDate = shell_exec('git log -1 --format="%at" -- ' . $file); + if (basename($file) != 'en.json' && $fileModDate > $lastModDate) { + $lastModDate = $fileModDate; + } + } + } catch (\Exception $e) { + } + + if ($lastModDate != 0) { + $arguments['--lastupdate'] = $lastModDate; + } + } + $inputObject = new ArrayInput($arguments); + $inputObject->setInteractive($input->isInteractive()); + $command->run($inputObject, $output); + } } diff --git a/plugins/LanguagesManager/Test/Integration/LanguagesManagerTest.php b/plugins/LanguagesManager/Test/Integration/LanguagesManagerTest.php index 1573d4ec37..1d0b74f3bf 100755 --- a/plugins/LanguagesManager/Test/Integration/LanguagesManagerTest.php +++ b/plugins/LanguagesManager/Test/Integration/LanguagesManagerTest.php @@ -97,7 +97,7 @@ class LanguagesManagerTest extends \PHPUnit_Framework_TestCase $translationWriter->saveTemporary(); $this->markTestSkipped(implode("\n", $translationWriter->getFilterMessages()) . "\n" . 'Translation file errors detected in ' . $language . "...\n" - . "To synchronise the language files with the english strings, you can manually edit the language files or run the following command may work if you have access to oTrance: \n" + . "To synchronise the language files with the english strings, you can manually edit the language files or run the following command may work if you have access to Transifex: \n" . "$ ./console translations:update [--plugin=XYZ] \n" ); } |