summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2016-05-09 18:07:50 +0200
committerSimon Rettberg2016-05-09 18:07:50 +0200
commitfca3b58e5b5a9821f99bfafb833a3cf85c9478d9 (patch)
tree2290edcfc1d3d0432476b6fbceb26d9ab82711da
parentWork on translations: templates and messages work (diff)
downloadslx-admin-fca3b58e5b5a9821f99bfafb833a3cf85c9478d9.tar.gz
slx-admin-fca3b58e5b5a9821f99bfafb833a3cf85c9478d9.tar.xz
slx-admin-fca3b58e5b5a9821f99bfafb833a3cf85c9478d9.zip
Message string editing works now
-rw-r--r--inc/dictionary.inc.php16
-rw-r--r--modules-available/backup/lang/en/template-tags.json1
-rw-r--r--modules-available/translation/lang/de/template-tags.json19
-rw-r--r--modules-available/translation/lang/en/template-tags.json13
-rw-r--r--modules-available/translation/page.inc.php397
-rw-r--r--modules-available/translation/templates/_page.html1
-rw-r--r--modules-available/translation/templates/edit.html23
-rw-r--r--modules-available/translation/templates/message-list.html30
-rw-r--r--modules-available/translation/templates/module-heading.html1
-rw-r--r--modules-available/translation/templates/template-list.html2
-rw-r--r--style/default.css1
11 files changed, 303 insertions, 201 deletions
diff --git a/inc/dictionary.inc.php b/inc/dictionary.inc.php
index c139c8bf..72139601 100644
--- a/inc/dictionary.inc.php
+++ b/inc/dictionary.inc.php
@@ -118,8 +118,9 @@ class Dictionary
self::$languagesLong = array();
foreach (self::$languages as $lang) {
if (file_exists("lang/$lang/name.txt")) {
- $name = @file_get_contents("lang/$lang/name.txt");
- } else {
+ $name = file_get_contents("lang/$lang/name.txt");
+ }
+ if (!isset($name) || $name === false) {
$name = $lang;
}
self::$languagesLong[] = array(
@@ -130,6 +131,17 @@ class Dictionary
}
return self::$languagesLong;
}
+
+ public static function getLanguageName($langCC)
+ {
+ if (file_exists("lang/$langCC/name.txt")) {
+ $name = file_get_contents("lang/$langCC/name.txt");
+ }
+ if (!isset($name) || $name === false) {
+ $name = $langCC;
+ }
+ return $name;
+ }
}
diff --git a/modules-available/backup/lang/en/template-tags.json b/modules-available/backup/lang/en/template-tags.json
index 713f3d5e..cb8aced2 100644
--- a/modules-available/backup/lang/en/template-tags.json
+++ b/modules-available/backup/lang/en/template-tags.json
@@ -5,7 +5,6 @@
"lang_browseForFile": "Browse",
"lang_download": "Download",
"lang_dozmodExplanation": "This restores all the virtual machine and lecture meta data created using the \"Dozentenmodul\". Please make sure the VM-storage configured still contains all the VM-Images associated with the virtual machines. If the location of the storage changed, make sure the relative pathes on the share are still the same, otherwise the virtual machines won't be usable.",
- "lang_file": "File",
"lang_reboot": "System reboot",
"lang_restore": "Upload",
"lang_restoreConfig": "Restore config",
diff --git a/modules-available/translation/lang/de/template-tags.json b/modules-available/translation/lang/de/template-tags.json
index 60af942b..f84bb0af 100644
--- a/modules-available/translation/lang/de/template-tags.json
+++ b/modules-available/translation/lang/de/template-tags.json
@@ -1,20 +1,25 @@
{
"lang_adminInfo": "Dies ist eine Liste aller Templates. Die \"Status\"-Spalte zeigt an, wenn f\u00fcr ein Template \u00fcbersetzungen fehlen, oder veraltete Tags definiert sind.",
- "lang_back": "Z\u00fcruck",
- "lang_createTag": "TAG schafen",
+ "lang_back": "Zur\u00fcck",
+ "lang_createTag": "Tag erstellen",
"lang_deleteTAG": "L\u00f6schen",
"lang_editConfigModule": "Konfigurationsmodulbezeichnungsphrasen editieren",
"lang_editHardcoded": "Hardcoded-Texte bearbeiten",
"lang_editMessages": "Nachrichten bearbeiten",
+ "lang_editModules": "Modul bearbeiten",
"lang_editSettings": "Einstellungstexte bearbeiten",
"lang_editTemplates": "Template-Texte bearbeiten",
- "lang_englishTAG": "Englisch TAG",
- "lang_germanTAG": "Deutsch TAG",
"lang_langAdministration": "Templates",
- "lang_newTAG": "Neue Tag",
- "lang_portugueseTAG": "Portugiesisch TAG",
+ "lang_missing": "Fehlt",
+ "lang_module": "Modul",
+ "lang_sample": "Beispiel",
"lang_save": "Speichern",
"lang_status": "Status",
+ "lang_tag": "Tag",
+ "lang_tags": "Tags",
"lang_templateAdminHelp": "Hier k\u00f6nnen Sie die verwendeten Texte und S\u00e4tze \u00fcbersetzen.",
- "lang_templateHint": "Hinweis: Gelbe Linie zeigt eine \u00dcbersetzung fehlt und roten Linien zeigen ein Tag wird nicht von das Template verwendet."
+ "lang_templateHint": "Hinweis: Gelbe Linie zeigt eine \u00dcbersetzung fehlt und roten Linien zeigen ein Tag wird nicht von das Template verwendet.",
+ "lang_templates": "Templates",
+ "lang_translation": "\u00dcbersetzung",
+ "lang_unused": "Ungenutzt"
} \ No newline at end of file
diff --git a/modules-available/translation/lang/en/template-tags.json b/modules-available/translation/lang/en/template-tags.json
index f9c6b3ba..48389f9b 100644
--- a/modules-available/translation/lang/en/template-tags.json
+++ b/modules-available/translation/lang/en/template-tags.json
@@ -9,14 +9,17 @@
"lang_editModules": "Edit Module Translations",
"lang_editSettings": "Edit configuration variables related strings",
"lang_editTemplates": "Edit template strings",
- "lang_englishTAG": "English TAG",
- "lang_germanTAG": "German TAG",
"lang_langAdministration": "Templates",
+ "lang_missing": "Missing",
"lang_module": "Module",
- "lang_newTAG": "New TAG",
- "lang_portugueseTAG": "Portuguese TAG",
+ "lang_sample": "Sample",
"lang_save": "Save",
"lang_status": "Status",
+ "lang_tag": "Tag",
+ "lang_tags": "Tags",
"lang_templateAdminHelp": "Here you can translate and edit phrases and texts.",
- "lang_templateHint": "Hint: Yellow lines indicate a translation is missing and red lines indicate a tag is not being used by the template."
+ "lang_templateHint": "Hint: Yellow lines indicate a translation is missing and red lines indicate a tag is not being used by the template.",
+ "lang_templates": "Templates",
+ "lang_translation": "Translation",
+ "lang_unused": "Unused"
} \ No newline at end of file
diff --git a/modules-available/translation/page.inc.php b/modules-available/translation/page.inc.php
index 789500c5..674756a2 100644
--- a/modules-available/translation/page.inc.php
+++ b/modules-available/translation/page.inc.php
@@ -59,6 +59,23 @@ class Page_Translation extends Page
require $path;
return $HANDLER;
}
+
+ /**
+ * Redirect to the closest matching page, as extracted from
+ * get/post parameters.
+ */
+ private function redirect($level = 99)
+ {
+ $params = array('do' => 'translation');
+ if ($level > 0 && $this->module !== false) {
+ $params['module'] = $this->module->getIdentifier();
+ }
+ if ($level > 1 && $this->section !== false && $this->destLang !== false && in_array($this->destLang, Dictionary::getLanguages())) {
+ $params['section'] = $this->section;
+ $params['destlang'] = $this->destLang;
+ }
+ Util::redirect('?' . http_build_query($params));
+ }
protected function doPreprocess()
{
@@ -76,26 +93,24 @@ class Page_Translation extends Page
$this->module = Module::get($moduleName, true);
if ($this->module === false) {
Message::addError('main.no-such-module', $moduleName);
- Util::redirect('?do=Translation');
+ $this->redirect();
} elseif ($this->module->hasMissingDependencies()) {
Message::addError('main.module-missing-deps', $moduleName);
- Util::redirect('?do=Translation');
+ $this->redirect();
}
$this->customHandler = $this->loadCustomHandler($moduleName);
}
- // Section
- $sectionName = Request::any('section', false, 'string');
- if ($sectionName !== false) {
- if (!$this->isValidSection($sectionName)) {
- Message::addError('invalid-section', $sectionName);
- if ($moduleName !== false) {
- Util::redirect('?do=Translation&module=' . $moduleName);
+ if ($this->module !== false) {
+ // Section
+ $sectionName = Request::any('section', false, 'string');
+ if ($sectionName !== false) {
+ if (!$this->isValidSection($sectionName)) {
+ Message::addError('invalid-section', $sectionName);
+ $this->redirect();
}
- Util::redirect('?do=Translation');
}
+ $this->section = $sectionName;
}
- // Section
- $this->section = $sectionName;
// Subsection (being checked when used)
$this->subsection = Request::any('subsection', false, 'string');
// LANG (verify if needed)
@@ -103,7 +118,7 @@ class Page_Translation extends Page
if (Request::post('update')) {
$this->updateJson();
- Util::redirect('?do=Translation');
+ $this->redirect(1);
}
}
@@ -111,7 +126,7 @@ class Page_Translation extends Page
{
if (!in_array($this->destLang, Dictionary::getLanguages())) {
Message::addError('i18n-invalid-lang', $this->destLang);
- Util::redirect('?do=Translation');
+ $this->redirect();
}
}
@@ -121,7 +136,7 @@ class Page_Translation extends Page
// Overview (list of modules)
if ($this->module === false) {
- $this->showModuleList();
+ $this->showListOfModules();
return;
}
@@ -190,7 +205,7 @@ class Page_Translation extends Page
}
}
- private function showModuleList()
+ private function showListOfModules()
{
$table = array();
@@ -213,11 +228,21 @@ class Page_Translation extends Page
private function showModule()
{
- $templateTags = $this->loadModuleTemplateTags();
- $data = array(
+ // Heading
+ Render::addTemplate('module-heading', array(
'module' => $this->module->getIdentifier(),
'moduleName' => $this->module->getDisplayName()
- );
+ ));
+ // Templates
+ $this->showModuleTemplates();
+ // Messages
+ $this->showModuleMessages();
+ }
+
+ private function showModuleTemplates()
+ {
+ $templateTags = $this->loadUsedTemplateTags();
+ $data = array('module' => $this->module->getIdentifier());
$list = array();
$data['tagcount'] = 0;
foreach ($templateTags as $templates) {
@@ -239,11 +264,38 @@ class Page_Translation extends Page
}
Render::addTemplate('template-list', $data);
}
+
+ private function showModuleMessages()
+ {
+ $messageTags = $this->loadUsedMessageTags();
+ $data = array('module' => $this->module->getIdentifier());
+ $list = array();
+ $data['messagecount'] = 0;
+ foreach ($messageTags as $templates) {
+ $list = array_merge($list, array_keys($templates['files']));
+ $data['messagecount']++;
+ }
+ foreach (Dictionary::getLanguages(true) as $lang) {
+ list($missing, $unused) = $this->getModuleTranslationStatus($lang['cc'], 'messages', $messageTags);
+ $data['langs'][] = array(
+ 'cc' => $lang['cc'],
+ 'name' => $lang['name'],
+ 'missing' => $missing,
+ 'unused' => $unused
+ );
+ }
+ $data['files'] = array();
+ foreach (array_unique($list) as $template) {
+ $data['files'][] = array('file' => $template);
+ }
+ Render::addTemplate('message-list', $data);
+ }
private function showTemplateEdit()
{
Render::addTemplate('edit', array(
'destlang' => $this->destLang,
+ 'language' => Dictionary::getLanguageName($this->destLang),
'tags' => $this->loadTemplateEditArray(),
'module' => $this->module->getIdentifier(),
'section' => $this->section
@@ -254,49 +306,19 @@ class Page_Translation extends Page
{
Render::addTemplate('edit', array(
'destlang' => $this->destLang,
+ 'language' => Dictionary::getLanguageName($this->destLang),
'tags' => $this->loadMessagesEditArray(),
'module' => $this->module->getIdentifier(),
'section' => $this->section
));
}
- private function loadModuleEdit(){
- $table = array();
- $tags = array_flip($this->loadModuleTemplateTags($this->module));
- foreach ($this->langs as $lang) {
- $tags = array_merge($tags, Dictionary::getArray($this->module,$lang['cc']));
- }
- foreach ($tags as $tag => $value) {
- $langArray = array();
- $class = '';
- foreach ($this->langs as $lang) {
- $translations = Dictionary::getArray($this->module,$lang['cc']);
- $langArray[] = array(
- 'lang' => $lang['cc'],
- 'placeholder' => 'TAG - ' . $lang['name'],
- 'translation' => $translations[$tag]
- );
- if(!in_array($tag, $this->loadModuleTemplateTags($this->module)))
- $class = 'danger';
- else if(!$translations[$tag])
- $class = 'warning';
- }
- $table[] = array(
- 'tag' => $tag,
- 'class' => $class,
- 'langs' => $langArray
- );
- }
-
- return $table;
- }
-
/**
* Get all tags used by templates of the given module.
* @param \Module $module module in question, false to use the one being edited
- * @return array inde is tag, valie is array of templates using that tag
+ * @return array index is tag, value is array of templates using that tag
*/
- private function loadModuleTemplateTags($module = false)
+ private function loadUsedTemplateTags($module = false)
{
if ($module === false) {
$module = $this->module;
@@ -305,18 +327,47 @@ class Page_Translation extends Page
$path = 'modules/' . $module->getIdentifier() . '/templates';
if (is_dir($path)) {
// Return an array with the module language tags
- $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path));
- foreach ($objects as $name => $object) {
- if (substr($name, -5) === '.html' && is_file($name)) {
- $relTemplateName = substr($name, strlen($path), -5);
- foreach ($this->getTagsFromTemplate($name) as $tag) {
- $tags[$tag][] = $relTemplateName;
- }
+ foreach ($this->getAllFiles($path, '.html') as $name) {
+ $relTemplateName = substr($name, strlen($path), -5);
+ foreach ($this->getTagsFromTemplate($name) as $tag) {
+ $tags[$tag][] = $relTemplateName;
}
}
}
return $tags;
}
+
+ /**
+ * Get all message tags of the given module.
+ * Returns array indexed by tag, value is
+ * array(
+ * 'data' => rest of arguments to message
+ * 'files' => array(filename => occurencecount, ...)
+ * )
+ *
+ * @param \Module $module module in question, false to use the one being edited
+ * @return array see above
+ */
+ private function loadUsedMessageTags($module = false)
+ {
+ if ($module === false) {
+ $module = $this->module;
+ }
+ $tags = $this->loadTagsFromPhp('/Message\s*::\s*add\w+\s*\(\s*[\'"](?<module>[^\'"\.]*)\.(?<tag>[^\'"]*)[\'"]\s*(?<data>\)|\,.*)/i',
+ $this->getAllFiles('modules', '.php'));
+ // Filter out tags that don't refer to this module
+ foreach (array_keys($tags) as $tag) {
+ // Figure out if this is a message from this module or not
+ if ($tags[$tag]['module'] === $module->getIdentifier()) {
+ // Direct reference to this module via module.id
+ continue;
+ }
+ unset($tags[$tag]);
+ }
+ $tags += $this->loadTagsFromPhp('/Message\s*::\s*add\w+\s*\(\s*[\'"](?<tag>[^\'"\.]*)[\'"]\s*(?<data>\)|\,.*)/i',
+ $this->getModulePhpFiles($module));
+ return $tags;
+ }
private function getTagsFromTemplate($templateFile)
{
@@ -348,10 +399,10 @@ class Page_Translation extends Page
$module = $this->module;
}
if ($tags === false) {
- $tags = $this->loadModuleTemplateTags($module);
+ $tags = $this->loadUsedTemplateTags();
}
$globalTranslation = Dictionary::getArray('main', 'global-template-tags', $lang);
- $translation = array_unique(array_merge(Dictionary::getArray($module->getIdentifier(), 'template-tags', $lang), $globalTranslation));
+ $translation = Dictionary::getArray($module->getIdentifier(), 'template-tags', $lang) + $globalTranslation;
$matches = 0;
$unused = 0;
$expected = count($tags);
@@ -368,10 +419,39 @@ class Page_Translation extends Page
$missing = $expected - $matches;
return array($missing, $unused);
}
+
+ /**
+ * Get missing and unused counters for given module's templates.
+ *
+ * @param type $lang lang to use
+ * @param type $tags
+ * @param type $module
+ * @return array list(missingCount, unusedCount)
+ */
+ private function getModuleTranslationStatus($lang, $file, $tags, $module = false)
+ {
+ if ($module === false) {
+ $module = $this->module;
+ }
+ $translation = Dictionary::getArray($module->getIdentifier(), $file, $lang);
+ $matches = 0;
+ $unused = 0;
+ $expected = count($tags);
+ foreach ($translation as $key => $value) {
+ if(!isset($tags[$key])) {
+ $unused++;
+ } else {
+ $matches++;
+ }
+
+ }
+ $missing = $expected - $matches;
+ return array($missing, $unused);
+ }
private function checkModuleTranslation($module)
{
- $tags = $this->loadModuleTemplateTags($module);
+ $tags = $this->loadUsedTemplateTags($module);
$msgs = '';
foreach (Dictionary::getLanguages() as $lang) {
list($missing, $unused) = $this->getModuleTemplateStatus($lang, $tags, $module);
@@ -392,77 +472,38 @@ class Page_Translation extends Page
}
return $msgs;
}
+
/**
- * Load the main table with all the website's templates and it's informations
- * @return array with the templates' information
+ * Finds and returns all PHP files of slxadmin.
+ *
+ * @return array of all php file names
*/
- private function loadTemplatesList()
+ private function getAllFiles($dir, $extension)
{
- $table = array();
-
- //loads every template
- $files = $this->listTemplates();
- $langs = Dictionary::getLanguages(true);
-
- //checks the JSON tags from every language
- foreach ($files as $file) {
- $tags = $this->loadTemplateTags($file['path']);
- // Don't list templates without lang tags
- if (empty($tags))
+ $php = array();
+ $extLen = -strlen($extension);
+ foreach (scandir($dir, SCANDIR_SORT_NONE) as $name) {
+ if ($name === '.' || $name === '..')
continue;
- $msgs = '';
- foreach ($langs as $lang) {
- $msg = $this->checkJson($file['path'], $lang['cc'], $tags);
- if (!empty($msg))
- $msgs .= "<div><span class='badge'>{$lang['name']}:</span>$msg</div>";
- }
- if (empty($msgs))
- $msgs = 'OK';
- $table[] = array(
- 'template' => $file['name'],
- 'link' => $file['name'],
- 'status' => $msgs
- );
- }
- sort($table);
- return $table;
- }
-
- /**
- * Finds and returns all the website's templates
- * @return array
- */
- private function listTemplates()
- {
- $files = array();
- $dir = 'modules/';
- $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
- foreach ($objects as $name => $object) {
- if (substr($name, -5) === '.html') {
- $files[] = array(
- 'path' => substr($name, 0, -5),
- 'name' => substr($name, strlen($dir), -5)
- );
+ $name = $dir . '/' . $name;
+ if (substr($name, $extLen) === $extension && is_file($name)) {
+ $php[] = $name;
+ } else if (is_dir($name)) {
+ $php = array_merge($php, $this->getAllFiles($name, $extension));
}
}
- return $files;
+ return $php;
}
/**
- * Finds and returns all PHP files of slxadmin
- * @return array of all php files
+ * Finds and returns all PHP files of current module.
+ *
+ * @param \Module $module Module to get the php files of
+ * @return array of php file names
*/
- private function getModulePhpFiles()
+ private function getModulePhpFiles($module)
{
- $php = array();
- $dir = 'modules/' . $this->module->getIdentifier();
- $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
- foreach ($objects as $name => $object) {
- if (substr($name, -4) === '.php' && is_file($name)) {
- $php[] = $name;
- }
- }
- return $php;
+ return $this->getAllFiles('modules/' . $module->getIdentifier(), '.php');
}
/**
@@ -518,7 +559,7 @@ class Page_Translation extends Page
*/
private function loadTemplateEditArray()
{
- $tags = $this->loadModuleTemplateTags();
+ $tags = $this->loadUsedTemplateTags();
if ($tags === false)
return false;
$table = $this->buildTranslationTable('template-tags', array_keys($tags), true);
@@ -542,12 +583,20 @@ class Page_Translation extends Page
*/
private function loadMessagesEditArray()
{
- // TODO: Scan for uses in other modules, handle module.id syntax
- $tags = $this->loadTagsFromPhp('/Message\s*::\s*add\w+\s*\(\s*[\'"]([^\'"]*)[\'"]\s*(\)|\,.*)/i');
+ $tags = $this->loadUsedMessageTags();
$table = $this->buildTranslationTable('messages', array_keys($tags), true);
foreach ($table as &$entry) {
- if (isset($tags[$entry['tag']]) && is_string($tags[$entry['tag']])) {
- $entry['notes'] = 'Params: ' . $this->countMessageParams($tags[$entry['tag']]);
+ if (!isset($tags[$entry['tag']]))
+ continue;
+ $tag =& $tags[$entry['tag']];
+ // Add tag information
+ if (isset($tag['data']) && is_string($tag['data'])) {
+ $entry['notes'] = '<b>Params: ' . $this->countMessageParams($tag['data']) . '</b>';
+ } else {
+ $entry['notes'] = '';
+ }
+ foreach ($tag['files'] as $file => $count) {
+ $entry['notes'] .= '<br>' . htmlspecialchars($file) . ': ' . $count . '×';
}
}
return $table;
@@ -555,7 +604,6 @@ class Page_Translation extends Page
private function countMessageParams($str)
{
- error_log($str);
$quote = false;
$escape = false;
$count = 0;
@@ -591,58 +639,39 @@ class Page_Translation extends Page
}
/**
- * Load array of tags used in given template.
- * @param string $path the path of the template, relative to templates/, without .html extension.
- * @return array all tags in template
- */
- private function loadTemplateTags($path)
- {
- $templateFile = "$path.html";
- //checks if the template is valid
- if (!file_exists($templateFile)) {
- Message::addError('invalid-template', $templateFile);
- return false;
- }
-
- //finds every mustache tag within the html template
- $htmlTemplate = file_get_contents($templateFile);
- preg_match_all('/{{(lang_.*?)}}/s', $htmlTemplate, $matches);
- if (!isset($matches[1]) || !is_array($matches[1]))
- return array();
- return array_unique($matches[1]);
- }
-
- /**
- * Load array of tags and translations of all strings found in the php files.
- * @return array the information about the JSON tags
- */
- private function loadHardcodedStringEditArray()
- {
- // TODO: Return changed
- $tags = $this->loadTagsFromPhp('/Dictionary\s*::\s*translate\s*\(\s*[\'"]([^\'"]*?)[\'"]\s*\)/i');
- if ($tags === false)
- return false;
- return $this->buildTranslationTable('messages-hardcoded', $tags);
- }
-
- /**
- * Load array of tags used in all the php files, by given regexp. Capture group 1 should return
- * the exact tag name.
- * @param string $regexp regular expression matching all tags in capture group 1
- * @return array of all tags found
+ * Load array of tags used in all the php files, by given regexp.
+ * The capture group containing the tag name must be named tag, which
+ * can be achieved by using (?<tag>..). All other capture groups will
+ * be returned in the resulting array.
+ * The return value is an array indexed by tag, and the value for each tag is of type
+ * array('captureX' => captureX, 'captureY' => captureY, 'files' => array(
+ * file1 => count,
+ * fileN => count
+ * )).
+ *
+ * @param string $regexp regular expression
+ * @param array $files list of files to scan
+ * @return array of all tags found, where the tag is the key, and the value is as described above
*/
- private function loadTagsFromPhp($regexp)
+ private function loadTagsFromPhp($regexp, $files)
{
// Get all php files, so we can find all strings that need to be translated
- $php = $this->getModulePhpFiles();
$tags = array();
// Now find all tags in all php files. Only works for literal usage, not something like $foo = 'bar'; Dictionary::translate($foo);
- foreach ($php as $file) {
+ foreach ($files as $file) {
$content = @file_get_contents($file);
if ($content === false || preg_match_all($regexp, $content, $out, PREG_SET_ORDER) < 1)
continue;
foreach ($out as $set) {
- $tags[$set[1]] = isset($set[2]) ? $set[2] : true;
+ if (!isset($tags[$set['tag']])) {
+ $tags[$set['tag']] = $set;
+ $tags[$set['tag']]['files'] = array();
+ }
+ if (isset($tags[$set['tag']]['files'][$file])) {
+ $tags[$set['tag']]['files'][$file]++;
+ } else {
+ $tags[$set['tag']]['files'][$file] = 1;
+ }
}
}
return $tags;
@@ -653,12 +682,16 @@ class Page_Translation extends Page
$tags = array();
if ($requiredTags !== false) {
foreach ($requiredTags as $tagName) {
- $tags[$tagName] = array('tag' => $tagName);
+ $tags[$tagName] = array('tag' => $tagName, 'required' => true);
}
}
+ // Sort here, so all tags known to be used are in alphabetical order
+ ksort($tags);
// Finds every tag within the JSON language file
$jsonTags = Dictionary::getArray($this->module->getIdentifier(), $file, $this->destLang);
if (is_array($jsonTags)) {
+ // Sort these separately so unused tags will be at the bottom of the list, but still ordered alphabetically
+ ksort($jsonTags);
foreach ($jsonTags as $tag => $translation) {
$tags[$tag]['translation'] = $translation;
if (strpos($translation, "\n") !== false) {
@@ -696,6 +729,14 @@ class Page_Translation extends Page
$tagid = 0;
foreach ($tags as &$tag) {
$tag['tagid'] = $tagid++;
+ if ($requiredTags !== false) {
+ // We have a list of required tags, so mark those that are missing or unused
+ if (!isset($tag['required'])) {
+ $tag['unused'] = true;
+ } elseif (!isset($tag['translation'])) {
+ $tag['missing'] = true;
+ }
+ }
}
// Finally remove $lang from the keys so mustache will iterate over them via {{#..}}
return array_values($tags);
@@ -734,16 +775,16 @@ class Page_Translation extends Page
if ($this->section === 'custom') {
if ($this->customHandler === false || !isset($this->customHandler['subsections'])) {
Message::addError('no-custom-handlers');
- Util::redirect('?do=Translation');
+ $this->redirect(1);
}
if (!in_array($this->subsection, $this->customHandler['subsections'], true)) {
Message::addError('invalid-custom-handler', $this->subsection);
- Util::redirect('?do=Translation');
+ $this->redirect(1);
}
return $prefix . '/' . $this->subsection;
}
Message::addError('invalid-section', $this->section);
- Util::redirect('?do=Translation');
+ $this->redirect(1);
}
/**
@@ -754,7 +795,7 @@ class Page_Translation extends Page
$this->ensureValidDestLanguage();
if ($this->module === false) {
Message::addError('main.no-module-given');
- Util::redirect('?do=Translation');
+ $this->redirect();
}
$file = $this->getJsonFile();
@@ -789,7 +830,7 @@ class Page_Translation extends Page
//saves the new values on the file
$path = dirname($file);
if (!is_dir($path)) {
- mkdir($path, 0755, true);
+ mkdir($path, 0775, true);
}
if (empty($data)) {
@@ -803,7 +844,7 @@ class Page_Translation extends Page
$json = up_json_encode($data, JSON_PRETTY_PRINT); // Also for better diffability of the json files, we pretty print
//exits the function in case the action was unsuccessful
if (file_put_contents($file, $json) === false) {
- Message::addError('invalid-template');
+ Message::addError('error-write', $file);
return;
}
}
diff --git a/modules-available/translation/templates/_page.html b/modules-available/translation/templates/_page.html
index 52a4c94b..45732c5b 100644
--- a/modules-available/translation/templates/_page.html
+++ b/modules-available/translation/templates/_page.html
@@ -1,3 +1,4 @@
+<h1>{{lang_mainHeading}}</h1>
<div class="panel panel-default">
<div class="panel-heading">
{{lang_langAdministration}}
diff --git a/modules-available/translation/templates/edit.html b/modules-available/translation/templates/edit.html
index 2cc0e599..3f3e926f 100644
--- a/modules-available/translation/templates/edit.html
+++ b/modules-available/translation/templates/edit.html
@@ -18,13 +18,19 @@
<button type="submit" class="btn btn-primary" name="update" value="true">{{lang_save}}</button>
<div class="row">
<div class="col-xs-4 col-sm-3">{{lang_tag}}</div>
- <div class="col-xs-6 col-sm-4">{{lang_translation}}</div>
- <div class="hidden-xs col-sm-4">{{lang_sample}}</div>
- <div class="col-xs-2 col-sm-1">!</div>
+ <div class="col-xs-6 col-sm-4">{{lang_translation}} (<b>{{language}}</b>)</div>
+ <div class="hidden-xs col-sm-3 col-lg-4">{{lang_sample}}</div>
+ <div class="col-xs-2 col-sm-2 col-lg-1">!</div>
</div>
{{#tags}}
- <div class="row {{class}}">
+ <div class="row">
<div class="col-xs-4 col-sm-3">
+ {{#unused}}
+ <span class="label label-info">{{lang_unused}}</span>
+ {{/unused}}
+ {{#missing}}
+ <span class="label label-warning">{{lang_missing}}</span>
+ {{/missing}}
{{tag}}
<div class="slx-notebox">{{{notes}}}</div>
</div>
@@ -36,14 +42,17 @@
<textarea rows="3" class="form-control" name="lang#!#{{tag}}" placeholder="{{placeholder}}">{{translation}}</textarea>
{{/big}}
</div>
- <div class="hidden-xs col-sm-4">
+ <div class="hidden-xs col-sm-3 col-lg-4">
<div class="slx-textpreview"><div>
<div class="badge">{{samplelang}}</div>
{{sampletext}}
</div></div>
</div>
- <div class="col-xs-2 col-sm-1">
- <button type="button" class="btn btn-danger btn-xs" onclick="slxDelTag({{tagid}})"><span class="glyphicon glyphicon-remove"></span> {{lang_deleteTAG}}</button>
+ <div class="col-xs-2 col-sm-2 col-lg-1">
+ <button type="button" class="btn btn-danger btn-xs" onclick="slxDelTag({{tagid}})" tabindex="-1">
+ <span class="glyphicon glyphicon-remove"></span>
+ <span class="hidden-xs">{{lang_deleteTAG}}</span>
+ </button>
</div>
</div>
{{/tags}}
diff --git a/modules-available/translation/templates/message-list.html b/modules-available/translation/templates/message-list.html
new file mode 100644
index 00000000..06cb4964
--- /dev/null
+++ b/modules-available/translation/templates/message-list.html
@@ -0,0 +1,30 @@
+<div class="panel panel-default">
+ <div class="panel-heading">
+ {{lang_messages}}
+ </div>
+ <div class="panel-body">
+ <div class="row">
+ <div class="col-sm-6">
+ {{#langs}}
+ <a href="?do=Translation&amp;module={{module}}&amp;section=messages&amp;destlang={{cc}}">{{name}} &raquo;</a>
+ <ul>
+ <li>{{lang_missing}}: {{missing}}</li>
+ <li>{{lang_unused}}: {{unused}}</li>
+ </ul>
+ {{/langs}}
+ </div>
+ <div class="col-sm-6">
+ <div>{{lang_messages}}: {{messagecount}}</div>
+ <ul>
+ {{#files}}
+ <li>{{file}}</li>
+ {{/files}}
+ </ul>
+ <div>
+ <span class="label label-info">{{lang_hint}}</span>
+ {{lang_unusedUnreliableHint}}
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/modules-available/translation/templates/module-heading.html b/modules-available/translation/templates/module-heading.html
new file mode 100644
index 00000000..540828e9
--- /dev/null
+++ b/modules-available/translation/templates/module-heading.html
@@ -0,0 +1 @@
+<h1>{{moduleName}} ({{module}})</h1> \ No newline at end of file
diff --git a/modules-available/translation/templates/template-list.html b/modules-available/translation/templates/template-list.html
index 59d0f7cf..5d3689ad 100644
--- a/modules-available/translation/templates/template-list.html
+++ b/modules-available/translation/templates/template-list.html
@@ -1,4 +1,3 @@
-<h1>{{moduleName}} ({{module}})</h1>
<div class="panel panel-default">
<div class="panel-heading">
{{lang_templates}}
@@ -22,5 +21,6 @@
{{/templates}}
</ul>
</div>
+ </div>
</div>
</div>
diff --git a/style/default.css b/style/default.css
index 7c0a39ec..12c67918 100644
--- a/style/default.css
+++ b/style/default.css
@@ -260,6 +260,7 @@ input[readonly] {
.slx-textpreview {
max-height: 60px;
overflow-y: auto;
+ overflow-x: hidden;
}
/*