mirror of
https://github.com/processwire/processwire.git
synced 2025-08-11 17:24:46 +02:00
Add @LostKobrakai PR #52 - Implement a way for modules to supply translations, plus some related updates
Co-authored-by: LostKobrakai <benni@kobrakai.de>
This commit is contained in:
@@ -4974,9 +4974,9 @@ class Modules extends WireArray {
|
||||
if(!in_array($id, $this->moduleIDs)) unset($this->modulesLastVersions[$id]);
|
||||
}
|
||||
if(count($this->modulesLastVersions)) {
|
||||
$this->wire('cache')->save(self::moduleLastVersionsCacheName, $this->modulesLastVersions, WireCache::expireReserved);
|
||||
$this->wire()->cache->save(self::moduleLastVersionsCacheName, $this->modulesLastVersions, WireCache::expireReserved);
|
||||
} else {
|
||||
$this->wire('cache')->delete(self::moduleLastVersionsCacheName);
|
||||
$this->wire()->cache->delete(self::moduleLastVersionsCacheName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5355,6 +5355,48 @@ class Modules extends WireArray {
|
||||
return $cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get module language translation files
|
||||
*
|
||||
* @param Module|string $module
|
||||
* @return array Array of translation files including full path, indexed by basename without extension
|
||||
* @since 3.0.181
|
||||
*
|
||||
*/
|
||||
public function getModuleLanguageFiles($module) {
|
||||
|
||||
$module = $this->getModuleClass($module);
|
||||
if(empty($module)) return array();
|
||||
|
||||
$path = $this->wire()->config->paths($module);
|
||||
if(empty($path)) return array();
|
||||
|
||||
$pathHidden = $path . '.languages/';
|
||||
$pathVisible = $path . 'languages/';
|
||||
|
||||
if(is_dir($pathVisible)) {
|
||||
$path = $pathVisible;
|
||||
} else if(is_dir($pathHidden)) {
|
||||
$path = $pathHidden;
|
||||
} else {
|
||||
return array();
|
||||
}
|
||||
|
||||
$items = array();
|
||||
$options = array(
|
||||
'extensions' => array('csv'),
|
||||
'recursive' => false,
|
||||
'excludeHidden' => true,
|
||||
);
|
||||
|
||||
foreach($this->wire()->files->find($path, $options) as $file) {
|
||||
$basename = basename($file, '.csv');
|
||||
$items[$basename] = $file;
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables use of $modules('ModuleName')
|
||||
*
|
||||
|
@@ -170,7 +170,23 @@ class LanguageTranslator extends Wire {
|
||||
} else {
|
||||
|
||||
$reflection = new \ReflectionClass($o);
|
||||
$filename = $reflection->getFileName();
|
||||
$filename = $reflection->getFileName();
|
||||
|
||||
if($o instanceof Module) {
|
||||
$ds = \DIRECTORY_SEPARATOR;
|
||||
if(strpos($filename, "{$ds}wire{$ds}modules{$ds}") === false) {
|
||||
// not a core module
|
||||
$config = $this->wire()->config;
|
||||
$filename = $this->wire()->files->unixFileName($filename);
|
||||
if(strpos($filename, $config->urls($o)) === false && strpos($filename, "/$class/") !== false) {
|
||||
// module likely in a symbolic link directory, so determine our own path for textdomain
|
||||
// rather than using the one provided by ReflectionClass
|
||||
list(, $filename) = explode("/$class/", $filename, 2);
|
||||
$filename = $config->paths($class) . $filename;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$textdomain = $this->filenameToTextdomain($filename);
|
||||
$this->classNamesToTextdomains[$class] = $textdomain;
|
||||
$parentTextdomains = array();
|
||||
@@ -286,7 +302,7 @@ class LanguageTranslator extends Wire {
|
||||
*
|
||||
*/
|
||||
public function getTranslation($textdomain, $text, $context = '') {
|
||||
if($this->wire('hooks')->isHooked('LanguageTranslator::getTranslation()')) {
|
||||
if($this->wire()->hooks->isHooked('LanguageTranslator::getTranslation()')) {
|
||||
// if method has hooks, we let them run
|
||||
return $this->__call('getTranslation', array($textdomain, $text, $context));
|
||||
} else {
|
||||
@@ -474,7 +490,7 @@ class LanguageTranslator extends Wire {
|
||||
*/
|
||||
public function textdomainFileExists($textdomain) {
|
||||
$file = $this->getTextdomainTranslationFile($textdomain);
|
||||
return is_file($file);
|
||||
return file_exists($file);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -767,6 +767,27 @@ class Languages extends PagesType {
|
||||
public function get($key) {
|
||||
return parent::get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Import a language translations file
|
||||
*
|
||||
* @param Language|string $language
|
||||
* @param string $file Full path to .csv translations file
|
||||
* The .csv file must be one generated by ProcessWire’s language translation tools.
|
||||
* @param bool $quiet Specify true to suppress error/success notifications being generated (default=false)
|
||||
* @return bool|int Returns integer with number of translations imported or boolean false on error
|
||||
* @throws WireException
|
||||
* @since 3.0.181
|
||||
*
|
||||
*/
|
||||
public function importTranslationsFile($language, $file, $quiet = false) {
|
||||
if(!wireInstanceOf($language, 'Language')) $language = $this->get($language);
|
||||
if(!$language || !$language->id) throw new WireException("Unknown language");
|
||||
$process = $this->wire()->modules->getModule('ProcessLanguage', array('noInit' => true)); /** @var ProcessLanguage $process */
|
||||
if(!$this->wire()->files->exists($file)) throw new WireException("Language file does not exist: $file");
|
||||
if(pathinfo($file, PATHINFO_EXTENSION) !== 'csv') throw new WireException("Language file does not have .csv extension");
|
||||
return $process->processCSV($file, $language, array('quiet' => $quiet));
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to WireDatabasePDO::unknownColumnError
|
||||
|
@@ -8,14 +8,16 @@
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.Inputfields .InputfieldFile .InputfieldFileLanguageInfo {
|
||||
|
||||
.AdminThemeReno .Inputfields .InputfieldFile .InputfieldFileLanguageInfo,
|
||||
.AdminThemeDefault .Inputfields .InputfieldFile .InputfieldFileLanguageInfo {
|
||||
position: relative;
|
||||
margin-top: 0;
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.InputfieldFileList .InputfieldFileLanguageInfo {
|
||||
margin-top: -1em;
|
||||
.Inputfields .InputfieldFile a.action:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.InputfieldFileList .InputfieldFileLanguageInfo a i.hover-only {
|
||||
|
@@ -253,9 +253,9 @@ class ProcessLanguage extends ProcessPageType {
|
||||
|
||||
$out =
|
||||
"<div class='InputfieldFileData InputfieldFileLanguageInfo'>" .
|
||||
"<span class='InputfieldFileLanguageFilename description'>/$file —</span> <span class='notes'>$message</span> " .
|
||||
"<a class='action' href='{$translationUrl}edit/?language_id={$page->id}&textdomain=$textdomain'> " .
|
||||
"<i class='fa fa-edit'></i> $editLabel <i class='fa fa-angle-double-right hover-only'></i></a>" .
|
||||
"<span class='InputfieldFileLanguageFilename description'>/$file —</span> <span class='notes'>$message</span> " .
|
||||
"<a class='action' href='{$translationUrl}edit/?language_id={$page->id}&textdomain=$textdomain'> " .
|
||||
"<i class='fa fa-edit'></i> $editLabel <i class='fa fa-angle-double-right hover-only'></i></a>" .
|
||||
"</div>";
|
||||
|
||||
$page->translator->unloadTextdomain($textdomain);
|
||||
@@ -347,27 +347,62 @@ class ProcessLanguage extends ProcessPageType {
|
||||
*/
|
||||
public function ___executeDownload() {
|
||||
|
||||
$id = (int) $this->input->get('language_id');
|
||||
$config = $this->wire()->config;
|
||||
$input = $this->wire()->input;
|
||||
|
||||
$id = (int) $input->get('language_id');
|
||||
if(!$id) throw new WireException("No language specified");
|
||||
|
||||
$language = $this->wire('languages')->get($id);
|
||||
$language = $this->wire()->languages->get($id);
|
||||
if(!$language->id) throw new WireException("Unknown language");
|
||||
|
||||
$fieldName = $this->input->get('field') == 'language_files_site' ? 'language_files_site' : 'language_files';
|
||||
$csv = (int) $this->wire('input')->get('csv');
|
||||
$fieldName = $input->get('field') == 'language_files_site' ? 'language_files_site' : 'language_files';
|
||||
$textdomain = $this->wire()->sanitizer->textdomain($input->get('textdomain'));
|
||||
$textdomains = array();
|
||||
$csv = (int) $input->get('csv');
|
||||
$path = $language->$fieldName->path();
|
||||
$files = array();
|
||||
|
||||
foreach($language->$fieldName as $file) {
|
||||
$files[] = $file->filename;
|
||||
if($textdomain) {
|
||||
$file = $language->translator->textdomainToFilename($textdomain);
|
||||
if($file) {
|
||||
$files[] = $file;
|
||||
$textdomains[$file] = $textdomain;
|
||||
} else {
|
||||
$textdomain = '';
|
||||
}
|
||||
}
|
||||
|
||||
if(!count($files) && $fieldName) {
|
||||
foreach($language->$fieldName as $file) {
|
||||
$files[] = $file->filename;
|
||||
}
|
||||
}
|
||||
|
||||
if(!count($files)) {
|
||||
throw new WireException('No translation files specified to download');
|
||||
}
|
||||
|
||||
if($csv) {
|
||||
// CSV
|
||||
$filename = $language->name . "-" . (strpos($fieldName, 'site') ? 'site' : 'wire') . ".csv";
|
||||
header("Content-type: application/force-download");
|
||||
header("Content-Transfer-Encoding: Binary");
|
||||
header("Content-disposition: attachment; filename=$filename");
|
||||
if($textdomain) {
|
||||
// i.e. es-modulename.csv
|
||||
$parts = explode('--', $textdomain);
|
||||
$basename = array_pop($parts);
|
||||
$parts = explode('-', $basename);
|
||||
$basename = array_shift($parts);
|
||||
$filename = "$language->name-$basename.csv";
|
||||
} else {
|
||||
// i.e. es-site.csv or es-wire.csv
|
||||
$filename = $language->name . "-" . (strpos($fieldName, 'site') ? 'site' : 'wire') . ".csv";
|
||||
}
|
||||
if($input->get('view')) {
|
||||
header("Content-type: text/plain");
|
||||
} else {
|
||||
header("Content-type: application/force-download");
|
||||
header("Content-Transfer-Encoding: Binary");
|
||||
header("Content-disposition: attachment; filename=$filename");
|
||||
}
|
||||
|
||||
$fp = fopen('php://output', 'w');
|
||||
$defaultCol = $language->name == 'en' ? 'default' : 'en';
|
||||
@@ -375,13 +410,20 @@ class ProcessLanguage extends ProcessPageType {
|
||||
fputcsv($fp, $fields);
|
||||
|
||||
foreach($files as $f) {
|
||||
|
||||
if(isset($textdomains[$f])) {
|
||||
$textdomain = $textdomains[$f];
|
||||
} else {
|
||||
$textdomain = basename($f, '.json');
|
||||
}
|
||||
|
||||
$textdomain = basename($f, '.json');
|
||||
$data = $language->translator->getTextdomain($textdomain);
|
||||
if(empty($data)) continue;
|
||||
|
||||
$file = $data['file'];
|
||||
$pathname = $this->wire('config')->paths->root . $file;
|
||||
$pathname = $config->paths->root . $file;
|
||||
$translated =& $data['translations'];
|
||||
$parser = $this->wire(new LanguageParser($language->translator, $pathname));
|
||||
$parser = $this->wire(new LanguageParser($language->translator, $pathname)); /** @var LanguageParser $parser */
|
||||
$untranslated = $parser->getUntranslated();
|
||||
$comments = $parser->getComments();
|
||||
|
||||
@@ -420,16 +462,26 @@ class ProcessLanguage extends ProcessPageType {
|
||||
*
|
||||
* @param string $csvFile
|
||||
* @param Language $language
|
||||
* @return bool
|
||||
* @param array $options Additional options (3.0.181+)
|
||||
* - `file` (string): Use this path/file (relative to install root)
|
||||
* - `quiet` (bool): Suppress generating notifications? (default=false)
|
||||
* @return bool|int Returns false on error or integer on success, where value is number of translations imported
|
||||
* @throws WireException
|
||||
*
|
||||
*/
|
||||
public function processCSV($csvFile, Language $language) {
|
||||
public function processCSV($csvFile, Language $language, array $options = array()) {
|
||||
|
||||
$defaults = array(
|
||||
'file' => '',
|
||||
'quiet' => false,
|
||||
);
|
||||
|
||||
$options = array_merge($defaults, $options);
|
||||
|
||||
$fp = fopen($csvFile, "r");
|
||||
|
||||
if($fp === false) {
|
||||
$this->error($this->csvImportLabel . "Unable to open: $csvFile");
|
||||
if(!$options['quiet']) $this->error($this->csvImportLabel . "Unable to open: $csvFile");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -450,8 +502,16 @@ class ProcessLanguage extends ProcessPageType {
|
||||
$numTotal = 0;
|
||||
$numGross = 0;
|
||||
$translations = null;
|
||||
$optionsFileBasename = '';
|
||||
$halt = false;
|
||||
|
||||
$this->wire($translator);
|
||||
|
||||
if(!empty($options['file'])) {
|
||||
$options['file'] = ltrim($this->wire()->files->unixFileName($options['file']), '/');
|
||||
$optionsFileBasename = basename($options['file']);
|
||||
}
|
||||
|
||||
while(($csvData = fgetcsv($fp, 8192, ",")) !== FALSE) {
|
||||
|
||||
if(++$n === 1) {
|
||||
@@ -463,13 +523,16 @@ class ProcessLanguage extends ProcessPageType {
|
||||
// make sure everything we need is present
|
||||
foreach($keys as $k => $key) {
|
||||
if($k > 1 && !in_array($key, $header)) {
|
||||
$this->error($this->csvImportLabel . "CSV data missing required column '$key'");
|
||||
$halt = true;
|
||||
if($key === 'file' && !empty($options['file'])) {
|
||||
// default file provided so not required in CSV data
|
||||
} else {
|
||||
if(!$options['quiet']) $this->error($this->csvImportLabel . "CSV data missing required column '$key'");
|
||||
$halt = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if($halt) break;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
$row = array();
|
||||
@@ -479,7 +542,22 @@ class ProcessLanguage extends ProcessPageType {
|
||||
$row[$name] = $csvData[$key];
|
||||
}
|
||||
|
||||
if(empty($row['file']) || empty($row['original'])) continue;
|
||||
if($options['file']) {
|
||||
if(empty($row['file'])) {
|
||||
$row['file'] = $options['file'];
|
||||
} else {
|
||||
$rowFileBasename = basename($row['file']);
|
||||
if($rowFileBasename === $optionsFileBasename) {
|
||||
// i.e. site/modules/Hello/Hello.module
|
||||
$row['file'] = $options['file'];
|
||||
} else {
|
||||
// i.e. site/modules/Hello/World.module
|
||||
$row['file'] = dirname($options['file']) . '/' . $rowFileBasename;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($row['original']) || empty($row['file'])) continue;
|
||||
|
||||
$file = $row['file'];
|
||||
$hash = $row['hash'];
|
||||
@@ -489,17 +567,17 @@ class ProcessLanguage extends ProcessPageType {
|
||||
|
||||
if(!$translator->textdomainFileExists($textdomain)) {
|
||||
$textdomain = $translator->addFileToTranslate($file, false, false);
|
||||
//$translator->loadTextdomain($textdomain);
|
||||
}
|
||||
|
||||
if(is_null($translations)) $translations = $translator->getTranslations($textdomain);
|
||||
if(is_null($translations)) {
|
||||
$translations = $translator->getTranslations($textdomain);
|
||||
}
|
||||
|
||||
if(!$textdomain) {
|
||||
$this->warning($this->csvImportLabel . sprintf(
|
||||
$this->_('Unrecognized textdomain for file: %s'),
|
||||
$this->wire('sanitizer')->entities($file)
|
||||
)
|
||||
);
|
||||
if(!$options['quiet']) $this->warning($this->csvImportLabel . sprintf(
|
||||
$this->_('Unrecognized textdomain for file: %s'),
|
||||
$this->wire()->sanitizer->entities($file)
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -529,9 +607,11 @@ class ProcessLanguage extends ProcessPageType {
|
||||
$language->save();
|
||||
|
||||
fclose($fp);
|
||||
$this->message($this->csvImportLabel . sprintf($this->_('%d total translations, %d total changes'), $numGross, $numTotal));
|
||||
if(!$options['quiet']) {
|
||||
$this->message($this->csvImportLabel . sprintf($this->_('%d total translations, %d total changes'), $numGross, $numTotal), Notice::noGroup);
|
||||
}
|
||||
|
||||
return $halt ? false : true;
|
||||
return $halt ? false : $numGross;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -549,7 +629,7 @@ class ProcessLanguage extends ProcessPageType {
|
||||
if($numChanges) {
|
||||
try {
|
||||
$translator->saveTextdomain($textdomain);
|
||||
$this->message($this->csvImportLabel . sprintf($this->_('Saved %d change(s) for file: %s'), $numChanges, $file));
|
||||
$this->message($this->csvImportLabel . sprintf($this->_('Saved %d change(s) for file: %s'), $numChanges, $file), Notice::noGroup);
|
||||
} catch(\Exception $e) {
|
||||
$this->error($e->getMessage());
|
||||
}
|
||||
|
@@ -139,6 +139,7 @@ class ProcessModule extends Process {
|
||||
$this->labels['download_install'] = $this->_('Download and Install');
|
||||
}
|
||||
$this->labels['get_module_info'] = $this->_('Get Module Info');
|
||||
$this->labels['modules'] = $this->_('Modules');
|
||||
$this->labels['module_information'] = $this->_x("Module Information", 'edit');
|
||||
$this->labels['download_now'] = $this->_('Download Now');
|
||||
$this->labels['download_dir'] = $this->_('Add Module From Directory');
|
||||
@@ -197,7 +198,17 @@ class ProcessModule extends Process {
|
||||
*
|
||||
*/
|
||||
public function ___executeNavJSON(array $options = array()) {
|
||||
$page = $this->wire('page');
|
||||
|
||||
$page = $this->wire()->page;
|
||||
$input = $this->wire()->input;
|
||||
$modules = $this->wire()->modules;
|
||||
|
||||
$site = (int) $input->get('site');
|
||||
$core = (int) $input->get('core');
|
||||
$configurable = (int) $input->get('configurable');
|
||||
$install = (int) $input->get('install');
|
||||
$moduleNames = array();
|
||||
|
||||
$data = array(
|
||||
'url' => $page->url,
|
||||
'label' => (string) $page->get('title|name'),
|
||||
@@ -205,36 +216,32 @@ class ProcessModule extends Process {
|
||||
'list' => array(),
|
||||
);
|
||||
|
||||
$site = $this->wire('input')->get('site');
|
||||
$core = $this->wire('input')->get('core');
|
||||
$configurable = $this->wire('input')->get('configurable');
|
||||
$install = $this->wire('input')->get('install');
|
||||
|
||||
if($site || $install) $data['add'] = array(
|
||||
'url' => "?new#tab_new_modules",
|
||||
'label' => __('Add New', '/wire/templates-admin/default.php'),
|
||||
'icon' => 'plus-circle',
|
||||
);
|
||||
|
||||
$modules = $this->wire('modules');
|
||||
$moduleNames = array();
|
||||
if($install) {
|
||||
$moduleNames = array_keys($modules->getInstallable());
|
||||
} else {
|
||||
foreach($modules as $module) $moduleNames[] = $module->className();
|
||||
foreach($modules as $module) {
|
||||
$moduleNames[] = $module->className();
|
||||
}
|
||||
}
|
||||
|
||||
sort($moduleNames);
|
||||
|
||||
foreach($moduleNames as $moduleName) {
|
||||
|
||||
$info = $this->wire('modules')->getModuleInfoVerbose($moduleName);
|
||||
$info = $modules->getModuleInfoVerbose($moduleName);
|
||||
|
||||
if($site && $info['core']) continue;
|
||||
if($core && !$info['core']) continue;
|
||||
|
||||
if($configurable) {
|
||||
if(!$info['configurable'] || !$info['installed']) continue;
|
||||
$flags = $this->wire('modules')->getFlags($moduleName);
|
||||
$flags = $modules->getFlags($moduleName);
|
||||
if($flags & Modules::flagsNoUserConfig) continue;
|
||||
}
|
||||
|
||||
@@ -242,7 +249,7 @@ class ProcessModule extends Process {
|
||||
// exclude already installed modules
|
||||
if($info['installed']) continue;
|
||||
// check that it can be installed NOW (i.e. all dependencies met)
|
||||
if(!$this->wire('modules')->isInstallable($moduleName, true)) continue;
|
||||
if(!$modules->isInstallable($moduleName, true)) continue;
|
||||
}
|
||||
|
||||
$label = $info['name'];
|
||||
@@ -264,7 +271,8 @@ class ProcessModule extends Process {
|
||||
ksort($data['list']);
|
||||
$data['list'] = array_values($data['list']);
|
||||
|
||||
if($this->wire('config')->ajax) header("Content-Type: application/json");
|
||||
if($this->wire()->config->ajax) header("Content-Type: application/json");
|
||||
|
||||
return json_encode($data);
|
||||
}
|
||||
|
||||
@@ -863,6 +871,12 @@ class ProcessModule extends Process {
|
||||
$summary .= "<span class='notes requires'>" . $this->labels['requires'] . " - " . implode(', ', $requires) . "</span>";
|
||||
}
|
||||
} else $requires = array();
|
||||
|
||||
$nsClassName = $modules->getModuleClass($name, true);
|
||||
if(!wireInstanceOf($nsClassName, 'Module')) {
|
||||
$summary .= "<span class='notes requires'>" . $this->_('Module class must implement the “ProcessWire\Module” interface.') . "</span>";
|
||||
$requires[] = 'Module interface';
|
||||
}
|
||||
|
||||
if(count($info['installs'])) {
|
||||
$summary .= "<span class='detail installs'>" . $this->labels['installs'] . " - " . implode(', ', $info['installs']) . "</span>";
|
||||
@@ -1697,6 +1711,13 @@ class ProcessModule extends Process {
|
||||
if($hooksStr) {
|
||||
$table->row(array($this->_x('Hooks To', 'edit'), $hooksStr));
|
||||
}
|
||||
|
||||
$languageFiles = $languages ? $modules->getModuleLanguageFiles($moduleName) : array();
|
||||
if(count($languageFiles)) {
|
||||
$languages = wireIconMarkup('language') . ' ' . $sanitizer->entities(implode(', ', array_keys($languageFiles)));
|
||||
$languages .= " - <a href='{$config->urls->admin}module/translation/?name=$moduleName'>" . $this->_('install translations') . "</a>";
|
||||
$table->row(array($this->_x('Languages', 'edit'), $languages));
|
||||
}
|
||||
|
||||
if(!empty($moduleInfo['href'])) {
|
||||
$table->row(array($this->_x('More Information', 'edit'), "<a target='_blank' class='label' href='$moduleInfo[href]'>$moduleInfo[href]</a>"));
|
||||
@@ -1750,10 +1771,9 @@ class ProcessModule extends Process {
|
||||
|
||||
public function ___executeInstallConfirm() {
|
||||
|
||||
$name = $this->wire('input')->get('name');
|
||||
$name = $this->wire('input')->get->name('name');
|
||||
if(!$name) throw new WireException("No module name specified");
|
||||
$name = $this->wire('sanitizer')->fieldName($name);
|
||||
if(!$this->wire('modules')->isInstallable($name, true)) throw new WireException("Module is not currently installable");
|
||||
if(!$this->wire()->modules->isInstallable($name, true)) throw new WireException("Module is not currently installable");
|
||||
|
||||
$this->headline($this->labels['install']);
|
||||
|
||||
@@ -1778,6 +1798,84 @@ class ProcessModule extends Process {
|
||||
return $form->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Languages translations import
|
||||
*
|
||||
* @return string
|
||||
* @since 3.0.181
|
||||
*
|
||||
*/
|
||||
public function ___executeTranslation() {
|
||||
|
||||
$languages = $this->wire()->languages;
|
||||
$modules = $this->wire()->modules;
|
||||
$session = $this->wire()->session;
|
||||
$input = $this->wire()->input;
|
||||
$config = $this->wire()->config;
|
||||
$moduleName = $input->get->name('name');
|
||||
|
||||
if(empty($moduleName)) throw new WireException('No module name specified');
|
||||
if(!$modules->isInstalled($moduleName)) throw new WireException("Unknown module: $moduleName");
|
||||
|
||||
$moduleEditUrl = $modules->getModuleEditUrl($moduleName);
|
||||
$languageFiles = $modules->getModuleLanguageFiles($moduleName);
|
||||
|
||||
if(!$languages || !count($languageFiles)){
|
||||
$session->message($this->_('No module language files available'));
|
||||
$session->location($moduleEditUrl);
|
||||
}
|
||||
|
||||
$this->headline($this->_('Module language translations'));
|
||||
$this->breadcrumb($config->urls->admin . 'modules/', $this->labels['modules']);
|
||||
$this->breadcrumb($moduleEditUrl, $moduleName);
|
||||
|
||||
/** @var InputfieldForm $form */
|
||||
$form = $modules->get('InputfieldForm');
|
||||
$form->attr('id', 'ModuleImportTranslationForm');
|
||||
$form->attr('action', $config->urls->admin . "module/translation/?name=$moduleName");
|
||||
$form->attr('method', 'post');
|
||||
$form->description = sprintf($this->_('Import translations for module %s'), $moduleName);
|
||||
|
||||
foreach($languages as $language) {
|
||||
/** @var InputfieldSelect $lang */
|
||||
$langLabel = $language->get('title');
|
||||
$langLabel .= $langLabel ? " ($language->name)" : $language->name;
|
||||
|
||||
/** @var InputfieldSelect $f */
|
||||
$f = $modules->get('InputfieldSelect');
|
||||
$f->attr('name', "language_$language->name");
|
||||
$f->label = sprintf($this->_('Import into %s'), $langLabel);
|
||||
$f->addOption('');
|
||||
foreach($languageFiles as $basename => $filename) {
|
||||
$f->addOption($basename);
|
||||
}
|
||||
$form->append($f);
|
||||
}
|
||||
|
||||
if($input->post('submit_import_translations')) {
|
||||
foreach($languages as $language) {
|
||||
$basename = $input->post->pageName("language_$language->name");
|
||||
if(empty($basename)) continue;
|
||||
if(empty($languageFiles[$basename])) continue;
|
||||
$file = $languageFiles[$basename];
|
||||
if(!is_file($file)) {
|
||||
$session->error($this->_('Cannot find CSV file') . " - " . basename($file));
|
||||
continue;
|
||||
}
|
||||
$languages->importTranslationsFile($language, $file);
|
||||
}
|
||||
$session->location($moduleEditUrl);
|
||||
}
|
||||
|
||||
/** @var InputfieldSubmit $f */
|
||||
$f = $modules->get('InputfieldSubmit');
|
||||
$f->attr('name', 'submit_import_translations');
|
||||
$f->showInHeader(true);
|
||||
$form->add($f);
|
||||
|
||||
return $form->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to redirect to after non-authenticated user is logged-in, or false if module does not support
|
||||
*
|
||||
|
Reference in New Issue
Block a user