From b4dc1a50932ba45acd3b3fa7dca0a4eec78ed8ef Mon Sep 17 00:00:00 2001 From: Jean-Christian Denis Date: Wed, 15 Mar 2023 00:26:31 +0100 Subject: [PATCH] use namespace --- src/Backend.php | 134 ++--- src/BackendBehaviors.php | 86 +++ src/Config.php | 246 +++++--- src/Exception.php | 21 + src/Install.php | 86 ++- src/Manage.php | 1107 ++++++++++++++++++----------------- src/My.php | 140 +++++ src/Prepend.php | 40 +- src/ProposalGoogle.php | 16 +- src/ProposalMicrosoft.php | 18 +- src/ProposalTranslater.php | 4 + src/Rest.php | 15 +- src/Translater.php | 171 ++---- src/TranslaterLang.php | 50 +- src/TranslaterModule.php | 147 ++--- src/TranslaterProposals.php | 7 + src/Uninstall.php | 157 ++--- 17 files changed, 1409 insertions(+), 1036 deletions(-) create mode 100644 src/BackendBehaviors.php create mode 100644 src/Exception.php create mode 100644 src/My.php diff --git a/src/Backend.php b/src/Backend.php index c1847f9..42e1047 100644 --- a/src/Backend.php +++ b/src/Backend.php @@ -10,112 +10,58 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_CONTEXT_ADMIN')) { - return; -} +declare(strict_types=1); -if (!dcCore::app()->auth->isSuperAdmin()) { - return null; -} +namespace Dotclear\Plugin\translater; -dcCore::app()->addBehaviors([ - 'adminModulesListGetActions' => ['translaterAdminBehaviors', 'adminModulesGetActions'], - 'adminModulesListDoActions' => ['translaterAdminBehaviors', 'adminModulesDoActions'], - 'adminDashboardFavoritesV2' => ['translaterAdminBehaviors', 'adminDashboardFavoritesV2'], -]); +use dcAdmin; +use dcCore; +use dcFavorites; +use dcNsProcess; +use dcPage; -dcCore::app()->menu[dcAdmin::MENU_PLUGINS]->addItem( - __('Translater'), - dcCore::app()->adminurl->get(basename(__DIR__)), - dcPage::getPF(basename(__DIR__) . '/icon.svg'), - preg_match( - '/' . preg_quote(dcCore::app()->adminurl->get(basename(__DIR__))) . '(&.*)?$/', - $_SERVER['REQUEST_URI'] - ), - dcCore::app()->auth->isSuperAdmin() -); - -class translaterAdminBehaviors +class Backend extends dcNsProcess { - /** @var dcTranslater dcTranslater instance */ - private static $translater = null; - - /** - * Create instance of dcTranslater once - * - * @return dcTranslater dcTranslater instance - */ - private static function translater(): dcTranslater + public static function init(): bool { - if (!is_a(self::$translater, 'dcTranslater')) { - self::$translater = new dcTranslater(false); + if (defined('DC_CONTEXT_ADMIN')) { + self::$init = dcCore::app()->auth->isSuperAdmin(); } - return self::$translater; + return self::$init; } - /** - * Add button to go to module translation - * - * @param adminModulesList $list adminModulesList instance - * @param string $id Module id - * @param array $prop Module properties - * - * @return string HTML submit button - */ - public static function adminModulesGetActions(adminModulesList $list, string $id, array $prop): ?string + public static function process(): bool { - if ($list->getList() != $prop['type'] . '-activate' - || !self::translater()->{$prop['type'] . '_menu'} - || !dcCore::app()->auth->isSuperAdmin() - ) { - return null; - } - if (self::translater()->hide_default - && in_array($id, dcTranslater::$default_distrib_modules[$prop['type']]) - ) { - return null; + if (!self::$init) { + return false; } - return - ' '; - } - - /** - * Redirect to module translation - * - * @param adminModulesList $list adminModulesList instance - * @param array $modules Selected modules ids - * @param string $type List type (plugin|theme) - */ - public static function adminModulesDoActions(adminModulesList $list, array $modules, string $type): void - { - if (empty($_POST['translater']) || !is_array($_POST['translater'])) { - return; - } - - dcCore::app()->adminurl->redirect( - basename(__DIR__), - ['part' => 'module', 'type' => $type, 'module' => key($_POST['translater'])], - '#module-lang' - ); - } - - /** - * Add dashboard favorites icon - * - * @param dcFavorites $favs dcFavorites instance - */ - public static function adminDashboardFavoritesV2(dcFavorites $favs): void - { - $favs->register('translater', [ - 'title' => __('Translater'), - 'url' => dcCore::app()->adminurl->get(basename(__DIR__)), - 'small-icon' => urldecode(dcPage::getPF(basename(__DIR__) . '/icon.svg')), - 'large-icon' => urldecode(dcPage::getPF(basename(__DIR__) . '/icon.svg')), - //'permissions' => null, + dcCore::app()->addBehaviors([ + 'adminModulesListGetActions' => [BackendBehaviors::class, 'adminModulesGetActions'], + 'adminModulesListDoActions' => [BackendBehaviors::class, 'adminModulesDoActions'], + 'adminDashboardFavoritesV2' => function (dcFavorites $favs): void { + $favs->register(My::id(), [ + 'title' => My::name(), + 'url' => dcCore::app()->adminurl->get(My::id()), + 'small-icon' => urldecode(dcPage::getPF(My::id() . '/icon.svg')), + 'large-icon' => urldecode(dcPage::getPF(My::id() . '/icon.svg')), + //'permissions' => null, + ]); + }, ]); + + dcCore::app()->menu[dcAdmin::MENU_PLUGINS]->addItem( + My::name(), + dcCore::app()->adminurl->get(My::id()), + dcPage::getPF(My::id() . '/icon.svg'), + preg_match( + '/' . preg_quote(dcCore::app()->adminurl->get(My::id())) . '(&.*)?$/', + $_SERVER['REQUEST_URI'] + ), + dcCore::app()->auth->isSuperAdmin() + ); + + return true; } } diff --git a/src/BackendBehaviors.php b/src/BackendBehaviors.php new file mode 100644 index 0000000..2369bdf --- /dev/null +++ b/src/BackendBehaviors.php @@ -0,0 +1,86 @@ +getList() != $prop['type'] . '-activate' + || !self::translater()->get($prop['type'] . '_menu') + || !dcCore::app()->auth->isSuperAdmin() + ) { + return null; + } + if (self::translater()->get('hide_default') + && in_array($id, My::defaultDistribModules($prop['type'])) + ) { + return null; + } + + return (new Input(['translater[' . html::escapeHTML($id) . ']', null]))->value(__('Translate')); + } + + /** + * Redirect to module translation + * + * @param adminModulesList $list adminModulesList instance + * @param array $modules Selected modules ids + * @param string $type List type (plugin|theme) + */ + public static function adminModulesDoActions(adminModulesList $list, array $modules, string $type): void + { + if (empty($_POST['translater']) || !is_array($_POST['translater'])) { + return; + } + + dcCore::app()->adminurl->redirect( + My::id(), + ['part' => 'module', 'type' => $type, 'module' => key($_POST['translater'])], + '#module-lang' + ); + } +} diff --git a/src/Config.php b/src/Config.php index 3f94537..cfdf027 100644 --- a/src/Config.php +++ b/src/Config.php @@ -10,93 +10,169 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_CONTEXT_MODULE')) { - return null; -} +declare(strict_types=1); -$translater = new dcTranslater(); +namespace Dotclear\Plugin\translater; -if (!empty($_POST['save'])) { - try { - foreach ($translater->getDefaultSettings() as $key => $value) { - $translater->$key = $_POST[$key] ?? ''; +use dcCore; +use dcNsProcess; +use dcPage; + +use Dotclear\Helper\Html\Form\{ + Checkbox, + Div, + Fieldset, + Input, + Label, + Legend, + Note, + Number, + Para, + Select +}; + +class Config extends dcNsProcess +{ + public static function init(): bool + { + self::$init = defined('DC_CONTEXT_ADMIN'); + + return self::$init; + } + + public static function process(): bool + { + if (!self::$init) { + return false; } - $translater->writeSettings(); - dcAdminNotices::addSuccessNotice( - __('Configuration successfully updated.') - ); - dcCore::app()->adminurl->redirect( - 'admin.plugins', - ['module' => basename(__DIR__), 'conf' => 1, 'redir' => dcCore::app()->admin->__get('list')->getRedir()] - ); - } catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); + + // nothing to process + if (empty($_POST['save'])) { + return true; + } + + $translater = new Translater(); + + try { + foreach (My::defaultSettings() as $key => $value) { + $translater->set($key, $_POST[$key] ?? ''); + } + $translater->writeSettings(); + + dcPage::addSuccessNotice( + __('Configuration successfully updated.') + ); + dcCore::app()->adminurl->redirect( + 'admin.plugins', + ['module' => My::id(), 'conf' => 1, 'redir' => dcCore::app()->admin->__get('list')->getRedir()] + ); + } catch (Exception $e) { + dcCore::app()->error->add($e->getMessage()); + } + + return true; + } + + public static function render(): void + { + if (!self::$init) { + return; + } + + $translater = new Translater(); + + echo (new Div())->items([ + (new Fieldset())->class('fieldset')->legend((new Legend(__('Translation'))))->fields([ + // write_langphp + (new Para())->items([ + (new Checkbox('write_langphp', $translater->get('write_langphp')))->value(1), + (new Label(__('Write .lang.php files'), Label::OUTSIDE_LABEL_AFTER))->for('write_langphp')->class('classic'), + ]), + // scan_tpl + (new Para())->items([ + (new Checkbox('scan_tpl', $translater->get('scan_tpl')))->value(1), + (new Label(__('Translate also strings of template files'), Label::OUTSIDE_LABEL_AFTER))->for('scan_tpl')->class('classic'), + ]), + // parse_nodc + (new Para())->items([ + (new Checkbox('parse_nodc', $translater->get('parse_nodc')))->value(1), + (new Label(__('Translate only unknow strings'), Label::OUTSIDE_LABEL_AFTER))->for('parse_nodc')->class('classic'), + ]), + // hide_default + (new Para())->items([ + (new Checkbox('hide_default', $translater->get('hide_default')))->value(1), + (new Label(__('Hide default modules of Dotclear'), Label::OUTSIDE_LABEL_AFTER))->for('hide_default')->class('classic'), + ]), + // parse_comment + (new Para())->items([ + (new Checkbox('parse_comment', $translater->get('parse_comment')))->value(1), + (new Label(__('Write comments in files'), Label::OUTSIDE_LABEL_AFTER))->for('parse_comment')->class('classic'), + ]), + // parse_user + (new Para())->items([ + (new Checkbox('parse_user', $translater->get('parse_user')))->value(1), + (new Label(__('Write informations about author in files'), Label::OUTSIDE_LABEL_AFTER))->for('parse_user')->class('classic'), + ]), + // parse_userinfo + (new Para())->items([ + (new Label(__('User info:')))->for('parse_userinfo'), + (new Input('parse_userinfo'))->size(65)->maxlenght(255)->value($translater->get('parse_userinfo')), + ]), + (new Note())->text(sprintf( + __('Following informations can be used: %s'), + implode(', ', My::defaultUserInformations()) + ))->class('form-note'), + ]), + (new Fieldset())->class('fieldset')->legend((new Legend(__('Import/Export'))))->fields([ + // import_overwrite + (new Para())->items([ + (new Checkbox('import_overwrite', $translater->get('import_overwrite')))->value(1), + (new Label(__('Overwrite existing languages'), Label::OUTSIDE_LABEL_AFTER))->for('import_overwrite')->class('classic'), + ]), + // export_filename + (new Para())->items([ + (new Label(__('Name of exported package:')))->for('export_filename'), + (new Input('export_filename'))->size(65)->maxlenght(255)->value($translater->get('export_filename')), + ]), + ]), + (new Fieldset())->class('fieldset')->legend((new Legend(__('Backups'))))->fields([ + // backup_auto + (new Para())->items([ + (new Checkbox('backup_auto', $translater->get('backup_auto')))->value(1), + (new Label(__('Make backups when changes are made'), Label::OUTSIDE_LABEL_AFTER))->for('backup_auto')->class('classic'), + ]), + // backup_limit + (new Para())->items([ + (new Label(__('Limit backups per module to:')))->for('backup_limit')->class('classic'), + (new Number('backup_limit'))->min(0)->max(50)->value($translater->get('backup_limit')), + ]), + (new Note())->text(__('Set to 0 for no limit.'))->class('form-note'), + // backup_folder + (new Para())->items([ + (new Label(__('Store backups in:')))->for('backup_folder'), + (new Select('backup_folder'))->default($translater->get('backup_folder'))->items(My::backupFoldersCombo()), + ]), + ]), + (new Fieldset())->class('fieldset')->legend((new Legend(__('Behaviors'))))->fields([ + // start_page + (new Para())->items([ + (new Label(__('Default start menu:')))->for('start_page'), + (new Select('start_page'))->default($translater->get('start_page'))->items(My::startPageCombo()), + ]), + // plugin_menu + (new Para())->items([ + (new Checkbox('plugin_menu', $translater->get('plugin_menu')))->value(1), + (new Label(__('Enable menu on plugins page'), Label::OUTSIDE_LABEL_AFTER))->for('plugin_menu')->class('classic'), + ]), + // theme_menu + (new Para())->items([ + (new Checkbox('theme_menu', $translater->get('theme_menu')))->value(1), + (new Label(__('Enable menu on themes page'), Label::OUTSIDE_LABEL_AFTER))->for('theme_menu')->class('classic'), + ]), + + ]), + ])->render(); + + dcPage::helpBlock('translater.config'); } } - -echo ' -

' . __('Translation') . '

-

-

-

-

-

-

-

' . -form::field('parse_userinfo', 65, 255, $translater->parse_userinfo) . '

-

' . sprintf( - __('Following informations can be used: %s'), - implode(', ', $translater::$allowed_user_informations) -) . ' -

-
- -

' . __('Import/Export') . '

-

-

' . -form::field('export_filename', 65, 255, $translater->export_filename) . '

-
- -

' . __('Backups') . '

-

-

-

' . __('Set to 0 for no limit.') . '

-

' . -form::combo('backup_folder', $translater::$allowed_backup_folders, $translater->backup_folder) . '

-
- -

' . __('Behaviors') . '

-

' . -form::combo('start_page', [ - __('Plugins') => 'plugin', - __('Themes') => 'theme', - __('Home') => '-', -], $translater->start_page) . '

-

-

-
'; - -dcPage::helpBlock('translater.config'); diff --git a/src/Exception.php b/src/Exception.php new file mode 100644 index 0000000..3279487 --- /dev/null +++ b/src/Exception.php @@ -0,0 +1,21 @@ +newVersion( - basename(__DIR__), - dcCore::app()->plugins->moduleInfo(basename(__DIR__), 'version') - )) { - return null; - } - $translater = new dcTranslater(false); - if (!$translater->growUp()) { - $translater->writeSettings(false); +namespace Dotclear\Plugin\translater; + +use dcCore; +use dcNamespace; +use dcNsProcess; + +class Install extends dcNsProcess +{ + public static function init(): bool + { + self::$init = defined('DC_CONTEXT_ADMIN') && dcCore::app()->newVersion(My::id(), dcCore::app()->plugins->moduleInfo(My::id(), 'version')); + + return self::$init; } - return true; -} catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); -} + public static function process(): bool + { + if (!self::$init) { + return false; + } -return false; + try { + self::growUp(); + + foreach (My::defaultSettings() as $key => $value) { + dcCore::app()->blog->settings->get(My::id())->drop($key); + dcCore::app()->blog->settings->get(My::id())->put($key, $value, gettype($value), '', false, true); + } + + return true; + } catch (Exception $e) { + dcCore::app()->error->add($e->getMessage()); + } + + return true; + } + + /** + * Upgrade plugin + * + * @return bool Upgrade done + */ + public static function growUp() + { + $current = dcCore::app()->getVersion(My::id()); + + // use short settings id + if ($current && version_compare($current, '2022.12.22', '<')) { + $record = dcCore::app()->con->select( + 'SELECT * FROM ' . dcCore::app()->prefix . dcNamespace::NS_TABLE_NAME . ' ' . + "WHERE setting_ns = 'translater' " + ); + while ($record->fetch()) { + if (preg_match('/^translater_(.*?)$/', $record->setting_id, $match)) { + $cur = dcCore::app()->con->openCursor(dcCore::app()->prefix . dcNamespace::NS_TABLE_NAME); + $cur->setting_id = $match[1]; + $cur->setting_ns = My::id(); + $cur->update( + "WHERE setting_id = '" . $record->setting_id . "' and setting_ns = 'translater' " . + 'AND blog_id ' . (null === $record->blog_id ? 'IS NULL ' : ("= '" . dcCore::app()->con->escape($record->blog_id) . "' ")) + ); + } + } + + return true; + } + + return false; + } +} diff --git a/src/Manage.php b/src/Manage.php index 6207bcb..f37f400 100644 --- a/src/Manage.php +++ b/src/Manage.php @@ -10,510 +10,495 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_CONTEXT_ADMIN')) { - return; -} +declare(strict_types=1); -dcPage::checkSuper(); +namespace Dotclear\Plugin\translater; -$translater = new dcTranslater(); +use dcCore; +use dcNsProcess; +use dcPage; +use dt; +use html; +use files; +use form; -$type = $_REQUEST['type'] ?? $translater->start_page ?: ''; -$module = $_REQUEST['module'] ?? ''; -$lang = $_REQUEST['lang'] ?? ''; -$action = $_POST['action'] ?? ''; - -if (!in_array($type, ['plugin', 'theme'])) { - $type = ''; -} - -if (!empty($type) && !empty($module)) { - try { - $module = $translater->getModule($type, $module); - } catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); - $module = ''; - } -} - -if (!empty($module) && !empty($lang)) { - try { - $lang = $translater->getLang($module, $lang); - } catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); - $lang = ''; - } -} - -$breadcrumb = [__('Translater') => dcCore::app()->adminurl->get(basename(__DIR__), ['type' => '-'])]; -if (empty($type)) { - $breadcrumb = [__('Translater') => '']; -} elseif (empty($module)) { - $breadcrumb[$type == 'plugin' ? __('Plugins') : __('Themes')] = ''; -} elseif (empty($lang)) { - $breadcrumb[$type == 'plugin' ? __('Plugins') : __('Themes')] = dcCore::app()->adminurl->get(basename(__DIR__), ['type' => $type]); - $breadcrumb[html::escapeHTML($module->name)] = ''; -} elseif (!empty($lang)) { - $breadcrumb[$type == 'plugin' ? __('Plugins') : __('Themes')] = dcCore::app()->adminurl->get(basename(__DIR__), ['type' => $type]); - $breadcrumb[html::escapeHTML($module->name)] = dcCore::app()->adminurl->get(basename(__DIR__), ['type' => $type, 'module' => $module->id]); - $breadcrumb[html::escapeHTML(sprintf(__('%s language edition'), $lang->name))] = ''; -} - -try { - if ($action == 'module_create_backups') { - if (empty($module) || empty($_POST['codes'])) { - throw new Exception(__('Nothing to backup')); +class Manage extends dcNsProcess +{ + public static function init(): bool + { + if (defined('DC_CONTEXT_ADMIN')) { + self::$init = dcCore::app()->auth->isSuperAdmin(); } - $module_codes = $module->getUsedlangs(); - foreach ($module_codes as $code_id) { - if (in_array($code_id, $_POST['codes'])) { - $module->createBackup($code_id); + + return self::$init; + } + + public static function process(): bool + { + if (!self::$init) { + return false; + } + + // set vars used in process and render methods + dcCore::app()->admin->translater = new Translater(); + dcCore::app()->admin->type = $_REQUEST['type'] ?? dcCore::app()->admin->translater->get('start_page') ?: ''; + dcCore::app()->admin->module = $_REQUEST['module'] ?? ''; + dcCore::app()->admin->lang = $_REQUEST['lang'] ?? ''; + $action = $_POST['action'] ?? ''; + + // check module type + if (!in_array(dcCore::app()->admin->type, ['plugin', 'theme'])) { + dcCore::app()->admin->type = ''; + } + // check if module exists + if (!empty(dcCore::app()->admin->type) && !empty(dcCore::app()->admin->module)) { + try { + dcCore::app()->admin->module = dcCore::app()->admin->translater->getModule(dcCore::app()->admin->type, dcCore::app()->admin->module); + } catch (Exception $e) { + dcCore::app()->error->add($e->getMessage()); + dcCore::app()->admin->module = ''; } } - dcAdminNotices::addSuccessNotice(__('Backup successfully created')); - dcCore::app()->adminurl->redirect(basename(__DIR__), ['type' => $type, 'module' => $module->id]); - } - - if ($action == 'module_restore_backup') { - if (empty($module) || empty($_POST['files'])) { - throw new Exception(__('Nothing to restore')); - } - $module_backups = $module->getBackups(true); - foreach ($module_backups as $backup_file) { - if (in_array($backup_file, $_POST['files'])) { - $module->restoreBackup($backup_file); + //check if module lang exists + if (!empty(dcCore::app()->admin->module) && !empty(dcCore::app()->admin->lang)) { + try { + dcCore::app()->admin->lang = dcCore::app()->admin->translater->getLang(dcCore::app()->admin->module, dcCore::app()->admin->lang); + } catch (Exception $e) { + dcCore::app()->error->add($e->getMessage()); + dcCore::app()->admin->lang = ''; } } - dcAdminNotices::addSuccessNotice(__('Backup successfully restored')); - dcCore::app()->adminurl->redirect(basename(__DIR__), ['type' => $type, 'module' => $module->id]); - } - if ($action == 'module_delete_backup') { - if (empty($module) || empty($_POST['files'])) { - throw new Exception(__('Nothing to delete')); - } - $module_backups = $module->getBackups(true); - foreach ($module_backups as $backup_file) { - if (in_array($backup_file, $_POST['files'])) { - $module->deleteBackup($backup_file); - } - } - dcAdminNotices::addSuccessNotice(__('Backup successfully deleted')); - dcCore::app()->adminurl->redirect(basename(__DIR__), ['type' => $type, 'module' => $module->id]); - } - - if ($action == 'module_export_pack') { - if (empty($module) || empty($_POST['codes'])) { - throw new Exception(__('Nothing to export')); - } - $module->exportPack($_POST['codes']); - - dcAdminNotices::addSuccessNotice(__('Language successfully exported')); - dcCore::app()->adminurl->redirect(basename(__DIR__), ['type' => $type, 'module' => $module->id]); - } - - if ($action == 'module_import_pack') { - if (empty($_FILES['packfile']['name'])) { - throw new Exception(__('Nothing to import')); - } - $module->importPack($_FILES['packfile']); - - dcAdminNotices::addSuccessNotice(__('Language successfully imported')); - dcCore::app()->adminurl->redirect(basename(__DIR__), ['type' => $type, 'module' => $module->id]); - } - - if ($action == 'module_add_code') { - if (empty($module) || empty($_POST['code'])) { - throw new Exception(__('Nothing to create')); - } - $module->addLang($_POST['code'], $_POST['from'] ?? ''); - - dcAdminNotices::addSuccessNotice(__('Language successfully added')); - dcCore::app()->adminurl->redirect(basename(__DIR__), ['type' => $type, 'module' => $module->id, 'lang' => $_POST['code']]); - } - - if ($action == 'module_delete_codes') { - if (empty($module) || empty($_POST['codes'])) { - throw new Exception(__('Nothing to delete')); - } - $module_codes = $module->getUsedlangs(); - foreach ($module_codes as $code_id) { - if (in_array($code_id, $_POST['codes'])) { - $module->delLang($code_id); - } - } - dcAdminNotices::addSuccessNotice(__('Language successfully deleted')); - dcCore::app()->adminurl->redirect(basename(__DIR__), ['type' => $type, 'module' => $module->id, 'lang' => $_POST['code']]); - } - - if ($action == 'module_update_code') { - if (empty($module) || empty($_POST['code']) || empty($_POST['entries'])) { - throw new Exception(__('Nothing to update')); - } - if (!empty($_POST['update_group'])) { - foreach ($_POST['entries'] as $i => $entry) { - if (isset($entry['check']) && isset($_POST['multigroup'])) { - $_POST['entries'][$i]['group'] = $_POST['multigroup']; + // execute action + try { + if ($action == 'module_create_backups') { + if (empty(dcCore::app()->admin->module) || empty($_POST['codes'])) { + throw new Exception(__('Nothing to backup')); + } + $module_codes = dcCore::app()->admin->module->getUsedlangs(); + foreach ($module_codes as $code_id) { + if (in_array($code_id, $_POST['codes'])) { + dcCore::app()->admin->module->createBackup($code_id); + } } - } - } - $module->updLang($_POST['code'], $_POST['entries']); - dcAdminNotices::addSuccessNotice(__('Language successfully updated')); - dcCore::app()->adminurl->redirect(basename(__DIR__), ['type' => $type, 'module' => $module->id, 'lang' => $_POST['code']]); + self::redirect(__('Backup successfully created')); + } + + if ($action == 'module_restore_backup') { + if (empty(dcCore::app()->admin->module) || empty($_POST['files'])) { + throw new Exception(__('Nothing to restore')); + } + $module_backups = dcCore::app()->admin->module->getBackups(true); + foreach ($module_backups as $backup_file) { + if (in_array($backup_file, $_POST['files'])) { + dcCore::app()->admin->module->restoreBackup($backup_file); + } + } + + self::redirect(__('Backup successfully restored')); + } + + if ($action == 'module_delete_backup') { + if (empty(dcCore::app()->admin->module) || empty($_POST['files'])) { + throw new Exception(__('Nothing to delete')); + } + $module_backups = dcCore::app()->admin->module->getBackups(true); + foreach ($module_backups as $backup_file) { + if (in_array($backup_file, $_POST['files'])) { + dcCore::app()->admin->module->deleteBackup($backup_file); + } + } + + self::redirect(__('Backup successfully deleted')); + } + + if ($action == 'module_export_pack') { + if (empty(dcCore::app()->admin->module) || empty($_POST['codes'])) { + throw new Exception(__('Nothing to export')); + } + dcCore::app()->admin->module->exportPack($_POST['codes']); + + self::redirect(__('Language successfully exported')); + } + + if ($action == 'module_import_pack') { + if (empty($_FILES['packfile']['name'])) { + throw new Exception(__('Nothing to import')); + } + dcCore::app()->admin->module->importPack($_FILES['packfile']); + + self::redirect(__('Language successfully imported')); + } + + if ($action == 'module_add_code') { + if (empty(dcCore::app()->admin->module) || empty($_POST['code'])) { + throw new Exception(__('Nothing to create')); + } + dcCore::app()->admin->module->addLang($_POST['code'], $_POST['from'] ?? ''); + + self::redirect(__('Language successfully added'), $_POST['code']); + } + + if ($action == 'module_delete_codes') { + if (empty(dcCore::app()->admin->module) || empty($_POST['codes'])) { + throw new Exception(__('Nothing to delete')); + } + $module_codes = dcCore::app()->admin->module->getUsedlangs(); + foreach ($module_codes as $code_id) { + if (in_array($code_id, $_POST['codes'])) { + dcCore::app()->admin->module->delLang($code_id); + } + } + + self::redirect(__('Language successfully deleted'), $_POST['code']); + } + + if ($action == 'module_update_code') { + if (empty(dcCore::app()->admin->module) || empty($_POST['code']) || empty($_POST['entries'])) { + throw new Exception(__('Nothing to update')); + } + if (!empty($_POST['update_group'])) { + foreach ($_POST['entries'] as $i => $entry) { + if (isset($entry['check']) && isset($_POST['multigroup'])) { + $_POST['entries'][$i]['group'] = $_POST['multigroup']; + } + } + } + dcCore::app()->admin->module->updLang($_POST['code'], $_POST['entries']); + + self::redirect(__('Language successfully updated'), $_POST['code']); + } + } catch (Exception $e) { + dcCore::app()->error->add($e->getMessage()); + } + + return true; } -} catch (Exception $e) { - dcCore::app()->error->add($e->getMessage()); -} -echo -'' . __('Translater') . '' . -dcPage::jsPageTabs() . -dcPage::cssModuleLoad(basename(__DIR__) . '/css/translater.css') . -dcPage::jsJson('translater', [ - 'title_add_detail' => __('Use this text'), - 'image_field' => dcPage::getPF(basename(__DIR__) . '/img/field.png'), - 'image_toggle' => dcPage::getPF(basename(__DIR__) . '/img/toggle.png'), -]) . -dcPage::jsModuleLoad(basename(__DIR__) . '/js/translater.js') . - -# --BEHAVIOR-- translaterAdminHeaders -dcCore::app()->callBehavior('translaterAdminHeaders') . - -'' . - -dcPage::breadcrumb($breadcrumb) . -dcPage::notices(); - -if (empty($module) && $type != '') { - // modules list - echo '
'; - - $res = ''; - $modules = $translater->getModules($type); - ksort($modules); - foreach ($modules as $module) { - if ($translater->hide_default && in_array($module->id, $translater::$default_distrib_modules[$type])) { - continue; + public static function render(): void + { + if (!self::$init) { + return; } - if ($module->root_writable) { - $res .= sprintf( - '%s', - dcCore::app()->adminurl->get(basename(__DIR__), ['type' => $module->type, 'module' => $module->id]), - html::escapeHTML(sprintf(__('Translate module %s'), __($module->name))), - html::escapeHTML($module->id) - ); - } else { - $res .= sprintf( - '%s', - html::escapeHTML($module->id) - ); + + $breadcrumb = [My::name() => dcCore::app()->adminurl->get(My::id(), ['type' => '-'])]; + if (empty(dcCore::app()->admin->type)) { + $breadcrumb = [My::name() => '']; + } elseif (empty(dcCore::app()->admin->module)) { + $breadcrumb[dcCore::app()->admin->type == 'plugin' ? __('Plugins') : __('Themes')] = ''; + } elseif (empty(dcCore::app()->admin->lang)) { + $breadcrumb[dcCore::app()->admin->type == 'plugin' ? __('Plugins') : __('Themes')] = dcCore::app()->adminurl->get(My::id(), ['type' => dcCore::app()->admin->type]); + $breadcrumb[html::escapeHTML(dcCore::app()->admin->module->name)] = ''; + } elseif (!empty(dcCore::app()->admin->lang)) { + $breadcrumb[dcCore::app()->admin->type == 'plugin' ? __('Plugins') : __('Themes')] = dcCore::app()->adminurl->get(My::id(), ['type' => dcCore::app()->admin->type]); + $breadcrumb[html::escapeHTML(dcCore::app()->admin->module->name)] = dcCore::app()->adminurl->get(My::id(), ['type' => dcCore::app()->admin->type, 'module' => dcCore::app()->admin->module->id]); + $breadcrumb[html::escapeHTML(sprintf(__('%s language edition'), dcCore::app()->admin->lang->name))] = ''; } - $codes = $module->getLangs(); - foreach ($codes as $code_id => $code_name) { - if ($module->root_writable) { - $codes[$code_id] = sprintf( - '%s (%s)', - html::escapeHTML(sprintf(__('Edit language %s of module %s'), html::escapeHTML($code_name), __($module->name))), - dcCore::app()->adminurl->get(basename(__DIR__), ['type' => $module->type, 'module' => $module->id, 'lang' => $code_id]), - html::escapeHTML($code_name), - $code_id - ); - } else { - $codes[$code_id] = html::escapeHTML($code_name) . '(' . $code_id . ')'; - } - } - $res .= sprintf( - '%s%s%s', - implode(', ', $codes), - html::escapeHTML(__($module->name)), - $module->version + + dcPage::openModule( + My::name(), + dcPage::jsPageTabs() . + dcPage::cssModuleLoad(My::id() . '/css/backend.css') . + dcPage::jsJson('translater', [ + 'title_add_detail' => __('Use this text'), + 'image_field' => dcPage::getPF(My::id() . '/img/field.png'), + 'image_toggle' => dcPage::getPF(My::id() . '/img/toggle.png'), + ]) . + dcPage::jsModuleLoad(My::id() . '/js/backend.js') . + + # --BEHAVIOR-- translaterAdminHeaders + dcCore::app()->callBehavior('translaterAdminHeaders') ); - } - if ($res) { - echo ' -
- - - - - - - - ' . - $res . - '
' . sprintf(__('Modules list of type "%s"'), $type) . '
' . __('Id') . '' . __('Languages') . '' . __('Name') . '' . __('Version') . '
'; - } else { - echo '' . __('There is no editable modules') . ''; - } - echo '
'; - dcPage::helpBlock('translater.type'); -} elseif (!empty($module) && empty($lang)) { - $codes = $module->getUsedLangs(); - $backups = $module->getBackups(); - $unused_codes = $module->getUnusedLangs(); - - // module summary - echo '

' . sprintf(__('Module %s %s by %s'), $module->name, $module->version, $module->author) . '

- -

 

'; - - // existing languages - if (count($codes)) { echo - '

' . __('Translations') . '

' . - '
' . - '' . - '' . - '' . - '' . - '' . - '' . - '' . - ''; + dcPage::breadcrumb($breadcrumb) . + dcPage::notices(); - foreach ($codes as $code_name => $code_id) { - echo - '' . - '' . - '' . - ''; + if (empty(dcCore::app()->admin->module) && dcCore::app()->admin->type != '') { + // modules list + echo ''; - if (isset($backups[$code_id])) { - $time[$code_id] = 0; - foreach ($backups[$code_id] as $file => $info) { - $time[$code_id] = isset($time[$code_id]) && $time[$code_id] > $info['time'] ? - $time[$code_id] : $info['time']; + $res = ''; + $modules = dcCore::app()->admin->translater->getModules(dcCore::app()->admin->type); + ksort($modules); + foreach ($modules as $module) { + if (dcCore::app()->admin->translater->get('hide_default') && in_array($module->id, My::defaultDistribModules(dcCore::app()->admin->type))) { + continue; } - echo - '' . - ''; - } else { - echo ''; - } - echo ''; - } - echo '
' . __('Existing languages translations') . '
' . __('Language') . '' . __('Code') . '' . __('Backups') . '' . __('Last backup') . '
' . form::checkbox(['codes[]', 'existing_code_' . $code_id], $code_id, '', '', '', false) . '' . - '' . $code_name . '' . - ' ' . $code_id . '' . count($backups[$code_id]) . ' ' . - dt::str('%Y-%m-%d %H:%M', (int) $time[$code_id], dcCore::app()->blog->settings->system->blog_timezone) . - '' . __('no backups') . '-
-
-

- -

' . __('Selected languages action:') . ' ' . - form::combo('action', [ - __('Backup languages') => 'module_create_backups', - __('Delete languages') => 'module_delete_codes', - __('Export languages') => 'module_export_pack', - ]) . ' -

' . - dcCore::app()->formNonce() . - dcCore::app()->adminurl->getHiddenFormFields( - basename(__DIR__), - ['type' => $module->type, 'module' => $module->id] - ) . ' -

 

'; - } - - // backups - if (!empty($codes) || !empty($backups)) { - // delete / retore backups - if (!empty($backups)) { - echo '

' . __('Backups') . '

' . - '
' . - '' . - '' . - '' . - '' . - '' . - '' . - '' . - '' . - ''; - - $table_line = '' . - '' . - '' . - '' . - '' . - '' . - '' . - ''; - - $i = 0; - foreach ($backups as $backup_codes) { - foreach ($backup_codes as $backup_file => $backup_code) { - $i++; - $form_id = 'form_file_' . $backup_code['code'] . $backup_code['time']; - echo sprintf( - $table_line, - form::checkbox(['files[]', $form_id], $backup_file, '', '', '', false), - $form_id, - $backup_code['name'], - $backup_code['code'], - dt::str( - dcCore::app()->blog->settings->system->date_format . ' ' . dcCore::app()->blog->settings->system->time_format, - (int) $backup_code['time'], - dcCore::app()->blog->settings->system->blog_timezone - ), - $backup_code['path']['basename'], - files::size($backup_code['size']) + if ($module->root_writable) { + $res .= sprintf( + '', + dcCore::app()->adminurl->get(My::id(), ['type' => $module->type, 'module' => $module->id]), + html::escapeHTML(sprintf(__('Translate module %s'), __($module->name))), + html::escapeHTML($module->id) + ); + } else { + $res .= sprintf( + '', + html::escapeHTML($module->id) ); } + $codes = $module->getLangs(); + foreach ($codes as $code_id => $code_name) { + if ($module->root_writable) { + $codes[$code_id] = sprintf( + '%s (%s)', + html::escapeHTML(sprintf(__('Edit language %s of module %s'), html::escapeHTML($code_name), __($module->name))), + dcCore::app()->adminurl->get(My::id(), ['type' => $module->type, 'module' => $module->id, 'lang' => $code_id]), + html::escapeHTML($code_name), + $code_id + ); + } else { + $codes[$code_id] = html::escapeHTML($code_name) . '(' . $code_id . ')'; + } + } + $res .= sprintf( + '', + implode(', ', $codes), + html::escapeHTML(__($module->name)), + $module->version + ); } - echo ' -
' . __('Existing languages backups') . '
' . __('Language') . '' . __('Code') . '' . __('Date') . '' . __('File') . '' . __('Size') . '
%s%s%s%s%s
%s
%s%s%s%s
-
-

+ if ($res) { + echo ' +
+ + + + + + + + ' . + $res . + '
' . sprintf(__('Modules list of type "%s"'), dcCore::app()->admin->type) . '
' . __('Id') . '' . __('Languages') . '' . __('Name') . '' . __('Version') . '
'; + } else { + echo '' . __('There is no editable modules') . ''; + } + echo ''; -

' . __('Selected backups action:') . ' ' . - form::combo('action', [ - __('Restore backups') => 'module_restore_backup', - __('Delete backups') => 'module_delete_backup', - ]) . ' -

' . + dcPage::helpBlock('translater.type'); + } elseif (!empty(dcCore::app()->admin->module) && empty(dcCore::app()->admin->lang)) { + $codes = dcCore::app()->admin->module->getUsedLangs(); + $backups = dcCore::app()->admin->module->getBackups(); + $unused_codes = dcCore::app()->admin->module->getUnusedLangs(); + + // module summary + echo '

' . sprintf(__('Module %s %s by %s'), dcCore::app()->admin->module->name, dcCore::app()->admin->module->version, dcCore::app()->admin->module->author) . '

+
    +
  • ' . __('Root') . ' ' . dcCore::app()->admin->module->root . '
  • +
  • ' . __('Locales') . ' ' . dcCore::app()->admin->module->locales . '
  • +
  • ' . __('Backups') . ' ' . dcCore::app()->admin->module->getBackupRoot() . '
  • +
+

 

'; + + // existing languages + if (count($codes)) { + echo + '

' . __('Translations') . '

' . + '
' . + '' . + '' . + '' . + '' . + '' . + '' . + '' . + ''; + + foreach ($codes as $code_name => $code_id) { + echo + '' . + '' . + '' . + ''; + + if (isset($backups[$code_id])) { + $time[$code_id] = 0; + foreach ($backups[$code_id] as $file => $info) { + $time[$code_id] = isset($time[$code_id]) && $time[$code_id] > $info['time'] ? + $time[$code_id] : $info['time']; + } + echo + '' . + ''; + } else { + echo ''; + } + echo ''; + } + echo '
' . __('Existing languages translations') . '
' . __('Language') . '' . __('Code') . '' . __('Backups') . '' . __('Last backup') . '
' . form::checkbox(['codes[]', 'existing_code_' . $code_id], $code_id, '', '', '', false) . '' . + '' . $code_name . '' . + ' ' . $code_id . '' . count($backups[$code_id]) . ' ' . + dt::str('%Y-%m-%d %H:%M', (int) $time[$code_id], dcCore::app()->blog->settings->get('system')->get('blog_timezone')) . + '' . __('no backups') . '-
+
+

+ +

' . __('Selected languages action:') . ' ' . + form::combo('action', [ + __('Backup languages') => 'module_create_backups', + __('Delete languages') => 'module_delete_codes', + __('Export languages') => 'module_export_pack', + ]) . ' +

' . + dcCore::app()->formNonce() . + dcCore::app()->adminurl->getHiddenFormFields( + My::id(), + ['type' => dcCore::app()->admin->module->type, 'module' => dcCore::app()->admin->module->id] + ) . ' +

 

'; + } + + // backups + if (!empty($codes) || !empty($backups)) { + // delete / retore backups + if (!empty($backups)) { + echo '

' . __('Backups') . '

' . + '
' . + '' . + '' . + '' . + '' . + '' . + '' . + '' . + '' . + ''; + + $table_line = '' . + '' . + '' . + '' . + '' . + '' . + '' . + ''; + + $i = 0; + foreach ($backups as $backup_codes) { + foreach ($backup_codes as $backup_file => $backup_code) { + $i++; + $form_id = 'form_file_' . $backup_code['code'] . $backup_code['time']; + echo sprintf( + $table_line, + form::checkbox(['files[]', $form_id], $backup_file, '', '', '', false), + $form_id, + $backup_code['name'], + $backup_code['code'], + dt::str( + dcCore::app()->blog->settings->get('system')->get('date_format') . ' ' . dcCore::app()->blog->get('settings')->get('system->time_format'), + (int) $backup_code['time'], + dcCore::app()->blog->settings->get('system')->get('blog_timezone') + ), + $backup_code['path']['basename'], + files::size($backup_code['size']) + ); + } + } + echo ' +
' . __('Existing languages backups') . '
' . __('Language') . '' . __('Code') . '' . __('Date') . '' . __('File') . '' . __('Size') . '
%s%s%s%s%s
+
+

+ +

' . __('Selected backups action:') . ' ' . + form::combo('action', [ + __('Restore backups') => 'module_restore_backup', + __('Delete backups') => 'module_delete_backup', + ]) . ' +

' . + dcCore::app()->formNonce() . + dcCore::app()->adminurl->getHiddenFormFields( + My::id(), + ['type' => dcCore::app()->admin->module->type, 'module' => dcCore::app()->admin->module->id] + ) . ' +

 

'; + } + } + + echo '
'; + + // add language + if (!empty($unused_codes)) { + echo '

' . __('Add language') . '

+
+

' . + form::combo(['code'], array_merge(['-' => '-'], $unused_codes), dcCore::app()->auth->getInfo('user_lang')) . '

'; + if (empty($codes)) { + echo '

' . form::hidden(['from'], '') . '

'; + } else { + echo + '

' . + form::combo(['from'], array_merge(['-' => ''], $codes)) . ' (' . __('optionnal') . ')

'; + } + echo ' +

' . + dcCore::app()->formNonce() . + dcCore::app()->adminurl->getHiddenFormFields( + My::id(), + ['type' => dcCore::app()->admin->module->type, 'module' => dcCore::app()->admin->module->id, 'action' => 'module_add_code'] + ) . ' +

 

'; + } + + // Import + echo '

' . __('Import') . '

+
+

+

+ ' . dcCore::app()->formNonce() . dcCore::app()->adminurl->getHiddenFormFields( - basename(__DIR__), - ['type' => $module->type, 'module' => $module->id] + My::id(), + ['type' => dcCore::app()->admin->module->type, 'module' => dcCore::app()->admin->module->id, 'action' => 'module_import_pack'] ) . ' -

 

'; - } - } +

 

'; - echo '
'; + echo '
'; + + dcPage::helpBlock('translater.module'); + } elseif (!empty(dcCore::app()->admin->lang)) { + $lines = dcCore::app()->admin->lang->getMessages(); + $allowed_l10n_groups = []; - // add language - if (!empty($unused_codes)) { - echo '

' . __('Add language') . '

-
-

' . - form::combo(['code'], array_merge(['-' => '-'], $unused_codes), dcCore::app()->auth->getInfo('user_lang')) . '

'; - if (empty($codes)) { - echo '

' . form::hidden(['from'], '') . '

'; - } else { echo - '

' . - form::combo(['from'], array_merge(['-' => ''], $codes)) . ' (' . __('optionnal') . ')

'; - } - echo ' -

' . - dcCore::app()->formNonce() . - dcCore::app()->adminurl->getHiddenFormFields( - basename(__DIR__), - ['type' => $module->type, 'module' => $module->id, 'action' => 'module_add_code'] - ) . ' -

 

'; - } + '
' . + '
' . + '' . + '' . + '' . + '' . + '' . + '' . + '' . + '' . + ''; - // Import - echo '

' . __('Import') . '

- -

-

- ' . - dcCore::app()->formNonce() . - dcCore::app()->adminurl->getHiddenFormFields( - basename(__DIR__), - ['type' => $module->type, 'module' => $module->id, 'action' => 'module_import_pack'] - ) . ' -

 

'; + $table_line = '' . + '' . + '' . + '' . + '' . + '' . + '' . + ''; + $table_ul = '
%s
%s

'; + $table_li = '%s
'; - echo ''; + $i = 1; + foreach ($lines as $msgid => $rs) { + $in_dc = ($rs['in_dc'] && dcCore::app()->admin->translater->get('parse_nodc')); + $t_msgstr = $t_files = $strin = []; - dcPage::helpBlock('translater.module'); -} elseif (!empty($lang)) { - $lines = $lang->getMessages(); - $allowed_l10n_groups = []; - - echo - '
' . - '
' . - '
' . sprintf(__('List of %s localized strings'), count($lines)) . '
' . __('Group') . '' . __('String') . '' . __('Translation') . '' . __('Existing') . '' . __('File') . '
%s%s%s%s%s%s
' . - '' . - '' . - '' . - '' . - '' . - '' . - '' . - ''; - - $table_line = '' . - '' . - '' . - '' . - '' . - '' . - '' . - ''; - $table_ul = '
%s
%s

'; - $table_li = '%s
'; - - $i = 1; - foreach ($lines as $msgid => $rs) { - $in_dc = ($rs['in_dc'] && $translater->parse_nodc); - $allowed_l10n_groups = array_combine($translater::$allowed_l10n_groups, $translater::$allowed_l10n_groups); - $t_msgstr = $t_files = $strin = []; - - foreach ($rs['o_msgstrs'] as $o_msgstr) { - if (!isset($strin[$o_msgstr['msgstr'][0]])) { - $strin[$o_msgstr['msgstr'][0]] = []; - } - $strin[$o_msgstr['msgstr'][0]][] = ['module' => $o_msgstr['module'], 'file' => $o_msgstr['file']]; - } - foreach ($strin as $k => $v) { - $res = []; - foreach ($v as $str) { - $res[] = sprintf($table_li, html::escapeHTML($str['module'] . ':' . $str['file'])); - } - $t_msgstr[] = sprintf($table_ul, html::escapeHTML($k), implode('', $res)); - } - - if (!empty($rs['files'][0])) { - if (count($rs['files']) == 1) { - $t_files[] = $rs['files'][0][0] . ':' . $rs['files'][0][1]; - } else { - $res = []; - foreach ($rs['files'] as $location) { - $res[] = sprintf($table_li, implode(' : ', $location)); - } - $t_files[] = sprintf($table_ul, sprintf(__('%s occurrences'), count($rs['files'])), implode('', $res)); - ; - } - } - - echo sprintf( - $table_line, - $in_dc ? ' offline' : ' translaterline', - form::checkbox(['entries[' . $i . '][check]'], 1), - form::combo(['entries[' . $i . '][group]'], $allowed_l10n_groups, $rs['group'], '', '', $in_dc), - html::escapeHTML($msgid), - form::hidden(['entries[' . $i . '][msgid]'], html::escapeHTML($msgid)) . - form::field(['entries[' . $i . '][msgstr][0]'], 48, 255, html::escapeHTML($rs['msgstr'][0]), '', '', $in_dc), - implode('', $t_msgstr), - implode('', $t_files) - ); - - if (!empty($rs['plural'])) { - $t_msgstr = $strin = []; - foreach ($lang->plural as $j => $plural) { foreach ($rs['o_msgstrs'] as $o_msgstr) { - if (isset($o_msgstr['msgstr'][$j + 1])) { - if (!isset($strin[$o_msgstr['msgstr'][$j + 1]])) { - $strin[$o_msgstr['msgstr'][$j + 1]] = []; - } - $strin[$o_msgstr['msgstr'][$j + 1]][] = ['module' => $o_msgstr['module'], 'file' => $o_msgstr['file']]; + if (!isset($strin[$o_msgstr['msgstr'][0]])) { + $strin[$o_msgstr['msgstr'][0]] = []; } + $strin[$o_msgstr['msgstr'][0]][] = ['module' => $o_msgstr['module'], 'file' => $o_msgstr['file']]; } foreach ($strin as $k => $v) { $res = []; @@ -523,76 +508,136 @@ if (empty($module) && $type != '') { $t_msgstr[] = sprintf($table_ul, html::escapeHTML($k), implode('', $res)); } + if (!empty($rs['files'][0])) { + if (count($rs['files']) == 1) { + $t_files[] = $rs['files'][0][0] . ':' . $rs['files'][0][1]; + } else { + $res = []; + foreach ($rs['files'] as $location) { + $res[] = sprintf($table_li, implode(' : ', $location)); + } + $t_files[] = sprintf($table_ul, sprintf(__('%s occurrences'), count($rs['files'])), implode('', $res)); + ; + } + } + echo sprintf( $table_line, $in_dc ? ' offline' : ' translaterline', - '+', - sprintf(__('Plural "%s"'), $plural), - sprintf(__('Plural form of "%s"'), $rs['plural']), - form::hidden(['entries[' . $i . '][msgid_plural]'], html::escapeHTML($rs['plural'])) . - form::field(['entries[' . $i . '][msgstr][' . ($j + 1) . ']'], 48, 255, html::escapeHTML($rs['msgstr'][$j + 1] ?? ''), '', '', $in_dc), + form::checkbox(['entries[' . $i . '][check]'], 1), + form::combo(['entries[' . $i . '][group]'], My::l10nGroupsCombo(), $rs['group'], '', '', $in_dc), + html::escapeHTML($msgid), + form::hidden(['entries[' . $i . '][msgid]'], html::escapeHTML($msgid)) . + form::field(['entries[' . $i . '][msgstr][0]'], 48, 255, html::escapeHTML($rs['msgstr'][0]), '', '', $in_dc), implode('', $t_msgstr), - '' + implode('', $t_files) ); + + if (!empty($rs['plural'])) { + $t_msgstr = $strin = []; + foreach (dcCore::app()->admin->lang->plural as $j => $plural) { + foreach ($rs['o_msgstrs'] as $o_msgstr) { + if (isset($o_msgstr['msgstr'][$j + 1])) { + if (!isset($strin[$o_msgstr['msgstr'][$j + 1]])) { + $strin[$o_msgstr['msgstr'][$j + 1]] = []; + } + $strin[$o_msgstr['msgstr'][$j + 1]][] = ['module' => $o_msgstr['module'], 'file' => $o_msgstr['file']]; + } + } + foreach ($strin as $k => $v) { + $res = []; + foreach ($v as $str) { + $res[] = sprintf($table_li, html::escapeHTML($str['module'] . ':' . $str['file'])); + } + $t_msgstr[] = sprintf($table_ul, html::escapeHTML($k), implode('', $res)); + } + + echo sprintf( + $table_line, + $in_dc ? ' offline' : ' translaterline', + '+', + sprintf(__('Plural "%s"'), $plural), + sprintf(__('Plural form of "%s"'), $rs['plural']), + form::hidden(['entries[' . $i . '][msgid_plural]'], html::escapeHTML($rs['plural'])) . + form::field(['entries[' . $i . '][msgstr][' . ($j + 1) . ']'], 48, 255, html::escapeHTML($rs['msgstr'][$j + 1] ?? ''), '', '', $in_dc), + implode('', $t_msgstr), + '' + ); + } + } + $i++; } - } - $i++; - } - echo sprintf( - $table_line, - ' offline', - form::checkbox(['entries[' . $i . '][check]'], 1), - form::combo(['entries[' . $i . '][group]'], $allowed_l10n_groups, 'main'), - form::field(['entries[' . $i . '][msgid]'], 48, 255, ''), - form::field(['entries[' . $i . '][msgstr][0]'], 48, 255, ''), - '', - '' - ); - echo - '
' . sprintf(__('List of %s localized strings'), count($lines)) . '
' . __('Group') . '' . __('String') . '' . __('Translation') . '' . __('Existing') . '' . __('File') . '
%s%s%s%s%s%s
' . + echo sprintf( + $table_line, + ' offline', + form::checkbox(['entries[' . $i . '][check]'], 1), + form::combo(['entries[' . $i . '][group]'], My::l10nGroupsCombo(), 'main'), + form::field(['entries[' . $i . '][msgid]'], 48, 255, ''), + form::field(['entries[' . $i . '][msgstr][0]'], 48, 255, ''), + '', + '' + ); + echo + '' . - '
' . - '
' . - '

' . - '

' . - '
' . - '

' . - '

' . - dcCore::app()->formNonce() . - form::hidden(['code'], $lang->code) . - dcCore::app()->adminurl->getHiddenFormFields( - basename(__DIR__), - ['type' => $module->type, 'module' => $module->id, 'lang' => $lang->code, 'action' => 'module_update_code'] - ) . - '

' . - '' . - '

 

' . - '
'; - - dcPage::helpBlock('translater.lang'); -} else { - $line = '
  • %s
  • '; - echo '

    ' . __('Translate your Dotclear plugins and themes') . '

    ' . - sprintf( - '

      %s

    ', - sprintf( - $line, - dcCore::app()->adminurl->get(basename(__DIR__), ['type' => 'plugin']), - $type == 'plugin' ? ' class="active"' : '', - __('Translate plugins') + '
    ' . + '
    ' . + '

    ' . + '

    ' . + '
    ' . + '

    ' . + '

    ' . + dcCore::app()->formNonce() . + form::hidden(['code'], dcCore::app()->admin->lang->code) . + dcCore::app()->adminurl->getHiddenFormFields( + My::id(), + ['type' => dcCore::app()->admin->module->type, 'module' => dcCore::app()->admin->module->id, 'lang' => dcCore::app()->admin->lang->code, 'action' => 'module_update_code'] ) . - sprintf( - $line, - dcCore::app()->adminurl->get(basename(__DIR__), ['type' => 'theme']), - $type == 'theme' ? ' class="active"' : '', - __('Translate themes') - ) - ); + '

    ' . + '' . + '

     

    ' . + '
    '; - dcPage::helpBlock('translater.index'); + dcPage::helpBlock('translater.lang'); + } else { + $line = '
  • %s
  • '; + echo '

    ' . __('Translate your Dotclear plugins and themes') . '

    ' . + sprintf( + '

    ', + sprintf( + $line, + dcCore::app()->adminurl->get(My::id(), ['type' => 'plugin']), + dcCore::app()->admin->type == 'plugin' ? ' class="active"' : '', + __('Translate plugins') + ) . + sprintf( + $line, + dcCore::app()->adminurl->get(My::id(), ['type' => 'theme']), + dcCore::app()->admin->type == 'theme' ? ' class="active"' : '', + __('Translate themes') + ) + ); + + dcPage::helpBlock('translater.index'); + } + + dcPage::closeModule(); + } + + private static function redirect(string $msg, ?string $lang = null): void + { + $redir = [ + 'type' => dcCore::app()->admin->type, + 'module' => dcCore::app()->admin->module->id, + ]; + if ($lang) { + $redir['lang'] = $lang; + } + + dcPage::addSuccessNotice($msg); + dcCore::app()->adminurl->redirect(My::id(), $redir); + } } - -echo ''; diff --git a/src/My.php b/src/My.php new file mode 100644 index 0000000..bc67a3b --- /dev/null +++ b/src/My.php @@ -0,0 +1,140 @@ +plugins->moduleInfo(self::id(), 'name')); + } + + /** + * List of allowed backup folder + */ + public static function backupFoldersCombo(): array + { + return [ + __('locales folders of each module') => 'module', + __('plugins folder root') => 'plugin', + __('public folder root') => 'public', + __('cache folder of Dotclear') => 'cache', + __('locales folder of translater') => self::id(), + ]; + } + + /** + * List of possible home tab of the plugin + */ + public static function startPageCombo() + { + return [ + __('Plugins') => 'plugin', + __('Themes') => 'theme', + __('Home') => '-', + ]; + } + + /** + * List of place of tranlsations + */ + public static function l10nGroupsCombo(): array + { + $groups = [ + 'main', 'public', 'theme', 'admin', 'date', 'error', + ]; + + return array_combine($groups, $groups); + } + + /** + * List of user info can be parsed + */ + public static function defaultUserInformations(): array + { + return [ + 'firstname', 'displayname', 'name', 'email', 'url', + ]; + } + + /** + * List of distributed plugins and themes + */ + public static function defaultDistribModules(string $type): array + { + $types = [ + 'plugin' => explode(',', DC_DISTRIB_PLUGINS), + 'theme' => explode(',', DC_DISTRIB_THEMES), + ]; + + return $types[$type] ?? []; + } + + public static function defaultSettings(): array + { + return [ + // Show tranlsater button on plugins list + 'plugin_menu' => false, + // Show tranlsater button on themes list + 'theme_menu' => false, + // Create language backup on save + 'backup_auto' => false, + // Backups number limit + 'backup_limit' => 20, + // Backup main folder + 'backup_folder' => 'module', + // Default ui start page + 'start_page' => '-', + // Write .lang.php file (deprecated) + 'write_langphp' => false, + // Scan also template files for translations + 'scan_tpl' => true, + // Disable translation of know dotclear strings + 'parse_nodc' => true, + // Hide official modules + 'hide_default' => true, + // Add comment to translations files + 'parse_comment' => false, + // Parse user info to translations files + 'parse_user' => false, + // User infos to parse + 'parse_userinfo' => 'displayname, email', + // Overwrite existing languages on import + 'import_overwrite' => false, + // Filename of exported lang + 'export_filename' => 'type-module-l10n-timestamp', + // Default service for external proposal tool + 'proposal_tool' => 'google', + // Default lang for external proposal tool + 'proposal_lang' => 'en', + ]; + } +} diff --git a/src/Prepend.php b/src/Prepend.php index c4c5beb..42e2cc3 100644 --- a/src/Prepend.php +++ b/src/Prepend.php @@ -10,18 +10,34 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_RC_PATH')) { - return; -} +declare(strict_types=1); -Clearbricks::lib()->autoload([ - 'dcTranslater' => __DIR__ . '/inc/class.dc.translater.php', - 'dcTranslaterDefaultSettings' => __DIR__ . '/inc/class.dc.translater.php', - 'dcTranslaterModule' => __DIR__ . '/inc/class.dc.translater.module.php', - 'dcTranslaterLang' => __DIR__ . '/inc/class.dc.translater.lang.php', - 'translaterRest' => __DIR__ . '/class.translater.rest.php', -]); +namespace Dotclear\Plugin\translater; -if (isset(dcCore::app()->adminurl)) { - dcCore::app()->adminurl->register(basename(__DIR__), 'plugin.php', ['p' => basename(__DIR__)]); +use dcCore; +use dcNsProcess; + +class Prepend extends dcNsProcess +{ + public static function init(): bool + { + if (defined('DC_CONTEXT_ADMIN')) { + self::$init = dcCore::app()->auth->isSuperAdmin(); + } + + return self::$init; + } + + public static function process(): bool + { + if (!self::$init) { + return false; + } + + if (isset(dcCore::app()->adminurl)) { + dcCore::app()->adminurl->register(My::id(), 'plugin.php', ['p' => My::id()]); + } + + return true; + } } diff --git a/src/ProposalGoogle.php b/src/ProposalGoogle.php index d682b9d..dcdeacd 100644 --- a/src/ProposalGoogle.php +++ b/src/ProposalGoogle.php @@ -10,9 +10,13 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_CONTEXT_ADMIN')) { - return; -} +declare(strict_types=1); + +namespace Dotclear\Plugin\translater; + +use dcCore; +use form; +use netHttp; /** * Google proposal tool. @@ -22,12 +26,12 @@ if (!defined('DC_CONTEXT_ADMIN')) { class googleProposalTool extends translaterProposalTool { private $api = 'https://www.googleapis.com/language/translate/v2'; - private $agent = 'dcTranslater - http://jcd.lv/?q=translater'; + private $agent = 'Translater - http://jcd.lv/?q=translater'; private $key = null; //ex: AsSDqsGsfdSDSQFQsfedj9bnzY390aIg-1d protected function setup() { - $this->key = dcCore::app()->blog->settings->get(basename(dirname(__DIR__)))->get('google_proposal_key'); + $this->key = dcCore::app()->blog->settings->get(My::id())->get('google_proposal_key'); $this->setName(__('Google')); $this->setDesc(__('Google Translation Tool API')); @@ -53,7 +57,7 @@ class googleProposalTool extends translaterProposalTool $key = empty($_POST['translater_google_proposal_key']) ? '' : $_POST['translater_google_proposal_key']; - dcCore::app()->blog->settings->get(basename(dirname(__DIR__)))->put('google_proposal_key', $key, 'string', '', true, true); + dcCore::app()->blog->settings->get(My::id())->put('google_proposal_key', $key, 'string', '', true, true); } public function translate($str, $from, $to) diff --git a/src/ProposalMicrosoft.php b/src/ProposalMicrosoft.php index eba73c6..bb0ad13 100644 --- a/src/ProposalMicrosoft.php +++ b/src/ProposalMicrosoft.php @@ -10,9 +10,12 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_CONTEXT_ADMIN')) { - return; -} +declare(strict_types=1); + +namespace Dotclear\Plugin\translater; + +use dcCore; +use form; /** * Microsoft proposal tool. @@ -27,8 +30,8 @@ class microsoftProposalTool extends translaterProposalTool protected function setup() { $this->setActive(false); - $this->client = dcCore::app()->blog->settings->get(basename(dirname(__DIR__)))->get('microsoft_proposal_client'); - $this->secret = dcCore::app()->blog->settings->get(basename(dirname(__DIR__)))->get('microsoft_proposal_secret'); + $this->client = dcCore::app()->blog->settings->get(My::id())->get('microsoft_proposal_client'); + $this->secret = dcCore::app()->blog->settings->get(My::id())->get('microsoft_proposal_secret'); $this->setName(__('Bing')); $this->setDesc(__('Microsoft Bing translation tool')); @@ -61,8 +64,8 @@ class microsoftProposalTool extends translaterProposalTool $secret = empty($_POST['translater_microsoft_proposal_secret']) ? '' : $_POST['translater_microsoft_proposal_secret']; - dcCore::app()->blog->settings->get(basename(dirname(__DIR__)))->put('microsoft_proposal_client', $client, 'string', '', true, true); - dcCore::app()->blog->settings->get(basename(dirname(__DIR__)))->put('microsoft_proposal_secret', $secret, 'string', '', true, true); + dcCore::app()->blog->settings->get(My::id())->put('microsoft_proposal_client', $client, 'string', '', true, true); + dcCore::app()->blog->settings->get(My::id())->put('microsoft_proposal_secret', $secret, 'string', '', true, true); } public function translate($str, $from, $to) @@ -82,6 +85,7 @@ class microsoftProposalTool extends translaterProposalTool private function doYourFuckingJob($client, $secret, $str, $from, $to) { try { + $translatedStr = ''; //Client ID of the application. $clientID = $client; //Client Secret key of the application. diff --git a/src/ProposalTranslater.php b/src/ProposalTranslater.php index 306737b..2012bb9 100644 --- a/src/ProposalTranslater.php +++ b/src/ProposalTranslater.php @@ -10,6 +10,10 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ +declare(strict_types=1); + +namespace Dotclear\Plugin\translater; + /** * Translater proposal tool. * diff --git a/src/Rest.php b/src/Rest.php index d7f565c..c367c0f 100644 --- a/src/Rest.php +++ b/src/Rest.php @@ -10,9 +10,14 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_CONTEXT_ADMIN')) { - return; -} +declare(strict_types=1); + +namespace Dotclear\Plugin\translater; + +use dcCore; +use html; +use text; +use xmlTag; /** * Translater REST service. @@ -20,7 +25,7 @@ if (!defined('DC_CONTEXT_ADMIN')) { * Admin service de retrieve translation of a string * Queries come from translater jquery tools */ -class translaterRest +class Rest { public static function getProposal($get) { @@ -40,7 +45,7 @@ class translaterRest throw new Exception(__('Missing params')); } - $translater = new dcTranslater(); + $translater = new Translater(); if (!empty($str_in)) { if (!$translater->proposal->hasTool($tool)) { diff --git a/src/Translater.php b/src/Translater.php index f3a62cf..3703774 100644 --- a/src/Translater.php +++ b/src/Translater.php @@ -10,79 +10,24 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_CONTEXT_ADMIN')) { - return; -} +declare(strict_types=1); -class dcTranslaterDefaultSettings -{ - /** @var boolean Show tranlsater button on plugins list */ - public $plugin_menu = false; - /** @var boolean Show tranlsater button on themes list */ - public $theme_menu = false; - /** @var boolean Create language backup on save */ - public $backup_auto = false; - /** @var integer Backups number limit */ - public $backup_limit = 20; - /** @var string Backup main folder */ - public $backup_folder = 'module'; - /** @var string Default ui start page */ - public $start_page = '-'; - /** @var boolean Write .lang.php file (deprecated) */ - public $write_langphp = false; - /** @var boolean SCan also template files for translations */ - public $scan_tpl = true; - /** @var boolean Disable translation of know dotclear strings */ - public $parse_nodc = true; - /** @var boolean Hide official modules */ - public $hide_default = true; - /** @var boolean Add comment to translations files */ - public $parse_comment = false; - /** @var boolean Parse user info to translations files */ - public $parse_user = false; - /** @var string User infos to parse */ - public $parse_userinfo = 'displayname, email'; - /** @var boolean Overwrite existing languages on import */ - public $import_overwrite = false; - /** @var string Filename of exported lang */ - public $export_filename = 'type-module-l10n-timestamp'; - /** @var string Default service for external proposal tool */ - public $proposal_tool = 'google'; - /** @var string Default lang for external proposal tool */ - public $proposal_lang = 'en'; +namespace Dotclear\Plugin\translater; - /** - * get default settings - * - * @return array Settings key/value pair - */ - public static function getDefaultSettings() - { - return get_class_vars('dcTranslaterDefaultSettings'); - } -} +use dcCore; +use dcThemes; +use files; +use l10n; +use path; +use text; /** * Translater tools. */ -class dcTranslater extends dcTranslaterDefaultSettings +class Translater { - /** @var array $allowed_backup_folders List of allowed backup folder */ - public static $allowed_backup_folders = []; - - /** @var array $allowed_l10n_groups List of place of tranlsations */ - public static $allowed_l10n_groups = [ - 'main', 'public', 'theme', 'admin', 'date', 'error', - ]; - - /** @var array $allowed_user_informations List of user info can be parsed */ - public static $allowed_user_informations = [ - 'firstname', 'displayname', 'name', 'email', 'url', - ]; - - /** @var array $default_distrib_modules List of distributed plugins and themes */ - public static $default_distrib_modules = ['plugin' => [], 'theme' => []]; - + /** @var array $settings Translater settings */ + private $settings = []; /** @var array $modules List of modules we could work on */ private $modules = []; @@ -98,18 +43,6 @@ class dcTranslater extends dcTranslaterDefaultSettings if ($full) { $this->loadModules(); } - - self::$allowed_backup_folders = [ - __('locales folders of each module') => 'module', - __('plugins folder root') => 'plugin', - __('public folder root') => 'public', - __('cache folder of Dotclear') => 'cache', - __('locales folder of translater') => basename(dirname(__DIR__)), - ]; - self::$default_distrib_modules = [ - 'plugin' => explode(',', DC_DISTRIB_PLUGINS), - 'theme' => explode(',', DC_DISTRIB_THEMES), - ]; } /// @name settings methods @@ -119,13 +52,9 @@ class dcTranslater extends dcTranslaterDefaultSettings */ public function loadSettings(): void { - foreach ($this->getDefaultSettings() as $key => $value) { - $this->$key = dcCore::app()->blog->settings->get(basename(dirname(__DIR__)))->get($key); - - try { - settype($this->$key, gettype($value)); - } catch (Exception $e) { - } + foreach (My::defaultSettings() as $key => $value) { + $this->settings[$key] = $value; + $this->set($key, dcCore::app()->blog->settings->get(My::id())->get($key)); } } @@ -136,43 +65,39 @@ class dcTranslater extends dcTranslaterDefaultSettings */ public function writeSettings($overwrite = true): void { - foreach ($this->getDefaultSettings() as $key => $value) { - dcCore::app()->blog->settings->get(basename(dirname(__DIR__)))->drop($key); - dcCore::app()->blog->settings->get(basename(dirname(__DIR__)))->put($key, $this->$key, gettype($value), '', true, true); + foreach (My::defaultSettings() as $key => $value) { + dcCore::app()->blog->settings->get(My::id())->drop($key); + dcCore::app()->blog->settings->get(My::id())->put($key, $this->settings[$key], gettype($value), '', true, true); } } /** - * Upgrade plugin + * Read a setting * - * @return bool Upgrade done + * @param string $key The setting id + * + * @return mixed The setting value */ - public function growUp() + public function get(string $key): mixed { - $current = dcCore::app()->getVersion(basename(dirname(__DIR__))); + return $this->settings[$key] ?? null; + } - // use short settings id - if ($current && version_compare($current, '2022.12.22', '<')) { - $record = dcCore::app()->con->select( - 'SELECT * FROM ' . dcCore::app()->prefix . dcNamespace::NS_TABLE_NAME . ' ' . - "WHERE setting_ns = 'translater' " - ); - while ($record->fetch()) { - if (preg_match('/^translater_(.*?)$/', $record->setting_id, $match)) { - $cur = dcCore::app()->con->openCursor(dcCore::app()->prefix . dcNamespace::NS_TABLE_NAME); - $cur->setting_id = $this->{$match[1]} = $match[1]; - $cur->setting_ns = basename(dirname(__DIR__)); - $cur->update( - "WHERE setting_id = '" . $record->setting_id . "' and setting_ns = 'translater' " . - 'AND blog_id ' . (null === $record->blog_id ? 'IS NULL ' : ("= '" . dcCore::app()->con->escape($record->blog_id) . "' ")) - ); - } + /** + * Write (temporary) a setting + * + * @param string $key The setting id + * @param mixed $value The setting value + */ + public function set(string $key, mixed $value): void + { + if (isset($this->settings[$key])) { + try { + settype($value, gettype($this->settings[$key])); + $this->settings[$key] = $value; + } catch (Exception $e) { } - - return true; } - - return false; } //@} @@ -185,11 +110,13 @@ class dcTranslater extends dcTranslaterDefaultSettings { $this->modules['theme'] = $this->modules['plugin'] = []; - $themes = new dcThemes(); - $themes->loadModules(dcCore::app()->blog->themes_path, null); + if (!(dcCore::app()->themes instanceof dcThemes)) { + dcCore::app()->themes = new dcThemes(); + dcCore::app()->themes->loadModules(dcCore::app()->blog->themes_path, null); + } $list = [ - 'theme' => $themes->getModules(), + 'theme' => dcCore::app()->themes->getModules(), 'plugin' => dcCore::app()->plugins->getModules(), ]; foreach ($list as $type => $modules) { @@ -199,7 +126,7 @@ class dcTranslater extends dcTranslaterDefaultSettings } $info['id'] = $id; $info['type'] = $type; - $this->modules[$type][$id] = new dcTranslaterModule($this, $info); + $this->modules[$type][$id] = new TranslaterModule($this, $info); } } } @@ -224,9 +151,9 @@ class dcTranslater extends dcTranslaterDefaultSettings * @param string $type The module type * @param string $id The module id * - * @return dcTranslaterModule The dcTranslaterModule instance + * @return TranslaterModule The TranslaterModule instance */ - public function getModule(string $type, string $id) + public function getModule(string $type, string $id): TranslaterModule { if (!isset($this->modules[$type][$id])) { throw new Exception( @@ -240,12 +167,12 @@ class dcTranslater extends dcTranslaterDefaultSettings /** * Return module class of a particular module for a given type of module * - * @param dcTranslaterModule $module dcTranslaterModule instance + * @param TranslaterModule $module TranslaterModule instance * @param string $lang The lang iso code * - * @return dcTranslaterLang dcTranslaterLang instance or false + * @return TranslaterLang TranslaterLang instance or false */ - public function getLang(dcTranslaterModule $module, string $lang) + public function getLang(TranslaterModule $module, string $lang): TranslaterLang { if (!l10n::isCode($lang)) { throw new Exception( @@ -253,7 +180,7 @@ class dcTranslater extends dcTranslaterDefaultSettings ); } - return new dcTranslaterLang($module, $lang); + return new TranslaterLang($module, $lang); } //@} diff --git a/src/TranslaterLang.php b/src/TranslaterLang.php index 3879578..46e5dc7 100644 --- a/src/TranslaterLang.php +++ b/src/TranslaterLang.php @@ -10,17 +10,25 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -class dcTranslaterLang +declare(strict_types=1); + +namespace Dotclear\Plugin\translater; + +use files; +use l10n; +use path; + +class TranslaterLang { - /** @var dcTranslater dcTranslater instance */ + /** @var Translater Translater instance */ public $translater = null; - /** @var dcTranslaterModule dcTranslaterModule instance */ + /** @var TranslaterModule TranslaterModule instance */ public $module = null; /** @var array Lang properies */ private $prop = []; - public function __construct(dcTranslaterModule $module, string $lang) + public function __construct(TranslaterModule $module, string $lang) { $this->translater = $module->translater; $this->module = $module; @@ -61,12 +69,12 @@ class dcTranslaterLang $m_msgstrs = $this->getMsgStrs(); foreach ($this->translater->getModules() as $module) { - if ($module->id != $this->module->id) { - $m_o_msgstrs[$module->id] = $this->translater->getlang($module, $this->code)->getMsgStrs(); + if ($module->id != $this->module->get('id')) { + $m_o_msgstrs[$module->get('id')] = $this->translater->getlang($module, $this->get('code'))->getMsgStrs(); } } - $dc_module = new dcTranslaterModule($this->translater, ['id' => 'dotclear', 'root' => DC_ROOT]); - $dc_lang = new dcTranslaterLang($dc_module, $this->code); + $dc_module = new TranslaterModule($this->translater, ['id' => 'dotclear', 'root' => DC_ROOT]); + $dc_lang = new TranslaterLang($dc_module, $this->get('code')); $m_o_msgstrs['dotclear'] = $dc_lang->getMsgStrs(); # From id list @@ -122,30 +130,30 @@ class dcTranslaterLang { $res = []; $scan_ext = ['php']; - if ($this->translater->scan_tpl) { + if ($this->translater->get('scan_tpl')) { $scan_ext[] = 'html'; } - $files = dcTranslater::scandir($this->module->root); + $files = Translater::scandir($this->module->get('root')); foreach ($files as $file) { $extension = files::getExtension($file); - if (is_dir($this->module->root . '/' . $file) || !in_array($extension, $scan_ext)) { + if (is_dir($this->module->get('root') . '/' . $file) || !in_array($extension, $scan_ext)) { continue; } - $contents = file_get_contents($this->module->root . '/' . $file); + $contents = file_get_contents($this->module->get('root') . '/' . $file); $msgs = []; # php files if ($extension == 'php') { - $msgs = dcTranslater::extractPhpMsgs($contents); + $msgs = Translater::extractPhpMsgs($contents); # tpl files } elseif ($extension == 'html') { - $msgs = dcTranslater::extractTplMsgs($contents); + $msgs = Translater::extractTplMsgs($contents); } foreach ($msgs as $msg) { $res[] = [ - 'msgid' => dcTranslater::encodeMsg($msg[0][0]), - 'msgid_plural' => empty($msg[0][1]) ? '' : dcTranslater::encodeMsg($msg[0][1]), + 'msgid' => Translater::encodeMsg($msg[0][0]), + 'msgid_plural' => empty($msg[0][1]) ? '' : Translater::encodeMsg($msg[0][1]), 'file' => $file, 'line' => $msg[1], ]; @@ -167,18 +175,18 @@ class dcTranslaterLang $res = $exists = $scanned = []; $langs = $this->module->getLangs(true); - if (!isset($langs[$this->code])) { + if (!isset($langs[$this->get('code')])) { return $res; } - foreach ($langs[$this->code] as $file) { + foreach ($langs[$this->get('code')] as $file) { if (in_array($file, $scanned)) { continue; } $scanned[] = $file; - $path = path::clean($this->module->locales . '/' . $file); + $path = path::clean($this->module->get('locales') . '/' . $file); - if (dcTranslater::isPoFile($file)) { + if (Translater::isPoFile($file)) { $po = l10n::parsePoFile($path); if (!is_array($po)) { continue; @@ -189,7 +197,7 @@ class dcTranslaterLang 'msgid' => $entry['msgid'], 'msgid_plural' => $entry['msgid_plural'] ?? '', 'msgstr' => is_array($entry['msgstr']) ? $entry['msgstr'] : [$entry['msgstr']], - 'lang' => $this->code, + 'lang' => $this->get('code'), 'type' => 'po', 'path' => $path, 'file' => basename($file), diff --git a/src/TranslaterModule.php b/src/TranslaterModule.php index 8b32561..179d4e1 100644 --- a/src/TranslaterModule.php +++ b/src/TranslaterModule.php @@ -10,16 +10,25 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_CONTEXT_ADMIN')) { - return; -} +declare(strict_types=1); + +namespace Dotclear\Plugin\translater; + +use dcCore; +use dt; +use html; +use files; +use fileZip; +use fileUnzip; +use l10n; +use path; /** * Translater tools. */ -class dcTranslaterModule +class TranslaterModule { - /** @var dcTranslater dcTranslater instance */ + /** @var Translater Translater instance */ public $translater = null; /** @var array Module properies */ @@ -28,10 +37,7 @@ class dcTranslaterModule /** @var string Backup file regexp */ private $backup_file_regexp = '/^l10n-%s-(.*?)-[0-9]*?\.bck\.zip$/'; - /** @var string Locales file regexp */ - private $locales_file_regexp = '/^(.*?)\/locales\/(.*?)\/(.*?)(.po|.lang.php)$/'; - - public function __construct(dcTranslater $translater, array $module) + public function __construct(Translater $translater, array $module) { $this->translater = $translater; $this->prop = $module; @@ -72,7 +78,7 @@ class dcTranslaterModule public function getBackupRoot(bool $throw = false) { $dir = false; - switch ($this->translater->backup_folder) { + switch ($this->translater->get('backup_folder')) { case 'module': if ($this->prop['root_writable']) { $dir = $this->prop['locales']; @@ -81,7 +87,8 @@ class dcTranslaterModule break; case 'plugin': - $tmp = path::real(array_pop(explode(PATH_SEPARATOR, DC_PLUGINS_ROOT))); + $exp = explode(PATH_SEPARATOR, DC_PLUGINS_ROOT); + $tmp = path::real(array_pop($exp)); if ($tmp && is_writable($tmp)) { $dir = $tmp; } @@ -106,7 +113,7 @@ class dcTranslaterModule break; case 'translater': - $tmp = path::real(dcCore::app()->plugins->moduleRoot(basename(dirname(__DIR__)))); + $tmp = path::real(dcCore::app()->plugins->moduleRoot(My::id())); if ($tmp && is_writable($tmp)) { @mkDir($tmp . '/locales'); $dir = $tmp . '/locales'; @@ -138,7 +145,7 @@ class dcTranslaterModule } $res = []; - $files = dcTranslater::scandir($backup); + $files = Translater::scandir($backup); foreach ($files as $file) { $is_backup = preg_match(sprintf($this->backup_file_regexp, preg_quote($this->prop['id'])), $file, $m); @@ -182,17 +189,17 @@ class dcTranslaterModule } $res = []; - $files = dcTranslater::scandir($this->prop['locales'] . '/' . $lang); + $files = Translater::scandir($this->prop['locales'] . '/' . $lang); foreach ($files as $file) { if (!is_dir($this->prop['locales'] . '/' . $lang . '/' . $file) - && (dcTranslater::isLangphpFile($file) || dcTranslater::isPoFile($file)) + && (Translater::isLangphpFile($file) || Translater::isPoFile($file)) ) { $res[$this->prop['locales'] . '/' . $lang . '/' . $file] = $this->prop['id'] . '/locales/' . $lang . '/' . $file; } } if (!empty($res)) { - dcTranslater::isBackupLimit($this->prop['id'], $backup, $this->translater->backup_limit, true); + Translater::isBackupLimit($this->prop['id'], $backup, $this->translater->get('backup_limit'), true); @set_time_limit(300); $fp = fopen($backup . '/l10n-' . $this->prop['id'] . '-' . $lang . '-' . time() . '.bck.zip', 'wb'); @@ -206,6 +213,8 @@ class dcTranslaterModule return true; } + + return false; } /** @@ -291,7 +300,7 @@ class dcTranslaterModule foreach ($files as $file) { $f = $this->parseZipFilename($file, true); - if (!$this->translater->import_overwrite + if (!$this->translater->get('import_overwrite') && file_exists($this->prop['locales'] . '/' . $f['lang'] . '/' . $f['group'] . $f['ext']) ) { $not_overwrited[] = implode('-', [$f['lang'], $f['group'], $f['ext']]); @@ -337,7 +346,7 @@ class dcTranslaterModule * * @param array $langs Langs to export */ - public function exportPack(array $langs) + public function exportPack(array $langs): void { if (empty($langs)) { throw new Exception( @@ -345,7 +354,7 @@ class dcTranslaterModule ); } - $filename = files::tidyFileName($this->translater->export_filename); + $filename = files::tidyFileName($this->translater->get('export_filename')); if (empty($filename)) { throw new Exception( __('Export mask is not set in plugin configuration') @@ -358,11 +367,11 @@ class dcTranslaterModule continue; } - $files = dcTranslater::scandir($this->prop['locales'] . '/' . $lang); + $files = Translater::scandir($this->prop['locales'] . '/' . $lang); foreach ($files as $file) { if (is_dir($this->prop['locales'] . '/' . $lang . '/' . $file) - || !dcTranslater::isLangphpFile($file) - && !dcTranslater::isPoFile($file) + || !Translater::isLangphpFile($file) + && !Translater::isPoFile($file) ) { continue; } @@ -387,7 +396,7 @@ class dcTranslaterModule $filename = files::tidyFileName(dt::str(str_replace( ['timestamp', 'module', 'type', 'version'], [time(), $this->prop['id'], $this->prop['type'], $this->prop['version']], - $this->translater->export_filename + $this->translater->get('export_filename') ))); header('Content-Disposition: attachment;filename=' . $filename . '.zip'); @@ -402,7 +411,7 @@ class dcTranslaterModule * * @param string $file The zip filename * @param boolean $throw Silently failed - * @return mixed Array of file info + * @return array Array of file info */ public function parseZipFilename(string $file = '', bool $throw = false): array { @@ -411,8 +420,8 @@ class dcTranslaterModule if ($is_file) { $module = $f[1] == $this->prop['id'] ? $f[1] : false; $lang = l10n::isCode($f[2]) ? $f[2] : false; - $group = in_array($f[3], dcTranslater::$allowed_l10n_groups) ? $f[3] : false; - $ext = dcTranslater::isLangphpFile($f[4]) || dcTranslater::isPoFile($f[4]) ? $f[4] : false; + $group = in_array($f[3], My::l10nGroupsCombo()) ? $f[3] : false; + $ext = Translater::isLangphpFile($f[4]) || Translater::isPoFile($f[4]) ? $f[4] : false; } if (!$is_file || !$module || !$lang || !$group || !$ext) { @@ -449,7 +458,7 @@ class dcTranslaterModule $prefix = preg_match('/(locales(.*))$/', $this->prop['locales']) ? 'locales' : ''; - $files = dcTranslater::scandir($this->prop['locales']); + $files = Translater::scandir($this->prop['locales']); foreach ($files as $file) { if (!preg_match('/.*?locales\/([^\/]*?)\/([^\/]*?)(.lang.php|.po)$/', $prefix . $file, $m)) { continue; @@ -474,7 +483,7 @@ class dcTranslaterModule * * @return array The list of iso names and codes */ - public function getUsedLangs() + public function getUsedLangs(): array { return array_flip($this->getLangs()); } @@ -484,7 +493,7 @@ class dcTranslaterModule * * @return array The list of iso names and codes */ - public function getUnusedLangs() + public function getUnusedLangs(): array { return array_diff(l10n::getISOcodes(true, false), $this->getUsedLangs()); } @@ -496,7 +505,7 @@ class dcTranslaterModule * @param string $from_lang The lang to copy from * @return boolean True on success */ - public function addLang(string $lang, string $from_lang = '') + public function addLang(string $lang, string $from_lang = ''): bool { if (!l10n::isCode($lang)) { throw new Exception(sprintf( @@ -523,11 +532,11 @@ class dcTranslaterModule } if (!empty($from_lang) && isset($langs[$from_lang])) { - $files = dcTranslater::scandir($this->prop['locales'] . '/' . $from_lang); + $files = Translater::scandir($this->prop['locales'] . '/' . $from_lang); foreach ($files as $file) { if (is_dir($this->prop['locales'] . '/' . $from_lang . '/' . $file) - || !dcTranslater::isLangphpFile($file) - && !dcTranslater::isPoFile($file) + || !Translater::isLangphpFile($file) + && !Translater::isPoFile($file) ) { continue; } @@ -541,6 +550,8 @@ class dcTranslaterModule $this->setPoContent($lang, 'main', []); $this->setLangphpContent($lang, 'main', []); } + + return true; } /** @@ -549,7 +560,7 @@ class dcTranslaterModule * @param string $lang The lang * @param array $msgs The messages */ - public function updLang(string $lang, array $msgs) + public function updLang(string $lang, array $msgs): void { if (!l10n::isCode($lang)) { throw new Exception(sprintf( @@ -566,7 +577,7 @@ class dcTranslaterModule )); } - if ($this->translater->backup_auto) { + if ($this->translater->get('backup_auto')) { $this->createBackup($lang); } @@ -578,7 +589,7 @@ class dcTranslaterModule $rs[$msg['group']][] = $msg; } - foreach (dcTranslater::$allowed_l10n_groups as $group) { + foreach (My::l10nGroupsCombo() as $group) { if (isset($rs[$group])) { continue; } @@ -636,12 +647,12 @@ class dcTranslaterModule unlink($this->prop['locales'] . '/' . $file); } - $dir = dcTranslater::scandir($this->prop['locales'] . '/' . $lang); + $dir = Translater::scandir($this->prop['locales'] . '/' . $lang); if (empty($dir)) { rmdir($this->prop['locales'] . '/' . $lang); } - $loc = dcTranslater::scandir($this->prop['locales']); + $loc = Translater::scandir($this->prop['locales']); if (empty($loc)) { rmdir($this->prop['locales']); } @@ -656,32 +667,33 @@ class dcTranslaterModule * @param string $group The lang group * @param array $msgs The strings */ - private function setPoContent(string $lang, string $group, array $msgs) + private function setPoContent(string $lang, string $group, array $msgs): void { - $lang = new dcTranslaterLang($this, $lang); + $lang = new TranslaterLang($this, $lang); $content = ''; - if ($this->translater->parse_comment) { - $content .= '# Language: ' . $lang->name . "\n" . - '# Module: ' . $this->id . ' - ' . $this->version . "\n" . + if ($this->translater->get('parse_comment')) { + $content .= '# Language: ' . $lang->get('name') . "\n" . + '# Module: ' . $this->get('id') . ' - ' . $this->get('version') . "\n" . '# Date: ' . dt::str('%Y-%m-%d %H:%M:%S') . "\n"; - if ($this->translater->parse_user && $this->translater->parse_userinfo != '') { - $search = dcTranslater::$allowed_user_informations; + if ($this->translater->get('parse_user') && $this->translater->get('parse_userinfo') != '') { + $search = My::defaultUserInformations(); + $replace = []; foreach ($search as $n) { $replace[] = dcCore::app()->auth->getInfo('user_' . $n); } - $info = trim(str_replace($search, $replace, $this->translater->parse_userinfo)); + $info = trim(str_replace($search, $replace, $this->translater->get('parse_userinfo'))); if (!empty($info)) { $content .= '# Author: ' . html::escapeHTML($info) . "\n"; } } - $content .= '# Translated with translater ' . dcCore::app()->plugins->moduleInfo(basename(dirname(__DIR__)), 'version') . "\n\n"; + $content .= '# Translated with translater ' . dcCore::app()->plugins->moduleInfo(My::id(), 'version') . "\n\n"; } $content .= "msgid \"\"\n" . "msgstr \"\"\n" . '"Content-Type: text/plain; charset=UTF-8\n"' . "\n" . - '"Project-Id-Version: ' . $this->id . ' ' . $this->version . '\n"' . "\n" . + '"Project-Id-Version: ' . $this->get('id') . ' ' . $this->get('version') . '\n"' . "\n" . '"POT-Creation-Date: \n"' . "\n" . '"PO-Revision-Date: ' . date('c') . '\n"' . "\n" . '"Last-Translator: ' . dcCore::app()->auth->getInfo('user_cn') . '\n"' . "\n" . @@ -691,7 +703,7 @@ class dcTranslaterModule '"Plural-Forms: nplurals=2; plural=(n > 1);\n"' . "\n\n"; $comments = []; - if ($this->translater->parse_comment) { + if ($this->translater->get('parse_comment')) { $msgids = $lang->getMsgids(); foreach ($msgids as $msg) { $comments[$msg['msgid']] = ($comments[$msg['msgid']] ?? '') . @@ -703,22 +715,22 @@ class dcTranslaterModule if (empty($msg['msgstr'][0])) { continue; } - if ($this->translater->parse_comment && isset($comments[$msg['msgid']])) { + if ($this->translater->get('parse_comment') && isset($comments[$msg['msgid']])) { $content .= $comments[$msg['msgid']]; } - $content .= 'msgid "' . dcTranslater::poString($msg['msgid'], true) . '"' . "\n"; + $content .= 'msgid "' . Translater::poString($msg['msgid'], true) . '"' . "\n"; if (empty($msg['msgid_plural'])) { - $content .= 'msgstr "' . dcTranslater::poString($msg['msgstr'][0], true) . '"' . "\n"; + $content .= 'msgstr "' . Translater::poString($msg['msgstr'][0], true) . '"' . "\n"; } else { - $content .= 'msgid_plural "' . dcTranslater::poString($msg['msgid_plural'], true) . '"' . "\n"; + $content .= 'msgid_plural "' . Translater::poString($msg['msgid_plural'], true) . '"' . "\n"; foreach ($msg['msgstr'] as $i => $plural) { - $content .= 'msgstr[' . $i . '] "' . dcTranslater::poString(($msg['msgstr'][$i] ?: ''), true) . '"' . "\n"; + $content .= 'msgstr[' . $i . '] "' . Translater::poString(($msg['msgstr'][$i] ?: ''), true) . '"' . "\n"; } } $content .= "\n"; } - $file = $this->locales . '/' . $lang->code . '/' . $group . '.po'; + $file = $this->get('locales') . '/' . $lang->get('code') . '/' . $group . '.po'; $path = path::info($file); if (is_dir($path['dirname']) && !is_writable($path['dirname']) || file_exists($file) && !is_writable($file)) { @@ -743,34 +755,35 @@ class dcTranslaterModule * @param string $group The lang group * @param array $msgs The strings */ - private function setLangphpContent(string $lang, string $group, array $msgs) + private function setLangphpContent(string $lang, string $group, array $msgs): void { - if (!$this->translater->write_langphp) { - return null; + if (!$this->translater->get('write_langphp')) { + return; } - $lang = new dcTranslaterLang($this, $lang); + $lang = new TranslaterLang($this, $lang); $content = ''; - if ($this->translater->parse_comment) { - $content .= '// Language: ' . $lang->name . "\n" . - '// Module: ' . $this->id . ' - ' . $this->verison . "\n" . + if ($this->translater->get('parse_comment')) { + $content .= '// Language: ' . $lang->get('name') . "\n" . + '// Module: ' . $this->get('id') . ' - ' . $this->get('verison') . "\n" . '// Date: ' . dt::str('%Y-%m-%d %H:%M:%S') . "\n"; - if ($this->translater->parse_user && !empty($this->translater->parse_userinfo)) { - $search = dcTranslater::$allowed_user_informations; + if ($this->translater->get('parse_user') && !empty($this->translater->get('parse_userinfo'))) { + $search = My::defaultUserInformations(); + $replace = []; foreach ($search as $n) { $replace[] = dcCore::app()->auth->getInfo('user_' . $n); } - $info = trim(str_replace($search, $replace, $this->translater->parse_userinfo)); + $info = trim(str_replace($search, $replace, $this->translater->get('parse_userinfo'))); if (!empty($info)) { $content .= '// Author: ' . html::escapeHTML($info) . "\n"; } } - $content .= '// Translated with dcTranslater - ' . dcCore::app()->plugins->moduleInfo(basename(dirname(__DIR__)), 'version') . "\n\n"; + $content .= '// Translated with Translater - ' . dcCore::app()->plugins->moduleInfo(My::id(), 'version') . "\n\n"; } - l10n::generatePhpFileFromPo($this->locales . '/' . $lang->code . '/' . $group, $content); + l10n::generatePhpFileFromPo($this->get('locales') . '/' . $lang->get('code') . '/' . $group, $content); } //@} } diff --git a/src/TranslaterProposals.php b/src/TranslaterProposals.php index dcf3f2a..db80b7e 100644 --- a/src/TranslaterProposals.php +++ b/src/TranslaterProposals.php @@ -10,6 +10,13 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ +declare(strict_types=1); + +namespace Dotclear\Plugin\translater; + +use dcCore; +use ReflectionClass; + /** * Translater proposal tools container. */ diff --git a/src/Uninstall.php b/src/Uninstall.php index 3076edc..1098941 100644 --- a/src/Uninstall.php +++ b/src/Uninstall.php @@ -10,72 +10,93 @@ * @copyright Jean-Christian Denis * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html */ -if (!defined('DC_CONTEXT_ADMIN')) { - return; +declare(strict_types=1); + +namespace Dotclear\Plugin\translater; + +class Uninstall +{ + protected static $init = false; + + public static function init(): bool + { + self::$init = defined('DC_RC_PATH'); + + return self::$init; + } + + public static function process($uninstaller): ?bool + { + if (!self::$init) { + return false; + } + + $uninstaller->addUserAction( + /* type */ + 'settings', + /* action */ + 'delete_all', + /* ns */ + My::id(), + /* description */ + __('delete all settings') + ); + + $uninstaller->addUserAction( + /* type */ + 'plugins', + /* action */ + 'delete', + /* ns */ + My::id(), + /* description */ + __('delete plugin files') + ); + + $uninstaller->addUserAction( + /* type */ + 'versions', + /* action */ + 'delete', + /* ns */ + My::id(), + /* description */ + __('delete the version number') + ); + + $uninstaller->addDirectAction( + /* type */ + 'settings', + /* action */ + 'delete_all', + /* ns */ + My::id(), + /* description */ + sprintf(__('delete all %s settings'), My::id()) + ); + + $uninstaller->addDirectAction( + /* type */ + 'plugins', + /* action */ + 'delete', + /* ns */ + My::id(), + /* description */ + sprintf(__('delete %s plugin files'), My::id()) + ); + + $uninstaller->addDirectAction( + /* type */ + 'versions', + /* action */ + 'delete', + /* ns */ + My::id(), + /* description */ + sprintf(__('delete %s version number'), My::id()) + ); + + return true; + } } - -$this->addUserAction( - /* type */ - 'settings', - /* action */ - 'delete_all', - /* ns */ - basename(__DIR__), - /* description */ - __('delete all settings') -); - -$this->addUserAction( - /* type */ - 'plugins', - /* action */ - 'delete', - /* ns */ - basename(__DIR__), - /* description */ - __('delete plugin files') -); - -$this->addUserAction( - /* type */ - 'versions', - /* action */ - 'delete', - /* ns */ - basename(__DIR__), - /* description */ - __('delete the version number') -); - -$this->addDirectAction( - /* type */ - 'settings', - /* action */ - 'delete_all', - /* ns */ - basename(__DIR__), - /* description */ - sprintf(__('delete all %s settings'), basename(__DIR__)) -); - -$this->addDirectAction( - /* type */ - 'plugins', - /* action */ - 'delete', - /* ns */ - basename(__DIR__), - /* description */ - sprintf(__('delete %s plugin files'), basename(__DIR__)) -); - -$this->addDirectAction( - /* type */ - 'versions', - /* action */ - 'delete', - /* ns */ - basename(__DIR__), - /* description */ - sprintf(__('delete %s version number'), basename(__DIR__)) -);