Compare commits

...

3 Commits

Author SHA1 Message Date
fe476152d2
code review 2023-11-04 22:03:58 +01:00
d63eaeb95a
maybe better permissions check 2023-10-21 22:45:58 +02:00
12481455ca
upgrade to dotclear 2.28 2023-10-21 11:45:02 +02:00
19 changed files with 785 additions and 580 deletions

View File

@ -1,3 +1,16 @@
translater 2023.11.04
===========================================================
* Require Dotclear 2.28
* Require PHP 8.1
* Cosmetic code review
translater 2023.10.21
===========================================================
* Require Dotclear 2.28
* Require PHP 8.1
* Upgrade to Dotclear 2.28
* Code review (phpstan)
translater 2023.08.15
===========================================================
* Require Dotclear 2.27

View File

@ -1,25 +1,22 @@
# README
[![Release](https://img.shields.io/badge/release-2023.08.15-a2cbe9.svg)](https://git.dotclear.watch/JcDenis/translater/releases)
[![Date](https://img.shields.io/badge/date-2023.08.15-c44d58.svg)](https://git.dotclear.watch/JcDenis/translater/releases)
[![Dotclear](https://img.shields.io/badge/dotclear-v2.27-137bbb.svg)](https://fr.dotclear.org/download)
[![Release](https://img.shields.io/badge/release-2023.11.04-a2cbe9.svg)](https://git.dotclear.watch/JcDenis/translater/releases)
![Date](https://img.shields.io/badge/date-2023.11.04-c44d58.svg)
[![Dotclear](https://img.shields.io/badge/dotclear-v2.28-137bbb.svg)](https://fr.dotclear.org/download)
[![Dotaddict](https://img.shields.io/badge/dotaddict-official-9ac123.svg)](https://plugins.dotaddict.org/dc2/details/translater)
[![License](https://img.shields.io/github/license/JcDenis/translater)](https://git.dotclear.watch/JcDenis/translater/blob/master/LICENSE)
[![License](https://img.shields.io/badge/license-GPL--2.0-ececec.svg)](https://git.dotclear.watch/JcDenis/translater/src/branch/master/LICENSE)
## WHAT IS TRANSLATER ?
## ABOUT
_translater_ is a plugins for the open-source
web publishing software called Dotclear.
_translater_ is a plugin for the open-source web publishing software called [Dotclear](https://www.dotclear.org).
It helps dev to translate plugin and theme.
> Help dev to translate plugin and theme.
## REQUIREMENTS
_translater_ requires:
* super admin permissions
* Dotclear 2.27
* Dotclear 2.28
* PHP 8.1+
* Dotclear super admin permissions
## USAGE
@ -35,10 +32,11 @@ or direct from plugins / themes list with a ''Translate'' button.
## LINKS
* License : [GNU GPL v2](https://www.gnu.org/licenses/old-licenses/lgpl-2.0.html)
* Source & contribution : [Gitea Page](https://git.dotclear.watch/JcDenis/translater) or [GitHub Page](https://github.com/JcDenis/translater)
* Packages & details: [Gitea Page](https://git.dotclear.watch/JcDenis/translater/releases) or [Dotaddict Page](https://plugins.dotaddict.org/dc2/details/translater)
* Discussion & Help: [Dotclear Forum](https://forum.dotclear.org/viewtopic.php?id=39220)
* [License](https://git.dotclear.watch/JcDenis/translater/src/branch/master/LICENSE)
* [Packages & details](https://git.dotclear.watch/JcDenis/translater/releases) (or on [Dotaddict](https://plugins.dotaddict.org/dc2/details/translater))
* [Sources & contributions](https://git.dotclear.watch/JcDenis/translater) (or on [GitHub](https://github.com/JcDenis/translater))
* [Issues & security](https://git.dotclear.watch/JcDenis/translater/issues) (or on [GitHub](https://github.com/JcDenis/translater/issues))
* [Discussion & Help](https://forum.dotclear.org/viewtopic.php?id=39220)
## CONTRIBUTORS

View File

@ -1,30 +1,26 @@
<?php
/**
* @brief translater, a plugin for Dotclear 2
* @file
* @brief The plugin translater definition
* @ingroup translater
*
* @package Dotclear
* @subpackage Plugin
* @defgroup translater Plugin translater.
*
* @author Jean-Christian Denis & contributors
* Translate your Dotclear plugins and themes.
*
* @copyright Jean-Christian Denis
* @author 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);
$this->registerModule(
'Translater',
'Translate your Dotclear plugins and themes',
'Jean-Christian Denis & contributors',
'2023.08.15',
'2023.11.04',
[
'requires' => [
['php', '8.1'],
['core', '2.27'],
],
'permissions' => null,
'requires' => [['core', '2.28']],
'permissions' => 'My',
'type' => 'plugin',
'support' => 'https://git.dotclear.watch/JcDenis/' . basename(__DIR__) . '/issues',
'details' => 'https://git.dotclear.watch/JcDenis/' . basename(__DIR__) . '/src/branch/master/README.md',

View File

@ -2,11 +2,11 @@
<modules xmlns:da="http://dotaddict.org/da/">
<module id="translater">
<name>Translater</name>
<version>2023.08.15</version>
<version>2023.11.04</version>
<author>Jean-Christian Denis &amp; contributors</author>
<desc>Translate your Dotclear plugins and themes</desc>
<file>https://git.dotclear.watch/JcDenis/translater/releases/download/v2023.08.15/plugin-translater.zip</file>
<da:dcmin>2.27</da:dcmin>
<file>https://git.dotclear.watch/JcDenis/translater/releases/download/v2023.11.04/plugin-translater.zip</file>
<da:dcmin>2.28</da:dcmin>
<da:details>https://git.dotclear.watch/JcDenis/translater/src/branch/master/README.md</da:details>
<da:support>https://git.dotclear.watch/JcDenis/translater/issues</da:support>
</module>

View File

@ -1,10 +1,11 @@
<?php
/**
* @package Dotclear
*
* @copyright Olivier Meunier & Association Dotclear
* @copyright GPL-2.0-only
*/
// Language: Français
// Module: translater - 2023.10.21
// Date: 2023-10-21 09:42:21
// Author: , contact@jcdenis.fr
// Translated with Translater - 2023.10.21
#
# DOT NOT MODIFY THIS FILE !
#
@ -46,7 +47,6 @@ L10n::$locales['Language successfully added'] = 'Langue cr
L10n::$locales['Language successfully deleted'] = 'Langue effacée avec succès';
L10n::$locales['Nothing to update'] = 'Rien à mettre à jour';
L10n::$locales['Language successfully updated'] = 'Langue mise à jour avec succès';
L10n::$locales['Themes'] = 'Thèmes';
L10n::$locales['%s language edition'] = 'Edition de la langue %s';
L10n::$locales['Use this text'] = 'Utiliser ce texte';
L10n::$locales['Translate module %s'] = 'Traduire le module %s';

View File

@ -1,394 +1,389 @@
# Language: Français
# Module: translater - 2023.03.17
# Date: 2023-03-17 23:23:46
# Module: translater - 2023.10.21
# Date: 2023-10-21 09:42:21
# Author: , contact@jcdenis.fr
# Translated with translater 2023.03.17
# Translated with translater 2023.10.21
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Project-Id-Version: translater 2023.03.17\n"
"Project-Id-Version: translater 2023.10.21\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: 2023-03-17T23:23:46+00:00\n"
"PO-Revision-Date: 2023-10-21T09:42:21+00:00\n"
"Last-Translator: Jean-Christian Denis\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: src/BackendBehaviors.php:64
#: src/BackendBehaviors.php:68
msgid "Translate"
msgstr "Traduire"
#: src/Config.php:90
#: src/Manage.php:446
#: src/Config.php:89
#: src/Manage.php:473
msgid "Translation"
msgstr "Traduction"
#: src/Config.php:94
#: src/Config.php:93
msgid "Write .lang.php files"
msgstr "Ecrire le fichier .lang.php"
#: src/Config.php:99
#: src/Config.php:98
msgid "Translate also strings of template files"
msgstr "Traduire également les chaines des fichiers de template"
#: src/Config.php:104
#: src/Config.php:103
msgid "Translate only unknow strings"
msgstr "Traduire uniquement les chaines inconnues"
#: src/Config.php:109
#: src/Config.php:108
msgid "Hide default modules of Dotclear"
msgstr "Cacher les modules de la distribution de Dotclear"
#: src/Config.php:114
#: src/Config.php:113
msgid "Write comments in files"
msgstr "Ecrire les commentaires dans les fichiers"
#: src/Config.php:119
#: src/Config.php:118
msgid "Write informations about author in files"
msgstr "Ecrire les informations à propos de l'auteur"
#: src/Config.php:123
#: src/Config.php:122
msgid "User info:"
msgstr "Information à propos de l'auteur :"
#: src/Config.php:127
#: src/Config.php:126
msgid "Following informations can be used: %s"
msgstr "Les informations suivantes peuvent être utilisées : %s"
#: src/Config.php:135
#: src/Config.php:134
msgid "Overwrite existing languages"
msgstr "Ecraser les langues existantes"
#: src/Config.php:139
#: src/Config.php:138
msgid "Name of exported package:"
msgstr "Nom du paquetage exporté :"
#: src/Config.php:143
#: src/Manage.php:262
#: src/Config.php:142
#: src/Manage.php:274
msgid "Backups"
msgstr "Sauvegardes"
#: src/Config.php:147
#: src/Config.php:146
msgid "Make backups when changes are made"
msgstr "Faire une sauvegarde quand des changements sont effectués"
#: src/Config.php:151
#: src/Config.php:150
msgid "Limit backups per module to:"
msgstr "Limiter les sauvegardes par module à :"
#: src/Config.php:154
#: src/Config.php:153
msgid "Set to 0 for no limit."
msgstr "Mettre à 0 pour aucune limite."
#: src/Config.php:157
#: src/Config.php:156
msgid "Store backups in:"
msgstr "Enregistrer les sauvegardes dans :"
#: src/Config.php:161
#: src/Config.php:160
msgid "Behaviors"
msgstr "Comportements"
#: src/Config.php:164
#: src/Config.php:163
msgid "Default start menu:"
msgstr "Menu de départ par défaut :"
#: src/Config.php:170
#: src/Config.php:169
msgid "Enable menu on plugins page"
msgstr "Activer le menu sur la page des plugins"
#: src/Config.php:175
#: src/Config.php:174
msgid "Enable menu on themes page"
msgstr "Activer le menu sur la page des thèmes"
#: src/Manage.php:48
#: src/Manage.php:57
msgid "Nothing to backup"
msgstr "Rien à sauvegarder"
#: src/Manage.php:56
#: src/Manage.php:65
msgid "Backup successfully created"
msgstr "Sauvegarde créée avec succès"
#: src/Manage.php:61
#: src/Manage.php:70
msgid "Nothing to restore"
msgstr "Rien à restaurer"
#: src/Manage.php:69
#: src/Manage.php:78
msgid "Backup successfully restored"
msgstr "Sauvegarde restaurée avec succès"
#: src/Manage.php:74
#: src/Manage.php:83
msgid "Nothing to delete"
msgstr "Rien à effacer"
#: src/Manage.php:82
#: src/Manage.php:91
msgid "Backup successfully deleted"
msgstr "Sauvegarde effacée avec succès"
#: src/Manage.php:87
#: src/TranslaterModule.php:359
#: src/Manage.php:96
#: src/TranslaterModule.php:435
msgid "Nothing to export"
msgstr "Rien à exporter"
#: src/Manage.php:91
#: src/Manage.php:100
msgid "Language successfully exported"
msgstr "Langue exportée avec succès"
#: src/Manage.php:100
#: src/Manage.php:109
msgid "Language successfully imported"
msgstr "Langue importée avec succès"
#: src/Manage.php:105
#: src/Manage.php:114
msgid "Nothing to create"
msgstr "Rien à créer"
#: src/Manage.php:109
#: src/Manage.php:118
msgid "Language successfully added"
msgstr "Langue créée avec succès"
#: src/Manage.php:122
#: src/Manage.php:131
msgid "Language successfully deleted"
msgstr "Langue effacée avec succès"
#: src/Manage.php:127
#: src/Manage.php:136
msgid "Nothing to update"
msgstr "Rien à mettre à jour"
#: src/Manage.php:138
#: src/Manage.php:147
msgid "Language successfully updated"
msgstr "Langue mise à jour avec succès"
#: src/Manage.php:159
#: src/My.php:64
msgid "Themes"
msgstr "Thèmes"
#: src/Manage.php:166
#: src/Manage.php:175
msgid "%s language edition"
msgstr "Edition de la langue %s"
#: src/Manage.php:174
#: src/Manage.php:183
msgid "Use this text"
msgstr "Utiliser ce texte"
#: src/Manage.php:203
#: src/Manage.php:212
msgid "Translate module %s"
msgstr "Traduire le module %s"
#: src/Manage.php:217
#: src/Manage.php:229
msgid "Edit language %s of module %s"
msgstr "Modifier la langue %s du module %s"
#: src/Manage.php:237
#: src/Manage.php:249
msgid "Modules list of type \"%s\""
msgstr "Listes de modules de type \"%s\""
#: src/Manage.php:247
#: src/Manage.php:259
msgid "There is no editable modules"
msgstr "Il n'y a pas de module modifiable"
#: src/Manage.php:258
#: src/Manage.php:270
msgid "Module %s %s by %s"
msgstr "Module %s %s par %s"
#: src/Manage.php:260
#: src/Manage.php:272
msgid "Root"
msgstr "Racine"
#: src/Manage.php:272
#: src/Manage.php:284
msgid "Existing languages translations"
msgstr "Traductions existantes"
#: src/Manage.php:277
#: src/Manage.php:289
msgid "Last backup"
msgstr "Dernière sauvegarde"
#: src/Manage.php:287
#: src/Manage.php:299
msgid "Edit %s language"
msgstr "Modifier la langue %s"
#: src/Manage.php:303
#: src/Manage.php:315
msgid "no backups"
msgstr "aucune sauvegarde"
#: src/Manage.php:311
#: src/Manage.php:324
msgid "Selected languages action:"
msgstr "Action sur les langues sélectionnées :"
#: src/Manage.php:313
#: src/Manage.php:326
msgid "Backup languages"
msgstr "Sauvegarder les langues"
#: src/Manage.php:314
#: src/Manage.php:327
msgid "Delete languages"
msgstr "Effacer les langues"
#: src/Manage.php:315
#: src/Manage.php:328
msgid "Export languages"
msgstr "Exporter les langues"
#: src/Manage.php:333
#: src/Manage.php:346
msgid "Existing languages backups"
msgstr "Sauvegardes existantes"
#: src/Manage.php:377
#: src/Manage.php:391
msgid "Selected backups action:"
msgstr "Action sur les sauvegardes sélectionnées :"
#: src/Manage.php:379
#: src/Manage.php:393
msgid "Restore backups"
msgstr "Restaurer des sauvegardes"
#: src/Manage.php:380
#: src/Manage.php:394
msgid "Delete backups"
msgstr "Effacer des sauvegardes"
#: src/Manage.php:396
#: src/Manage.php:410
msgid "Add language"
msgstr "Ajouter une langue"
#: src/Manage.php:404
#: src/Manage.php:422
msgid "Copy from language:"
msgstr "Copier depuis la langue :"
#: src/Manage.php:405
#: src/Manage.php:424
msgid "optionnal"
msgstr "optionnel"
#: src/Manage.php:420
#: src/Manage.php:443
msgid "Select languages package to import:"
msgstr "Sélectionner le paquetage de langues à importer :"
#: src/Manage.php:442
#: src/Manage.php:469
msgid "List of %s localized strings"
msgstr "Liste des %s chaines de traduction"
#: src/Manage.php:444
#: src/Manage.php:471
msgid "Group"
msgstr "Groupe"
#: src/Manage.php:445
#: src/Manage.php:472
msgid "String"
msgstr "Chaine"
#: src/Manage.php:447
#: src/Manage.php:474
msgid "Existing"
msgstr "Existant"
#: src/Manage.php:489
#: src/Manage.php:516
msgid "%s occurrences"
msgstr "%s occurences"
#: src/Manage.php:529
#: src/Manage.php:556
msgid "Plural \"%s\""
msgstr "Pluriel \"%s\""
#: src/Manage.php:530
#: src/Manage.php:557
msgid "Plural form of \"%s\""
msgstr "Forme plurielle de \"%s\""
#: src/Manage.php:558
#: src/Manage.php:586
msgid "Change the group of the selected translations to:"
msgstr "Changer le groupe des chaines sélectionnées vers :"
#: src/Manage.php:577
#: src/Manage.php:608
msgid "Translate your Dotclear plugins and themes"
msgstr "Traduire vos plugins et thèmes Dotclear"
#: src/Manage.php:584
#: src/Manage.php:615
msgid "Translate plugins"
msgstr "Traduire des plugins"
#: src/Manage.php:590
#: src/Manage.php:621
msgid "Translate themes"
msgstr "Traduire des thèmes"
#: src/My.php:49
#: src/My.php:39
msgid "locales folders of each module"
msgstr "le fichier locales de chaque module"
#: src/My.php:50
#: src/My.php:40
msgid "plugins folder root"
msgstr "la racine du dossier des plugins"
#: src/My.php:51
#: src/My.php:41
msgid "public folder root"
msgstr "la racine du dossier public"
#: src/My.php:52
#: src/My.php:42
msgid "cache folder of Dotclear"
msgstr "le dossier cache de Dotclear"
#: src/My.php:53
#: src/My.php:43
msgid "locales folder of translater"
msgstr "le dossier locales de Traducteur"
#: src/Translater.php:97
#: src/Translater.php:94
msgid "Failed to find module %s"
msgstr "Impossible de trouver le module %s"
#: src/Translater.php:116
#: src/Translater.php:113
msgid "Failed find language %s"
msgstr "Impossible de trouver la langue %s"
#: src/Translater.php:240
#: src/Translater.php:243
msgid "Limit of %s backups for module %s exceed"
msgstr "La limite de %s sauvegardes pour le module %s est atteinte"
#: src/TranslaterModule.php:131
#: src/TranslaterModule.php:177
msgid "Failed to find backups folder for module %s"
msgstr "Impossible de trouver le dossier de sauvegarde pour le module %s"
#: src/TranslaterModule.php:192
#: src/TranslaterModule.php:267
msgid "Failed to find language %s"
msgstr "Impossible de trouver la langue %s"
#: src/TranslaterModule.php:238
#: src/TranslaterModule.php:312
msgid "Failed to find file %s"
msgstr "Impossible de trouver le fichier %s"
#: src/TranslaterModule.php:278
#: src/TranslaterModule.php:353
msgid "Failed to delete file %s"
msgstr "Impossible d'effacer le fichier %s"
#: src/TranslaterModule.php:337
#: src/TranslaterModule.php:413
msgid "Some languages has not been overwrited %s"
msgstr "Des langues n'ont pas été écrasées : %s"
#: src/TranslaterModule.php:342
#: src/TranslaterModule.php:418
msgid "Nothing to import from %s"
msgstr "Rien à importer"
#: src/TranslaterModule.php:366
#: src/TranslaterModule.php:442
msgid "Export mask is not set in plugin configuration"
msgstr "Le masque d'export n'est pas renseigné dans la configuration du plugin"
#: src/TranslaterModule.php:436
#: src/TranslaterModule.php:512
msgid "Zip file %s is not in translater format"
msgstr "Le fichier zip n'est pas au format de traduction"
#: src/TranslaterModule.php:518
#: src/TranslaterModule.php:616
msgid "Unknow language %s"
msgstr "Langue %s inconnue"
#: src/TranslaterModule.php:526
#: src/TranslaterModule.php:624
msgid "Language %s already exists"
msgstr "La langue %s existe déjà"
#: src/TranslaterModule.php:535
#: src/TranslaterModule.php:633
msgid "Failed to copy file from language %s"
msgstr "Impossible de copier le fichier depuis la langue %s"
#: src/TranslaterModule.php:616
#: src/TranslaterModule.php:714
msgid "No string to write, language %s deleted"
msgstr "Rien à écrire, le fichiers de langue %s est effacé"
#: src/TranslaterModule.php:744
#: src/TranslaterModule.php:844
msgid "Failed to grant write acces on file %s"
msgstr "Impossible d'avoir les droits en écriture sur le fichier %s"
#: src/TranslaterModule.php:751
#: src/TranslaterModule.php:851
msgid "Failed to write file %s"
msgstr "Impossible d'écrire le fichier %s"

View File

@ -1,19 +1,12 @@
<?php
/**
* @brief translater, a plugin for Dotclear 2
* @file
* @brief The plugin translater locales resources
* @ingroup translater
*
* @package Dotclear
* @subpackage Plugin
*
* @author Jean-Christian Denis & contributors
*
* @copyright Jean-Christian Denis
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_RC_PATH')) {
return;
}
foreach (['index', 'type', 'module', 'lang', 'config'] as $v) {
dcCore::app()->resources['help']['translater.' . $v] = __DIR__ . '/help/translater.' . $v . '.html';
\Dotclear\App::backend()->resources()->set('help', 'translater.' . $v, __DIR__ . '/help/translater.' . $v . '.html');
}

View File

@ -1,23 +1,20 @@
<?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;
use Dotclear\App;
use Dotclear\Core\Process;
use Dotclear\Core\Backend\Favorites;
/**
* @brief translater backend class.
* @ingroup translater
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class Backend extends Process
{
public static function init(): bool
@ -33,16 +30,15 @@ class Backend extends Process
My::addBackendMenuItem();
dcCore::app()->addBehaviors([
'adminModulesListGetActions' => [BackendBehaviors::class, 'adminModulesGetActions'],
'adminModulesListDoActions' => [BackendBehaviors::class, 'adminModulesDoActions'],
App::behavior()->addBehaviors([
'adminModulesListGetActions' => BackendBehaviors::adminModulesGetActions(...),
'adminModulesListDoActions' => BackendBehaviors::adminModulesDoActions(...),
'adminDashboardFavoritesV2' => function (Favorites $favs): void {
$favs->register(My::id(), [
'title' => My::name(),
'url' => My::manageUrl(),
'small-icon' => My::icons(),
'large-icon' => My::icons(),
//'permissions' => null,
]);
},
]);

View File

@ -1,37 +1,38 @@
<?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;
use Dotclear\App;
use Dotclear\Core\Backend\ModulesList;
use Dotclear\Helper\Html\Form\Submit;
use Dotclear\Helper\Html\Html;
/**
* @brief translater backend behaviors class.
* @ingroup translater
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class BackendBehaviors
{
/** @var Translater Translater instance */
/**
* Translater instance.
*
* @var ?Translater $translater
*/
private static $translater = null;
/**
* Create instance of Translater once
* Create instance of Translater once.
*
* @return Translater Translater instance
*/
private static function translater(): Translater
{
if (!is_a(self::$translater, Translater::class)) {
if (is_null(self::$translater)) {
self::$translater = new Translater(false);
}
@ -39,19 +40,22 @@ class BackendBehaviors
}
/**
* Add button to go to module translation
* Add button to go to module translation.
*
* @param ModulesList $list ModulesList instance
* @param string $id Module id
* @param array $prop Module properties
* @param array<string, mixed> $prop Module properties
*
* @return string HTML submit button
* @return ?string HTML submit button
*/
public static function adminModulesGetActions(ModulesList $list, string $id, array $prop): ?string
{
if (!is_string($prop['type'])) {
return null;
}
if ($list->getList() != $prop['type'] . '-activate'
|| !self::translater()->getSetting($prop['type'] . '_menu')
|| !dcCore::app()->auth?->isSuperAdmin()
|| !App::auth()->isSuperAdmin()
) {
return null;
}
@ -61,14 +65,14 @@ class BackendBehaviors
return null;
}
return (new Submit(['translater[' . Html::escapeHTML($id) . ']', null]))->value(__('Translate'))->render();
return (new Submit(['translater[' . Html::escapeHTML($id) . ']']))->value(__('Translate'))->render();
}
/**
* Redirect to module translation
* Redirect to module translation.
*
* @param ModulesList $list ModulesList instance
* @param array $modules Selected modules ids
* @param array<int, string> $modules Selected modules ids
* @param string $type List type (plugin|theme)
*/
public static function adminModulesDoActions(ModulesList $list, array $modules, string $type): void

View File

@ -1,20 +1,10 @@
<?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;
use Dotclear\App;
use Dotclear\Core\Process;
use Dotclear\Core\Backend\{
Notices,
@ -34,6 +24,13 @@ use Dotclear\Helper\Html\Form\{
};
use Exception;
/**
* @brief translater backend config class.
* @ingroup translater
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class Config extends Process
{
public static function init(): bool
@ -56,6 +53,9 @@ class Config extends Process
try {
foreach ($s->listSettings() as $key => $value) {
if (!is_string($key)) {
continue;
}
if (is_bool($value)) {
$s->writeSetting($key, !empty($_POST[$key]));
} else {
@ -66,12 +66,12 @@ class Config extends Process
Notices::addSuccessNotice(
__('Configuration successfully updated.')
);
dcCore::app()->admin->url->redirect(
App::backend()->url()->redirect(
'admin.plugins',
['module' => My::id(), 'conf' => 1, 'redir' => dcCore::app()->admin->__get('list')->getRedir()]
['module' => My::id(), 'conf' => 1, 'redir' => App::backend()->__get('list')->getRedir()]
);
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
App::error()->add($e->getMessage());
}
return true;
@ -120,7 +120,7 @@ class Config extends Process
// parse_userinfo
(new Para())->items([
(new Label(__('User info:')))->for('parse_userinfo'),
(new Input('parse_userinfo'))->size(65)->maxlenght(255)->value($s->parse_userinfo),
(new Input('parse_userinfo'))->size(65)->maxlength(255)->value($s->parse_userinfo),
]),
(new Note())->text(sprintf(
__('Following informations can be used: %s'),
@ -136,7 +136,7 @@ class Config extends Process
// export_filename
(new Para())->items([
(new Label(__('Name of exported package:')))->for('export_filename'),
(new Input('export_filename'))->size(65)->maxlenght(255)->value($s->export_filename),
(new Input('export_filename'))->size(65)->maxlength(255)->value($s->export_filename),
]),
]),
(new Fieldset())->class('fieldset')->legend((new Legend(__('Backups'))))->fields([

View File

@ -1,24 +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 dcCore;
use dcNamespace;
use Dotclear\App;
use Dotclear\Core\Process;
use Dotclear\Database\Statement\SelectStatement;
use Exception;
/**
* @brief translater install class.
* @ingroup translater
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class Install extends Process
{
public static function init(): bool
@ -37,7 +34,7 @@ class Install extends Process
return true;
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
App::error()->add($e->getMessage());
}
return true;
@ -50,22 +47,29 @@ class Install extends Process
*/
private static function growUp()
{
$current = dcCore::app()->getVersion(My::id());
$current = App::version()->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' "
);
$sql = new SelectStatement();
$record = $sql
->column('*')
->from(App::con()->prefix() . App::blogWorkspace()::NS_TABLE_NAME)
->where("setting_ns = 'translater' ")
->select();
if (!$record) {
return true;
}
while ($record->fetch()) {
if (preg_match('/^translater_(.*?)$/', $record->f('setting_id'), $match)) {
$cur = dcCore::app()->con->openCursor(dcCore::app()->prefix . dcNamespace::NS_TABLE_NAME);
$cur = App::blogWorkspace()->openBlogWorkspaceCursor();
$cur->setField('setting_id', $match[1]);
$cur->setField('setting_ns', My::id());
$cur->update(
"WHERE setting_id = '" . $record->f('setting_id') . "' and setting_ns = 'translater' " .
'AND blog_id ' . (null === $record->f('blog_id') ? 'IS NULL ' : ("= '" . dcCore::app()->con->escapeStr((string) $record->f('blog_id')) . "' "))
'AND blog_id ' . (null === $record->f('blog_id') ? 'IS NULL ' : ("= '" . App::con()->escapeStr((string) $record->f('blog_id')) . "' "))
);
}
}

View File

@ -1,20 +1,10 @@
<?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;
use Dotclear\App;
use Dotclear\Core\Process;
use Dotclear\Core\Backend\{
Notices,
@ -38,6 +28,13 @@ use Dotclear\Helper\Date;
use Dotclear\Helper\Html\Html;
use Exception;
/**
* @brief translater manage class.
* @ingroup translater
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class Manage extends Process
{
public static function init(): bool
@ -72,7 +69,7 @@ class Manage extends Process
if (empty($current->module) || empty($_POST['files'])) {
throw new Exception(__('Nothing to restore'));
}
foreach ($current->module->getBackups(true) as $backup_file) {
foreach ($current->module->getBackupsFilename() as $backup_file) {
if (in_array($backup_file, $_POST['files'])) {
$current->module->restoreBackup($backup_file);
}
@ -85,7 +82,7 @@ class Manage extends Process
if (empty($current->module) || empty($_POST['files'])) {
throw new Exception(__('Nothing to delete'));
}
foreach ($current->module->getBackups(true) as $backup_file) {
foreach ($current->module->getBackupsFilename() as $backup_file) {
if (in_array($backup_file, $_POST['files'])) {
$current->module->deleteBackup($backup_file);
}
@ -150,7 +147,7 @@ class Manage extends Process
self::redirect(__('Language successfully updated'), $_POST['code']);
}
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
App::error()->add($e->getMessage());
}
return true;
@ -190,7 +187,7 @@ class Manage extends Process
My::jsLoad('backend') .
# --BEHAVIOR-- translaterAdminHeaders
dcCore::app()->callBehavior('translaterAdminHeaders')
App::behavior()->callBehavior('translaterAdminHeaders')
);
echo
@ -223,6 +220,9 @@ class Manage extends Process
}
$codes = $module->getLangs();
foreach ($codes as $code_id => $code_name) {
if (!is_string($code_name)) {
continue;
}
if ($module->root_writable) {
$codes[$code_id] = sprintf(
'<a class="wait maximal nowrap" title="%s" href="%s">%s (%s)</a>',
@ -309,7 +309,7 @@ class Manage extends Process
echo
'<td class="nowrap">' . count($backups[$code_id]) . '</td>' .
'<td class="nowrap"> ' .
Date::str('%Y-%m-%d %H:%M', (int) $time[$code_id], (string) dcCore::app()->blog?->settings->get('system')->get('blog_timezone')) .
Date::str('%Y-%m-%d %H:%M', (int) $time[$code_id], (string) App::blog()->settings()->get('system')->get('blog_timezone')) .
'</td>';
} else {
echo '<td class="nowrap">' . __('no backups') . '</td><td class="maximal nowrap">-</td>';
@ -365,20 +365,20 @@ class Manage extends Process
foreach ($backups as $backup_codes) {
foreach ($backup_codes as $backup_file => $backup_code) {
$i++;
$form_id = 'form_file_' . $backup_code['code'] . $backup_code['time'];
$form_id = 'form_file_' . (is_string($backup_code['code']) ? $backup_code['code'] : '') . (is_string($backup_code['time']) ? $backup_code['time'] : '');
echo sprintf(
$table_line,
(new Checkbox(['files[]', $form_id]))->value($backup_file)->render(),
$form_id,
$backup_code['name'],
$backup_code['code'],
is_string($backup_code['name']) ? $backup_code['name'] : 'unknown',
is_string($backup_code['code']) ? $backup_code['code'] : 'unknown',
Date::str(
dcCore::app()->blog?->settings->get('system')->get('date_format') . ' ' . dcCore::app()->blog?->settings->get('system')->get('time_format'),
App::blog()->settings()->get('system')->get('date_format') . ' ' . App::blog()->settings()->get('system')->get('time_format'),
(int) $backup_code['time'],
dcCore::app()->blog?->settings->get('system')->get('blog_timezone')
App::blog()->settings()->get('system')->get('blog_timezone')
),
$backup_code['path']['basename'],
Files::size($backup_code['size'])
is_array($backup_code['path']) ? $backup_code['path']['basename'] : '',
Files::size((int) $backup_code['size'])
);
}
}
@ -411,7 +411,7 @@ class Manage extends Process
<form id="module-code-create-form" method="post" action="' . My::manageUrl() . '">' .
(new Para())->class('field')->items([
(new Label(__('Select language:')))->for('code'),
(new Select(['code']))->default((string) dcCore::app()->auth?->getInfo('user_lang'))->items(array_merge(['-' => '-'], $unused_codes)),
(new Select(['code']))->default((string) App::auth()->getInfo('user_lang'))->items(array_merge(['-' => '-'], $unused_codes)),
])->render();
if (empty($codes)) {
@ -525,7 +525,7 @@ class Manage extends Process
(new Select(['entries[' . $i . '][group]']))->default($rs['group'])->items(My::l10nGroupsCombo())->disabled($in_dc)->render(),
Html::escapeHTML($msgid),
(new Hidden(['entries[' . $i . '][msgid]'], Html::escapeHTML($msgid)))->render() .
(new Input(['entries[' . $i . '][msgstr][0]']))->size(48)->maxlenght(255)->value(Html::escapeHTML($rs['msgstr'][0]))->disabled($in_dc)->render(),
(new Input(['entries[' . $i . '][msgstr][0]']))->size(48)->maxlength(255)->value(Html::escapeHTML($rs['msgstr'][0]))->disabled($in_dc)->render(),
implode('', $t_msgstr),
implode('', $t_files)
);
@ -556,7 +556,7 @@ class Manage extends Process
sprintf(__('Plural "%s"'), $plural),
sprintf(__('Plural form of "%s"'), $rs['plural']),
(new Hidden(['entries[' . $i . '][msgid_plural]'], Html::escapeHTML($rs['plural'])))->render() .
(new Input(['entries[' . $i . '][msgstr][' . ($j + 1) . ']']))->size(48)->maxlenght(255)->value(Html::escapeHTML($rs['msgstr'][$j + 1] ?? ''))->disbaled($in_dc)->render(),
(new Input(['entries[' . $i . '][msgstr][' . ($j + 1) . ']']))->size(48)->maxlength(255)->value(Html::escapeHTML($rs['msgstr'][$j + 1] ?? ''))->disabled($in_dc)->render(),
implode('', $t_msgstr),
''
);
@ -569,8 +569,8 @@ class Manage extends Process
' offline',
(new Checkbox(['entries[' . $i . '][check]']))->value(1)->render(),
(new Select(['entries[' . $i . '][group]']))->items(My::l10nGroupsCombo())->default('main')->render(),
(new Input(['entries[' . $i . '][msgid]']))->size(48)->maxlenght(255)->render(),
(new Input(['entries[' . $i . '][msgstr][0]']))->size(48)->maxlenght(255)->render(),
(new Input(['entries[' . $i . '][msgid]']))->size(48)->maxlength(255)->render(),
(new Input(['entries[' . $i . '][msgstr][0]']))->size(48)->maxlength(255)->render(),
'',
''
);
@ -590,8 +590,8 @@ class Manage extends Process
(new Para())->class('col right')->items([
(new Submit('do-action'))->value(__('Save') . ' (s)')->accesskey('s'),
... My::hiddenFields([
'type' => $current->module->type,
'module' => $current->module->id,
'type' => (string) $current->module?->type,
'module' => (string) $current->module?->id,
'action' => 'module_update_code',
'lang' => $current->lang->code,
'code' => $current->lang->code, //?
@ -634,7 +634,7 @@ class Manage extends Process
$redir = [
'type' => $current->type,
'module' => $current->module?->id,
'module' => (string) $current->module?->id,
];
if ($lang) {
$redir['lang'] = $lang;

View File

@ -1,35 +1,66 @@
<?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;
use Dotclear\App;
use Exception;
/**
* @brief translater vars helper.
* @ingroup translater
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class ManageVars
{
/**
* @var ManageVars self instance
* self instance.
*
* @var ManageVars $instance
*/
private static $container;
private static $instance;
/**
* translater instance.
*
* @var Translater $translater
*/
public readonly Translater $translater;
/**
* Module instance.
*
* @var TranslaterModule $module
*/
public readonly ?TranslaterModule $module;
/**
* Lang instance.
*
* @var TranslaterLang $lang
*/
public readonly ?TranslaterLang $lang;
/**
* The module type.
*
* @var string $type
*/
public readonly string $type;
/**
* The action.
*
* @var string $action
*/
public readonly string $action;
/**
* Constructor.
*/
protected function __construct()
{
$this->translater = new Translater();
@ -48,7 +79,7 @@ class ManageVars
try {
$module = $this->translater->getModule($type, $module);
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
App::error()->add($e->getMessage());
$module = null;
}
}
@ -57,7 +88,7 @@ class ManageVars
try {
$lang = $this->translater->getLang($module, $lang);
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
App::error()->add($e->getMessage());
$lang = null;
}
}
@ -68,12 +99,17 @@ class ManageVars
$this->action = $action;
}
/**
* Get self instance.
*
* @return ManageVars self instance
*/
public static function init(): ManageVars
{
if (!(self::$container instanceof self)) {
self::$container = new self();
if (!(self::$instance instanceof self)) {
self::$instance = new self();
}
return self::$container;
return self::$instance;
}
}

View File

@ -1,36 +1,41 @@
<?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;
use Dotclear\App;
use Dotclear\Module\MyPlugin;
/**
* Plugin definitions
* @brief translater My helper.
* @ingroup translater
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class My extends MyPlugin
{
/** @var string Locales folder name */
/**
* Locales folder name.
*
* @var string LOCALES_FOLDER
*/
public const LOCALES_FOLDER = 'locales';
public static function checkCustomContext(int $context): ?bool
{
return in_array($context, [My::BACKEND, My::MANAGE, My::MENU]) ? dcCore::app()->auth->isSuperAdmin() : null;
return match ($context) {
// Limit to super admin
self::MODULE => App::auth()->isSuperAdmin(),
default => null,
};
}
/**
* List of allowed backup folder
* List of allowed backup folder.
*
* @return array<string, string>
*/
public static function backupFoldersCombo(): array
{
@ -44,7 +49,9 @@ class My extends MyPlugin
}
/**
* List of possible home tab of the plugin
* List of possible home tab of the plugin.
*
* @return array<string, string>
*/
public static function startPageCombo(): array
{
@ -56,7 +63,9 @@ class My extends MyPlugin
}
/**
* List of place of tranlsations
* List of place of tranlsations.
*
* @return array<string, string>
*/
public static function l10nGroupsCombo(): array
{
@ -68,7 +77,9 @@ class My extends MyPlugin
}
/**
* List of user info can be parsed
* List of user info can be parsed.
*
* @return array<int, string>
*/
public static function defaultUserInformations(): array
{
@ -78,13 +89,17 @@ class My extends MyPlugin
}
/**
* List of distributed plugins and themes
* List of distributed plugins and themes.
*
* @param string $type The modules type
*
* @return array<int, string>
*/
public static function defaultDistribModules(string $type): array
{
$types = [
'plugin' => explode(',', DC_DISTRIB_PLUGINS),
'theme' => explode(',', DC_DISTRIB_THEMES),
'plugin' => explode(',', App::config()->distributedPlugins()),
'theme' => explode(',', App::config()->distributedThemes()),
];
return $types[$type] ?? [];

View File

@ -1,64 +1,121 @@
<?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;
/**
* @brief translater settings helper.
* @ingroup translater
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class Settings
{
// Show tranlsater button on plugins list
/**
* Show tranlsater button on plugins list.
*
* @var bool $plugin_menu
*/
public readonly bool $plugin_menu;
// Show tranlsater button on themes list
/**
* Show tranlsater button on themes list.
*
* @var bool $theme_menu
*/
public readonly bool $theme_menu;
// Create language backup on save
/**
* Create language backup on save.
*
* @var bool $backup_auto
*/
public readonly bool $backup_auto;
// Backups number limit
/**
* Backups number limit.
*
* @var int $backup_limit
*/
public readonly int $backup_limit;
// Backup main folder
/**
* Backup main folder.
*
* @var string $backup_folder
*/
public readonly string $backup_folder;
// Default ui start page
/**
* Default ui start page.
*
* @var string $start_page
*/
public readonly string $start_page;
// Write .lang.php file (deprecated)
/**
* Write .lang.php file (deprecated).
*
* @var bool $write_langphp
*/
public readonly bool $write_langphp;
// Scan also template files for translations
/**
* Scan also template files for translations.
*
* @var bool $scan_tpl
*/
public readonly bool $scan_tpl;
// Disable translation of know dotclear strings
/**
* Disable translation of know dotclear strings.
*
* @var bool $parse_nodc
*/
public readonly bool $parse_nodc;
// Hide official modules
/**
* Hide official modules.
*
* @var bool $hide_default
*/
public readonly bool $hide_default;
// Add comment to translations files
/**
* Add comment to translations files.
*
* @var bool $parse_comment
*/
public readonly bool $parse_comment;
// Parse user info to translations files
/**
* Parse user info to translations files.
*
* @var bool $parse_user
*/
public readonly bool $parse_user;
// User infos to parse
/**
* User infos to parse.
*
* @var string $parse_userinfo
*/
public readonly string $parse_userinfo;
// Overwrite existing languages on import
/**
* Overwrite existing languages on import.
*
* @var bool $import_overwrite
*/
public readonly bool $import_overwrite;
// Filename of exported lang
/**
* Filename of exported lang.
*
* @var string $export_filename
*/
public readonly string $export_filename;
/**
@ -68,30 +125,35 @@ class Settings
{
$s = My::settings();
$this->plugin_menu = (bool) ($s?->get('plugin_menu') ?? false);
$this->theme_menu = (bool) ($s?->get('theme_menu') ?? false);
$this->backup_auto = (bool) ($s?->get('backup_auto') ?? false);
$this->backup_limit = (int) ($s?->get('backup_limit') ?? 20);
$this->backup_folder = (string) ($s?->get('backup_folder') ?? 'module');
$this->start_page = (string) ($s?->get('start_page') ?? '-');
$this->write_langphp = (bool) ($s?->get('write_langphp') ?? false);
$this->scan_tpl = (bool) ($s?->get('scan_tpl') ?? true);
$this->parse_nodc = (bool) ($s?->get('parse_nodc') ?? true);
$this->hide_default = (bool) ($s?->get('hide_default') ?? true);
$this->parse_comment = (bool) ($s?->get('parse_comment') ?? false);
$this->parse_user = (bool) ($s?->get('parse_user') ?? false);
$this->parse_userinfo = (string) ($s?->get('parse_userinfo') ?? 'displayname, email');
$this->import_overwrite = (bool) ($s?->get('import_overwrite') ?? false);
$this->export_filename = (string) ($s?->get('export_filename') ?? 'type-module-l10n-timestamp');
$this->plugin_menu = (bool) ($s->get('plugin_menu') ?? false);
$this->theme_menu = (bool) ($s->get('theme_menu') ?? false);
$this->backup_auto = (bool) ($s->get('backup_auto') ?? false);
$this->backup_limit = (int) ($s->get('backup_limit') ?? 20);
$this->backup_folder = (string) ($s->get('backup_folder') ?? 'module');
$this->start_page = (string) ($s->get('start_page') ?? '-');
$this->write_langphp = (bool) ($s->get('write_langphp') ?? false);
$this->scan_tpl = (bool) ($s->get('scan_tpl') ?? true);
$this->parse_nodc = (bool) ($s->get('parse_nodc') ?? true);
$this->hide_default = (bool) ($s->get('hide_default') ?? true);
$this->parse_comment = (bool) ($s->get('parse_comment') ?? false);
$this->parse_user = (bool) ($s->get('parse_user') ?? false);
$this->parse_userinfo = (string) ($s->get('parse_userinfo') ?? 'displayname, email');
$this->import_overwrite = (bool) ($s->get('import_overwrite') ?? false);
$this->export_filename = (string) ($s->get('export_filename') ?? 'type-module-l10n-timestamp');
}
/**
* Get a setting.
*
* @return null|bool|int|string
*/
public function getSetting(string $key): mixed
{
return $this->{$key} ?? null;
}
/**
* Overwrite a plugin settings (in db)
* Overwrite a plugin settings (in db).
*
* @param string $key The setting ID
* @param mixed $value The setting value
@ -111,9 +173,9 @@ class Settings
}
/**
* List defined settings keys
* List defined settings keys.
*
* @return array The settings keys
* @return array<string, null|bool|int|string> The settings keys
*/
public function listSettings(): array
{

View File

@ -1,40 +1,37 @@
<?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;
use dcModuleDefine;
use dcThemes;
use Dotclear\App;
use Dotclear\Helper\File\Files;
use Dotclear\Helper\File\Path;
use Dotclear\Helper\L10n;
use Dotclear\Helper\Text;
use Dotclear\Module\ModuleDefine;
use Exception;
/**
* Translater tools.
* @brief translater main tools class.
* @ingroup translater
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class Translater extends Settings
{
/** @var array $modules List of modules we could work on */
/**
* List of modules we could work on.
*
* @var array<string, array<string, TranslaterModule>> $modules
*/
private $modules = [];
/**
* translater instance
* Construct translater instance.
*
* @param boolean $full Also load modules
* @param bool $full Also load modules
*/
public function __construct(bool $full = true)
{
@ -48,33 +45,32 @@ class Translater extends Settings
/// @name modules methods
//@{
/**
* Load array of modules infos by type of modules
* Load array of modules infos by type of modules.
*/
private function loadModules(): void
{
$this->modules = ['theme' => [], 'plugin' => []];
if (!(dcCore::app()->themes instanceof dcThemes)) {
dcCore::app()->themes = new dcThemes();
dcCore::app()->themes->loadModules((string) dcCore::app()->blog?->themes_path, null);
if (App::themes()->isEmpty()) {
App::themes()->loadModules(App::blog()->themesPath(), null);
}
foreach ([
dcCore::app()->themes->getDefines(['state' => dcModuleDefine::STATE_ENABLED]),
dcCore::app()->plugins->getDefines(['state' => dcModuleDefine::STATE_ENABLED]),
App::themes()->getDefines(['state' => ModuleDefine::STATE_ENABLED]),
App::plugins()->getDefines(['state' => ModuleDefine::STATE_ENABLED]),
] as $modules) {
foreach ($modules as $define) {
$this->modules[$define->get('type')][$define->get('id')] = new TranslaterModule($this, $define);
$this->modules[(string) $define->get('type')][(string) $define->get('id')] = new TranslaterModule($this, $define);
}
}
}
/**
* Return array of modules infos by type of modules
* Return array of modules infos by type of modules.
*
* @param string $type The modules type
*
* @return array The list of modules infos
* @return array<string, TranslaterModule> The list of modules infos
*/
public function getModules(string $type = ''): array
{
@ -84,7 +80,7 @@ class Translater extends Settings
}
/**
* 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 string $type The module type
* @param string $id The module id
@ -103,7 +99,7 @@ class Translater extends Settings
}
/**
* 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 TranslaterModule $module TranslaterModule instance
* @param string $lang The lang iso code
@ -125,12 +121,13 @@ class Translater extends Settings
/// @name helper methods
//@{
/**
* Scan recursively a folder and return files and folders names
* Scan recursively a folder and return files and folders names.
*
* @param string $path The path to scan
* @param string $dir Internal recursion
* @param array $res Internal recursion
* @return array List of path
* @param array<int, string> $res Internal recursion
*
* @return array<int, string> List of path
*/
public static function scandir(string $path, string $dir = '', array $res = []): array
{
@ -157,9 +154,10 @@ class Translater extends Settings
}
/**
* Encode a string
* Encode a string.
*
* @param string $str The string to encode
*
* @return string The encoded string
*/
public static function encodeMsg(string $str): string
@ -168,10 +166,11 @@ class Translater extends Settings
}
/**
* Clean a po string
* Clean a po string.
*
* @param string $string The string to clean
* @param boolean $reverse Un/escape string
* @param bool $reverse Un/escape string
*
* @return string The cleaned string
*/
public static function poString(string $string, bool $reverse = false): string
@ -189,10 +188,11 @@ class Translater extends Settings
}
/**
* Try if a file is a .po file
* Try if a file is a po file.
*
* @param string $file The path to test
* @return boolean Success
*
* @return bool Success
*/
public static function isPoFile(string $file): bool
{
@ -200,10 +200,11 @@ class Translater extends Settings
}
/**
* Try if a file is a .lang.php file
* Try if a file is a .lang.php file.
*
* @param string $file The path to test
* @return boolean Success
*
* @return bool Success
*/
public static function isLangphpFile(string $file): bool
{
@ -211,13 +212,14 @@ class Translater extends Settings
}
/**
* Check limit number of backup for a module
* Check limit number of backup for a module.
*
* @param string $id The module id
* @param string $root The backups root
* @param integer $limit The backups limit
* @param boolean $throw Silently failed
* @return boolean True if limit is riched
* @param int $limit The backups limit
* @param bool $throw Silently failed
*
* @return bool True if limit is riched
*/
public static function isBackupLimit(string $id, string $root, int $limit = 10, bool $throw = false): bool
{
@ -249,13 +251,14 @@ class Translater extends Settings
}
/**
* Extract messages from a php contents
* Extract messages from a php contents.
*
* support plurals
*
* @param string $content The contents
* @param string $func The function name
* @return array The messages
*
* @return array<int<0, max>, array{0: array<int,string>, 1: int}> The messages
*/
public static function extractPhpMsgs(string $content, string $func = '__'): array
{
@ -308,11 +311,12 @@ class Translater extends Settings
}
/**
* Extract messages from a tpl contents
* Extract messages from a tpl contents.
*
* @param string $content The contents
* @param string $func The function name
* @return array The messages
*
* @return array<int<0, max>, array{0: array<int,string>, 1: int}> The messages
*/
public static function extractTplMsgs(string $content, string $func = 'tpl:lang'): array
{

View File

@ -1,50 +1,56 @@
<?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 dcModuleDefine;
use Dotclear\App;
use Dotclear\Helper\File\Files;
use Dotclear\Helper\File\Path;
use Dotclear\Helper\L10n;
use Dotclear\Module\ModuleDefine;
/**
* @brief translater lang tools class.
* @ingroup translater
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class TranslaterLang
{
/** @var string Lang code */
public readonly string $code;
/** @var string Lang name */
/**
* Lang name.
*
* @var string $name
*/
public readonly string $name;
/** @var array Lang plural forms */
/**
* Lang plural forms.
*
* @var array<int, string> $plural
*/
public readonly array $plural;
/** @var TranslaterModule TranslaterModule instance */
private TranslaterModule $module;
public function __construct(TranslaterModule $module, string $lang)
{
$this->module = $module;
$this->code = $lang;
$this->name = L10n::getLanguageName($lang);
$this->plural = explode(':', L10n::getLanguagePluralExpression($lang));
/**
* Constructor.
*
* @param TranslaterModule $module The module
* @param string $code The lang code
*/
public function __construct(
private TranslaterModule $module,
public readonly string $code
) {
$this->name = L10n::getLanguageName($code);
$this->plural = explode(':', L10n::getLanguagePluralExpression($code));
}
/**
* Get a lang messages
* Get a lang messages.
*
* @return array The messages ids and translations
* @return array<string, array<string, mixed>> The messages ids and translations
*/
public function getMessages(): array
{
@ -59,7 +65,7 @@ class TranslaterLang
}
# Add Dotclear str
$dc_define = (new dcModuleDefine('dotclear'))->set('root', DC_ROOT);
$dc_define = (new ModuleDefine('dotclear'))->set('root', App::config()->dotclearRoot());
$dc_module = new TranslaterModule($this->module->translater, $dc_define);
$dc_lang = new TranslaterLang($dc_module, $this->code);
$m_o_msgstrs['dotclear'] = $dc_lang->getMsgStrs();
@ -76,7 +82,7 @@ class TranslaterLang
# From str list
foreach ($m_msgstrs as $rs) {
if (!isset($res[$rs['msgid']])) {
if (!is_string($rs['msgid']) || !isset($res[$rs['msgid']])) {
$res[$rs['msgid']]['files'][] = [];
$res[$rs['msgid']]['in_dc'] = false;
$res[$rs['msgid']]['o_msgstrs'] = [];
@ -90,7 +96,7 @@ class TranslaterLang
# From others str list
foreach ($m_o_msgstrs as $o_module => $o_msgstrs) {
foreach ($o_msgstrs as $rs) {
if (!isset($res[$rs['msgid']])) {
if (!is_string($rs['msgid']) || !isset($res[$rs['msgid']])) {
continue;
}
@ -109,9 +115,9 @@ class TranslaterLang
}
/**
* Get messages ids
* Get messages ids.
*
* @return array The messages ids
* @return array<int, array<string, mixed>> The messages ids
*/
public function getMsgIds(): array
{
@ -129,12 +135,11 @@ class TranslaterLang
}
$contents = file_get_contents($this->module->root . '/' . $file);
$msgs = [];
# php files
if ($extension == 'php') {
# php files
$msgs = Translater::extractPhpMsgs((string) $contents);
# tpl files
} elseif ($extension == 'html') {
# tpl files
$msgs = Translater::extractTplMsgs((string) $contents);
}
foreach ($msgs as $msg) {
@ -153,15 +158,15 @@ class TranslaterLang
}
/**
* Get messages translations
* Get messages translations.
*
* @return array The messages translations
* @return array<int, array<string, string|array<int, string>>> The messages translations
*/
public function getMsgStrs(): array
{
$res = $exists = $scanned = [];
$langs = $this->module->getLangs(true);
$langs = $this->module->getLangsPath();
if (!isset($langs[$this->code])) {
return $res;
}

View File

@ -1,21 +1,10 @@
<?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;
use dcModuleDefine;
use Dotclear\App;
use Dotclear\Helper\Date;
use Dotclear\Helper\File\Files;
use Dotclear\Helper\File\Path;
@ -23,46 +12,91 @@ use Dotclear\Helper\File\Zip\Unzip;
use Dotclear\Helper\File\Zip\Zip;
use Dotclear\Helper\Html\Html;
use Dotclear\Helper\L10n;
use Dotclear\Module\ModuleDefine;
use Exception;
/**
* Translater tools.
* @brief translater module tools class.
* @ingroup translater
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class TranslaterModule
{
/** @var string Module id */
/**
* Module id.
*
* @var string $id
*/
public readonly string $id;
/** @var string Module type */
/**
* Module type.
*
* @var string $type
*/
public readonly string $type;
/** @var string Module name */
/**
* Module name.
*
* @var string $name
*/
public readonly string $name;
/** @var string Module author */
/**
* Module author.
*
* @var string $author
*/
public readonly string $author;
/** @var string Module version */
/**
* Module version.
*
* @var string $version
*/
public readonly string $version;
/** @var bool Module root writable */
/**
* Module root writable.
*
* @var bool $root_writable
*/
public readonly bool $root_writable;
/** @var string Module root (cleaned) */
/**
* Module root (cleaned).
*
* @var string $root
*/
public readonly string $root;
/** @var string Module locales root path */
/**
* Module locales root path.
*
* @var string $locales
*/
public readonly string $locales;
/** @var Translater Translater instance */
public readonly Translater $translater;
/** @var string Backup file regexp */
/**
* Backup file regexp.
*
* @var string $backup_file_regexp
*/
private $backup_file_regexp = '/^l10n-%s-(.*?)-[0-9]*?\.bck\.zip$/';
public function __construct(Translater $translater, dcModuleDefine $define)
{
$this->translater = $translater;
/**
* Constructor.
*
* @param Translater $translater The tanslater instance
* @param ModuleDefine $define The module define
*/
public function __construct(
public readonly Translater $translater,
ModuleDefine $define
) {
$this->id = $define->get('id');
$this->type = $define->get('type');
$this->name = $define->get('name');
@ -76,9 +110,10 @@ class TranslaterModule
/// @name backup methods
//@{
/**
* Find backup folder of a module
* Find backup folder of a module.
*
* @param bool $throw Silently failed
*
* @param boolean $throw Silently failed
* @return string|false The backup folder directory or false
*/
public function getBackupRoot(bool $throw = false): string|false
@ -93,7 +128,7 @@ class TranslaterModule
break;
case 'plugin':
$exp = explode(PATH_SEPARATOR, DC_PLUGINS_ROOT);
$exp = explode(PATH_SEPARATOR, App::config()->pluginsRoot());
$tmp = Path::real(array_pop($exp));
if ($tmp !== false && is_writable($tmp)) {
$dir = $tmp;
@ -102,7 +137,7 @@ class TranslaterModule
break;
case 'public':
$tmp = Path::real((string) dcCore::app()->blog?->public_path);
$tmp = Path::real(App::blog()->publicPath());
if ($tmp !== false && is_writable($tmp)) {
$dir = $tmp;
}
@ -110,7 +145,7 @@ class TranslaterModule
break;
case 'cache':
$tmp = Path::real(DC_TPL_CACHE);
$tmp = Path::real(App::config()->cacheRoot());
if ($tmp !== false && is_writable($tmp)) {
@mkDir($tmp . '/l10n');
$dir = $tmp . '/l10n';
@ -138,12 +173,11 @@ class TranslaterModule
}
/**
* Get a list of available backups
* Get a list of available backups.
*
* @param boolean $return_filename Return only filenames
* @return array The module backups info
* @return array<string, array<string, array<string, string|array<string, string>>>> The module backups info
*/
public function getBackups(bool $return_filename = false): array
public function getBackups(): array
{
$backup = $this->getBackupRoot();
if (!$backup) {
@ -162,26 +196,53 @@ class TranslaterModule
continue;
}
if ($return_filename) {
$res[] = $file;
} else {
$res[$m[1]][$file]['code'] = $m[1];
$res[$m[1]][$file]['name'] = L10n::getLanguageName($m[1]);
$res[$m[1]][$file]['path'] = Path::info($backup . '/' . $file);
$res[$m[1]][$file]['time'] = filemtime($backup . '/' . $file);
$res[$m[1]][$file]['size'] = filesize($backup . '/' . $file);
$res[$m[1]][$file]['time'] = (string) filemtime($backup . '/' . $file);
$res[$m[1]][$file]['size'] = (string) filesize($backup . '/' . $file);
$res[$m[1]][$file]['module'] = $this->id;
}
}
return $res;
}
/**
* Create a backup
* Get a list of available backups filemnames.
*
* @return array<int, string> The module backups info
*/
public function getBackupsFilename(): array
{
$backup = $this->getBackupRoot();
if (!$backup) {
return [];
}
$res = [];
$files = Translater::scandir($backup);
foreach ($files as $file) {
$is_backup = preg_match(sprintf($this->backup_file_regexp, preg_quote($this->id)), $file, $m);
if (is_dir($backup . '/' . $file)
|| !$is_backup
|| !L10n::isCode($m[1])
) {
continue;
}
$res[] = $file;
}
return $res;
}
/**
* Create a backup.
*
* @param string $lang The backup lang
* @return boolean True on success
*
* @return bool True on success
*/
public function createBackup(string $lang): bool
{
@ -226,10 +287,11 @@ class TranslaterModule
}
/**
* Retore a backup
* Retore a backup.
*
* @param string $file The backup filename
* @return boolean True on success
*
* @return bool True on success
*/
public function restoreBackup(string $file): bool
{
@ -257,10 +319,11 @@ class TranslaterModule
}
/**
* Delete a module backup
* Delete a module backup.
*
* @param string $file The backup filename
* @return boolean True on success
*
* @return bool True on success
*/
public function deleteBackup(string $file): bool
{
@ -288,10 +351,11 @@ class TranslaterModule
}
/**
* Import a language pack
* Import a language pack.
*
* @param array $zip_file The uploaded file info
* @return boolean True on success
* @param array<string, mixed> $zip_file The uploaded file info
*
* @return bool True on success
*/
public function importPack(array $zip_file): bool
{
@ -350,9 +414,9 @@ class TranslaterModule
}
/**
* Export (to output) language pack
* Export (to output) language pack.
*
* @param array $langs Langs to export
* @param array<int, string> $langs Langs to export
*/
public function exportPack(array $langs): void
{
@ -414,11 +478,12 @@ class TranslaterModule
}
/**
* Parse zip filename to module, lang info
* Parse zip filename to module, lang info.
*
* @param string $file The zip filename
* @param boolean $throw Silently failed
* @return array Array of file info
* @param bool $throw Silently failed
*
* @return array<string, string> Array of file info
*/
public function parseZipFilename(string $file = '', bool $throw = false): array
{
@ -454,12 +519,11 @@ class TranslaterModule
/// @name lang methods
//@{
/**
* List available langs of a module
* List available langs of a module.
*
* @param boolean $return_path Return path or name
* @return array The lang list
* @return array<string, string> The lang list
*/
public function getLangs(bool $return_path = false): array
public function getLangs(): array
{
$res = [];
@ -475,20 +539,42 @@ class TranslaterModule
continue;
}
if ($return_path) {
$res[$m[1]][] = $file; // Path
} else {
$res[$m[1]] = L10n::getLanguageName($m[1]); // Lang name
}
return $res;
}
/**
* List available langs path of a module.
*
* @return array<string, array<int, string>> The lang list
*/
public function getLangsPath(): array
{
$res = [];
$prefix = preg_match('/(' . preg_quote(My::LOCALES_FOLDER) . '(.*))$/', $this->locales) ? My::LOCALES_FOLDER : '';
$files = Translater::scandir($this->locales);
foreach ($files as $file) {
if (!preg_match('/.*?' . preg_quote(My::LOCALES_FOLDER) . '\/([^\/]*?)\/([^\/]*?)(.lang.php|.po)$/', $prefix . $file, $m)) {
continue;
}
if (!L10n::isCode($m[1])) {
continue;
}
$res[$m[1]][] = $file; // Path
}
return $res;
}
/**
* List of used langs of a module
* List of used langs of a module.
*
* @return array The list of iso names and codes
* @return array<string, string> The list of iso names and codes
*/
public function getUsedLangs(): array
{
@ -496,9 +582,9 @@ class TranslaterModule
}
/**
* List of unsused langs of a module
* List of unsused langs of a module.
*
* @return array The list of iso names and codes
* @return array<string, string> The list of iso names and codes
*/
public function getUnusedLangs(): array
{
@ -506,11 +592,12 @@ class TranslaterModule
}
/**
* Add a lang to a module
* Add a lang to a module.
*
* @param string $lang The lang id
* @param string $from_lang The lang to copy from
* @return boolean True on success
*
* @return bool True on success
*/
public function addLang(string $lang, string $from_lang = ''): bool
{
@ -562,10 +649,10 @@ class TranslaterModule
}
/**
* Update an existing lang
* Update an existing lang.
*
* @param string $lang The lang
* @param array $msgs The messages
* @param array<string, mixed> $msgs The messages
*/
public function updLang(string $lang, array $msgs): void
{
@ -627,11 +714,12 @@ class TranslaterModule
}
/**
* Delete a lang
* Delete a lang.
*
* @param string $lang The lang code
* @param boolean $del_empty_dir Also remove empty locales dir
* @return boolean True on success
* @param bool $del_empty_dir Also remove empty locales dir
*
* @return bool True on success
*/
public function delLang(string $lang, bool $del_empty_dir = true): bool
{
@ -643,7 +731,7 @@ class TranslaterModule
));
}
$files = $this->getLangs(true);
$files = $this->getLangsPath();
if (!isset($files[$lang])) {
throw new Exception(sprintf(
__('Failed to find language %s'),
@ -669,11 +757,11 @@ class TranslaterModule
}
/**
* Construct and parse a .po file
* Construct and parse a po file.
*
* @param string $lang The lang code
* @param string $group The lang group
* @param array $msgs The strings
* @param array<int, mixed> $msgs The strings
*/
private function setPoContent(string $lang, string $group, array $msgs): void
{
@ -689,14 +777,14 @@ class TranslaterModule
$search = My::defaultUserInformations();
$replace = [];
foreach ($search as $n) {
$replace[] = dcCore::app()->auth?->getInfo('user_' . $n);
$replace[] = App::auth()->getInfo('user_' . $n);
}
$info = trim(str_replace($search, $replace, $this->translater->parse_userinfo));
if (!empty($info)) {
$content .= '# Author: ' . Html::escapeHTML($info) . "\n";
}
}
$content .= '# Translated with translater ' . dcCore::app()->plugins->moduleInfo(My::id(), 'version') . "\n\n";
$content .= '# Translated with translater ' . App::plugins()->moduleInfo(My::id(), 'version') . "\n\n";
}
$content .= "msgid \"\"\n" .
"msgstr \"\"\n" .
@ -704,7 +792,7 @@ class TranslaterModule
'"Project-Id-Version: ' . $this->id . ' ' . $this->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" .
'"Last-Translator: ' . App::auth()->getInfo('user_cn') . '\n"' . "\n" .
'"Language-Team: \n"' . "\n" .
'"MIME-Version: 1.0\n"' . "\n" .
'"Content-Transfer-Encoding: 8bit\n"' . "\n" .
@ -757,11 +845,11 @@ class TranslaterModule
}
/**
* Construct and write a .lang.php file
* Construct and write a .lang.php file.
*
* @param string $lang The lang code
* @param string $group The lang group
* @param array $msgs The strings
* @param array<int, mixed> $msgs The strings
*/
private function setLangphpContent(string $lang, string $group, array $msgs): void
{
@ -781,14 +869,14 @@ class TranslaterModule
$search = My::defaultUserInformations();
$replace = [];
foreach ($search as $n) {
$replace[] = dcCore::app()->auth?->getInfo('user_' . $n);
$replace[] = App::auth()->getInfo('user_' . $n);
}
$info = trim(str_replace($search, $replace, $this->translater->parse_userinfo));
if (!empty($info)) {
$content .= '// Author: ' . Html::escapeHTML($info) . "\n";
}
}
$content .= '// Translated with Translater - ' . dcCore::app()->plugins->moduleInfo(My::id(), 'version') . "\n\n";
$content .= '// Translated with Translater - ' . App::plugins()->moduleInfo(My::id(), 'version') . "\n\n";
}
L10n::generatePhpFileFromPo(implode(DIRECTORY_SEPARATOR, [$this->locales, $lang->code, $group]), $content);

View File

@ -1,23 +1,19 @@
<?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;
use Dotclear\Core\Process;
use Dotclear\Plugin\Uninstaller\Uninstaller;
/**
* @brief translater uninstall class.
* @ingroup translater
*
* @author Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class Uninstall extends Process
{
public static function init(): bool
@ -27,7 +23,7 @@ class Uninstall extends Process
public static function process(): bool
{
if (!self::status() || !dcCore::app()->plugins->moduleExists('Uninstaller')) {
if (!self::status()) {
return false;
}