setName(self::NAME)
->addOption('language', null, InputOption::VALUE_OPTIONAL, 'Optional language to pull', null)
->addOption('bundle', null, InputOption::VALUE_OPTIONAL, 'Optional bundle to pull. Example value: WebhookBundle', null)
->addOption('path', null, InputOption::VALUE_OPTIONAL, 'Optional path to a directory where to store the traslations.', null)
->setHelp(<<<'EOT'
The %command.name% command is used to retrieve updated Mautic translations from Transifex and writes them to the filesystem.
php %command.full_name%
The command can optionally only pull files for a specific language with the --language option
php %command.full_name% --language=
EOT
);
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$languageFilter = $input->getOption('language');
$bundleFilter = $input->getOption('bundle');
$path = $input->getOption('path');
$files = $this->languageHelper->getLanguageFiles();
$translationDir = ($path ?? $this->pathsHelper->getTranslationsPath()).'/';
try {
$transifex = $this->transifexFactory->getTransifex();
} catch (InvalidConfigurationException) {
$output->writeln($this->translator->trans('mautic.core.command.transifex_no_credentials'));
return Command::FAILURE;
}
$statistics = $transifex->getConnector(Statistics::class);
\assert($statistics instanceof Statistics);
$translations = $transifex->getConnector(Translations::class);
\assert($translations instanceof Translations);
/** @var \SplQueue $queue */
$queue = new \SplQueue();
foreach ($files as $bundle => $stringFiles) {
if ($bundleFilter && $bundle !== $bundleFilter) {
continue;
}
foreach ($stringFiles as $file) {
$name = $bundle.' '.str_replace('.ini', '', basename($file));
$resource = UrlHelper::stringURLUnicodeSlug($name);
$output->writeln($this->translator->trans('mautic.core.command.transifex_processing_resource', ['%resource%' => $name]));
try {
$response = $statistics->getLanguageStats($resource);
$languageStats = json_decode((string) $response->getBody(), true);
foreach ($languageStats['data'] as $stats) {
$language = ltrim($stats['relationships']['language']['data']['id'], 'l:');
if ('en' === $language) {
continue;
}
// If we are filtering on a specific language, skip anything that doesn't match
if ($languageFilter && $languageFilter !== $language) {
continue;
}
$output->writeln($this->translator->trans('mautic.core.command.transifex_processing_language', ['%language%' => $language]));
$completed = $stats['attributes']['translated_strings'] / $stats['attributes']['total_strings'];
// We only want resources which are 80% completed
if ($completed >= 0.8) {
$path = $translationDir.$language.'/'.$bundle.'/'.basename($file);
try {
$promise = $transifex->getApiConnector()->createPromise($translations->download($resource, $language));
$promise->setFilePath($path);
$queue->enqueue($promise);
} catch (ResponseException $responseException) {
$output->writeln($this->translator->trans($responseException->getMessage()));
}
}
}
} catch (\Exception $exception) {
$output->writeln($this->translator->trans('mautic.core.command.transifex_error_pulling_data', ['%message%' => $exception->getMessage()]));
return Command::FAILURE;
}
}
}
$transifex->getApiConnector()->fulfillPromises(
$queue,
function (ResponseInterface $response, Promise $promise) use ($output): void {
try {
$this->languageHelper->createLanguageFile($promise->getFilePath(), $response->getBody()->__toString());
} catch (\Exception $exception) {
$output->writeln($exception->getMessage());
}
},
function (ResponseException $exception) use ($output): void {
$output->writeln($exception->getMessage());
}
);
$output->writeln($this->translator->trans('mautic.core.command.transifex_resource_downloaded'));
return Command::SUCCESS;
}
protected static $defaultDescription = 'Fetches translations for Mautic from Transifex';
}