new command to work with translation files (#2993)
This commit is contained in:
135
src/Command/TranslationCommand.php
Normal file
135
src/Command/TranslationCommand.php
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Kimai time-tracking app.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use App\Kernel;
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command used to execute all the basic application bootstrapping AFTER "composer install" was executed.
|
||||||
|
*
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
*/
|
||||||
|
class TranslationCommand extends Command
|
||||||
|
{
|
||||||
|
private $projectDirectory;
|
||||||
|
private $environment;
|
||||||
|
|
||||||
|
public function __construct(string $projectDirectory, string $kernelEnvironment)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
$this->projectDirectory = $projectDirectory;
|
||||||
|
$this->environment = $kernelEnvironment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this
|
||||||
|
->setName('kimai:translations')
|
||||||
|
->setDescription('Translation adjustments')
|
||||||
|
->addOption('resname', null, InputOption::VALUE_NONE, 'Fix the resname vs. id attribute')
|
||||||
|
->addOption('duplicates', null, InputOption::VALUE_NONE, 'Find duplicate translation keys')
|
||||||
|
->addOption('extension', null, InputOption::VALUE_NONE, 'Find translation files with wrong extensions')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isEnabled(): bool
|
||||||
|
{
|
||||||
|
return $this->environment !== 'prod';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): ?int
|
||||||
|
{
|
||||||
|
$io = new SymfonyStyle($input, $output);
|
||||||
|
|
||||||
|
$bases = [
|
||||||
|
'core' => $this->projectDirectory . '/translations',
|
||||||
|
'plugins' => $this->projectDirectory . Kernel::PLUGIN_DIRECTORY . '/*/Resources/translations',
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($input->getOption('resname')) {
|
||||||
|
foreach ($bases as $id => $directory) {
|
||||||
|
$files = glob($directory . '/*.xlf');
|
||||||
|
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$this->fixXlfFile($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($input->getOption('extension')) {
|
||||||
|
foreach ($bases as $id => $directory) {
|
||||||
|
$files = glob($directory . '/*.xliff');
|
||||||
|
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$file = str_replace($this->projectDirectory, '', $file);
|
||||||
|
$io->warning($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($input->getOption('duplicates')) {
|
||||||
|
$duplicates = [];
|
||||||
|
|
||||||
|
$files = glob($bases['core'] . '/*.xlf');
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$xml = simplexml_load_file($file);
|
||||||
|
foreach ($xml->file->body->{'trans-unit'} as $unit) {
|
||||||
|
$n = (string) $unit['resname'];
|
||||||
|
if (!\array_key_exists($n, $duplicates)) {
|
||||||
|
$duplicates[$n] = [];
|
||||||
|
}
|
||||||
|
$b = explode('.', basename($file))[0];
|
||||||
|
if (!\in_array($b, $duplicates[$n])) {
|
||||||
|
$duplicates[$n][] = $b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($duplicates as $id => $files) {
|
||||||
|
if (\count($files) > 1) {
|
||||||
|
$io->text($id . ' => ' . implode(', ', $files));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function fixXlfFile(string $file): void
|
||||||
|
{
|
||||||
|
$xml = simplexml_load_file($file);
|
||||||
|
if (isset($xml->file->header)) {
|
||||||
|
unset($xml->file->header);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($xml->file->body->{'trans-unit'} as $unit) {
|
||||||
|
$source = $unit->source;
|
||||||
|
if (!isset($unit['resname'])) {
|
||||||
|
$unit['resname'] = $source;
|
||||||
|
}
|
||||||
|
$unit['id'] = strtr(substr(base64_encode(hash('sha256', $source, true)), 0, 7), '/+', '._');
|
||||||
|
}
|
||||||
|
|
||||||
|
$xmlDocument = new \DOMDocument('1.0');
|
||||||
|
$xmlDocument->preserveWhiteSpace = false;
|
||||||
|
$xmlDocument->formatOutput = true;
|
||||||
|
$xmlDocument->loadXML($xml->asXML());
|
||||||
|
|
||||||
|
file_put_contents($file, $xmlDocument->saveXML());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,6 +45,7 @@ class Kernel extends BaseKernel
|
|||||||
{
|
{
|
||||||
use MicroKernelTrait;
|
use MicroKernelTrait;
|
||||||
|
|
||||||
|
public const PLUGIN_DIRECTORY = '/var/plugins';
|
||||||
public const CONFIG_EXTS = '.{php,xml,yaml,yml}';
|
public const CONFIG_EXTS = '.{php,xml,yaml,yml}';
|
||||||
|
|
||||||
public const TAG_PLUGIN = 'kimai.plugin';
|
public const TAG_PLUGIN = 'kimai.plugin';
|
||||||
@@ -128,7 +129,7 @@ class Kernel extends BaseKernel
|
|||||||
|
|
||||||
private function getBundleClasses(): array
|
private function getBundleClasses(): array
|
||||||
{
|
{
|
||||||
$pluginsDir = $this->getProjectDir() . '/var/plugins';
|
$pluginsDir = $this->getProjectDir() . self::PLUGIN_DIRECTORY;
|
||||||
if (!file_exists($pluginsDir)) {
|
if (!file_exists($pluginsDir)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user