diff --git a/src/Manage.php b/src/Manage.php index 171fdac..d6130c2 100644 --- a/src/Manage.php +++ b/src/Manage.php @@ -39,7 +39,7 @@ class Manage extends dcNsProcess return false; } - $current = ManageContainer::init(); + $current = ManageVars::init(); // execute action try { @@ -150,7 +150,7 @@ class Manage extends dcNsProcess return; } - $current = ManageContainer::init(); + $current = ManageVars::init(); $breadcrumb = [My::name() => dcCore::app()->adminurl->get(My::id(), ['type' => '-'])]; if (empty($current->type)) { diff --git a/src/ManageVars.php b/src/ManageVars.php index dbb01fc..71864c3 100644 --- a/src/ManageVars.php +++ b/src/ManageVars.php @@ -16,16 +16,16 @@ namespace Dotclear\Plugin\translater; use dcCore; -class ManageContainer +class ManageVars { /** - * @var ManageContainer self instance + * @var ManageVars self instance */ private static $container; public readonly Translater $translater; - public readonly string|TranslaterModule $module; - public readonly string|TranslaterLang $lang; + public readonly ?TranslaterModule $module; + public readonly ?TranslaterLang $lang; public readonly string $type; public readonly string $action; @@ -34,8 +34,8 @@ class ManageContainer $this->translater = new Translater(); $type = $_REQUEST['type'] ?? $this->translater->start_page ?: ''; - $module = $_REQUEST['module'] ?? ''; - $lang = $_REQUEST['lang'] ?? ''; + $module = $_REQUEST['module'] ?? null; + $lang = $_REQUEST['lang'] ?? null; $action = $_POST['action'] ?? ''; // check module type @@ -48,7 +48,7 @@ class ManageContainer $module = $this->translater->getModule($type, $module); } catch (Exception $e) { dcCore::app()->error->add($e->getMessage()); - $module = ''; + $module = null; } } //check if module lang exists @@ -57,7 +57,7 @@ class ManageContainer $lang = $this->translater->getLang($module, $lang); } catch (Exception $e) { dcCore::app()->error->add($e->getMessage()); - $lang = ''; + $lang = null; } } @@ -67,7 +67,7 @@ class ManageContainer $this->action = $action; } - public static function init(): ManageContainer + public static function init(): ManageVars { if (!(self::$container instanceof self)) { self::$container = new self(); diff --git a/src/Translater.php b/src/Translater.php index 82cb6fd..2844ca9 100644 --- a/src/Translater.php +++ b/src/Translater.php @@ -15,6 +15,7 @@ declare(strict_types=1); namespace Dotclear\Plugin\translater; use dcCore; +use dcModuleDefine; use dcThemes; use files; use l10n; @@ -50,25 +51,19 @@ class Translater extends Settings */ private function loadModules(): void { - $this->modules['theme'] = $this->modules['plugin'] = []; + $this->modules = ['theme' => [], 'plugin' => []]; if (!(dcCore::app()->themes instanceof dcThemes)) { dcCore::app()->themes = new dcThemes(); dcCore::app()->themes->loadModules(dcCore::app()->blog->themes_path, null); } - $list = [ - 'theme' => dcCore::app()->themes->getModules(), - 'plugin' => dcCore::app()->plugins->getModules(), - ]; - foreach ($list as $type => $modules) { - foreach ($modules as $id => $info) { - if (!$info['root_writable']) { -// continue; - } - $info['id'] = $id; - $info['type'] = $type; - $this->modules[$type][$id] = new TranslaterModule($this, $info); + foreach ([ + dcCore::app()->themes->getDefines(['state' => dcModuleDefine::STATE_ENABLED]), + dcCore::app()->plugins->getDefines(['state' => dcModuleDefine::STATE_ENABLED]), + ] as $modules) { + foreach ($modules as $define) { + $this->modules[$define->get('type')][$define->get('id')] = new TranslaterModule($this, $define); } } } diff --git a/src/TranslaterLang.php b/src/TranslaterLang.php index 8cec16c..c1d480d 100644 --- a/src/TranslaterLang.php +++ b/src/TranslaterLang.php @@ -14,47 +14,31 @@ declare(strict_types=1); namespace Dotclear\Plugin\translater; +use dcModuleDefine; use files; use l10n; use path; class TranslaterLang { - /** @var Translater Translater instance */ - public $translater = null; - /** @var TranslaterModule TranslaterModule instance */ - public $module = null; + /** @var string Lang code */ + public readonly string $code; - /** @var array Lang properies */ - private $prop = []; + /** @var string Lang name */ + public readonly string $name; + + /** @var array Lang plural forms */ + public readonly array $plural; + + /** @var TranslaterModule TranslaterModule instance */ + private TranslaterModule $module; public function __construct(TranslaterModule $module, string $lang) { - $this->translater = $module->translater; - $this->module = $module; - - $this->prop['code'] = $lang; - $this->prop['name'] = l10n::getLanguageName($lang); - $this->prop['plural'] = explode(':', l10n::getLanguagePluralExpression($lang)); - } - - /** - * Get a lang property - * - * @param string $key The lang property key - * @return mixed The lang property value or null - */ - public function get(string $key): mixed - { - return array_key_exists($key, $this->prop) ? $this->prop[$key] : null; - } - - /** - * Magic get - */ - public function __get(string $key): mixed - { - return $this->get($key); + $this->module = $module; + $this->code = $lang; + $this->name = l10n::getLanguageName($lang); + $this->plural = explode(':', l10n::getLanguagePluralExpression($lang)); } /** @@ -68,13 +52,16 @@ class TranslaterLang $m_msgids = $this->getMsgIds(); $m_msgstrs = $this->getMsgStrs(); - foreach ($this->translater->getModules() as $module) { - if ($module->id != $this->module->get('id')) { - $m_o_msgstrs[$module->get('id')] = $this->translater->getlang($module, $this->get('code'))->getMsgStrs(); + foreach ($this->module->translater->getModules() as $module) { + if ($module->id != $this->module->id) { + $m_o_msgstrs[$module->id] = $this->module->translater->getlang($module, $this->code)->getMsgStrs(); } } - $dc_module = new TranslaterModule($this->translater, ['id' => 'dotclear', 'root' => DC_ROOT]); - $dc_lang = new TranslaterLang($dc_module, $this->get('code')); + + # Add Dotclear str + $dc_define = (new dcModuleDefine('dotclear'))->set('root', DC_ROOT); + $dc_module = new TranslaterModule($this->module->translater, $dc_define); + $dc_lang = new TranslaterLang($dc_module, $this->code); $m_o_msgstrs['dotclear'] = $dc_lang->getMsgStrs(); # From id list @@ -130,17 +117,17 @@ class TranslaterLang { $res = []; $scan_ext = ['php']; - if ($this->translater->scan_tpl) { + if ($this->module->translater->scan_tpl) { $scan_ext[] = 'html'; } - $files = Translater::scandir($this->module->get('root')); + $files = Translater::scandir($this->module->root); foreach ($files as $file) { $extension = files::getExtension($file); - if (is_dir($this->module->get('root') . '/' . $file) || !in_array($extension, $scan_ext)) { + if (is_dir($this->module->root . DIRECTORY_SEPARATOR . $file) || !in_array($extension, $scan_ext)) { continue; } - $contents = file_get_contents($this->module->get('root') . '/' . $file); + $contents = file_get_contents($this->module->root . '/' . $file); $msgs = []; # php files if ($extension == 'php') { @@ -175,16 +162,16 @@ class TranslaterLang $res = $exists = $scanned = []; $langs = $this->module->getLangs(true); - if (!isset($langs[$this->get('code')])) { + if (!isset($langs[$this->code])) { return $res; } - foreach ($langs[$this->get('code')] as $file) { + foreach ($langs[$this->code] as $file) { if (in_array($file, $scanned)) { continue; } $scanned[] = $file; - $path = path::clean($this->module->get('locales') . '/' . $file); + $path = path::clean($this->module->locales . DIRECTORY_SEPARATOR . $file); if (Translater::isPoFile($file)) { $po = l10n::parsePoFile($path); @@ -197,7 +184,7 @@ class TranslaterLang 'msgid' => $entry['msgid'], 'msgid_plural' => $entry['msgid_plural'] ?? '', 'msgstr' => is_array($entry['msgstr']) ? $entry['msgstr'] : [$entry['msgstr']], - 'lang' => $this->get('code'), + 'lang' => $this->code, 'type' => 'po', 'path' => $path, 'file' => basename($file), diff --git a/src/TranslaterModule.php b/src/TranslaterModule.php index e3d5d63..b3b8196 100644 --- a/src/TranslaterModule.php +++ b/src/TranslaterModule.php @@ -15,6 +15,7 @@ declare(strict_types=1); namespace Dotclear\Plugin\translater; use dcCore; +use dcModuleDefine; use dt; use html; use files; @@ -28,43 +29,47 @@ use path; */ class TranslaterModule { - /** @var Translater Translater instance */ - public $translater = null; + /** @var string Module id */ + public readonly string $id; - /** @var array Module properies */ - private $prop = []; + /** @var string Module type */ + public readonly string $type; + + /** @var string Module name */ + public readonly string $name; + + /** @var string Module author */ + public readonly string $author; + + /** @var string Module version */ + public readonly string $version; + + /** @var bool Module root writable */ + public readonly bool $root_writable; + + /** @var string Module root (cleaned) */ + public readonly string $root; + + /** @var string Module locales root path */ + public readonly string $locales; + + /** @var Translater Translater instance */ + public readonly Translater $translater; /** @var string Backup file regexp */ private $backup_file_regexp = '/^l10n-%s-(.*?)-[0-9]*?\.bck\.zip$/'; - public function __construct(Translater $translater, array $module) + public function __construct(Translater $translater, dcModuleDefine $define) { - $this->translater = $translater; - $this->prop = $module; - - $this->prop['root'] = path::real($this->prop['root']); - $i = path::info($this->prop['root']); - $this->prop['basename'] = $i['basename']; - $this->prop['locales'] = $this->prop['root'] . '/locales'; - } - - /** - * Get a module property - * - * @param string $key The module property key - * @return mixed The module property value or null - */ - public function get(string $key): mixed - { - return array_key_exists($key, $this->prop) ? $this->prop[$key] : null; - } - - /** - * Magic get - */ - public function __get(string $key): mixed - { - return $this->get($key); + $this->translater = $translater; + $this->id = $define->get('id'); + $this->type = $define->get('type'); + $this->name = $define->get('name'); + $this->author = $define->get('author'); + $this->version = $define->get('version'); + $this->root_writable = $define->get('root_writable'); + $this->root = path::real($define->get('root')); + $this->locales = $this->root . DIRECTORY_SEPARATOR . 'locales'; } /// @name backup methods @@ -80,8 +85,8 @@ class TranslaterModule $dir = false; switch ($this->translater->backup_folder) { case 'module': - if ($this->prop['root_writable']) { - $dir = $this->prop['locales']; + if ($this->root_writable) { + $dir = $this->locales; } break; @@ -124,7 +129,7 @@ class TranslaterModule if (!$dir && $throw) { throw new Exception(sprintf( __('Failed to find backups folder for module %s'), - $this->prop['basename'] + $this->id )); } @@ -147,7 +152,7 @@ class TranslaterModule $res = []; $files = Translater::scandir($backup); 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->id)), $file, $m); if (is_dir($backup . '/' . $file) || !$is_backup @@ -164,7 +169,7 @@ class TranslaterModule $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]['module'] = $this->prop['id']; + $res[$m[1]][$file]['module'] = $this->id; } } @@ -180,8 +185,9 @@ class TranslaterModule public function createBackup(string $lang): bool { $backup = $this->getBackupRoot(true); + $dir = $this->locales . DIRECTORY_SEPARATOR . $lang; - if (!is_dir($this->prop['locales'] . '/' . $lang)) { + if (!is_dir($dir)) { throw new Exception(sprintf( __('Failed to find language %s'), $lang @@ -189,20 +195,20 @@ class TranslaterModule } $res = []; - $files = Translater::scandir($this->prop['locales'] . '/' . $lang); + $files = Translater::scandir($dir); foreach ($files as $file) { - if (!is_dir($this->prop['locales'] . '/' . $lang . '/' . $file) + if (!is_dir($dir . DIRECTORY_SEPARATOR . $file) && (Translater::isLangphpFile($file) || Translater::isPoFile($file)) ) { - $res[$this->prop['locales'] . '/' . $lang . '/' . $file] = $this->prop['id'] . '/locales/' . $lang . '/' . $file; + $res[$dir . DIRECTORY_SEPARATOR . $file] = implode(DIRECTORY_SEPARATOR, [$this->locales, $lang, $file]); } } if (!empty($res)) { - Translater::isBackupLimit($this->prop['id'], $backup, $this->translater->backup_limit, true); + Translater::isBackupLimit($this->id, $backup, $this->translater->backup_limit, true); @set_time_limit(300); - $fp = fopen($backup . '/l10n-' . $this->prop['id'] . '-' . $lang . '-' . time() . '.bck.zip', 'wb'); + $fp = fopen($backup . '/l10n-' . $this->id . '-' . $lang . '-' . time() . '.bck.zip', 'wb'); $zip = new fileZip($fp); foreach ($res as $from => $to) { $zip->addFile($from, $to); @@ -239,7 +245,7 @@ class TranslaterModule foreach ($zip_files as $zip_file) { $f = $this->parseZipFilename($zip_file, true); - $zip->unzip($zip_file, $this->prop['locales'] . '/' . $f['lang'] . '/' . $f['group'] . $f['ext']); + $zip->unzip($zip_file, implode(DIRECTORY_SEPARATOR, [$this->locales, $f['lang'], $f['group'] . $f['ext']])); $done = true; } $zip->close(); @@ -258,7 +264,7 @@ class TranslaterModule { $backup = $this->getBackupRoot(true); - $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->id)), $file, $m); if (!file_exists($backup . '/' . $file) || !$is_backup @@ -301,7 +307,7 @@ class TranslaterModule $f = $this->parseZipFilename($file, true); if (!$this->translater->import_overwrite - && file_exists($this->prop['locales'] . '/' . $f['lang'] . '/' . $f['group'] . $f['ext']) + && file_exists(implode(DIRECTORY_SEPARATOR, [$this->locales, $f['lang'], $f['group'] . $f['ext']])) ) { $not_overwrited[] = implode('-', [$f['lang'], $f['group'], $f['ext']]); @@ -310,8 +316,8 @@ class TranslaterModule $res[] = [ 'from' => $file, - 'root' => $this->prop['locales'] . '/' . $f['lang'], - 'to' => $this->prop['locales'] . '/' . $f['lang'] . '/' . $f['group'] . $f['ext'], + 'root' => implode(DIRECTORY_SEPARATOR, [$this->locales, $f['lang']]), + 'to' => implode(DIRECTORY_SEPARATOR, [$this->locales, $f['lang'], $f['group'] . $f['ext']]), ]; } @@ -363,20 +369,20 @@ class TranslaterModule $res = []; foreach ($langs as $lang) { - if (!is_dir($this->prop['locales'] . '/' . $lang)) { + if (!is_dir($this->locales . DIRECTORY_SEPARATOR . $lang)) { continue; } - $files = Translater::scandir($this->prop['locales'] . '/' . $lang); + $files = Translater::scandir($this->locales . DIRECTORY_SEPARATOR . $lang); foreach ($files as $file) { - if (is_dir($this->prop['locales'] . '/' . $lang . '/' . $file) + if (is_dir(implode(DIRECTORY_SEPARATOR, [$this->locales, $lang, $file])) || !Translater::isLangphpFile($file) && !Translater::isPoFile($file) ) { continue; } - $res[$this->prop['locales'] . '/' . $lang . '/' . $file] = $this->prop['id'] . '/locales/' . $lang . '/' . $file; + $res[implode(DIRECTORY_SEPARATOR, [$this->locales, $lang, $file])] = implode(DIRECTORY_SEPARATOR, [$this->locales, $lang, $file]); } } @@ -395,7 +401,7 @@ class TranslaterModule $filename = files::tidyFileName(dt::str(str_replace( ['timestamp', 'module', 'type', 'version'], - [time(), $this->prop['id'], $this->prop['type'], $this->prop['version']], + [time(), $this->id, $this->type, $this->version], $this->translater->export_filename ))); @@ -418,7 +424,7 @@ class TranslaterModule $is_file = preg_match('/^(.*?)\/locales\/(.*?)\/(.*?)(.po|.lang.php)$/', $file, $f); if ($is_file) { - $module = $f[1] == $this->prop['id'] ? $f[1] : false; + $module = $f[1] == $this->id ? $f[1] : false; $lang = l10n::isCode($f[2]) ? $f[2] : false; $group = in_array($f[3], My::l10nGroupsCombo()) ? $f[3] : false; $ext = Translater::isLangphpFile($f[4]) || Translater::isPoFile($f[4]) ? $f[4] : false; @@ -456,9 +462,9 @@ class TranslaterModule { $res = []; - $prefix = preg_match('/(locales(.*))$/', $this->prop['locales']) ? 'locales' : ''; + $prefix = preg_match('/(locales(.*))$/', $this->locales) ? 'locales' : ''; - $files = Translater::scandir($this->prop['locales']); + $files = Translater::scandir($this->locales); foreach ($files as $file) { if (!preg_match('/.*?locales\/([^\/]*?)\/([^\/]*?)(.lang.php|.po)$/', $prefix . $file, $m)) { continue; @@ -522,7 +528,7 @@ class TranslaterModule )); } - files::makeDir($this->prop['locales'] . '/' . $lang, true); + files::makeDir($this->locales . DIRECTORY_SEPARATOR . $lang, true); if (!empty($from_lang) && !isset($langs[$from_lang])) { throw new Exception(sprintf( @@ -532,9 +538,9 @@ class TranslaterModule } if (!empty($from_lang) && isset($langs[$from_lang])) { - $files = Translater::scandir($this->prop['locales'] . '/' . $from_lang); + $files = Translater::scandir($this->locales . DIRECTORY_SEPARATOR . $from_lang); foreach ($files as $file) { - if (is_dir($this->prop['locales'] . '/' . $from_lang . '/' . $file) + if (is_dir(implode(DIRECTORY_SEPARATOR, [$this->locales, $from_lang, $file])) || !Translater::isLangphpFile($file) && !Translater::isPoFile($file) ) { @@ -542,8 +548,8 @@ class TranslaterModule } files::putContent( - $this->prop['locales'] . '/' . $lang . '/' . $file, - file_get_contents($this->prop['locales'] . '/' . $from_lang . '/' . $file) + implode(DIRECTORY_SEPARATOR, [$this->locales, $lang, $file]), + file_get_contents(implode(DIRECTORY_SEPARATOR, [$this->locales, $from_lang, $file])) ); } } else { @@ -594,8 +600,8 @@ class TranslaterModule continue; } - $po_file = $this->prop['locales'] . '/' . $lang . '/' . $group . '.po'; - $langphp_file = $this->prop['locales'] . '/' . $lang . '/' . $group . '.lang.php'; + $po_file = implode(DIRECTORY_SEPARATOR, [$this->locales, $lang, $group . '.po']); + $langphp_file = implode(DIRECTORY_SEPARATOR, [$this->locales, $lang, $group . '.lang.php']); if (file_exists($po_file)) { unlink($po_file); @@ -644,17 +650,17 @@ class TranslaterModule } foreach ($files[$lang] as $file) { - unlink($this->prop['locales'] . '/' . $file); + unlink($this->locales . DIRECTORY_SEPARATOR . $file); } - $dir = Translater::scandir($this->prop['locales'] . '/' . $lang); + $dir = Translater::scandir($this->locales . DIRECTORY_SEPARATOR . $lang); if (empty($dir)) { - rmdir($this->prop['locales'] . '/' . $lang); + rmdir($this->locales . DIRECTORY_SEPARATOR . $lang); } - $loc = Translater::scandir($this->prop['locales']); + $loc = Translater::scandir($this->locales); if (empty($loc)) { - rmdir($this->prop['locales']); + rmdir($this->locales); } return true; @@ -673,8 +679,8 @@ class TranslaterModule $content = ''; if ($this->translater->parse_comment) { - $content .= '# Language: ' . $lang->get('name') . "\n" . - '# Module: ' . $this->get('id') . ' - ' . $this->get('version') . "\n" . + $content .= '# Language: ' . $lang->name . "\n" . + '# Module: ' . $this->id . ' - ' . $this->version . "\n" . '# Date: ' . dt::str('%Y-%m-%d %H:%M:%S') . "\n"; if ($this->translater->parse_user && $this->translater->parse_userinfo != '') { @@ -693,7 +699,7 @@ class TranslaterModule $content .= "msgid \"\"\n" . "msgstr \"\"\n" . '"Content-Type: text/plain; charset=UTF-8\n"' . "\n" . - '"Project-Id-Version: ' . $this->get('id') . ' ' . $this->get('version') . '\n"' . "\n" . + '"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" . @@ -730,7 +736,7 @@ class TranslaterModule $content .= "\n"; } - $file = $this->get('locales') . '/' . $lang->get('code') . '/' . $group . '.po'; + $file = implode(DIRECTORY_SEPARATOR, [$this->locales, $lang->code, $group . '.po']); $path = path::info($file); if (is_dir($path['dirname']) && !is_writable($path['dirname']) || file_exists($file) && !is_writable($file)) { @@ -765,8 +771,8 @@ class TranslaterModule $content = ''; if ($this->translater->parse_comment) { - $content .= '// Language: ' . $lang->get('name') . "\n" . - '// Module: ' . $this->get('id') . ' - ' . $this->get('verison') . "\n" . + $content .= '// Language: ' . $lang->name . "\n" . + '// Module: ' . $this->id . ' - ' . $this->version . "\n" . '// Date: ' . dt::str('%Y-%m-%d %H:%M:%S') . "\n"; if ($this->translater->parse_user && !empty($this->translater->parse_userinfo)) { @@ -783,7 +789,7 @@ class TranslaterModule $content .= '// Translated with Translater - ' . dcCore::app()->plugins->moduleInfo(My::id(), 'version') . "\n\n"; } - l10n::generatePhpFileFromPo($this->get('locales') . '/' . $lang->get('code') . '/' . $group, $content); + l10n::generatePhpFileFromPo(implode(DIRECTORY_SEPARATOR, [$this->locales, $lang->code, $group]), $content); } //@} }