template = Request::get('template'); } if (Request::get('page')) { $this->page = Request::get('page'); } if (Request::get('delete')) { $this->delete = Request::get('delete'); } if (Request::post('update')) { $this->update = Request::post('update'); } } protected function doRender() { //calls the update function if ($this->update) $this->updateJson(); //calls the tag deletion function if ($this->delete && $this->template) $this->deleteTag($this->template, $this->delete); //load the page accordingly to the link switch ($this->page) { case 'messages': //renders the message edition page Render::addTemplate('translation/messages', array( 'token' => Session::get('token'), 'msgs' => $this->initMsg(false), 'msgsHC' => $this->initMsg(true) )); break; case 'templates': //renders the tag edition page if ($this->templateAnalysis($this->template)) { Render::addTemplate('translation/template', array( 'token' => Session::get('token'), 'template' => $this->template, 'tags' => $this->tags )); break; } default: //renders the template selection page Render::addTemplate('translation/_page', array( 'token' => Session::get('token'), 'table' => $this->initTable(), )); } } /** * Load the main table with all the website's templates and it's informations * @return array with the templates' information */ private function initTable() { $table = array(); //loads every template $files = $this->listTemplates(); //loads every json from each language $de = $this->listJson('de/'); $en = $this->listJson('en/'); $pt = $this->listJson('pt/'); //checks the JSON tags from every language foreach ($files as $key => $value) { $table[] = array( 'template' => $value, 'link' => $key, 'de' => $this->checkJson($de[$key], 'de'), 'en' => $this->checkJson($en[$key], 'en'), 'pt' => $this->checkJson($pt[$key], 'pt') ); } sort($table); return $table; } /** * Finds and returns all the website's templates * @return array */ private function listTemplates() { $files = array(); $dir = 'templates/'; $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)); foreach ($objects as $name => $object) { if (array_pop(explode('.', $name)) === 'html') { $key = str_replace($dir, '', $name); $key = str_replace('.html', '', $key); $files[$key] = $name; } } return $files; } /** * Finds and returns all the JSON files from a selected language * @param string the selected language (abbreviated) * @return array all the JSON files from the language */ private function listJson($lang) { $json = array(); $dir = 'lang/' . $lang; $objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)); foreach ($objects as $name => $object) { if (array_pop(explode('.', $name)) === 'json') { $key = str_replace($dir, '', $name); $key = str_replace('.json', '', $key); $json[$key] = $key; } } return $json; } /** * Checks the JSON tags from a template * @param string the template's path * @param string the selected language * @return string the information about the JSON tags */ private function checkJson($path, $lang) { //if there was not a valid template's path if (!$path) { return "JSON file is missing"; } //loads a template and find all its tags $htmlTemplate = file_get_contents('templates/' . $path . '.html'); preg_match_all('/{{lang_(.*?)}}/s', $htmlTemplate, $matches); $htmlCount = count(array_unique($matches[1])); //initialize the count variables $matchCount = 0; $unusedCount = 0; //loads the JSON tags and count the matches $json = Dictionary::getArrayTemplate($path, $lang); foreach ($json as $key => $value) { if ($key != 'lang') { if (!in_array(preg_replace('/^lang_/', '', $key), $matches[1])) { $unusedCount++; } else if ($value != '') { $matchCount++; } } } $diff = $htmlCount - $matchCount; //build the return string $str = ""; if ($diff == 0 && $unusedCount == 0) $str .= "OK"; if ($diff > 0) $str .= $diff . " JSON tag(s) are missing"; if ($diff > 0 && $unusedCount > 0) $str .= "
"; if ($unusedCount > 0) $str .= $unusedCount . " JSON tag(s) are not being used"; return $str; } /** * Builds the template page with the tags from its template and its JSON file * @param string the template's path * @param string the selected language * @return string the information about the JSON tags */ private function templateAnalysis($path) { //checks if the template is valid if (!file_exists('templates/' . $path . '.html')) { Message::addError('invalid-template'); return false; } //finds every mustache tag within the html template $htmlTemplate = file_get_contents('templates/' . $path . '.html'); preg_match_all('/{{lang_(.*?)}}/s', $htmlTemplate, $matches); $tags = $matches[1]; $tags = array_flip($tags); foreach ($tags as $key => $value) { $tags['lang_' . $key] = $value; unset($tags[$key]); } //finds every JSON tag withing the JSON language files $langArray = Dictionary::getLanguages(); $json = array(); foreach ($langArray as $lang) { $jsonTags = Dictionary::getArrayTemplate($path, $lang); if (is_array($jsonTags)) $json = array_merge($json, $jsonTags); } //remove unused tag unset($json['lang']); //merges the arrays to keep the unique tags $test = array_merge($json, $tags); //loads the content of every JSON tag from the specified language foreach ($test as $tag => $value) { $this->tags[] = array( 'tag' => $tag, 'de' => $this->checkJsonTag($path, $tag, 'de/'), 'en' => $this->checkJsonTag($path, $tag, 'en/'), 'pt' => $this->checkJsonTag($path, $tag, 'pt/'), 'class' => $this->checkJsonTags($path, $tag) ); } return true; } /** * Loads the content of a JSON tag * @param string the JSON's path * @param string the selected tag * @param string the specified language * @return string the tag's content */ private function checkJsonTag($path, $tag, $lang) { $json = Dictionary::getArrayTemplate($path, $lang); if (is_array($json) && isset($json[$tag])) { return $json[$tag]; } return ''; } /** * Change the color of the table line according to the tag status * @param string the JSON's path * @param string the selected tag * @return string the css class of the line */ private function checkJsonTags($path, $tag) { //return danger in case the tag is not found in the template $htmlTemplate = file_get_contents('templates/' . $path . '.html'); $htmlCount = substr_count($htmlTemplate, $tag); if ($htmlCount < 1) return "danger"; //return warning in case at least one of the tag's values is empty $langArray = array('de/', 'en/', 'pt/'); foreach ($langArray as $lang) { if (($json = Dictionary::getArrayTemplate($path, $lang))) { if (!isset($json[$tag]) || $json[$tag] == '') return 'warning'; } } //if it's ok don't change the class return ''; } /** * Updates a JSON file with it's new tags or/and tags values */ private function updateJson() { $langArray = Dictionary::getLanguages(); foreach ($langArray as $lang) { $json[$lang] = array(); } //find the tag requests to change the file foreach ($_REQUEST as $key => $value) { $str = explode('#', $key, 3); if (count($str) !== 3) continue; $pre = $str[0]; $lang = $str[1]; $tag = $str[2]; if ($pre !== 'lang') continue; if (in_array($lang, $langArray)) { if ($tag !== 'newtag') $json[$lang][$tag] = $value; else { $json[$lang][$_REQUEST['newtag']] = $value; } } } // JSON_PRETTY_PRINT is only available starting with php 5.4.0.... Use upgradephp's json_encode require_once('inc/up_json_encode.php'); //saves the new values on the file foreach ($json as $key => $array) { $path = 'lang/' . $key . '/' . $_POST['path'] . '.json'; // TODO: Wtf? Unvalidated user input -> filesystem access! ksort($array); // Sort by key, so the diff on the output is cleaner $json = up_json_encode($array, 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($path, $json) === false) { Message::addError('invalid-template'); return; } } Message::addSuccess('updated-tags'); } /** * Load the main table with all the website's messages or hardcoded messages * @var boolean choose between hardcoded and non-hardcoded messages * @return array with the selected messages */ private function initMsg($isHardcoded) { $msgs = array(); //chooses the path $path = 'messages'; if ($isHardcoded) { $path = 'messages-hardcoded'; } //loads the content of every JSON tag from the message file $json = Dictionary::getArrayTemplate($path, LANG); foreach ($json as $key => $array) { if ($key != 'lang') $msgs[] = array( 'tag' => $key, 'de' => $this->checkJsonTag($path, $key, 'de/'), // TODO: Hardcoded language list, use Dictionary::getLanguages() 'en' => $this->checkJsonTag($path, $key, 'en/'), 'pt' => $this->checkJsonTag($path, $key, 'pt/') ); } return $msgs; } /** * Delete a specific JSON tag from a JSON files * @var string the JSON's file path * @var the JSON tag to be deleted * @return boolean if the action was not successful */ private function deleteTag($path, $tag) { //delete the tag from every language file $langArray = unserialize(SITE_LANGUAGES); foreach ($langArray as $lang) { $json = Dictionary::getArrayTemplate($path, $lang); unset($json[$tag]); unset($json['lang']); $result = file_put_contents('lang/' . $lang . '/' . $path . '.json', json_encode($json)); //add warning and exit in case the action was unsuccessful if ($result === false) { Message::addWarning('unsuccessful-action'); return false; } } Message::addSuccess('deleted-tag'); } }