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 Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_CONTEXT_ADMIN')) { declare(strict_types=1);
return;
}
if (!dcCore::app()->auth->isSuperAdmin()) { namespace Dotclear\Plugin\translater;
return null;
}
dcCore::app()->addBehaviors([ use dcAdmin;
'adminModulesListGetActions' => ['translaterAdminBehaviors', 'adminModulesGetActions'], use dcCore;
'adminModulesListDoActions' => ['translaterAdminBehaviors', 'adminModulesDoActions'], use dcFavorites;
'adminDashboardFavoritesV2' => ['translaterAdminBehaviors', 'adminDashboardFavoritesV2'], use dcNsProcess;
]); use dcPage;
dcCore::app()->menu[dcAdmin::MENU_PLUGINS]->addItem( class Backend extends dcNsProcess
__('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
{ {
/** @var dcTranslater dcTranslater instance */ public static function init(): bool
private static $translater = null;
/**
* Create instance of dcTranslater once
*
* @return dcTranslater dcTranslater instance
*/
private static function translater(): dcTranslater
{ {
if (!is_a(self::$translater, 'dcTranslater')) { if (defined('DC_CONTEXT_ADMIN')) {
self::$translater = new dcTranslater(false); self::$init = dcCore::app()->auth->isSuperAdmin();
} }
return self::$translater; return self::$init;
} }
/** public static function process(): bool
* 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' if (!self::$init) {
|| !self::translater()->{$prop['type'] . '_menu'} return false;
|| !dcCore::app()->auth->isSuperAdmin()
) {
return null;
}
if (self::translater()->hide_default
&& in_array($id, dcTranslater::$default_distrib_modules[$prop['type']])
) {
return null;
} }
return dcCore::app()->addBehaviors([
' <input type="submit" name="translater[' . 'adminModulesListGetActions' => [BackendBehaviors::class, 'adminModulesGetActions'],
html::escapeHTML($id) . 'adminModulesListDoActions' => [BackendBehaviors::class, 'adminModulesDoActions'],
']" value="' . __('Translate') . '" /> '; 'adminDashboardFavoritesV2' => function (dcFavorites $favs): void {
} $favs->register(My::id(), [
'title' => My::name(),
/** 'url' => dcCore::app()->adminurl->get(My::id()),
* Redirect to module translation 'small-icon' => urldecode(dcPage::getPF(My::id() . '/icon.svg')),
* 'large-icon' => urldecode(dcPage::getPF(My::id() . '/icon.svg')),
* @param adminModulesList $list adminModulesList instance //'permissions' => null,
* @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()->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;
} }
} }

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 Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_CONTEXT_MODULE')) { declare(strict_types=1);
return null;
}
$translater = new dcTranslater(); namespace Dotclear\Plugin\translater;
if (!empty($_POST['save'])) { use dcCore;
try { use dcNsProcess;
foreach ($translater->getDefaultSettings() as $key => $value) { use dcPage;
$translater->$key = $_POST[$key] ?? '';
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( // nothing to process
__('Configuration successfully updated.') if (empty($_POST['save'])) {
); return true;
dcCore::app()->adminurl->redirect( }
'admin.plugins',
['module' => basename(__DIR__), 'conf' => 1, 'redir' => dcCore::app()->admin->__get('list')->getRedir()] $translater = new Translater();
);
} catch (Exception $e) { try {
dcCore::app()->error->add($e->getMessage()); 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 '
<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(
__('Following informations can be used: %s'),
implode(', ', $translater::$allowed_user_informations)
) . '
</p>
</div>
<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>';
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,25 +10,75 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_CONTEXT_ADMIN')) { declare(strict_types=1);
return null;
}
try { namespace Dotclear\Plugin\translater;
if (!dcCore::app()->newVersion(
basename(__DIR__), use dcCore;
dcCore::app()->plugins->moduleInfo(basename(__DIR__), 'version') use dcNamespace;
)) { use dcNsProcess;
return null;
} class Install extends dcNsProcess
$translater = new dcTranslater(false); {
if (!$translater->growUp()) { public static function init(): bool
$translater->writeSettings(false); {
self::$init = defined('DC_CONTEXT_ADMIN') && dcCore::app()->newVersion(My::id(), dcCore::app()->plugins->moduleInfo(My::id(), 'version'));
return self::$init;
} }
return true; public static function process(): bool
} catch (Exception $e) { {
dcCore::app()->error->add($e->getMessage()); 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;
}
}

File diff suppressed because it is too large Load Diff

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 Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_RC_PATH')) { declare(strict_types=1);
return;
}
Clearbricks::lib()->autoload([ namespace Dotclear\Plugin\translater;
'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',
]);
if (isset(dcCore::app()->adminurl)) { use dcCore;
dcCore::app()->adminurl->register(basename(__DIR__), 'plugin.php', ['p' => basename(__DIR__)]); 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;
}
} }

View File

@ -10,9 +10,13 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_CONTEXT_ADMIN')) { declare(strict_types=1);
return;
} namespace Dotclear\Plugin\translater;
use dcCore;
use form;
use netHttp;
/** /**
* Google proposal tool. * Google proposal tool.
@ -22,12 +26,12 @@ if (!defined('DC_CONTEXT_ADMIN')) {
class googleProposalTool extends translaterProposalTool class googleProposalTool extends translaterProposalTool
{ {
private $api = 'https://www.googleapis.com/language/translate/v2'; 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 private $key = null; //ex: AsSDqsGsfdSDSQFQsfedj9bnzY390aIg-1d
protected function setup() 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->setName(__('Google'));
$this->setDesc(__('Google Translation Tool API')); $this->setDesc(__('Google Translation Tool API'));
@ -53,7 +57,7 @@ class googleProposalTool extends translaterProposalTool
$key = empty($_POST['translater_google_proposal_key']) ? $key = empty($_POST['translater_google_proposal_key']) ?
'' : $_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) public function translate($str, $from, $to)

View File

@ -10,9 +10,12 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_CONTEXT_ADMIN')) { declare(strict_types=1);
return;
} namespace Dotclear\Plugin\translater;
use dcCore;
use form;
/** /**
* Microsoft proposal tool. * Microsoft proposal tool.
@ -27,8 +30,8 @@ class microsoftProposalTool extends translaterProposalTool
protected function setup() protected function setup()
{ {
$this->setActive(false); $this->setActive(false);
$this->client = dcCore::app()->blog->settings->get(basename(dirname(__DIR__)))->get('microsoft_proposal_client'); $this->client = dcCore::app()->blog->settings->get(My::id())->get('microsoft_proposal_client');
$this->secret = dcCore::app()->blog->settings->get(basename(dirname(__DIR__)))->get('microsoft_proposal_secret'); $this->secret = dcCore::app()->blog->settings->get(My::id())->get('microsoft_proposal_secret');
$this->setName(__('Bing')); $this->setName(__('Bing'));
$this->setDesc(__('Microsoft Bing translation tool')); $this->setDesc(__('Microsoft Bing translation tool'));
@ -61,8 +64,8 @@ class microsoftProposalTool extends translaterProposalTool
$secret = empty($_POST['translater_microsoft_proposal_secret']) ? $secret = empty($_POST['translater_microsoft_proposal_secret']) ?
'' : $_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(My::id())->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_secret', $secret, 'string', '', true, true);
} }
public function translate($str, $from, $to) public function translate($str, $from, $to)
@ -82,6 +85,7 @@ class microsoftProposalTool extends translaterProposalTool
private function doYourFuckingJob($client, $secret, $str, $from, $to) private function doYourFuckingJob($client, $secret, $str, $from, $to)
{ {
try { try {
$translatedStr = '';
//Client ID of the application. //Client ID of the application.
$clientID = $client; $clientID = $client;
//Client Secret key of the application. //Client Secret key of the application.

View File

@ -10,6 +10,10 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
declare(strict_types=1);
namespace Dotclear\Plugin\translater;
/** /**
* Translater proposal tool. * Translater proposal tool.
* *

View File

@ -10,9 +10,14 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_CONTEXT_ADMIN')) { declare(strict_types=1);
return;
} namespace Dotclear\Plugin\translater;
use dcCore;
use html;
use text;
use xmlTag;
/** /**
* Translater REST service. * Translater REST service.
@ -20,7 +25,7 @@ if (!defined('DC_CONTEXT_ADMIN')) {
* Admin service de retrieve translation of a string * Admin service de retrieve translation of a string
* Queries come from translater jquery tools * Queries come from translater jquery tools
*/ */
class translaterRest class Rest
{ {
public static function getProposal($get) public static function getProposal($get)
{ {
@ -40,7 +45,7 @@ class translaterRest
throw new Exception(__('Missing params')); throw new Exception(__('Missing params'));
} }
$translater = new dcTranslater(); $translater = new Translater();
if (!empty($str_in)) { if (!empty($str_in)) {
if (!$translater->proposal->hasTool($tool)) { if (!$translater->proposal->hasTool($tool)) {

View File

@ -10,79 +10,24 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_CONTEXT_ADMIN')) { declare(strict_types=1);
return;
}
class dcTranslaterDefaultSettings namespace Dotclear\Plugin\translater;
{
/** @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';
/** use dcCore;
* get default settings use dcThemes;
* use files;
* @return array Settings key/value pair use l10n;
*/ use path;
public static function getDefaultSettings() use text;
{
return get_class_vars('dcTranslaterDefaultSettings');
}
}
/** /**
* Translater tools. * Translater tools.
*/ */
class dcTranslater extends dcTranslaterDefaultSettings class Translater
{ {
/** @var array $allowed_backup_folders List of allowed backup folder */ /** @var array $settings Translater settings */
public static $allowed_backup_folders = []; private $settings = [];
/** @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 $modules List of modules we could work on */ /** @var array $modules List of modules we could work on */
private $modules = []; private $modules = [];
@ -98,18 +43,6 @@ class dcTranslater extends dcTranslaterDefaultSettings
if ($full) { if ($full) {
$this->loadModules(); $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 /// @name settings methods
@ -119,13 +52,9 @@ class dcTranslater extends dcTranslaterDefaultSettings
*/ */
public function loadSettings(): void public function loadSettings(): void
{ {
foreach ($this->getDefaultSettings() as $key => $value) { foreach (My::defaultSettings() as $key => $value) {
$this->$key = dcCore::app()->blog->settings->get(basename(dirname(__DIR__)))->get($key); $this->settings[$key] = $value;
$this->set($key, dcCore::app()->blog->settings->get(My::id())->get($key));
try {
settype($this->$key, gettype($value));
} catch (Exception $e) {
}
} }
} }
@ -136,43 +65,39 @@ class dcTranslater extends dcTranslaterDefaultSettings
*/ */
public function writeSettings($overwrite = true): void public function writeSettings($overwrite = true): void
{ {
foreach ($this->getDefaultSettings() as $key => $value) { foreach (My::defaultSettings() as $key => $value) {
dcCore::app()->blog->settings->get(basename(dirname(__DIR__)))->drop($key); dcCore::app()->blog->settings->get(My::id())->drop($key);
dcCore::app()->blog->settings->get(basename(dirname(__DIR__)))->put($key, $this->$key, gettype($value), '', true, true); 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', '<')) { * Write (temporary) a setting
$record = dcCore::app()->con->select( *
'SELECT * FROM ' . dcCore::app()->prefix . dcNamespace::NS_TABLE_NAME . ' ' . * @param string $key The setting id
"WHERE setting_ns = 'translater' " * @param mixed $value The setting value
); */
while ($record->fetch()) { public function set(string $key, mixed $value): void
if (preg_match('/^translater_(.*?)$/', $record->setting_id, $match)) { {
$cur = dcCore::app()->con->openCursor(dcCore::app()->prefix . dcNamespace::NS_TABLE_NAME); if (isset($this->settings[$key])) {
$cur->setting_id = $this->{$match[1]} = $match[1]; try {
$cur->setting_ns = basename(dirname(__DIR__)); settype($value, gettype($this->settings[$key]));
$cur->update( $this->settings[$key] = $value;
"WHERE setting_id = '" . $record->setting_id . "' and setting_ns = 'translater' " . } catch (Exception $e) {
'AND blog_id ' . (null === $record->blog_id ? 'IS NULL ' : ("= '" . dcCore::app()->con->escape($record->blog_id) . "' "))
);
}
} }
return true;
} }
return false;
} }
//@} //@}
@ -185,11 +110,13 @@ class dcTranslater extends dcTranslaterDefaultSettings
{ {
$this->modules['theme'] = $this->modules['plugin'] = []; $this->modules['theme'] = $this->modules['plugin'] = [];
$themes = new dcThemes(); if (!(dcCore::app()->themes instanceof dcThemes)) {
$themes->loadModules(dcCore::app()->blog->themes_path, null); dcCore::app()->themes = new dcThemes();
dcCore::app()->themes->loadModules(dcCore::app()->blog->themes_path, null);
}
$list = [ $list = [
'theme' => $themes->getModules(), 'theme' => dcCore::app()->themes->getModules(),
'plugin' => dcCore::app()->plugins->getModules(), 'plugin' => dcCore::app()->plugins->getModules(),
]; ];
foreach ($list as $type => $modules) { foreach ($list as $type => $modules) {
@ -199,7 +126,7 @@ class dcTranslater extends dcTranslaterDefaultSettings
} }
$info['id'] = $id; $info['id'] = $id;
$info['type'] = $type; $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 $type The module type
* @param string $id The module id * @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])) { if (!isset($this->modules[$type][$id])) {
throw new Exception( throw new Exception(
@ -240,12 +167,12 @@ class dcTranslater extends dcTranslaterDefaultSettings
/** /**
* Return module class of a particular module for a given type of module * 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 * @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)) { if (!l10n::isCode($lang)) {
throw new Exception( 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 Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @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; public $translater = null;
/** @var dcTranslaterModule dcTranslaterModule instance */ /** @var TranslaterModule TranslaterModule instance */
public $module = null; public $module = null;
/** @var array Lang properies */ /** @var array Lang properies */
private $prop = []; private $prop = [];
public function __construct(dcTranslaterModule $module, string $lang) public function __construct(TranslaterModule $module, string $lang)
{ {
$this->translater = $module->translater; $this->translater = $module->translater;
$this->module = $module; $this->module = $module;
@ -61,12 +69,12 @@ class dcTranslaterLang
$m_msgstrs = $this->getMsgStrs(); $m_msgstrs = $this->getMsgStrs();
foreach ($this->translater->getModules() as $module) { foreach ($this->translater->getModules() as $module) {
if ($module->id != $this->module->id) { if ($module->id != $this->module->get('id')) {
$m_o_msgstrs[$module->id] = $this->translater->getlang($module, $this->code)->getMsgStrs(); $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_module = new TranslaterModule($this->translater, ['id' => 'dotclear', 'root' => DC_ROOT]);
$dc_lang = new dcTranslaterLang($dc_module, $this->code); $dc_lang = new TranslaterLang($dc_module, $this->get('code'));
$m_o_msgstrs['dotclear'] = $dc_lang->getMsgStrs(); $m_o_msgstrs['dotclear'] = $dc_lang->getMsgStrs();
# From id list # From id list
@ -122,30 +130,30 @@ class dcTranslaterLang
{ {
$res = []; $res = [];
$scan_ext = ['php']; $scan_ext = ['php'];
if ($this->translater->scan_tpl) { if ($this->translater->get('scan_tpl')) {
$scan_ext[] = 'html'; $scan_ext[] = 'html';
} }
$files = dcTranslater::scandir($this->module->root); $files = Translater::scandir($this->module->get('root'));
foreach ($files as $file) { foreach ($files as $file) {
$extension = files::getExtension($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; continue;
} }
$contents = file_get_contents($this->module->root . '/' . $file); $contents = file_get_contents($this->module->get('root') . '/' . $file);
$msgs = []; $msgs = [];
# php files # php files
if ($extension == 'php') { if ($extension == 'php') {
$msgs = dcTranslater::extractPhpMsgs($contents); $msgs = Translater::extractPhpMsgs($contents);
# tpl files # tpl files
} elseif ($extension == 'html') { } elseif ($extension == 'html') {
$msgs = dcTranslater::extractTplMsgs($contents); $msgs = Translater::extractTplMsgs($contents);
} }
foreach ($msgs as $msg) { foreach ($msgs as $msg) {
$res[] = [ $res[] = [
'msgid' => dcTranslater::encodeMsg($msg[0][0]), 'msgid' => Translater::encodeMsg($msg[0][0]),
'msgid_plural' => empty($msg[0][1]) ? '' : dcTranslater::encodeMsg($msg[0][1]), 'msgid_plural' => empty($msg[0][1]) ? '' : Translater::encodeMsg($msg[0][1]),
'file' => $file, 'file' => $file,
'line' => $msg[1], 'line' => $msg[1],
]; ];
@ -167,18 +175,18 @@ class dcTranslaterLang
$res = $exists = $scanned = []; $res = $exists = $scanned = [];
$langs = $this->module->getLangs(true); $langs = $this->module->getLangs(true);
if (!isset($langs[$this->code])) { if (!isset($langs[$this->get('code')])) {
return $res; return $res;
} }
foreach ($langs[$this->code] as $file) { foreach ($langs[$this->get('code')] as $file) {
if (in_array($file, $scanned)) { if (in_array($file, $scanned)) {
continue; continue;
} }
$scanned[] = $file; $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); $po = l10n::parsePoFile($path);
if (!is_array($po)) { if (!is_array($po)) {
continue; continue;
@ -189,7 +197,7 @@ class dcTranslaterLang
'msgid' => $entry['msgid'], 'msgid' => $entry['msgid'],
'msgid_plural' => $entry['msgid_plural'] ?? '', 'msgid_plural' => $entry['msgid_plural'] ?? '',
'msgstr' => is_array($entry['msgstr']) ? $entry['msgstr'] : [$entry['msgstr']], 'msgstr' => is_array($entry['msgstr']) ? $entry['msgstr'] : [$entry['msgstr']],
'lang' => $this->code, 'lang' => $this->get('code'),
'type' => 'po', 'type' => 'po',
'path' => $path, 'path' => $path,
'file' => basename($file), 'file' => basename($file),

View File

@ -10,16 +10,25 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_CONTEXT_ADMIN')) { declare(strict_types=1);
return;
} namespace Dotclear\Plugin\translater;
use dcCore;
use dt;
use html;
use files;
use fileZip;
use fileUnzip;
use l10n;
use path;
/** /**
* Translater tools. * Translater tools.
*/ */
class dcTranslaterModule class TranslaterModule
{ {
/** @var dcTranslater dcTranslater instance */ /** @var Translater Translater instance */
public $translater = null; public $translater = null;
/** @var array Module properies */ /** @var array Module properies */
@ -28,10 +37,7 @@ class dcTranslaterModule
/** @var string Backup file regexp */ /** @var string Backup file regexp */
private $backup_file_regexp = '/^l10n-%s-(.*?)-[0-9]*?\.bck\.zip$/'; private $backup_file_regexp = '/^l10n-%s-(.*?)-[0-9]*?\.bck\.zip$/';
/** @var string Locales file regexp */ public function __construct(Translater $translater, array $module)
private $locales_file_regexp = '/^(.*?)\/locales\/(.*?)\/(.*?)(.po|.lang.php)$/';
public function __construct(dcTranslater $translater, array $module)
{ {
$this->translater = $translater; $this->translater = $translater;
$this->prop = $module; $this->prop = $module;
@ -72,7 +78,7 @@ class dcTranslaterModule
public function getBackupRoot(bool $throw = false) public function getBackupRoot(bool $throw = false)
{ {
$dir = false; $dir = false;
switch ($this->translater->backup_folder) { switch ($this->translater->get('backup_folder')) {
case 'module': case 'module':
if ($this->prop['root_writable']) { if ($this->prop['root_writable']) {
$dir = $this->prop['locales']; $dir = $this->prop['locales'];
@ -81,7 +87,8 @@ class dcTranslaterModule
break; break;
case 'plugin': 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)) { if ($tmp && is_writable($tmp)) {
$dir = $tmp; $dir = $tmp;
} }
@ -106,7 +113,7 @@ class dcTranslaterModule
break; break;
case 'translater': 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)) { if ($tmp && is_writable($tmp)) {
@mkDir($tmp . '/locales'); @mkDir($tmp . '/locales');
$dir = $tmp . '/locales'; $dir = $tmp . '/locales';
@ -138,7 +145,7 @@ class dcTranslaterModule
} }
$res = []; $res = [];
$files = dcTranslater::scandir($backup); $files = Translater::scandir($backup);
foreach ($files as $file) { foreach ($files as $file) {
$is_backup = preg_match(sprintf($this->backup_file_regexp, preg_quote($this->prop['id'])), $file, $m); $is_backup = preg_match(sprintf($this->backup_file_regexp, preg_quote($this->prop['id'])), $file, $m);
@ -182,17 +189,17 @@ class dcTranslaterModule
} }
$res = []; $res = [];
$files = dcTranslater::scandir($this->prop['locales'] . '/' . $lang); $files = Translater::scandir($this->prop['locales'] . '/' . $lang);
foreach ($files as $file) { foreach ($files as $file) {
if (!is_dir($this->prop['locales'] . '/' . $lang . '/' . $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; $res[$this->prop['locales'] . '/' . $lang . '/' . $file] = $this->prop['id'] . '/locales/' . $lang . '/' . $file;
} }
} }
if (!empty($res)) { 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); @set_time_limit(300);
$fp = fopen($backup . '/l10n-' . $this->prop['id'] . '-' . $lang . '-' . time() . '.bck.zip', 'wb'); $fp = fopen($backup . '/l10n-' . $this->prop['id'] . '-' . $lang . '-' . time() . '.bck.zip', 'wb');
@ -206,6 +213,8 @@ class dcTranslaterModule
return true; return true;
} }
return false;
} }
/** /**
@ -291,7 +300,7 @@ class dcTranslaterModule
foreach ($files as $file) { foreach ($files as $file) {
$f = $this->parseZipFilename($file, true); $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']) && file_exists($this->prop['locales'] . '/' . $f['lang'] . '/' . $f['group'] . $f['ext'])
) { ) {
$not_overwrited[] = implode('-', [$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 * @param array $langs Langs to export
*/ */
public function exportPack(array $langs) public function exportPack(array $langs): void
{ {
if (empty($langs)) { if (empty($langs)) {
throw new Exception( 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)) { if (empty($filename)) {
throw new Exception( throw new Exception(
__('Export mask is not set in plugin configuration') __('Export mask is not set in plugin configuration')
@ -358,11 +367,11 @@ class dcTranslaterModule
continue; continue;
} }
$files = dcTranslater::scandir($this->prop['locales'] . '/' . $lang); $files = Translater::scandir($this->prop['locales'] . '/' . $lang);
foreach ($files as $file) { foreach ($files as $file) {
if (is_dir($this->prop['locales'] . '/' . $lang . '/' . $file) if (is_dir($this->prop['locales'] . '/' . $lang . '/' . $file)
|| !dcTranslater::isLangphpFile($file) || !Translater::isLangphpFile($file)
&& !dcTranslater::isPoFile($file) && !Translater::isPoFile($file)
) { ) {
continue; continue;
} }
@ -387,7 +396,7 @@ class dcTranslaterModule
$filename = files::tidyFileName(dt::str(str_replace( $filename = files::tidyFileName(dt::str(str_replace(
['timestamp', 'module', 'type', 'version'], ['timestamp', 'module', 'type', 'version'],
[time(), $this->prop['id'], $this->prop['type'], $this->prop['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'); header('Content-Disposition: attachment;filename=' . $filename . '.zip');
@ -402,7 +411,7 @@ class dcTranslaterModule
* *
* @param string $file The zip filename * @param string $file The zip filename
* @param boolean $throw Silently failed * @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 public function parseZipFilename(string $file = '', bool $throw = false): array
{ {
@ -411,8 +420,8 @@ class dcTranslaterModule
if ($is_file) { if ($is_file) {
$module = $f[1] == $this->prop['id'] ? $f[1] : false; $module = $f[1] == $this->prop['id'] ? $f[1] : false;
$lang = l10n::isCode($f[2]) ? $f[2] : false; $lang = l10n::isCode($f[2]) ? $f[2] : false;
$group = in_array($f[3], dcTranslater::$allowed_l10n_groups) ? $f[3] : false; $group = in_array($f[3], My::l10nGroupsCombo()) ? $f[3] : false;
$ext = dcTranslater::isLangphpFile($f[4]) || dcTranslater::isPoFile($f[4]) ? $f[4] : false; $ext = Translater::isLangphpFile($f[4]) || Translater::isPoFile($f[4]) ? $f[4] : false;
} }
if (!$is_file || !$module || !$lang || !$group || !$ext) { if (!$is_file || !$module || !$lang || !$group || !$ext) {
@ -449,7 +458,7 @@ class dcTranslaterModule
$prefix = preg_match('/(locales(.*))$/', $this->prop['locales']) ? 'locales' : ''; $prefix = preg_match('/(locales(.*))$/', $this->prop['locales']) ? 'locales' : '';
$files = dcTranslater::scandir($this->prop['locales']); $files = Translater::scandir($this->prop['locales']);
foreach ($files as $file) { foreach ($files as $file) {
if (!preg_match('/.*?locales\/([^\/]*?)\/([^\/]*?)(.lang.php|.po)$/', $prefix . $file, $m)) { if (!preg_match('/.*?locales\/([^\/]*?)\/([^\/]*?)(.lang.php|.po)$/', $prefix . $file, $m)) {
continue; continue;
@ -474,7 +483,7 @@ class dcTranslaterModule
* *
* @return array The list of iso names and codes * @return array The list of iso names and codes
*/ */
public function getUsedLangs() public function getUsedLangs(): array
{ {
return array_flip($this->getLangs()); return array_flip($this->getLangs());
} }
@ -484,7 +493,7 @@ class dcTranslaterModule
* *
* @return array The list of iso names and codes * @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()); return array_diff(l10n::getISOcodes(true, false), $this->getUsedLangs());
} }
@ -496,7 +505,7 @@ class dcTranslaterModule
* @param string $from_lang The lang to copy from * @param string $from_lang The lang to copy from
* @return boolean True on success * @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)) { if (!l10n::isCode($lang)) {
throw new Exception(sprintf( throw new Exception(sprintf(
@ -523,11 +532,11 @@ class dcTranslaterModule
} }
if (!empty($from_lang) && isset($langs[$from_lang])) { 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) { foreach ($files as $file) {
if (is_dir($this->prop['locales'] . '/' . $from_lang . '/' . $file) if (is_dir($this->prop['locales'] . '/' . $from_lang . '/' . $file)
|| !dcTranslater::isLangphpFile($file) || !Translater::isLangphpFile($file)
&& !dcTranslater::isPoFile($file) && !Translater::isPoFile($file)
) { ) {
continue; continue;
} }
@ -541,6 +550,8 @@ class dcTranslaterModule
$this->setPoContent($lang, 'main', []); $this->setPoContent($lang, 'main', []);
$this->setLangphpContent($lang, 'main', []); $this->setLangphpContent($lang, 'main', []);
} }
return true;
} }
/** /**
@ -549,7 +560,7 @@ class dcTranslaterModule
* @param string $lang The lang * @param string $lang The lang
* @param array $msgs The messages * @param array $msgs The messages
*/ */
public function updLang(string $lang, array $msgs) public function updLang(string $lang, array $msgs): void
{ {
if (!l10n::isCode($lang)) { if (!l10n::isCode($lang)) {
throw new Exception(sprintf( throw new Exception(sprintf(
@ -566,7 +577,7 @@ class dcTranslaterModule
)); ));
} }
if ($this->translater->backup_auto) { if ($this->translater->get('backup_auto')) {
$this->createBackup($lang); $this->createBackup($lang);
} }
@ -578,7 +589,7 @@ class dcTranslaterModule
$rs[$msg['group']][] = $msg; $rs[$msg['group']][] = $msg;
} }
foreach (dcTranslater::$allowed_l10n_groups as $group) { foreach (My::l10nGroupsCombo() as $group) {
if (isset($rs[$group])) { if (isset($rs[$group])) {
continue; continue;
} }
@ -636,12 +647,12 @@ class dcTranslaterModule
unlink($this->prop['locales'] . '/' . $file); unlink($this->prop['locales'] . '/' . $file);
} }
$dir = dcTranslater::scandir($this->prop['locales'] . '/' . $lang); $dir = Translater::scandir($this->prop['locales'] . '/' . $lang);
if (empty($dir)) { if (empty($dir)) {
rmdir($this->prop['locales'] . '/' . $lang); rmdir($this->prop['locales'] . '/' . $lang);
} }
$loc = dcTranslater::scandir($this->prop['locales']); $loc = Translater::scandir($this->prop['locales']);
if (empty($loc)) { if (empty($loc)) {
rmdir($this->prop['locales']); rmdir($this->prop['locales']);
} }
@ -656,32 +667,33 @@ class dcTranslaterModule
* @param string $group The lang group * @param string $group The lang group
* @param array $msgs The strings * @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 = ''; $content = '';
if ($this->translater->parse_comment) { if ($this->translater->get('parse_comment')) {
$content .= '# Language: ' . $lang->name . "\n" . $content .= '# Language: ' . $lang->get('name') . "\n" .
'# Module: ' . $this->id . ' - ' . $this->version . "\n" . '# Module: ' . $this->get('id') . ' - ' . $this->get('version') . "\n" .
'# Date: ' . dt::str('%Y-%m-%d %H:%M:%S') . "\n"; '# Date: ' . dt::str('%Y-%m-%d %H:%M:%S') . "\n";
if ($this->translater->parse_user && $this->translater->parse_userinfo != '') { if ($this->translater->get('parse_user') && $this->translater->get('parse_userinfo') != '') {
$search = dcTranslater::$allowed_user_informations; $search = My::defaultUserInformations();
$replace = [];
foreach ($search as $n) { foreach ($search as $n) {
$replace[] = dcCore::app()->auth->getInfo('user_' . $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)) { if (!empty($info)) {
$content .= '# Author: ' . html::escapeHTML($info) . "\n"; $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" . $content .= "msgid \"\"\n" .
"msgstr \"\"\n" . "msgstr \"\"\n" .
'"Content-Type: text/plain; charset=UTF-8\n"' . "\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" . '"POT-Creation-Date: \n"' . "\n" .
'"PO-Revision-Date: ' . date('c') . '\n"' . "\n" . '"PO-Revision-Date: ' . date('c') . '\n"' . "\n" .
'"Last-Translator: ' . dcCore::app()->auth->getInfo('user_cn') . '\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"; '"Plural-Forms: nplurals=2; plural=(n > 1);\n"' . "\n\n";
$comments = []; $comments = [];
if ($this->translater->parse_comment) { if ($this->translater->get('parse_comment')) {
$msgids = $lang->getMsgids(); $msgids = $lang->getMsgids();
foreach ($msgids as $msg) { foreach ($msgids as $msg) {
$comments[$msg['msgid']] = ($comments[$msg['msgid']] ?? '') . $comments[$msg['msgid']] = ($comments[$msg['msgid']] ?? '') .
@ -703,22 +715,22 @@ class dcTranslaterModule
if (empty($msg['msgstr'][0])) { if (empty($msg['msgstr'][0])) {
continue; 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 .= $comments[$msg['msgid']];
} }
$content .= 'msgid "' . dcTranslater::poString($msg['msgid'], true) . '"' . "\n"; $content .= 'msgid "' . Translater::poString($msg['msgid'], true) . '"' . "\n";
if (empty($msg['msgid_plural'])) { if (empty($msg['msgid_plural'])) {
$content .= 'msgstr "' . dcTranslater::poString($msg['msgstr'][0], true) . '"' . "\n"; $content .= 'msgstr "' . Translater::poString($msg['msgstr'][0], true) . '"' . "\n";
} else { } 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) { 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"; $content .= "\n";
} }
$file = $this->locales . '/' . $lang->code . '/' . $group . '.po'; $file = $this->get('locales') . '/' . $lang->get('code') . '/' . $group . '.po';
$path = path::info($file); $path = path::info($file);
if (is_dir($path['dirname']) && !is_writable($path['dirname']) if (is_dir($path['dirname']) && !is_writable($path['dirname'])
|| file_exists($file) && !is_writable($file)) { || file_exists($file) && !is_writable($file)) {
@ -743,34 +755,35 @@ class dcTranslaterModule
* @param string $group The lang group * @param string $group The lang group
* @param array $msgs The strings * @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) { if (!$this->translater->get('write_langphp')) {
return null; return;
} }
$lang = new dcTranslaterLang($this, $lang); $lang = new TranslaterLang($this, $lang);
$content = ''; $content = '';
if ($this->translater->parse_comment) { if ($this->translater->get('parse_comment')) {
$content .= '// Language: ' . $lang->name . "\n" . $content .= '// Language: ' . $lang->get('name') . "\n" .
'// Module: ' . $this->id . ' - ' . $this->verison . "\n" . '// Module: ' . $this->get('id') . ' - ' . $this->get('verison') . "\n" .
'// Date: ' . dt::str('%Y-%m-%d %H:%M:%S') . "\n"; '// Date: ' . dt::str('%Y-%m-%d %H:%M:%S') . "\n";
if ($this->translater->parse_user && !empty($this->translater->parse_userinfo)) { if ($this->translater->get('parse_user') && !empty($this->translater->get('parse_userinfo'))) {
$search = dcTranslater::$allowed_user_informations; $search = My::defaultUserInformations();
$replace = [];
foreach ($search as $n) { foreach ($search as $n) {
$replace[] = dcCore::app()->auth->getInfo('user_' . $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)) { if (!empty($info)) {
$content .= '// Author: ' . html::escapeHTML($info) . "\n"; $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 Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @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. * Translater proposal tools container.
*/ */

View File

@ -10,72 +10,93 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_CONTEXT_ADMIN')) { declare(strict_types=1);
return;
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__))
);