From c27a5315318b91f4627a206e2851da9055b07ad2 Mon Sep 17 00:00:00 2001 From: Kamil Maliszewski Date: Fri, 31 Jan 2020 12:42:38 +0100 Subject: [PATCH 01/13] [FEATURE] Add tags for each language label --- Classes/Database/Database87.php | 6 +++-- Classes/Domain/Model/Label.php | 23 +++++++++++++++++++ .../TCA/tx_translatr_domain_model_label.php | 14 +++++++++-- .../Private/Backend/Templates/Label/List.html | 5 ++-- ...ng_csh_tx_translatr_domain_model_label.xlf | 5 +++- Resources/Private/Language/locallang_db.xlf | 3 +++ ext_tables.sql | 1 + 7 files changed, 50 insertions(+), 7 deletions(-) diff --git a/Classes/Database/Database87.php b/Classes/Database/Database87.php index 04f8cf7..f5c09e4 100644 --- a/Classes/Database/Database87.php +++ b/Classes/Database/Database87.php @@ -61,7 +61,8 @@ public function findDemandedForBe(BeLabelDemand $demand) label.ukey, 0 AS parent_uid, label.text, - label.ll_file + label.ll_file, + label.tags FROM tx_translatr_domain_model_label AS label WHERE label.language = "default" AND label.deleted = 0 @@ -74,7 +75,8 @@ public function findDemandedForBe(BeLabelDemand $demand) label.ukey, parent.uid AS parent_uid, label.text, - label.ll_file + label.ll_file, + label.tags FROM tx_translatr_domain_model_label AS label LEFT JOIN tx_translatr_domain_model_label AS parent ON (parent.language = "default" AND parent.ukey = label.ukey AND parent.ll_file = label.ll_file) diff --git a/Classes/Domain/Model/Label.php b/Classes/Domain/Model/Label.php index 24eb1ea..6010e94 100644 --- a/Classes/Domain/Model/Label.php +++ b/Classes/Domain/Model/Label.php @@ -61,6 +61,13 @@ class Label extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity */ protected $description = ''; + /** + * tags + * + * @var string + */ + protected $tags = ''; + /** * @var string */ @@ -211,4 +218,20 @@ public function setLanguage($language) { $this->language = $language; } + + /** + * @return string + */ + public function getTags() + { + return $this->tags; + } + + /** + * @param string $tags + */ + public function setTags($tags) + { + $this->tags = $tags; + } } diff --git a/Configuration/TCA/tx_translatr_domain_model_label.php b/Configuration/TCA/tx_translatr_domain_model_label.php index b57ba1e..e84f63c 100644 --- a/Configuration/TCA/tx_translatr_domain_model_label.php +++ b/Configuration/TCA/tx_translatr_domain_model_label.php @@ -25,7 +25,7 @@ 'showRecordFieldList' => 'extension, ukey, text, description, ll_file', ], 'types' => [ - '1' => ['showitem' => 'text, description, language, extension, ll_file, ukey, --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.access, starttime, endtime'], + '1' => ['showitem' => 'text, description, tags, language, extension, ll_file, ukey, --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.access, starttime, endtime'], ], 'palettes' => [ '1' => ['showitem' => ''], @@ -125,6 +125,16 @@ 'type' => 'user', 'userFunc' => \SourceBroker\Translatr\UserFunc\TcaFieldHidden::class . '->display', ], - ] + ], + 'tags' => [ + 'exclude' => 1, + 'label' => 'LLL:EXT:translatr/Resources/Private/Language/locallang_db.xlf:tx_translatr_domain_model_label.tags', + 'config' => [ + 'type' => 'text', + 'cols' => 40, + 'rows' => 1, + 'eval' => 'trim', + ], + ], ], ]; diff --git a/Resources/Private/Backend/Templates/Label/List.html b/Resources/Private/Backend/Templates/Label/List.html index 450db79..26de8ce 100644 --- a/Resources/Private/Backend/Templates/Label/List.html +++ b/Resources/Private/Backend/Templates/Label/List.html @@ -12,7 +12,6 @@ - @@ -22,6 +21,7 @@ + @@ -77,6 +77,7 @@ + @@ -84,4 +85,4 @@ - \ No newline at end of file + diff --git a/Resources/Private/Language/locallang_csh_tx_translatr_domain_model_label.xlf b/Resources/Private/Language/locallang_csh_tx_translatr_domain_model_label.xlf index ce8dd80..fcf3beb 100644 --- a/Resources/Private/Language/locallang_csh_tx_translatr_domain_model_label.xlf +++ b/Resources/Private/Language/locallang_csh_tx_translatr_domain_model_label.xlf @@ -19,6 +19,9 @@ Locallang relative path + + Tags + - \ No newline at end of file + diff --git a/Resources/Private/Language/locallang_db.xlf b/Resources/Private/Language/locallang_db.xlf index d795f06..c0f99d7 100644 --- a/Resources/Private/Language/locallang_db.xlf +++ b/Resources/Private/Language/locallang_db.xlf @@ -25,6 +25,9 @@ Language + + Tags (comma separated) + diff --git a/ext_tables.sql b/ext_tables.sql index 1a5a624..4f37682 100644 --- a/ext_tables.sql +++ b/ext_tables.sql @@ -10,6 +10,7 @@ CREATE TABLE tx_translatr_domain_model_label ( ukey varchar(255) DEFAULT '' NOT NULL, text text NOT NULL, description text NOT NULL, + tags text NOT NULL, ll_file varchar(255) DEFAULT '' NOT NULL, ll_file_index varchar(100) DEFAULT '' NOT NULL, language varchar(31) DEFAULT '' NOT NULL, From f88ba7729eea97a1935eba627504bf3e46f4522f Mon Sep 17 00:00:00 2001 From: Kamil Maliszewski Date: Fri, 31 Jan 2020 17:26:01 +0100 Subject: [PATCH 02/13] [FEATURE] Implementation of tags and imports from .yaml files --- Classes/Command/ImportTagsCommand.php | 55 +++++++ Classes/Command/LanguagePackCommand.php | 82 +++++++++++ Classes/Configuration/Commands.php | 13 ++ Classes/Domain/Repository/LabelRepository.php | 18 +++ Classes/Service/Tags/ImportProcess.php | 69 +++++++++ Classes/Service/Tags/YamlFileHandler.php | 137 ++++++++++++++++++ Configuration/Commands.php | 13 ++ 7 files changed, 387 insertions(+) create mode 100644 Classes/Command/ImportTagsCommand.php create mode 100644 Classes/Command/LanguagePackCommand.php create mode 100644 Classes/Configuration/Commands.php create mode 100644 Classes/Service/Tags/ImportProcess.php create mode 100644 Classes/Service/Tags/YamlFileHandler.php create mode 100644 Configuration/Commands.php diff --git a/Classes/Command/ImportTagsCommand.php b/Classes/Command/ImportTagsCommand.php new file mode 100644 index 0000000..44cdd7c --- /dev/null +++ b/Classes/Command/ImportTagsCommand.php @@ -0,0 +1,55 @@ +setAliases(['lang:fe:tags']); + $this->setDescription('Import labels tags from config file into Translatr'); + $this->objectManger = GeneralUtility::makeInstance(ObjectManager::class); + $this->importProcessService = $this->objectManger->get(ImportProcess::class); + } + + /** + * + * @param InputInterface $input + * @param OutputInterface $output + * @return int + */ + protected function execute(InputInterface $input, OutputInterface $output): int + { +// $output->writeln('Works'); + $this->importProcessService->import($output); + + return 0; + } +} diff --git a/Classes/Command/LanguagePackCommand.php b/Classes/Command/LanguagePackCommand.php new file mode 100644 index 0000000..fe37889 --- /dev/null +++ b/Classes/Command/LanguagePackCommand.php @@ -0,0 +1,82 @@ +setAliases(['lang:frontend:import']); + $this->setDescription('Import labels from config file into Translatr'); + } + + /** + * Update language packs of all active languages for all active extensions + * + * @param InputInterface $input + * @param OutputInterface $output + * @throws \InvalidArgumentException + * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException + * @return int + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + + $languagePackService = GeneralUtility::makeInstance(LanguagePackService::class); + + try { + $isos = $input->getArgument('locales'); + } catch (\Exception $e) { + $isos = []; + } + if (empty($isos)) { + $isos = $languagePackService->getActiveLanguages(); + } + + if ($output->isVerbose()) { + $output->writeln(sprintf( + 'Updating language packs of all activated extensions for locale(s) "%s"', + implode('", "', $isos) + )); + } + + $extensions = $languagePackService->getExtensionLanguagePackDetails(); + + if (!$output->isVerbose()) { + $progressBarOutput = new NullOutput(); + } else { + $progressBarOutput = $output; + } + $progressBar = new ProgressBar($progressBarOutput, count($isos) * count($extensions)); + $languagePackService->updateMirrorBaseUrl(); + foreach ($isos as $iso) { + foreach ($extensions as $extension) { + $languagePackService->languagePackDownload($extension['key'], $iso); + $progressBar->advance(); + } + } + $languagePackService->setLastUpdatedIsoCode($isos); + $progressBar->finish(); + + // Flush language cache + GeneralUtility::makeInstance(CacheManager::class)->getCache('l10n')->flush(); + + return 0; + } +} diff --git a/Classes/Configuration/Commands.php b/Classes/Configuration/Commands.php new file mode 100644 index 0000000..8b6d7f9 --- /dev/null +++ b/Classes/Configuration/Commands.php @@ -0,0 +1,13 @@ + [ + 'class' => \TYPO3\CMS\Install\Command\LanguagePackCommand::class + ], +]; diff --git a/Classes/Domain/Repository/LabelRepository.php b/Classes/Domain/Repository/LabelRepository.php index b30a57b..2108404 100644 --- a/Classes/Domain/Repository/LabelRepository.php +++ b/Classes/Domain/Repository/LabelRepository.php @@ -158,4 +158,22 @@ protected function getLanguageService() { return $GLOBALS['LANG']; } + + public function findByProperties(string $extension, string $path, string $key) + { + $query = $this->createQuery(); + + $query->getQuerySettings()->setEnableFieldsToBeIgnored([ + 'starttime', + 'endtime', + ]); + + return $query->matching( + $query->logicalAnd([ + $query->equals('extension', $extension), + $query->equals('llFile', $path), + $query->equals('ukey', $key), + ]) + )->execute(); + } } diff --git a/Classes/Service/Tags/ImportProcess.php b/Classes/Service/Tags/ImportProcess.php new file mode 100644 index 0000000..5304268 --- /dev/null +++ b/Classes/Service/Tags/ImportProcess.php @@ -0,0 +1,69 @@ +objectManger = GeneralUtility::makeInstance(ObjectManager::class); + $this->yamlFileHandler = $this->objectManger->get(YamlFileHandler::class); + $this->labelRepository = $this->objectManger->get(LabelRepository::class); + } + + public function import(OutputInterface $output): void + { + foreach ($this->yamlFileHandler->getConfiguration() as $configuration) { + $output->writeln('Extension processing: ' . $configuration['extension']); + $this->importDataFromSingleFile($configuration['extension'], $configuration['files'], $output); + } + } + + public function importDataFromSingleFile(string $extension, array $files, OutputInterface $output): void + { + $config = []; + foreach ($files as $file) { + $output->writeln('File processing: ' . $file['path']); + foreach ($file['labels'] as $key => $properties) { + foreach ($properties as $propertyName => $property) { + $config[] = [ + 'label' => $key, + 'tags' => implode(',', $property) + ]; + } + } + } + $output->writeln(print_r($config, true)); + } + +} diff --git a/Classes/Service/Tags/YamlFileHandler.php b/Classes/Service/Tags/YamlFileHandler.php new file mode 100644 index 0000000..502596b --- /dev/null +++ b/Classes/Service/Tags/YamlFileHandler.php @@ -0,0 +1,137 @@ +objectManger = GeneralUtility::makeInstance(ObjectManager::class); + $this->packageManager = $this->objectManger->get(PackageManager::class); + $this->yamlFileLoader = $this->objectManger->get(YamlFileLoader::class); + } + + public function getConfiguration(): array + { + $configuration = []; + $i = 0; + foreach ($this->getGlobalConfiguration() as $extensionName => $files) { + $configuration[$i]['extension'] = $extensionName; + foreach ($files as $fileName => $labels) { + $configuration[$i]['files'][] = [ + 'fileName' => $fileName, + 'path' => 'EXT:' . $extensionName . '/Resources/Private/Language/' . $fileName, + 'labels' => $labels + ]; + } + } + + return $configuration; + } + + /** + * @return array + */ + protected function getGlobalConfiguration(): array + { + $configuration = []; + foreach ($this->getYamlFilesFromPackages() as $file) { + foreach ($this->readSingleFile($file) as $ext => $files) { + if ($ext === self::RESERVED_NAME) { + continue; + } + if (!key_exists($ext, $configuration)) { + $configuration[$ext] = []; + } + $this->populateRows($configuration[$ext], $files); + } + } + + return $configuration; + } + + /** + * Merge and create configuration + * @param array $configuration + * @param array $files + */ + protected function populateRows(array &$configuration, array $files): void + { + foreach ($files as $langFile => $rows) { + if (!key_exists($langFile, $configuration)) { + $configuration[$langFile] = []; + } + foreach ($rows as $key => $properties) { + if (!key_exists($key, $configuration[$langFile])) { + $configuration[$langFile][$key] = []; + } + foreach ($properties as $property => $values) { + if (!key_exists($property, $configuration[$langFile][$key])) { + $configuration[$langFile][$key][$property] = $values; + } else { + $configuration[$langFile][$key][$property] = array_unique(array_merge($configuration[$langFile][$key][$property], $values)); + } + } + } + } + } + + /** + * @param string $file + * @return array + */ + protected function readSingleFile(string $file): array + { + return $this->yamlFileLoader->load($file, 0); + } + + /** + * @return array + */ + protected function getYamlFilesFromPackages(): array + { + $files = []; + foreach ($this->packageManager->getActivePackages() as $package) { + $tagsYaml = $package->getPackagePath() . 'Configuration/Translation/FrontendTags.yaml'; + if (@is_file($tagsYaml)) { + $files[] = $tagsYaml; + } + } + + return $files; + } + +} diff --git a/Configuration/Commands.php b/Configuration/Commands.php new file mode 100644 index 0000000..d1c9264 --- /dev/null +++ b/Configuration/Commands.php @@ -0,0 +1,13 @@ + [ + 'class' => \SourceBroker\Translatr\Command\ImportTagsCommand::class + ], +]; From 0cf6254f8447aa47ca9c1e8728b3ea07028d0881 Mon Sep 17 00:00:00 2001 From: Kamil Maliszewski Date: Fri, 31 Jan 2020 22:46:17 +0100 Subject: [PATCH 03/13] [FEATURE] Implementation of read & import configuration from YAML file into database --- .../Command/ImportConfigurationCommand.php | 72 +++++++++ Classes/Domain/Repository/LabelRepository.php | 35 +++-- Classes/Service/ImportProcess.php | 78 ++++++++++ Classes/Service/YamlFileHandler.php | 142 ++++++++++++++++++ Configuration/Commands.php | 4 +- .../TCA/tx_translatr_domain_model_label.php | 6 +- Documentation/Configuration-example.yaml | 8 + 7 files changed, 324 insertions(+), 21 deletions(-) create mode 100644 Classes/Command/ImportConfigurationCommand.php create mode 100644 Classes/Service/ImportProcess.php create mode 100644 Classes/Service/YamlFileHandler.php create mode 100644 Documentation/Configuration-example.yaml diff --git a/Classes/Command/ImportConfigurationCommand.php b/Classes/Command/ImportConfigurationCommand.php new file mode 100644 index 0000000..b16f533 --- /dev/null +++ b/Classes/Command/ImportConfigurationCommand.php @@ -0,0 +1,72 @@ +setAliases(['lang:import:config']); + $this->setDescription('Import configuration from YAML into Translatr'); + $this->objectManger = GeneralUtility::makeInstance(ObjectManager::class); + $this->importProcessService = $this->objectManger->get(ImportProcess::class); + } + + /** + * + * @param InputInterface $input + * @param OutputInterface $output + * @return int + */ + protected function execute(InputInterface $input, OutputInterface $output): int + { + $output->writeln('Import of Translatr Configuration started'); + $dataToImport = $this->importProcessService->getDataToImport(); + $progressBar = new ProgressBar( + !$output->isVerbose() ? new NullOutput() : $output, + count($dataToImport) + ); + foreach ($dataToImport as $configuration) { + $output->writeln('Extension processing: ' . $configuration['extension']); + foreach ($configuration['files'] as $file) { + $output->writeln('File processing: ' . $file['path']); + $this->importProcessService->importDataFromSingleFile( + $configuration['extension'], + $file + ); + } + $progressBar->advance(); + } + $output->writeln('Import finished'); + $progressBar->finish(); + + return 0; + } +} diff --git a/Classes/Domain/Repository/LabelRepository.php b/Classes/Domain/Repository/LabelRepository.php index 2108404..6fbcd92 100644 --- a/Classes/Domain/Repository/LabelRepository.php +++ b/Classes/Domain/Repository/LabelRepository.php @@ -7,6 +7,7 @@ use SourceBroker\Translatr\Utility\ExtensionsUtility; use SourceBroker\Translatr\Utility\FileUtility; use SourceBroker\Translatr\Utility\LanguageUtility; +use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager; @@ -40,6 +41,7 @@ */ class LabelRepository extends \TYPO3\CMS\Extbase\Persistence\Repository { + const TABLE = 'tx_translatr_domain_model_label'; /** * @param BeLabelDemand $demand @@ -159,21 +161,24 @@ protected function getLanguageService() return $GLOBALS['LANG']; } - public function findByProperties(string $extension, string $path, string $key) + /** + * @param string $key + * @param array $values + * @param string $extension + * @param string $path + */ + public function updateSelectedRow(string $key, string $extension, string $path, array $values): void { - $query = $this->createQuery(); - - $query->getQuerySettings()->setEnableFieldsToBeIgnored([ - 'starttime', - 'endtime', - ]); - - return $query->matching( - $query->logicalAnd([ - $query->equals('extension', $extension), - $query->equals('llFile', $path), - $query->equals('ukey', $key), - ]) - )->execute(); + GeneralUtility::makeInstance(ConnectionPool::class) + ->getConnectionForTable(self::TABLE) + ->update( + self::TABLE, + $values, + [ + 'extension' => $extension, + 'ukey' => $key, + 'll_file' => $path + ] + ); } } diff --git a/Classes/Service/ImportProcess.php b/Classes/Service/ImportProcess.php new file mode 100644 index 0000000..5f553ca --- /dev/null +++ b/Classes/Service/ImportProcess.php @@ -0,0 +1,78 @@ +objectManger = GeneralUtility::makeInstance(ObjectManager::class); + $this->yamlFileHandler = $this->objectManger->get(YamlFileHandler::class); + $this->labelRepository = $this->objectManger->get(LabelRepository::class); + } + + /** + * @return array + */ + public function getDataToImport(): array + { + return $this->yamlFileHandler->getConfiguration(); + } + + /** + * @param string $extension + * @param array $file + */ + public function importDataFromSingleFile(string $extension, array $file): void + { + foreach ($file['labels'] as $key => $properties) { + $values = []; + foreach ($properties as $propertyName => $property) { + if (in_array($propertyName, self::ALLOWED_PROPERTIES)) { + $values[$propertyName] = implode(',', array_map('trim', $property)); + } + } + if (count($values)) { + $this->labelRepository->updateSelectedRow( + $key, + $extension, + $file['path'], + $values + ); + } + } + } +} diff --git a/Classes/Service/YamlFileHandler.php b/Classes/Service/YamlFileHandler.php new file mode 100644 index 0000000..59fde96 --- /dev/null +++ b/Classes/Service/YamlFileHandler.php @@ -0,0 +1,142 @@ +objectManger = GeneralUtility::makeInstance(ObjectManager::class); + $this->packageManager = $this->objectManger->get(PackageManager::class); + $this->yamlFileLoader = $this->objectManger->get(YamlFileLoader::class); + } + + /** + * @return array + */ + public function getConfiguration(): array + { + $configuration = []; + $i = 0; + foreach ($this->getGlobalConfiguration() as $extensionName => $files) { + $configuration[$i]['extension'] = $extensionName; + foreach ($files as $fileName => $labels) { + $configuration[$i]['files'][] = [ + 'fileName' => $fileName, + 'path' => 'EXT:' . $extensionName . self::LANG_FILE_PATH . $fileName, + 'labels' => $labels + ]; + } + $i++; + } + + return $configuration; + } + + /** + * @return array + */ + protected function getGlobalConfiguration(): array + { + $configuration = []; + foreach ($this->getYamlFilesFromPackages() as $file) { + $fileContent = $this->readSingleFile($file); + if (isset($fileContent[self::ROOT_NAME])) { + foreach ($fileContent[self::ROOT_NAME] as $ext => $files) { + if (!key_exists($ext, $configuration)) { + $configuration[$ext] = []; + } + $this->populateRows($configuration[$ext], $files); + } + } + } + + return $configuration; + } + + /** + * Merge and create configuration + * @param array $configuration + * @param array $files + */ + protected function populateRows(array &$configuration, array $files): void + { + foreach ($files as $langFile => $rows) { + if (!key_exists($langFile, $configuration)) { + $configuration[$langFile] = []; + } + foreach ($rows as $key => $properties) { + if (!key_exists($key, $configuration[$langFile])) { + $configuration[$langFile][$key] = []; + } + foreach ($properties as $property => $values) { + if (!key_exists($property, $configuration[$langFile][$key])) { + $configuration[$langFile][$key][$property] = $values; + } else { + $configuration[$langFile][$key][$property] = array_unique( + array_merge($configuration[$langFile][$key][$property], $values) + ); + } + } + } + } + } + + /** + * @param string $file + * @return array + */ + protected function readSingleFile(string $file): array + { + return $this->yamlFileLoader->load($file, 0); + } + + /** + * @return array + */ + protected function getYamlFilesFromPackages(): array + { + $files = []; + foreach ($this->packageManager->getActivePackages() as $package) { + $yamlFile = $package->getPackagePath() . 'Configuration/Translation/' . self::FILENAME; + if (@is_file($yamlFile)) { + $files[] = $yamlFile; + } + } + + return $files; + } + +} diff --git a/Configuration/Commands.php b/Configuration/Commands.php index d1c9264..894d75a 100644 --- a/Configuration/Commands.php +++ b/Configuration/Commands.php @@ -7,7 +7,7 @@ * */ return [ - 'language:frontend:tags' => [ - 'class' => \SourceBroker\Translatr\Command\ImportTagsCommand::class + 'language:import:configuration' => [ + 'class' => \SourceBroker\Translatr\Command\ImportConfigurationCommand::class ], ]; diff --git a/Configuration/TCA/tx_translatr_domain_model_label.php b/Configuration/TCA/tx_translatr_domain_model_label.php index e84f63c..1f5b075 100644 --- a/Configuration/TCA/tx_translatr_domain_model_label.php +++ b/Configuration/TCA/tx_translatr_domain_model_label.php @@ -130,10 +130,8 @@ 'exclude' => 1, 'label' => 'LLL:EXT:translatr/Resources/Private/Language/locallang_db.xlf:tx_translatr_domain_model_label.tags', 'config' => [ - 'type' => 'text', - 'cols' => 40, - 'rows' => 1, - 'eval' => 'trim', + 'type' => 'user', + 'userFunc' => \SourceBroker\Translatr\UserFunc\TcaFieldHidden::class . '->display', ], ], ], diff --git a/Documentation/Configuration-example.yaml b/Documentation/Configuration-example.yaml new file mode 100644 index 0000000..6083c2e --- /dev/null +++ b/Documentation/Configuration-example.yaml @@ -0,0 +1,8 @@ +#Should be placed at '/Configuration/Translation/Configuration.yaml +presets: + local: &preset-local + tags: ['general', 'vue'] +ext: + local: + locallang.xml: + 'search.submit': *preset-local From 74819042e034642b26b4e254763cdffac0f52a94 Mon Sep 17 00:00:00 2001 From: Kamil Maliszewski Date: Fri, 31 Jan 2020 22:48:38 +0100 Subject: [PATCH 04/13] [FEATURE] Clean-up the code --- Classes/Command/ImportTagsCommand.php | 55 --------- Classes/Command/LanguagePackCommand.php | 82 -------------- Classes/Service/Tags/ImportProcess.php | 69 ------------ Classes/Service/Tags/YamlFileHandler.php | 137 ----------------------- 4 files changed, 343 deletions(-) delete mode 100644 Classes/Command/ImportTagsCommand.php delete mode 100644 Classes/Command/LanguagePackCommand.php delete mode 100644 Classes/Service/Tags/ImportProcess.php delete mode 100644 Classes/Service/Tags/YamlFileHandler.php diff --git a/Classes/Command/ImportTagsCommand.php b/Classes/Command/ImportTagsCommand.php deleted file mode 100644 index 44cdd7c..0000000 --- a/Classes/Command/ImportTagsCommand.php +++ /dev/null @@ -1,55 +0,0 @@ -setAliases(['lang:fe:tags']); - $this->setDescription('Import labels tags from config file into Translatr'); - $this->objectManger = GeneralUtility::makeInstance(ObjectManager::class); - $this->importProcessService = $this->objectManger->get(ImportProcess::class); - } - - /** - * - * @param InputInterface $input - * @param OutputInterface $output - * @return int - */ - protected function execute(InputInterface $input, OutputInterface $output): int - { -// $output->writeln('Works'); - $this->importProcessService->import($output); - - return 0; - } -} diff --git a/Classes/Command/LanguagePackCommand.php b/Classes/Command/LanguagePackCommand.php deleted file mode 100644 index fe37889..0000000 --- a/Classes/Command/LanguagePackCommand.php +++ /dev/null @@ -1,82 +0,0 @@ -setAliases(['lang:frontend:import']); - $this->setDescription('Import labels from config file into Translatr'); - } - - /** - * Update language packs of all active languages for all active extensions - * - * @param InputInterface $input - * @param OutputInterface $output - * @throws \InvalidArgumentException - * @throws \TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException - * @return int - */ - protected function execute(InputInterface $input, OutputInterface $output) - { - - $languagePackService = GeneralUtility::makeInstance(LanguagePackService::class); - - try { - $isos = $input->getArgument('locales'); - } catch (\Exception $e) { - $isos = []; - } - if (empty($isos)) { - $isos = $languagePackService->getActiveLanguages(); - } - - if ($output->isVerbose()) { - $output->writeln(sprintf( - 'Updating language packs of all activated extensions for locale(s) "%s"', - implode('", "', $isos) - )); - } - - $extensions = $languagePackService->getExtensionLanguagePackDetails(); - - if (!$output->isVerbose()) { - $progressBarOutput = new NullOutput(); - } else { - $progressBarOutput = $output; - } - $progressBar = new ProgressBar($progressBarOutput, count($isos) * count($extensions)); - $languagePackService->updateMirrorBaseUrl(); - foreach ($isos as $iso) { - foreach ($extensions as $extension) { - $languagePackService->languagePackDownload($extension['key'], $iso); - $progressBar->advance(); - } - } - $languagePackService->setLastUpdatedIsoCode($isos); - $progressBar->finish(); - - // Flush language cache - GeneralUtility::makeInstance(CacheManager::class)->getCache('l10n')->flush(); - - return 0; - } -} diff --git a/Classes/Service/Tags/ImportProcess.php b/Classes/Service/Tags/ImportProcess.php deleted file mode 100644 index 5304268..0000000 --- a/Classes/Service/Tags/ImportProcess.php +++ /dev/null @@ -1,69 +0,0 @@ -objectManger = GeneralUtility::makeInstance(ObjectManager::class); - $this->yamlFileHandler = $this->objectManger->get(YamlFileHandler::class); - $this->labelRepository = $this->objectManger->get(LabelRepository::class); - } - - public function import(OutputInterface $output): void - { - foreach ($this->yamlFileHandler->getConfiguration() as $configuration) { - $output->writeln('Extension processing: ' . $configuration['extension']); - $this->importDataFromSingleFile($configuration['extension'], $configuration['files'], $output); - } - } - - public function importDataFromSingleFile(string $extension, array $files, OutputInterface $output): void - { - $config = []; - foreach ($files as $file) { - $output->writeln('File processing: ' . $file['path']); - foreach ($file['labels'] as $key => $properties) { - foreach ($properties as $propertyName => $property) { - $config[] = [ - 'label' => $key, - 'tags' => implode(',', $property) - ]; - } - } - } - $output->writeln(print_r($config, true)); - } - -} diff --git a/Classes/Service/Tags/YamlFileHandler.php b/Classes/Service/Tags/YamlFileHandler.php deleted file mode 100644 index 502596b..0000000 --- a/Classes/Service/Tags/YamlFileHandler.php +++ /dev/null @@ -1,137 +0,0 @@ -objectManger = GeneralUtility::makeInstance(ObjectManager::class); - $this->packageManager = $this->objectManger->get(PackageManager::class); - $this->yamlFileLoader = $this->objectManger->get(YamlFileLoader::class); - } - - public function getConfiguration(): array - { - $configuration = []; - $i = 0; - foreach ($this->getGlobalConfiguration() as $extensionName => $files) { - $configuration[$i]['extension'] = $extensionName; - foreach ($files as $fileName => $labels) { - $configuration[$i]['files'][] = [ - 'fileName' => $fileName, - 'path' => 'EXT:' . $extensionName . '/Resources/Private/Language/' . $fileName, - 'labels' => $labels - ]; - } - } - - return $configuration; - } - - /** - * @return array - */ - protected function getGlobalConfiguration(): array - { - $configuration = []; - foreach ($this->getYamlFilesFromPackages() as $file) { - foreach ($this->readSingleFile($file) as $ext => $files) { - if ($ext === self::RESERVED_NAME) { - continue; - } - if (!key_exists($ext, $configuration)) { - $configuration[$ext] = []; - } - $this->populateRows($configuration[$ext], $files); - } - } - - return $configuration; - } - - /** - * Merge and create configuration - * @param array $configuration - * @param array $files - */ - protected function populateRows(array &$configuration, array $files): void - { - foreach ($files as $langFile => $rows) { - if (!key_exists($langFile, $configuration)) { - $configuration[$langFile] = []; - } - foreach ($rows as $key => $properties) { - if (!key_exists($key, $configuration[$langFile])) { - $configuration[$langFile][$key] = []; - } - foreach ($properties as $property => $values) { - if (!key_exists($property, $configuration[$langFile][$key])) { - $configuration[$langFile][$key][$property] = $values; - } else { - $configuration[$langFile][$key][$property] = array_unique(array_merge($configuration[$langFile][$key][$property], $values)); - } - } - } - } - } - - /** - * @param string $file - * @return array - */ - protected function readSingleFile(string $file): array - { - return $this->yamlFileLoader->load($file, 0); - } - - /** - * @return array - */ - protected function getYamlFilesFromPackages(): array - { - $files = []; - foreach ($this->packageManager->getActivePackages() as $package) { - $tagsYaml = $package->getPackagePath() . 'Configuration/Translation/FrontendTags.yaml'; - if (@is_file($tagsYaml)) { - $files[] = $tagsYaml; - } - } - - return $files; - } - -} From 62deb4f5ed841a4ff9edc43d7329fc4a339a8a42 Mon Sep 17 00:00:00 2001 From: Kamil Maliszewski Date: Wed, 5 Feb 2020 10:00:17 +0100 Subject: [PATCH 05/13] [FEATURE] Implement import translations in all languages used in YAML from files to database --- .../Command/ImportConfigurationCommand.php | 6 +- Classes/Configuration/Commands.php | 13 ---- Classes/Database/Database87.php | 28 ++++++-- Classes/Domain/Model/Dto/BeLabelDemand.php | 21 ++++++ Classes/Domain/Repository/LabelRepository.php | 67 +++++++++++++++---- Classes/Service/ImportProcess.php | 53 +++++++++++++-- Classes/Service/YamlFileHandler.php | 8 +-- 7 files changed, 151 insertions(+), 45 deletions(-) delete mode 100644 Classes/Configuration/Commands.php diff --git a/Classes/Command/ImportConfigurationCommand.php b/Classes/Command/ImportConfigurationCommand.php index b16f533..4e2a6f4 100644 --- a/Classes/Command/ImportConfigurationCommand.php +++ b/Classes/Command/ImportConfigurationCommand.php @@ -21,7 +21,7 @@ class ImportConfigurationCommand extends Command /** * @var ObjectManager */ - protected $objectManger; + protected $objectManager; /** * @var ImportProcess @@ -35,8 +35,8 @@ protected function configure(): void { $this->setAliases(['lang:import:config']); $this->setDescription('Import configuration from YAML into Translatr'); - $this->objectManger = GeneralUtility::makeInstance(ObjectManager::class); - $this->importProcessService = $this->objectManger->get(ImportProcess::class); + $this->objectManager = GeneralUtility::makeInstance(ObjectManager::class); + $this->importProcessService = $this->objectManager->get(ImportProcess::class); } /** diff --git a/Classes/Configuration/Commands.php b/Classes/Configuration/Commands.php deleted file mode 100644 index 8b6d7f9..0000000 --- a/Classes/Configuration/Commands.php +++ /dev/null @@ -1,13 +0,0 @@ - [ - 'class' => \TYPO3\CMS\Install\Command\LanguagePackCommand::class - ], -]; diff --git a/Classes/Database/Database87.php b/Classes/Database/Database87.php index f5c09e4..d8aba5d 100644 --- a/Classes/Database/Database87.php +++ b/Classes/Database/Database87.php @@ -51,7 +51,11 @@ public function findDemandedForBe(BeLabelDemand $demand) if (!$demand->isValid()) { return []; } - + $keyWhere = ''; + if ($demand->getKeys()) { + $keyWhere = ' AND label.ukey IN (' . implode(',', $this->wrapArrayByQuote($demand->getKeys())) . ') '; + } + $languages = implode(',', count($demand->getLanguages()) ? $this->wrapArrayByQuote($demand->getLanguages()) : ['default']); $query = <<getExtension(), - implode(',', $demand->getLanguages() ?: ['default']), $demand->getExtension() ], [ ParameterType::STRING, ParameterType::STRING, - ParameterType::STRING, ] ); @@ -169,4 +174,15 @@ public function getLocallanfFiles() ->groupBy('label.ll_file') ->execute()->fetchAll(); } + + /** + * @param array $arr + * @return array + */ + protected function wrapArrayByQuote(array $arr) : array + { + return array_map(function ($k) { + return '\'' . $k . '\''; + }, $arr); + } } diff --git a/Classes/Domain/Model/Dto/BeLabelDemand.php b/Classes/Domain/Model/Dto/BeLabelDemand.php index 7bdd12b..100c405 100644 --- a/Classes/Domain/Model/Dto/BeLabelDemand.php +++ b/Classes/Domain/Model/Dto/BeLabelDemand.php @@ -32,6 +32,11 @@ class BeLabelDemand extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity */ protected $languages = null; + /** + * @var array + */ + protected $keys = null; + /** * BeLabelDemand constructor. */ @@ -81,4 +86,20 @@ public function setLanguages($languages) { $this->languages = $languages; } + + /** + * @return array + */ + public function getKeys(): ?array + { + return $this->keys; + } + + /** + * @param array $keys + */ + public function setKeys(array $keys): void + { + $this->keys = $keys; + } } diff --git a/Classes/Domain/Repository/LabelRepository.php b/Classes/Domain/Repository/LabelRepository.php index 6fbcd92..a9d4c1f 100644 --- a/Classes/Domain/Repository/LabelRepository.php +++ b/Classes/Domain/Repository/LabelRepository.php @@ -9,6 +9,7 @@ use SourceBroker\Translatr\Utility\LanguageUtility; use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException; use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager; /*************************************************************** @@ -72,14 +73,15 @@ public function getExtensionsItems() * @param string $extKey * * @return void - * @todo Implement support for other translation files as currently only - * the main FE translation file is supported - * (EXT:{extKey}/Resources/Private/Language/locallang.xlf or - * EXT:{extKey}/Resources/Private/Language/locallang.xml) + * @throws IllegalObjectTypeException * @todo When support for more files will be implemented, then indexing * proces should be moved somewhere else to speed up the BE module * (currently it's done on every request to keep labels up to date) * + * @todo Implement support for other translation files as currently only + * the main FE translation file is supported + * (EXT:{extKey}/Resources/Private/Language/locallang.xlf or + * EXT:{extKey}/Resources/Private/Language/locallang.xml) */ public function indexExtensionLabels($extKey) { @@ -144,13 +146,11 @@ protected function isLabelIndexed(Label $label) 'endtime', ]); - return $query->matching( - $query->logicalAnd([ - $query->equals('language', $label->getLanguage()), - $query->equals('llFile', $label->getLlFile()), - $query->equals('ukey', $label->getUkey()), - ]) - )->count() > 0; + return $query->matching($query->logicalAnd([ + $query->equals('language', $label->getLanguage()), + $query->equals('llFile', $label->getLlFile()), + $query->equals('ukey', $label->getUkey()), + ]))->count() > 0; } /** @@ -167,7 +167,7 @@ protected function getLanguageService() * @param string $extension * @param string $path */ - public function updateSelectedRow(string $key, string $extension, string $path, array $values): void + public function updateSelectedRowInAllLanguages(string $key, string $extension, string $path, array $values): void { GeneralUtility::makeInstance(ConnectionPool::class) ->getConnectionForTable(self::TABLE) @@ -177,8 +177,49 @@ public function updateSelectedRow(string $key, string $extension, string $path, [ 'extension' => $extension, 'ukey' => $key, - 'll_file' => $path + 'll_file' => $path, + 'deleted' => 0, + 'hidden' => 0 + ] + ); + } + + /** + * @param int $uid + * @param array $values + */ + public function updateSelectedRow(int $uid, array $values): void + { + GeneralUtility::makeInstance(ConnectionPool::class) + ->getConnectionForTable(self::TABLE) + ->update( + self::TABLE, + $values, + [ + 'uid' => $uid, ] ); } + + /** + * @param array $defaultLabel + * @param string $translationFromFile + * @param string $language + */ + public function createLanguageChildFromDefault(array $defaultLabel, string $translationFromFile, string $language): void + { + /** @var Label $label */ + $label = GeneralUtility::makeInstance(Label::class); + $label->setExtension($defaultLabel['extension']); + $label->setText($translationFromFile); + $label->setUkey($defaultLabel['ukey']); + $label->setLlFile($defaultLabel['ll_file']); + $label->setLlFileIndex(strrev($defaultLabel['ll_file'])); + $label->setLanguage($language); + $label->setTags($defaultLabel['tags']); + try { + $this->add($label); + } catch (IllegalObjectTypeException $e) { + } + } } diff --git a/Classes/Service/ImportProcess.php b/Classes/Service/ImportProcess.php index 5f553ca..662cc4e 100644 --- a/Classes/Service/ImportProcess.php +++ b/Classes/Service/ImportProcess.php @@ -3,10 +3,12 @@ namespace SourceBroker\Translatr\Service; +use SourceBroker\Translatr\Domain\Model\Dto\BeLabelDemand; use SourceBroker\Translatr\Domain\Repository\LabelRepository; -use Symfony\Component\Console\Output\OutputInterface; +use SourceBroker\Translatr\Utility\LanguageUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Object\ObjectManager; +use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager; /** * Class ImportProcess @@ -22,7 +24,7 @@ class ImportProcess /** * @var ObjectManager */ - protected $objectManger; + protected $objectManager; /** * @var YamlFileHandler @@ -39,9 +41,9 @@ class ImportProcess */ public function __construct() { - $this->objectManger = GeneralUtility::makeInstance(ObjectManager::class); - $this->yamlFileHandler = $this->objectManger->get(YamlFileHandler::class); - $this->labelRepository = $this->objectManger->get(LabelRepository::class); + $this->objectManager = GeneralUtility::makeInstance(ObjectManager::class); + $this->yamlFileHandler = $this->objectManager->get(YamlFileHandler::class); + $this->labelRepository = $this->objectManager->get(LabelRepository::class); } /** @@ -58,6 +60,7 @@ public function getDataToImport(): array */ public function importDataFromSingleFile(string $extension, array $file): void { + $this->pushMissingKeyToDatabase($extension, $file['labels'], $file['path']); foreach ($file['labels'] as $key => $properties) { $values = []; foreach ($properties as $propertyName => $property) { @@ -66,7 +69,7 @@ public function importDataFromSingleFile(string $extension, array $file): void } } if (count($values)) { - $this->labelRepository->updateSelectedRow( + $this->labelRepository->updateSelectedRowInAllLanguages( $key, $extension, $file['path'], @@ -75,4 +78,42 @@ public function importDataFromSingleFile(string $extension, array $file): void } } } + + /** + * @param string $extension + * @param array $keys + * @param string $path + */ + protected function pushMissingKeyToDatabase(string $extension, array $keys, string $path): void + { + $allLanguages = array_keys(LanguageUtility::getAvailableLanguages()); + $demand = $this->objectManager->get(BeLabelDemand::class); + $demand->setExtension($extension); + $demand->setKeys(array_keys($keys)); + $demand->setLanguages($allLanguages); + foreach ($this->labelRepository->findDemandedForBe($demand) as $label) { + foreach ($allLanguages as $language) { + $parsedLabels = LanguageUtility::parseLanguageLabels($path, $language); + if (isset($parsedLabels[$language], $parsedLabels[$language][$label['ukey']]) && !empty($parsedLabels[$language][$label['ukey']][0]['target'])) { + if (isset($label['language_childs'][$language])) { + if (empty($label['language_childs'][$language]['modify'])) { + $this->labelRepository->updateSelectedRow( + $label['language_childs'][$language]['uid'], + [ + 'text' => $parsedLabels[$language][$label['ukey']][0]['target'] + ] + ); + } + } else { + $this->labelRepository->createLanguageChildFromDefault( + $label, + $parsedLabels[$language][$label['ukey']][0]['target'], + $language + ); + } + } + } + } + $this->objectManager->get(PersistenceManager::class)->persistAll(); + } } diff --git a/Classes/Service/YamlFileHandler.php b/Classes/Service/YamlFileHandler.php index 59fde96..85009e0 100644 --- a/Classes/Service/YamlFileHandler.php +++ b/Classes/Service/YamlFileHandler.php @@ -21,7 +21,7 @@ class YamlFileHandler /** * @var ObjectManager */ - protected $objectManger; + protected $objectManager; /** * @var YamlFileLoader @@ -38,9 +38,9 @@ class YamlFileHandler */ public function __construct() { - $this->objectManger = GeneralUtility::makeInstance(ObjectManager::class); - $this->packageManager = $this->objectManger->get(PackageManager::class); - $this->yamlFileLoader = $this->objectManger->get(YamlFileLoader::class); + $this->objectManager = GeneralUtility::makeInstance(ObjectManager::class); + $this->packageManager = $this->objectManager->get(PackageManager::class); + $this->yamlFileLoader = $this->objectManager->get(YamlFileLoader::class); } /** From 5eb4e1d5ce7051e16c93696f6b14a6bb7c5a43ba Mon Sep 17 00:00:00 2001 From: Kamil Maliszewski Date: Wed, 5 Feb 2020 10:48:50 +0100 Subject: [PATCH 06/13] [FIX] Fix problem with missing tags after create new translation from BE [FIX] Fix wrong extension name at creating new translation from BE --- Classes/Database/Database76.php | 4 +++- Classes/Domain/Repository/LabelRepository.php | 1 + Resources/Private/Backend/Templates/Label/List.html | 5 +++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Classes/Database/Database76.php b/Classes/Database/Database76.php index f511c07..c41758e 100644 --- a/Classes/Database/Database76.php +++ b/Classes/Database/Database76.php @@ -56,7 +56,9 @@ public function findDemandedForBe(BeLabelDemand $demand) label.ukey, 0 AS parent_uid, label.text, - label.ll_file + label.ll_file, + label.tags, + label.extension FROM tx_translatr_domain_model_label AS label WHERE label.language = "default" AND label.deleted = 0 diff --git a/Classes/Domain/Repository/LabelRepository.php b/Classes/Domain/Repository/LabelRepository.php index a9d4c1f..9e2e44f 100644 --- a/Classes/Domain/Repository/LabelRepository.php +++ b/Classes/Domain/Repository/LabelRepository.php @@ -210,6 +210,7 @@ public function createLanguageChildFromDefault(array $defaultLabel, string $tran { /** @var Label $label */ $label = GeneralUtility::makeInstance(Label::class); + $label->setPid(0); $label->setExtension($defaultLabel['extension']); $label->setText($translationFromFile); $label->setUkey($defaultLabel['ukey']); diff --git a/Resources/Private/Backend/Templates/Label/List.html b/Resources/Private/Backend/Templates/Label/List.html index 26de8ce..8d71055 100644 --- a/Resources/Private/Backend/Templates/Label/List.html +++ b/Resources/Private/Backend/Templates/Label/List.html @@ -65,10 +65,11 @@ }, ll_file: label.ll_file, extension: { - 0: 'news' + 0: label.extension }, ukey: label.ukey, - text: labelText + text: labelText, + tags: label.tags } }"/> From efe691e473dbf03cdb1d1bcb1f2c503cc6ef94c6 Mon Sep 17 00:00:00 2001 From: Kamil Maliszewski Date: Wed, 5 Feb 2020 11:45:25 +0100 Subject: [PATCH 07/13] [FEATURE] Implement flag to determine if record was edited from BE --- Classes/Database/Database87.php | 6 ++++-- Classes/Domain/Model/Label.php | 21 +++++++++++++++++++ Classes/Hooks/TceMain.php | 2 +- Classes/UserFunc/TcaFieldHidden.php | 10 ++++++--- .../TCA/tx_translatr_domain_model_label.php | 10 ++++++++- ...ng_csh_tx_translatr_domain_model_label.xlf | 3 +++ Resources/Private/Language/locallang_db.xlf | 3 +++ ext_tables.sql | 1 + 8 files changed, 49 insertions(+), 7 deletions(-) diff --git a/Classes/Database/Database87.php b/Classes/Database/Database87.php index d8aba5d..6130f2b 100644 --- a/Classes/Database/Database87.php +++ b/Classes/Database/Database87.php @@ -67,7 +67,8 @@ public function findDemandedForBe(BeLabelDemand $demand) label.text, label.ll_file, label.tags, - label.extension + label.extension, + label.modify FROM tx_translatr_domain_model_label AS label WHERE label.language = "default" AND label.deleted = 0 @@ -83,7 +84,8 @@ public function findDemandedForBe(BeLabelDemand $demand) label.text, label.ll_file, label.tags, - label.extension + label.extension, + label.modify FROM tx_translatr_domain_model_label AS label LEFT JOIN tx_translatr_domain_model_label AS parent ON (parent.language = "default" AND parent.ukey = label.ukey AND parent.ll_file = label.ll_file) diff --git a/Classes/Domain/Model/Label.php b/Classes/Domain/Model/Label.php index 6010e94..1e3a07e 100644 --- a/Classes/Domain/Model/Label.php +++ b/Classes/Domain/Model/Label.php @@ -83,6 +83,11 @@ class Label extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity */ protected $llFileIndex = ''; + /** + * @var int + */ + protected $modify = ''; + /** * Returns the extension * @@ -234,4 +239,20 @@ public function setTags($tags) { $this->tags = $tags; } + + /** + * @return int + */ + public function getModify() + { + return $this->modify; + } + + /** + * @param int $modify + */ + public function setModify(int $modify) + { + $this->modify = $modify; + } } diff --git a/Classes/Hooks/TceMain.php b/Classes/Hooks/TceMain.php index d9d2310..a9ef81d 100644 --- a/Classes/Hooks/TceMain.php +++ b/Classes/Hooks/TceMain.php @@ -51,7 +51,6 @@ public function processDatamap_afterDatabaseOperations( if ($status === 'new') { $id = $pObj->substNEWwithIDs[$id]; } - $record = BackendUtility::getRecord($table, $id); /** @var Database $db */ $db = GeneralUtility::makeInstance($GLOBALS['TYPO3_CONF_VARS']['EXT']['EXTCONF']['translatr']['database']); @@ -80,6 +79,7 @@ public function processDatamap_afterDatabaseOperations( } } } + $db->update('tx_translatr_domain_model_label', ['modify' => 1], ['uid' => (int)$id]); } } diff --git a/Classes/UserFunc/TcaFieldHidden.php b/Classes/UserFunc/TcaFieldHidden.php index f9b8214..1f85bc7 100644 --- a/Classes/UserFunc/TcaFieldHidden.php +++ b/Classes/UserFunc/TcaFieldHidden.php @@ -21,12 +21,16 @@ public function display(&$config) $value = array_shift($value); } - if (empty($value)) { - $returnValue = '

Ukey value couldn\'t be determined. Contact your administrator.

'; + if (!is_numeric($value) && empty($value)) { + $returnValue = $config['field'] == 'ukey' ? '

Ukey value couldn\'t be determined. Contact your administrator.

' : '

'; } else { + $displayValue = $value; + if (is_numeric($value)) { + $displayValue = $value === 0 ? 'No' : 'Yes'; + } $returnValue = << -

{$value}

+

{$displayValue}

HTML; } diff --git a/Configuration/TCA/tx_translatr_domain_model_label.php b/Configuration/TCA/tx_translatr_domain_model_label.php index 1f5b075..ef3fb61 100644 --- a/Configuration/TCA/tx_translatr_domain_model_label.php +++ b/Configuration/TCA/tx_translatr_domain_model_label.php @@ -25,7 +25,7 @@ 'showRecordFieldList' => 'extension, ukey, text, description, ll_file', ], 'types' => [ - '1' => ['showitem' => 'text, description, tags, language, extension, ll_file, ukey, --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.access, starttime, endtime'], + '1' => ['showitem' => 'text, description, tags, language, extension, ll_file, ukey, modify, --div--;LLL:EXT:cms/locallang_ttc.xlf:tabs.access, starttime, endtime'], ], 'palettes' => [ '1' => ['showitem' => ''], @@ -134,5 +134,13 @@ 'userFunc' => \SourceBroker\Translatr\UserFunc\TcaFieldHidden::class . '->display', ], ], + 'modify' => [ + 'exclude' => 1, + 'label' => 'LLL:EXT:translatr/Resources/Private/Language/locallang_db.xlf:tx_translatr_domain_model_label.modify', + 'config' => [ + 'type' => 'user', + 'userFunc' => \SourceBroker\Translatr\UserFunc\TcaFieldHidden::class . '->display', + ], + ], ], ]; diff --git a/Resources/Private/Language/locallang_csh_tx_translatr_domain_model_label.xlf b/Resources/Private/Language/locallang_csh_tx_translatr_domain_model_label.xlf index fcf3beb..9e0afaa 100644 --- a/Resources/Private/Language/locallang_csh_tx_translatr_domain_model_label.xlf +++ b/Resources/Private/Language/locallang_csh_tx_translatr_domain_model_label.xlf @@ -22,6 +22,9 @@ Tags + + Modify + diff --git a/Resources/Private/Language/locallang_db.xlf b/Resources/Private/Language/locallang_db.xlf index c0f99d7..3ff0889 100644 --- a/Resources/Private/Language/locallang_db.xlf +++ b/Resources/Private/Language/locallang_db.xlf @@ -28,6 +28,9 @@ Tags (comma separated) + + Record was modify from BE + diff --git a/ext_tables.sql b/ext_tables.sql index 4f37682..5dfcfa2 100644 --- a/ext_tables.sql +++ b/ext_tables.sql @@ -5,6 +5,7 @@ CREATE TABLE tx_translatr_domain_model_label ( uid int(11) NOT NULL auto_increment, pid int(11) DEFAULT '0' NOT NULL, + modify tinyint(4) DEFAULT '0' NOT NULL, extension varchar(255) DEFAULT '' NOT NULL, ukey varchar(255) DEFAULT '' NOT NULL, From 4e820444f8efb4fa44d10bc1ae02e19c246e5b76 Mon Sep 17 00:00:00 2001 From: Kamil Maliszewski Date: Wed, 5 Feb 2020 12:08:20 +0100 Subject: [PATCH 08/13] [FEATURE] Implement common cache cleaner service for whole ext --- .../Command/ImportConfigurationCommand.php | 8 +++ Classes/Hooks/TceMain.php | 45 ++++++---------- Classes/Service/BaseService.php | 27 ++++++++++ Classes/Service/CacheCleaner.php | 51 +++++++++++++++++++ Classes/Service/ImportProcess.php | 9 +--- Classes/Service/YamlFileHandler.php | 9 +--- Classes/Toolbar/ToolbarItem.php | 20 +++----- Classes/Utility/FileUtility.php | 1 + 8 files changed, 113 insertions(+), 57 deletions(-) create mode 100644 Classes/Service/BaseService.php create mode 100644 Classes/Service/CacheCleaner.php diff --git a/Classes/Command/ImportConfigurationCommand.php b/Classes/Command/ImportConfigurationCommand.php index 4e2a6f4..9cc208f 100644 --- a/Classes/Command/ImportConfigurationCommand.php +++ b/Classes/Command/ImportConfigurationCommand.php @@ -3,6 +3,7 @@ namespace SourceBroker\Translatr\Command; +use SourceBroker\Translatr\Service\CacheCleaner; use SourceBroker\Translatr\Service\ImportProcess; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\ProgressBar; @@ -28,6 +29,11 @@ class ImportConfigurationCommand extends Command */ protected $importProcessService; + /** + * @var CacheCleaner + */ + protected $cacheCleaner; + /** * Configure the command by defining the name, options and arguments */ @@ -37,6 +43,7 @@ protected function configure(): void $this->setDescription('Import configuration from YAML into Translatr'); $this->objectManager = GeneralUtility::makeInstance(ObjectManager::class); $this->importProcessService = $this->objectManager->get(ImportProcess::class); + $this->cacheCleaner = $this->objectManager->get(CacheCleaner::class); } /** @@ -65,6 +72,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $progressBar->advance(); } $output->writeln('Import finished'); + $this->cacheCleaner->flushCache(); $progressBar->finish(); return 0; diff --git a/Classes/Hooks/TceMain.php b/Classes/Hooks/TceMain.php index a9ef81d..99f1da3 100644 --- a/Classes/Hooks/TceMain.php +++ b/Classes/Hooks/TceMain.php @@ -3,7 +3,12 @@ namespace SourceBroker\Translatr\Hooks; use SourceBroker\Translatr\Database\Database; +use SourceBroker\Translatr\Service\CacheCleaner; +use SourceBroker\Translatr\Utility\FileUtility; use TYPO3\CMS\Backend\Utility\BackendUtility; +use TYPO3\CMS\Core\DataHandling\DataHandler; +use TYPO3\CMS\Core\Messaging\FlashMessage; +use TYPO3\CMS\Core\Messaging\FlashMessageService; use TYPO3\CMS\Core\Utility\GeneralUtility; /** @@ -17,19 +22,18 @@ class TceMain * @param $table * @param $id * @param $value - * @param \TYPO3\CMS\Core\DataHandling\DataHandler $pObj + * @param DataHandler $pObj */ public function processCmdmap_postProcess( $command, $table, $id, $value, - \TYPO3\CMS\Core\DataHandling\DataHandler &$pObj + DataHandler &$pObj ) { if ($table == 'tx_translatr_domain_model_label' && $command == 'delete') { - $record = BackendUtility::getRecord($table, $id); - $this->clearCacheForLanguage($record['language']); - \SourceBroker\Translatr\Utility\FileUtility::getTempFolderPath(); + GeneralUtility::makeInstance(CacheCleaner::class)->flushCache(); + FileUtility::getTempFolderPath(); } } @@ -38,14 +42,14 @@ public function processCmdmap_postProcess( * @param $table * @param $id * @param array $fieldArray - * @param \TYPO3\CMS\Core\DataHandling\DataHandler $pObj + * @param DataHandler $pObj */ public function processDatamap_afterDatabaseOperations( $status, $table, $id, array $fieldArray, - \TYPO3\CMS\Core\DataHandling\DataHandler &$pObj + DataHandler &$pObj ) { if ($table == 'tx_translatr_domain_model_label') { if ($status === 'new') { @@ -56,17 +60,17 @@ public function processDatamap_afterDatabaseOperations( $db = GeneralUtility::makeInstance($GLOBALS['TYPO3_CONF_VARS']['EXT']['EXTCONF']['translatr']['database']); if (empty($record['ukey'])) { - /** @var \TYPO3\CMS\Core\Messaging\FlashMessage $message */ + /** @var FlashMessage $message */ $message = GeneralUtility::makeInstance( - \TYPO3\CMS\Core\Messaging\FlashMessage::class, + FlashMessage::class, 'Ukey field value can\'t be empty', 'Translatr', - \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR, + FlashMessage::ERROR, true ); - /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */ - $flashMessageService = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService::class); + /** @var $flashMessageService FlashMessageService */ + $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class); $flashMessageService->getMessageQueueByIdentifier()->addMessage($message); $db->update('tx_translatr_domain_model_label', ['deleted' => 1], ['uid' => (int)$id]); @@ -82,21 +86,4 @@ public function processDatamap_afterDatabaseOperations( $db->update('tx_translatr_domain_model_label', ['modify' => 1], ['uid' => (int)$id]); } } - - /** - * Make atomic remove. - * @param $language - */ - private function clearCacheForLanguage($language) - { - // TODO: clear only for language and not for all - $tempPath = \SourceBroker\Translatr\Utility\FileUtility::getTempFolderPath(); - $tempPathRenamed = $tempPath . time(); - rename($tempPath, $tempPathRenamed); - GeneralUtility::rmdir($tempPathRenamed, true); - - /** @var \TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $cacheFrontend */ - $cacheFrontend = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Cache\\CacheManager')->getCache('l10n'); - $cacheFrontend->flush(); - } } diff --git a/Classes/Service/BaseService.php b/Classes/Service/BaseService.php new file mode 100644 index 0000000..be80704 --- /dev/null +++ b/Classes/Service/BaseService.php @@ -0,0 +1,27 @@ +objectManager = GeneralUtility::makeInstance(ObjectManager::class); + } +} diff --git a/Classes/Service/CacheCleaner.php b/Classes/Service/CacheCleaner.php new file mode 100644 index 0000000..39ad55a --- /dev/null +++ b/Classes/Service/CacheCleaner.php @@ -0,0 +1,51 @@ +cacheManager = $this->objectManager->get(CacheManager::class); + } + + /** + * @return null|HtmlResponse + */ + public function flushCache(): ?HtmlResponse + { + $tempPath = FileUtility::getTempFolderPath(); + $tempPathRenamed = $tempPath . time(); + rename($tempPath, $tempPathRenamed); + GeneralUtility::rmdir($tempPathRenamed, true); + try { + $cacheFrontend = $this->cacheManager->getCache('l10n'); + $cacheFrontend->flush(); + } catch (NoSuchCacheException $e) { + } + + return MiscUtility::isTypo39up() ? new HtmlResponse('') : null; + } +} diff --git a/Classes/Service/ImportProcess.php b/Classes/Service/ImportProcess.php index 662cc4e..69b1071 100644 --- a/Classes/Service/ImportProcess.php +++ b/Classes/Service/ImportProcess.php @@ -14,18 +14,13 @@ * Class ImportProcess * @package SourceBroker\Translatr\Service */ -class ImportProcess +class ImportProcess extends BaseService { /** * Should contain comma separated values */ const ALLOWED_PROPERTIES = ['tags']; - /** - * @var ObjectManager - */ - protected $objectManager; - /** * @var YamlFileHandler */ @@ -41,7 +36,7 @@ class ImportProcess */ public function __construct() { - $this->objectManager = GeneralUtility::makeInstance(ObjectManager::class); + parent::__construct(); $this->yamlFileHandler = $this->objectManager->get(YamlFileHandler::class); $this->labelRepository = $this->objectManager->get(LabelRepository::class); } diff --git a/Classes/Service/YamlFileHandler.php b/Classes/Service/YamlFileHandler.php index 85009e0..339f58b 100644 --- a/Classes/Service/YamlFileHandler.php +++ b/Classes/Service/YamlFileHandler.php @@ -12,17 +12,12 @@ * Class YamlFileHandler * @package SourceBroker\Translatr\Service */ -class YamlFileHandler +class YamlFileHandler extends BaseService { const LANG_FILE_PATH = '/Resources/Private/Language/'; const ROOT_NAME = 'ext'; const FILENAME = 'Configuration.yaml'; - /** - * @var ObjectManager - */ - protected $objectManager; - /** * @var YamlFileLoader */ @@ -38,7 +33,7 @@ class YamlFileHandler */ public function __construct() { - $this->objectManager = GeneralUtility::makeInstance(ObjectManager::class); + parent::__construct(); $this->packageManager = $this->objectManager->get(PackageManager::class); $this->yamlFileLoader = $this->objectManager->get(YamlFileLoader::class); } diff --git a/Classes/Toolbar/ToolbarItem.php b/Classes/Toolbar/ToolbarItem.php index 7370817..047cc75 100644 --- a/Classes/Toolbar/ToolbarItem.php +++ b/Classes/Toolbar/ToolbarItem.php @@ -14,6 +14,8 @@ * * The TYPO3 project - inspiring people to share! */ + +use SourceBroker\Translatr\Service\CacheCleaner; use SourceBroker\Translatr\Utility\MiscUtility; use TYPO3\CMS\Backend\Routing\UriBuilder; use TYPO3\CMS\Backend\Utility\BackendUtility; @@ -81,23 +83,13 @@ public function manipulateCacheActions(&$cacheActions, &$optionValues) } /** - * Flushes the language cache (l10n). - * - * @return void + * @return HtmlResponse|null */ - public function flushCache() + public function flushCache() : ?HtmlResponse { - $tempPath = \SourceBroker\Translatr\Utility\FileUtility::getTempFolderPath(); - $tempPathRenamed = $tempPath . time(); - rename($tempPath, $tempPathRenamed); - GeneralUtility::rmdir($tempPathRenamed, true); + $cache = GeneralUtility::makeInstance(CacheCleaner::class); - /** @var \TYPO3\CMS\Core\Cache\Frontend\FrontendInterface $cacheFrontend */ - $cacheFrontend = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Cache\\CacheManager')->getCache('l10n'); - $cacheFrontend->flush(); - if (MiscUtility::isTypo39up()) { - return new HtmlResponse(''); - } + return $cache->flushCache(); } /** diff --git a/Classes/Utility/FileUtility.php b/Classes/Utility/FileUtility.php index e732738..f7c5964 100644 --- a/Classes/Utility/FileUtility.php +++ b/Classes/Utility/FileUtility.php @@ -46,6 +46,7 @@ public static function getTempFolderPath() if (!is_dir($tempFolderPath)) { GeneralUtility::mkdir_deep($tempFolderPath); } + return $tempFolderPath; } } From 9d3f1446bbc62a6c1952bd52cdaa791a62a7a5e3 Mon Sep 17 00:00:00 2001 From: Kamil Maliszewski Date: Wed, 5 Feb 2020 12:16:28 +0100 Subject: [PATCH 09/13] [FIX] Fix not working button to remove from list in TYPO3 9.x --- .../Private/Backend/Partials/Label/ActionButtons/Remove.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Resources/Private/Backend/Partials/Label/ActionButtons/Remove.html b/Resources/Private/Backend/Partials/Label/ActionButtons/Remove.html index 01e9396..e0358f4 100644 --- a/Resources/Private/Backend/Partials/Label/ActionButtons/Remove.html +++ b/Resources/Private/Backend/Partials/Label/ActionButtons/Remove.html @@ -9,6 +9,8 @@ data-l10parent="{label.l10n_parent}" data-params="cmd[tx_translatr_domain_model_label][{label.uid}][delete]=1" data-title="{label.text}" + data-button-close-text="Cancel" + data-button-ok-text="Delete" data-message='Are you sure you want to delete "{label.text}" record?' title="" data-original-title="Delete record (!)" @@ -16,4 +18,4 @@ - \ No newline at end of file + From 95c6cd69632570b91114f2b84fec1cc1c70694a6 Mon Sep 17 00:00:00 2001 From: Kamil Maliszewski Date: Wed, 5 Feb 2020 23:51:15 +0100 Subject: [PATCH 10/13] [FIX] Fix problem with rendering BE list when no language is selected --- Classes/Database/Database87.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/Database/Database87.php b/Classes/Database/Database87.php index 6130f2b..872fc72 100644 --- a/Classes/Database/Database87.php +++ b/Classes/Database/Database87.php @@ -55,7 +55,7 @@ public function findDemandedForBe(BeLabelDemand $demand) if ($demand->getKeys()) { $keyWhere = ' AND label.ukey IN (' . implode(',', $this->wrapArrayByQuote($demand->getKeys())) . ') '; } - $languages = implode(',', count($demand->getLanguages()) ? $this->wrapArrayByQuote($demand->getLanguages()) : ['default']); + $languages = implode(',', $this->wrapArrayByQuote(count($demand->getLanguages()) ? $demand->getLanguages() : ['default'])); $query = << Date: Wed, 5 Feb 2020 23:52:20 +0100 Subject: [PATCH 11/13] [FEATURE] Create missing default labels from extension before each task execution --- Classes/Domain/Repository/LabelRepository.php | 6 ++++-- Classes/Service/ImportProcess.php | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Classes/Domain/Repository/LabelRepository.php b/Classes/Domain/Repository/LabelRepository.php index 9e2e44f..16d03c4 100644 --- a/Classes/Domain/Repository/LabelRepository.php +++ b/Classes/Domain/Repository/LabelRepository.php @@ -73,7 +73,6 @@ public function getExtensionsItems() * @param string $extKey * * @return void - * @throws IllegalObjectTypeException * @todo When support for more files will be implemented, then indexing * proces should be moved somewhere else to speed up the BE module * (currently it's done on every request to keep labels up to date) @@ -124,7 +123,10 @@ public function indexExtensionLabels($extKey) $obj->setLlFileIndex(strrev(FileUtility::getRelativePathFromAbsolute($llFile))); $obj->setLanguage('default'); if (!$this->isLabelIndexed($obj)) { - $this->add($obj); + try { + $this->add($obj); + } catch (IllegalObjectTypeException $e) { + } } unset($obj); } diff --git a/Classes/Service/ImportProcess.php b/Classes/Service/ImportProcess.php index 69b1071..9d1701b 100644 --- a/Classes/Service/ImportProcess.php +++ b/Classes/Service/ImportProcess.php @@ -55,7 +55,8 @@ public function getDataToImport(): array */ public function importDataFromSingleFile(string $extension, array $file): void { - $this->pushMissingKeyToDatabase($extension, $file['labels'], $file['path']); + $this->labelRepository->indexExtensionLabels($extension); + $this->pushMissingKeyTranslationsToDatabase($extension, $file['labels'], $file['path']); foreach ($file['labels'] as $key => $properties) { $values = []; foreach ($properties as $propertyName => $property) { @@ -79,7 +80,7 @@ public function importDataFromSingleFile(string $extension, array $file): void * @param array $keys * @param string $path */ - protected function pushMissingKeyToDatabase(string $extension, array $keys, string $path): void + protected function pushMissingKeyTranslationsToDatabase(string $extension, array $keys, string $path): void { $allLanguages = array_keys(LanguageUtility::getAvailableLanguages()); $demand = $this->objectManager->get(BeLabelDemand::class); From 3be555d06db3ddc9e44d5e35d5d02469b11c6cb3 Mon Sep 17 00:00:00 2001 From: Kamil Maliszewski Date: Mon, 10 Feb 2020 18:48:32 +0100 Subject: [PATCH 12/13] [FIX] Solve problem with rendering BE module when languages are selected [FEATURE] Override also labels in default language if flag `modify` doesn't exist --- Classes/Database/Database87.php | 2 +- Classes/Domain/Model/Dto/BeLabelDemand.php | 10 +--------- Classes/Domain/Repository/LabelRepository.php | 20 ++++++++++++++----- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/Classes/Database/Database87.php b/Classes/Database/Database87.php index 872fc72..7a61529 100644 --- a/Classes/Database/Database87.php +++ b/Classes/Database/Database87.php @@ -55,7 +55,7 @@ public function findDemandedForBe(BeLabelDemand $demand) if ($demand->getKeys()) { $keyWhere = ' AND label.ukey IN (' . implode(',', $this->wrapArrayByQuote($demand->getKeys())) . ') '; } - $languages = implode(',', $this->wrapArrayByQuote(count($demand->getLanguages()) ? $demand->getLanguages() : ['default'])); + $languages = implode(',', $this->wrapArrayByQuote($demand->getLanguages() ? $demand->getLanguages() : ['default'])); $query = <<languages = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage(); - } - /** * @return string */ diff --git a/Classes/Domain/Repository/LabelRepository.php b/Classes/Domain/Repository/LabelRepository.php index 16d03c4..be82270 100644 --- a/Classes/Domain/Repository/LabelRepository.php +++ b/Classes/Domain/Repository/LabelRepository.php @@ -10,6 +10,7 @@ use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException; +use TYPO3\CMS\Extbase\Persistence\Exception\UnknownObjectException; use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager; /*************************************************************** @@ -117,16 +118,25 @@ public function indexExtensionLabels($extKey) foreach ($labels as $labelKey => $label) { $obj = new Label(); $obj->setExtension($extKey); + $obj->setPid(0); $obj->setText($label); $obj->setUkey($labelKey); $obj->setLlFile(FileUtility::getRelativePathFromAbsolute($llFile)); $obj->setLlFileIndex(strrev(FileUtility::getRelativePathFromAbsolute($llFile))); $obj->setLanguage('default'); - if (!$this->isLabelIndexed($obj)) { - try { + /** @var Label $indexedLabel */ + $indexedLabel = $this->getIndexedLabel($obj); + try { + if ($indexedLabel) { + if (!$indexedLabel->getModify()) { + $indexedLabel->setText($obj->getText()); + $this->update($indexedLabel); + } + } else { $this->add($obj); - } catch (IllegalObjectTypeException $e) { } + } catch (IllegalObjectTypeException $e) { + } catch (UnknownObjectException $e) { } unset($obj); } @@ -139,7 +149,7 @@ public function indexExtensionLabels($extKey) * * @return bool */ - protected function isLabelIndexed(Label $label) + protected function getIndexedLabel(Label $label) { $query = $this->createQuery(); @@ -152,7 +162,7 @@ protected function isLabelIndexed(Label $label) $query->equals('language', $label->getLanguage()), $query->equals('llFile', $label->getLlFile()), $query->equals('ukey', $label->getUkey()), - ]))->count() > 0; + ]))->execute()->getFirst(); } /** From e8c16cd36285b4c29f178cd73b312eed9f68ccc9 Mon Sep 17 00:00:00 2001 From: Kamil Maliszewski Date: Wed, 16 Sep 2020 10:02:41 +0200 Subject: [PATCH 13/13] [FIX] Solve problem with cli task to create new records --- Classes/Domain/Repository/LabelRepository.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Classes/Domain/Repository/LabelRepository.php b/Classes/Domain/Repository/LabelRepository.php index 2bd43fa..3fc36ab 100644 --- a/Classes/Domain/Repository/LabelRepository.php +++ b/Classes/Domain/Repository/LabelRepository.php @@ -125,6 +125,7 @@ public function indexExtensionLabels($extKey) $obj->setLlFile(FileUtility::getRelativePathFromAbsolute($llFile)); $obj->setLlFileIndex(strrev(FileUtility::getRelativePathFromAbsolute($llFile))); $obj->setLanguage('default'); + $obj->setModify(0); /** @var Label $indexedLabel */ $indexedLabel = $this->getIndexedLabel($obj); try { @@ -231,6 +232,7 @@ public function createLanguageChildFromDefault(array $defaultLabel, string $tran $label->setLlFileIndex(strrev($defaultLabel['ll_file'])); $label->setLanguage($language); $label->setTags($defaultLabel['tags']); + $label->setModify(0); try { $this->add($label); } catch (IllegalObjectTypeException $e) {
Label ({language}) Tags
{label.tags}