use namespace

This commit is contained in:
Jean-Christian Paul Denis 2023-03-15 00:26:31 +01:00
parent 85d4985137
commit b4dc1a5093
Signed by: JcDenis
GPG Key ID: 1B5B8C5B90B6C951
17 changed files with 1409 additions and 1036 deletions

View File

@ -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);
namespace Dotclear\Plugin\translater;
use dcAdmin;
use dcCore;
use dcFavorites;
use dcNsProcess;
use dcPage;
class Backend extends dcNsProcess
{
public static function init(): bool
{
if (defined('DC_CONTEXT_ADMIN')) {
self::$init = dcCore::app()->auth->isSuperAdmin();
}
if (!dcCore::app()->auth->isSuperAdmin()) {
return null;
return self::$init;
}
public static function process(): bool
{
if (!self::$init) {
return false;
}
dcCore::app()->addBehaviors([
'adminModulesListGetActions' => ['translaterAdminBehaviors', 'adminModulesGetActions'],
'adminModulesListDoActions' => ['translaterAdminBehaviors', 'adminModulesDoActions'],
'adminDashboardFavoritesV2' => ['translaterAdminBehaviors', 'adminDashboardFavoritesV2'],
'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(
__('Translater'),
dcCore::app()->adminurl->get(basename(__DIR__)),
dcPage::getPF(basename(__DIR__) . '/icon.svg'),
My::name(),
dcCore::app()->adminurl->get(My::id()),
dcPage::getPF(My::id() . '/icon.svg'),
preg_match(
'/' . preg_quote(dcCore::app()->adminurl->get(basename(__DIR__))) . '(&.*)?$/',
'/' . preg_quote(dcCore::app()->adminurl->get(My::id())) . '(&.*)?$/',
$_SERVER['REQUEST_URI']
),
dcCore::app()->auth->isSuperAdmin()
);
class translaterAdminBehaviors
{
/** @var dcTranslater dcTranslater instance */
private static $translater = null;
/**
* Create instance of dcTranslater once
*
* @return dcTranslater dcTranslater instance
*/
private static function translater(): dcTranslater
{
if (!is_a(self::$translater, 'dcTranslater')) {
self::$translater = new dcTranslater(false);
}
return self::$translater;
}
/**
* 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
{
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;
}
return
' <input type="submit" name="translater[' .
html::escapeHTML($id) .
']" 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(
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,
]);
return true;
}
}

86
src/BackendBehaviors.php Normal file
View File

@ -0,0 +1,86 @@
<?php
/**
* @brief translater, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Jean-Christian Denis & contributors
*
* @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 adminModulesList;
use dcCore;
use Dotclear\Helper\Html\Form\Input;
use html;
class BackendBehaviors
{
/** @var Translater Translater instance */
private static $translater = null;
/**
* Create instance of Translater once
*
* @return Translater Translater instance
*/
private static function translater(): Translater
{
if (!is_a(self::$translater, Translater::class)) {
self::$translater = new Translater(false);
}
return self::$translater;
}
/**
* 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
{
if ($list->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'
);
}
}

View File

@ -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);
namespace Dotclear\Plugin\translater;
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;
}
$translater = new dcTranslater();
public static function process(): bool
{
if (!self::$init) {
return false;
}
// nothing to process
if (empty($_POST['save'])) {
return true;
}
$translater = new Translater();
if (!empty($_POST['save'])) {
try {
foreach ($translater->getDefaultSettings() as $key => $value) {
$translater->$key = $_POST[$key] ?? '';
foreach (My::defaultSettings() as $key => $value) {
$translater->set($key, $_POST[$key] ?? '');
}
$translater->writeSettings();
dcAdminNotices::addSuccessNotice(
dcPage::addSuccessNotice(
__('Configuration successfully updated.')
);
dcCore::app()->adminurl->redirect(
'admin.plugins',
['module' => basename(__DIR__), 'conf' => 1, 'redir' => dcCore::app()->admin->__get('list')->getRedir()]
['module' => My::id(), 'conf' => 1, 'redir' => dcCore::app()->admin->__get('list')->getRedir()]
);
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
}
return true;
}
echo '
<div class="fieldset"><h4>' . __('Translation') . '</h4>
<p><label for="write_langphp">' .
form::checkbox('write_langphp', '1', $translater->write_langphp) .
__('Write .lang.php files') . '</label></p>
<p><label for="scan_tpl">' .
form::checkbox('scan_tpl', '1', $translater->scan_tpl) .
__('Translate also strings of template files') . '</label></p>
<p><label for="parse_nodc">' .
form::checkbox('parse_nodc', '1', $translater->parse_nodc) .
__('Translate only unknow strings') . '</label></p>
<p><label for="hide_default">' .
form::checkbox('hide_default', '1', $translater->hide_default) .
__('Hide default modules of Dotclear') . '</label></p>
<p><label for="parse_comment">' .
form::checkbox('parse_comment', '1', $translater->parse_comment) .
__('Write comments in files') . '</label></p>
<p><label for="parse_user">' .
form::checkbox('parse_user', '1', $translater->parse_user) .
__('Write informations about author in files') . '</label></p>
<p><label for="parse_userinfo">' . __('User info:') . '</label>' .
form::field('parse_userinfo', 65, 255, $translater->parse_userinfo) . '</p>
<p class="form-note">' . sprintf(
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(', ', $translater::$allowed_user_informations)
) . '
</p>
</div>
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'),
]),
<div class="fieldset"><h4>' . __('Import/Export') . '</h4>
<p><label for="import_overwrite">' .
form::checkbox('import_overwrite', '1', $translater->import_overwrite) .
__('Overwrite existing languages') . '</label></p>
<p><label for="export_filename">' . __('Name of exported package:') . '</label>' .
form::field('export_filename', 65, 255, $translater->export_filename) . '</p>
</div>
<div class="fieldset"><h4>' . __('Backups') . '</h4>
<p><label for="backup_auto">' .
form::checkbox('backup_auto', '1', $translater->backup_auto) .
__('Make backups when changes are made') . '</label></p>
<p><label for="backup_limit" class="classic">' . sprintf(
__('Limit backups to %s files per module'),
form::number('backup_limit', ['min' => 0, 'max' => 50, 'default' => $translater->backup_limit])
) . '</label></p>
<p class="form-note">' . __('Set to 0 for no limit.') . '</p>
<p><label for="backup_folder">' . __('Store backups in:') . '</label>' .
form::combo('backup_folder', $translater::$allowed_backup_folders, $translater->backup_folder) . '</p>
</div>
<div class="fieldset"><h4>' . __('Behaviors') . '</h4>
<p><label for="start_page">' . __('Default start menu:') . '</label>' .
form::combo('start_page', [
__('Plugins') => 'plugin',
__('Themes') => 'theme',
__('Home') => '-',
], $translater->start_page) . '</p>
<p><label for="plugin_menu">' .
form::checkbox('plugin_menu', '1', $translater->plugin_menu) .
__('Enable menu on plugins page') . '</label></p>
<p><label for="theme_menu">' .
form::checkbox('theme_menu', '1', $translater->theme_menu) .
__('Enable menu on themes page') . '</label></p>
</div>';
]),
])->render();
dcPage::helpBlock('translater.config');
}
}

21
src/Exception.php Normal file
View File

@ -0,0 +1,21 @@
<?php
/**
* @brief translater, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Jean-Christian Denis & contributors
*
* @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 Exception as PhpException;
class Exception extends PhpException
{
}

View File

@ -10,20 +10,35 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_CONTEXT_ADMIN')) {
return null;
declare(strict_types=1);
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;
}
public static function process(): bool
{
if (!self::$init) {
return false;
}
try {
if (!dcCore::app()->newVersion(
basename(__DIR__),
dcCore::app()->plugins->moduleInfo(basename(__DIR__), 'version')
)) {
return null;
}
$translater = new dcTranslater(false);
if (!$translater->growUp()) {
$translater->writeSettings(false);
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;
@ -31,4 +46,39 @@ try {
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;
}
}

View File

@ -10,144 +10,152 @@
* @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 dcNsProcess;
use dcPage;
use dt;
use html;
use files;
use form;
class Manage extends dcNsProcess
{
public static function init(): bool
{
if (defined('DC_CONTEXT_ADMIN')) {
self::$init = dcCore::app()->auth->isSuperAdmin();
}
dcPage::checkSuper();
return self::$init;
}
$translater = new dcTranslater();
public static function process(): bool
{
if (!self::$init) {
return false;
}
$type = $_REQUEST['type'] ?? $translater->start_page ?: '';
$module = $_REQUEST['module'] ?? '';
$lang = $_REQUEST['lang'] ?? '';
// 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'] ?? '';
if (!in_array($type, ['plugin', 'theme'])) {
$type = '';
// check module type
if (!in_array(dcCore::app()->admin->type, ['plugin', 'theme'])) {
dcCore::app()->admin->type = '';
}
if (!empty($type) && !empty($module)) {
// check if module exists
if (!empty(dcCore::app()->admin->type) && !empty(dcCore::app()->admin->module)) {
try {
$module = $translater->getModule($type, $module);
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());
$module = '';
dcCore::app()->admin->module = '';
}
}
if (!empty($module) && !empty($lang)) {
//check if module lang exists
if (!empty(dcCore::app()->admin->module) && !empty(dcCore::app()->admin->lang)) {
try {
$lang = $translater->getLang($module, $lang);
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());
$lang = '';
dcCore::app()->admin->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))] = '';
}
// execute action
try {
if ($action == 'module_create_backups') {
if (empty($module) || empty($_POST['codes'])) {
if (empty(dcCore::app()->admin->module) || empty($_POST['codes'])) {
throw new Exception(__('Nothing to backup'));
}
$module_codes = $module->getUsedlangs();
$module_codes = dcCore::app()->admin->module->getUsedlangs();
foreach ($module_codes as $code_id) {
if (in_array($code_id, $_POST['codes'])) {
$module->createBackup($code_id);
dcCore::app()->admin->module->createBackup($code_id);
}
}
dcAdminNotices::addSuccessNotice(__('Backup successfully created'));
dcCore::app()->adminurl->redirect(basename(__DIR__), ['type' => $type, 'module' => $module->id]);
self::redirect(__('Backup successfully created'));
}
if ($action == 'module_restore_backup') {
if (empty($module) || empty($_POST['files'])) {
if (empty(dcCore::app()->admin->module) || empty($_POST['files'])) {
throw new Exception(__('Nothing to restore'));
}
$module_backups = $module->getBackups(true);
$module_backups = dcCore::app()->admin->module->getBackups(true);
foreach ($module_backups as $backup_file) {
if (in_array($backup_file, $_POST['files'])) {
$module->restoreBackup($backup_file);
dcCore::app()->admin->module->restoreBackup($backup_file);
}
}
dcAdminNotices::addSuccessNotice(__('Backup successfully restored'));
dcCore::app()->adminurl->redirect(basename(__DIR__), ['type' => $type, 'module' => $module->id]);
self::redirect(__('Backup successfully restored'));
}
if ($action == 'module_delete_backup') {
if (empty($module) || empty($_POST['files'])) {
if (empty(dcCore::app()->admin->module) || empty($_POST['files'])) {
throw new Exception(__('Nothing to delete'));
}
$module_backups = $module->getBackups(true);
$module_backups = dcCore::app()->admin->module->getBackups(true);
foreach ($module_backups as $backup_file) {
if (in_array($backup_file, $_POST['files'])) {
$module->deleteBackup($backup_file);
dcCore::app()->admin->module->deleteBackup($backup_file);
}
}
dcAdminNotices::addSuccessNotice(__('Backup successfully deleted'));
dcCore::app()->adminurl->redirect(basename(__DIR__), ['type' => $type, 'module' => $module->id]);
self::redirect(__('Backup successfully deleted'));
}
if ($action == 'module_export_pack') {
if (empty($module) || empty($_POST['codes'])) {
if (empty(dcCore::app()->admin->module) || empty($_POST['codes'])) {
throw new Exception(__('Nothing to export'));
}
$module->exportPack($_POST['codes']);
dcCore::app()->admin->module->exportPack($_POST['codes']);
dcAdminNotices::addSuccessNotice(__('Language successfully exported'));
dcCore::app()->adminurl->redirect(basename(__DIR__), ['type' => $type, 'module' => $module->id]);
self::redirect(__('Language successfully exported'));
}
if ($action == 'module_import_pack') {
if (empty($_FILES['packfile']['name'])) {
throw new Exception(__('Nothing to import'));
}
$module->importPack($_FILES['packfile']);
dcCore::app()->admin->module->importPack($_FILES['packfile']);
dcAdminNotices::addSuccessNotice(__('Language successfully imported'));
dcCore::app()->adminurl->redirect(basename(__DIR__), ['type' => $type, 'module' => $module->id]);
self::redirect(__('Language successfully imported'));
}
if ($action == 'module_add_code') {
if (empty($module) || empty($_POST['code'])) {
if (empty(dcCore::app()->admin->module) || empty($_POST['code'])) {
throw new Exception(__('Nothing to create'));
}
$module->addLang($_POST['code'], $_POST['from'] ?? '');
dcCore::app()->admin->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']]);
self::redirect(__('Language successfully added'), $_POST['code']);
}
if ($action == 'module_delete_codes') {
if (empty($module) || empty($_POST['codes'])) {
if (empty(dcCore::app()->admin->module) || empty($_POST['codes'])) {
throw new Exception(__('Nothing to delete'));
}
$module_codes = $module->getUsedlangs();
$module_codes = dcCore::app()->admin->module->getUsedlangs();
foreach ($module_codes as $code_id) {
if (in_array($code_id, $_POST['codes'])) {
$module->delLang($code_id);
dcCore::app()->admin->module->delLang($code_id);
}
}
dcAdminNotices::addSuccessNotice(__('Language successfully deleted'));
dcCore::app()->adminurl->redirect(basename(__DIR__), ['type' => $type, 'module' => $module->id, 'lang' => $_POST['code']]);
self::redirect(__('Language successfully deleted'), $_POST['code']);
}
if ($action == 'module_update_code') {
if (empty($module) || empty($_POST['code']) || empty($_POST['entries'])) {
if (empty(dcCore::app()->admin->module) || empty($_POST['code']) || empty($_POST['entries'])) {
throw new Exception(__('Nothing to update'));
}
if (!empty($_POST['update_group'])) {
@ -157,49 +165,71 @@ try {
}
}
}
$module->updLang($_POST['code'], $_POST['entries']);
dcCore::app()->admin->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(__('Language successfully updated'), $_POST['code']);
}
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
}
echo
'<html><head><title>' . __('Translater') . '</title>' .
return true;
}
public static function render(): void
{
if (!self::$init) {
return;
}
$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))] = '';
}
dcPage::openModule(
My::name(),
dcPage::jsPageTabs() .
dcPage::cssModuleLoad(basename(__DIR__) . '/css/translater.css') .
dcPage::cssModuleLoad(My::id() . '/css/backend.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'),
'image_field' => dcPage::getPF(My::id() . '/img/field.png'),
'image_toggle' => dcPage::getPF(My::id() . '/img/toggle.png'),
]) .
dcPage::jsModuleLoad(basename(__DIR__) . '/js/translater.js') .
dcPage::jsModuleLoad(My::id() . '/js/backend.js') .
# --BEHAVIOR-- translaterAdminHeaders
dcCore::app()->callBehavior('translaterAdminHeaders') .
'</head><body>' .
dcCore::app()->callBehavior('translaterAdminHeaders')
);
echo
dcPage::breadcrumb($breadcrumb) .
dcPage::notices();
if (empty($module) && $type != '') {
if (empty(dcCore::app()->admin->module) && dcCore::app()->admin->type != '') {
// modules list
echo '<form id="theme-form" method="post" action="' . dcCore::app()->adminurl->get(basename(__DIR__), ['type' => 'plugin']) . '">';
echo '<form id="theme-form" method="post" action="' . dcCore::app()->adminurl->get(My::id(), ['type' => 'plugin']) . '">';
$res = '';
$modules = $translater->getModules($type);
$modules = dcCore::app()->admin->translater->getModules(dcCore::app()->admin->type);
ksort($modules);
foreach ($modules as $module) {
if ($translater->hide_default && in_array($module->id, $translater::$default_distrib_modules[$type])) {
if (dcCore::app()->admin->translater->get('hide_default') && in_array($module->id, My::defaultDistribModules(dcCore::app()->admin->type))) {
continue;
}
if ($module->root_writable) {
$res .= sprintf(
'<tr class="line"><td class="nowrap minimal"><a href="%s" title="%s">%s</a></td>',
dcCore::app()->adminurl->get(basename(__DIR__), ['type' => $module->type, 'module' => $module->id]),
dcCore::app()->adminurl->get(My::id(), ['type' => $module->type, 'module' => $module->id]),
html::escapeHTML(sprintf(__('Translate module %s'), __($module->name))),
html::escapeHTML($module->id)
);
@ -215,7 +245,7 @@ if (empty($module) && $type != '') {
$codes[$code_id] = sprintf(
'<a class="wait maximal nowrap" title="%s" href="%s">%s (%s)</a>',
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]),
dcCore::app()->adminurl->get(My::id(), ['type' => $module->type, 'module' => $module->id, 'lang' => $code_id]),
html::escapeHTML($code_name),
$code_id
);
@ -234,7 +264,7 @@ if (empty($module) && $type != '') {
echo '
<div class="table-outer">
<table class="clear">
<caption>' . sprintf(__('Modules list of type "%s"'), $type) . '</caption>
<caption>' . sprintf(__('Modules list of type "%s"'), dcCore::app()->admin->type) . '</caption>
<tr>
<th class="nowrap">' . __('Id') . '</th>
<th class="nowrap">' . __('Languages') . '</th>
@ -249,17 +279,17 @@ if (empty($module) && $type != '') {
echo '</form>';
dcPage::helpBlock('translater.type');
} elseif (!empty($module) && empty($lang)) {
$codes = $module->getUsedLangs();
$backups = $module->getBackups();
$unused_codes = $module->getUnusedLangs();
} 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 '<h3>' . sprintf(__('Module %s %s by %s'), $module->name, $module->version, $module->author) . '</h3>
echo '<h3>' . sprintf(__('Module %s %s by %s'), dcCore::app()->admin->module->name, dcCore::app()->admin->module->version, dcCore::app()->admin->module->author) . '</h3>
<ul class="nice col">
<li><strong>' . __('Root') . '</strong> ' . $module->root . '</li>
<li><strong>' . __('Locales') . '</strong> ' . $module->locales . '</li>
<li><strong>' . __('Backups') . '</strong> ' . $module->getBackupRoot() . '</li>
<li><strong>' . __('Root') . '</strong> ' . dcCore::app()->admin->module->root . '</li>
<li><strong>' . __('Locales') . '</strong> ' . dcCore::app()->admin->module->locales . '</li>
<li><strong>' . __('Backups') . '</strong> ' . dcCore::app()->admin->module->getBackupRoot() . '</li>
</ul>
<p>&nbsp;</p>';
@ -267,7 +297,7 @@ if (empty($module) && $type != '') {
if (count($codes)) {
echo
'<div class="clear fieldset"><h3>' . __('Translations') . '</h3>' .
'<form id="module-translations-form" method="post" action="' . dcCore::app()->adminurl->get(basename(__DIR__)) . '">' .
'<form id="module-translations-form" method="post" action="' . dcCore::app()->adminurl->get(My::id()) . '">' .
'<table class="clear maximal">' .
'<caption>' . __('Existing languages translations') . '</caption>' .
'<tr>' .
@ -283,7 +313,7 @@ if (empty($module) && $type != '') {
'<td class="minimal">' . form::checkbox(['codes[]', 'existing_code_' . $code_id], $code_id, '', '', '', false) . '</td>' .
'<td class="nowrap">' .
'<a href="' .
dcCore::app()->adminurl->get(basename(__DIR__), ['type' => $module->type, 'module' => $module->id, 'lang' => $code_id])
dcCore::app()->adminurl->get(My::id(), ['type' => dcCore::app()->admin->module->type, 'module' => dcCore::app()->admin->module->id, 'lang' => $code_id])
. '" title="' . sprintf(__('Edit %s language'), html::escapeHTML($code_name)) . '">' . $code_name . '</a>' .
'</td>' .
'<td class="nowrap maximal"> ' . $code_id . '</td>';
@ -297,7 +327,7 @@ if (empty($module) && $type != '') {
echo
'<td class="nowrap">' . count($backups[$code_id]) . '</td>' .
'<td class="nowrap"> ' .
dt::str('%Y-%m-%d %H:%M', (int) $time[$code_id], dcCore::app()->blog->settings->system->blog_timezone) .
dt::str('%Y-%m-%d %H:%M', (int) $time[$code_id], dcCore::app()->blog->settings->get('system')->get('blog_timezone')) .
'</td>';
} else {
echo '<td class="nowrap">' . __('no backups') . '</td><td class="maximal nowrap">-</td>';
@ -317,8 +347,8 @@ if (empty($module) && $type != '') {
<input id="do-action" type="submit" value="' . __('ok') . '" /></p>' .
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]
) . '
</p></div></form><p>&nbsp;</p></div>';
}
@ -328,7 +358,7 @@ if (empty($module) && $type != '') {
// delete / retore backups
if (!empty($backups)) {
echo '<div class="fieldset"><h3>' . __('Backups') . '</h3>' .
'<form id="module-backups-form" method="post" action="' . dcCore::app()->adminurl->get(basename(__DIR__)) . '">' .
'<form id="module-backups-form" method="post" action="' . dcCore::app()->adminurl->get(My::id()) . '">' .
'<table class="clear">' .
'<caption>' . __('Existing languages backups') . '</caption>' .
'<tr>' .
@ -360,9 +390,9 @@ if (empty($module) && $type != '') {
$backup_code['name'],
$backup_code['code'],
dt::str(
dcCore::app()->blog->settings->system->date_format . ' ' . dcCore::app()->blog->settings->system->time_format,
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->system->blog_timezone
dcCore::app()->blog->settings->get('system')->get('blog_timezone')
),
$backup_code['path']['basename'],
files::size($backup_code['size'])
@ -382,8 +412,8 @@ if (empty($module) && $type != '') {
<input id="do-action" type="submit" value="' . __('ok') . '" /></p>' .
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]
) . '
</p></div></form><p>&nbsp;</p></div>';
}
@ -394,7 +424,7 @@ if (empty($module) && $type != '') {
// add language
if (!empty($unused_codes)) {
echo '<div class="col fieldset"><h3>' . __('Add language') . '</h3>
<form id="muodule-code-create-form" method="post" action="' . dcCore::app()->adminurl->get(basename(__DIR__)) . '">
<form id="muodule-code-create-form" method="post" action="' . dcCore::app()->adminurl->get(My::id()) . '">
<p class="field"><label for="code">' . __('Select language:') . '</label>' .
form::combo(['code'], array_merge(['-' => '-'], $unused_codes), dcCore::app()->auth->getInfo('user_lang')) . '</p>';
if (empty($codes)) {
@ -408,36 +438,36 @@ if (empty($module) && $type != '') {
<p><input type="submit" name="save" value="' . __('Create') . '" />' .
dcCore::app()->formNonce() .
dcCore::app()->adminurl->getHiddenFormFields(
basename(__DIR__),
['type' => $module->type, 'module' => $module->id, 'action' => 'module_add_code']
My::id(),
['type' => dcCore::app()->admin->module->type, 'module' => dcCore::app()->admin->module->id, 'action' => 'module_add_code']
) . '
</p></form><p>&nbsp;</p></div>';
}
// Import
echo '<div class="col fieldset"><h3>' . __('Import') . '</h3>
<form id="module-pack-import-form" method="post" action="' . dcCore::app()->adminurl->get(basename(__DIR__)) . '" enctype="multipart/form-data">
<form id="module-pack-import-form" method="post" action="' . dcCore::app()->adminurl->get(My::id()) . '" enctype="multipart/form-data">
<p><label for="packfile">' . __('Select languages package to import:') . '<label> ' .
'<input id="packfile" type="file" name="packfile" /></p>
<p>
<input type="submit" name="save" value="' . __('Import') . '" />' .
dcCore::app()->formNonce() .
dcCore::app()->adminurl->getHiddenFormFields(
basename(__DIR__),
['type' => $module->type, 'module' => $module->id, 'action' => 'module_import_pack']
My::id(),
['type' => dcCore::app()->admin->module->type, 'module' => dcCore::app()->admin->module->id, 'action' => 'module_import_pack']
) . '
</p></form><p>&nbsp;</p></div>';
echo '</div>';
dcPage::helpBlock('translater.module');
} elseif (!empty($lang)) {
$lines = $lang->getMessages();
} elseif (!empty(dcCore::app()->admin->lang)) {
$lines = dcCore::app()->admin->lang->getMessages();
$allowed_l10n_groups = [];
echo
'<div id="lang-form">' .
'<form id="lang-edit-form" method="post" action="' . dcCore::app()->adminurl->get(basename(__DIR__)) . '">' .
'<form id="lang-edit-form" method="post" action="' . dcCore::app()->adminurl->get(My::id()) . '">' .
'<table class="table-outer">' .
'<caption>' . sprintf(__('List of %s localized strings'), count($lines)) . '</caption>' .
'<tr>' .
@ -461,8 +491,7 @@ if (empty($module) && $type != '') {
$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);
$in_dc = ($rs['in_dc'] && dcCore::app()->admin->translater->get('parse_nodc'));
$t_msgstr = $t_files = $strin = [];
foreach ($rs['o_msgstrs'] as $o_msgstr) {
@ -496,7 +525,7 @@ if (empty($module) && $type != '') {
$table_line,
$in_dc ? ' offline' : ' translaterline',
form::checkbox(['entries[' . $i . '][check]'], 1),
form::combo(['entries[' . $i . '][group]'], $allowed_l10n_groups, $rs['group'], '', '', $in_dc),
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),
@ -506,7 +535,7 @@ if (empty($module) && $type != '') {
if (!empty($rs['plural'])) {
$t_msgstr = $strin = [];
foreach ($lang->plural as $j => $plural) {
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]])) {
@ -542,7 +571,7 @@ if (empty($module) && $type != '') {
$table_line,
' offline',
form::checkbox(['entries[' . $i . '][check]'], 1),
form::combo(['entries[' . $i . '][group]'], $allowed_l10n_groups, 'main'),
form::combo(['entries[' . $i . '][group]'], My::l10nGroupsCombo(), 'main'),
form::field(['entries[' . $i . '][msgid]'], 48, 255, ''),
form::field(['entries[' . $i . '][msgstr][0]'], 48, 255, ''),
'',
@ -557,15 +586,15 @@ if (empty($module) && $type != '') {
'<p><label for="update_group">' .
form::checkbox('update_group', 1) .
__('Change the group of the selected translations to:') . ' ' .
form::combo('multigroup', $allowed_l10n_groups) . '</label></p>' .
form::combo('multigroup', My::l10nGroupsCombo()) . '</label></p>' .
'</div>' .
'<p class="col right">' .
'<input id="do-action" type="submit" value="' . __('Save') . ' (s)" accesskey="s" /></p>' .
dcCore::app()->formNonce() .
form::hidden(['code'], $lang->code) .
form::hidden(['code'], dcCore::app()->admin->lang->code) .
dcCore::app()->adminurl->getHiddenFormFields(
basename(__DIR__),
['type' => $module->type, 'module' => $module->id, 'lang' => $lang->code, 'action' => 'module_update_code']
My::id(),
['type' => dcCore::app()->admin->module->type, 'module' => dcCore::app()->admin->module->id, 'lang' => dcCore::app()->admin->lang->code, 'action' => 'module_update_code']
) .
'</p></div>' .
'</form>' .
@ -580,14 +609,14 @@ if (empty($module) && $type != '') {
'<h3><ul class="nice">%s</ul></h3>',
sprintf(
$line,
dcCore::app()->adminurl->get(basename(__DIR__), ['type' => 'plugin']),
$type == 'plugin' ? ' class="active"' : '',
dcCore::app()->adminurl->get(My::id(), ['type' => 'plugin']),
dcCore::app()->admin->type == 'plugin' ? ' class="active"' : '',
__('Translate plugins')
) .
sprintf(
$line,
dcCore::app()->adminurl->get(basename(__DIR__), ['type' => 'theme']),
$type == 'theme' ? ' class="active"' : '',
dcCore::app()->adminurl->get(My::id(), ['type' => 'theme']),
dcCore::app()->admin->type == 'theme' ? ' class="active"' : '',
__('Translate themes')
)
);
@ -595,4 +624,20 @@ if (empty($module) && $type != '') {
dcPage::helpBlock('translater.index');
}
echo '</body></html>';
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);
}
}

140
src/My.php Normal file
View File

@ -0,0 +1,140 @@
<?php
/**
* @brief translater, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Jean-Christian Denis & contributors
*
* @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;
/**
* Plugin definitions
*/
class My
{
/**
* This module id
*/
public static function id(): string
{
return basename(dirname(__DIR__));
}
/**
* This module name
*/
public static function name(): string
{
return __((string) dcCore::app()->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',
];
}
}

View File

@ -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);
namespace Dotclear\Plugin\translater;
use dcCore;
use dcNsProcess;
class Prepend extends dcNsProcess
{
public static function init(): bool
{
if (defined('DC_CONTEXT_ADMIN')) {
self::$init = dcCore::app()->auth->isSuperAdmin();
}
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',
]);
return self::$init;
}
public static function process(): bool
{
if (!self::$init) {
return false;
}
if (isset(dcCore::app()->adminurl)) {
dcCore::app()->adminurl->register(basename(__DIR__), 'plugin.php', ['p' => basename(__DIR__)]);
dcCore::app()->adminurl->register(My::id(), 'plugin.php', ['p' => My::id()]);
}
return true;
}
}

View File

@ -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)

View File

@ -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.

View File

@ -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.
*

View File

@ -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)) {

View File

@ -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__)));
// 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) . "' "))
);
}
return $this->settings[$key] ?? null;
}
return true;
/**
* 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 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);
}
//@}

View File

@ -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),

View File

@ -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);
}
//@}
}

View File

@ -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.
*/

View File

@ -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;
}
$this->addUserAction(
public static function process($uninstaller): ?bool
{
if (!self::$init) {
return false;
}
$uninstaller->addUserAction(
/* type */
'settings',
/* action */
'delete_all',
/* ns */
basename(__DIR__),
My::id(),
/* description */
__('delete all settings')
);
$this->addUserAction(
$uninstaller->addUserAction(
/* type */
'plugins',
/* action */
'delete',
/* ns */
basename(__DIR__),
My::id(),
/* description */
__('delete plugin files')
);
$this->addUserAction(
$uninstaller->addUserAction(
/* type */
'versions',
/* action */
'delete',
/* ns */
basename(__DIR__),
My::id(),
/* description */
__('delete the version number')
);
$this->addDirectAction(
$uninstaller->addDirectAction(
/* type */
'settings',
/* action */
'delete_all',
/* ns */
basename(__DIR__),
My::id(),
/* description */
sprintf(__('delete all %s settings'), basename(__DIR__))
sprintf(__('delete all %s settings'), My::id())
);
$this->addDirectAction(
$uninstaller->addDirectAction(
/* type */
'plugins',
/* action */
'delete',
/* ns */
basename(__DIR__),
My::id(),
/* description */
sprintf(__('delete %s plugin files'), basename(__DIR__))
sprintf(__('delete %s plugin files'), My::id())
);
$this->addDirectAction(
$uninstaller->addDirectAction(
/* type */
'versions',
/* action */
'delete',
/* ns */
basename(__DIR__),
My::id(),
/* description */
sprintf(__('delete %s version number'), basename(__DIR__))
sprintf(__('delete %s version number'), My::id())
);
return true;
}
}