[web-doc] master: 1. Doc-base revcheck.php code injected and database production accelerated:

[email protected] (Nilgün Belma Bugüner) Sun, 16 May 2021 21:45:46 +0000
Newsgroups php.doc.web
Message-ID <[email protected]>
Author: Nilgün Belma Bugüner (nilgun)
Date: 2021-05-17T00:45:45+03:00

Commit: https://github.com/php/web-doc/commit/4725e3bd17986aa84356fc41a11db60f2447cead
Raw diff: https://github.com/php/web-doc/commit/4725e3bd17986aa84356fc41a11db60f2447cead.diff

1. Doc-base revcheck.php code injected and database production accelerated:
   dropped from 15 minutes to 2.5 seconds.
2. As in new Doc-base revcheck.php, more detailed and more accurate information is given to the teams.
3. Indentation fixed.

Changed paths:
  M  README.md
  M  include/lib_revcheck.inc.php
  M  scripts/gen_picture_info.php
  M  scripts/rev.php
  M  www/revcheck.php


Diff:

diff --git a/README.md b/README.md
index b6cc21e..2de9e44 100644
--- a/README.md
+++ b/README.md
@@ -12,19 +12,19 @@ Requirements:
 1. Unpack a copy of JpGraph 3.0.7 into `/include/jpgraph/` ([here](http://jpgraph.net/download/download.php?p=1))
 2. Increase memory limit for PHP scripts to at least 32MB
 3. Fill in two configuration files
-	- `build-ops.php.sample` (rename it to `build-ops.php`)
-		- `@GITDIR@` - absolute path to dir where scripts will clone SVN repos to and then use them for generating data
-		- `@SQLITEDIR@` - absolute path to `/sqlite/` directory
-	- `build-ops.sample` (rename it to `build-ops` [no ext])
-		- `@PHP@` - path to the PHP executable file
-		- `@GITDIR@` - absolute path to dir where scripts will clone SVN repos to and then use them and then use it for generating data
-		- `@DOCWEB@` - absolute path to `/www/` directory
-		- `@PHDDIR@` - absolute path to directory with PhD installed from Git master
-		- `@SCRIPTSDIR@`- absolute path to `/scripts/` directory
-		- `@SQLITEDIR@` - absolute path to `/sqlite/` directory
-		- `@SRCDIR@` - path to the directory with PHP source code in SVN repo
+- `build-ops.php.sample` (rename it to `build-ops.php`)
+- `@GITDIR@` - absolute path to dir where scripts will clone GIT repos to and then use them for generating data
+- `@SQLITEDIR@` - absolute path to `/sqlite/` directory
+- `build-ops.sample` (rename it to `build-ops` [no ext])
+- `@PHP@` - path to the PHP executable file
+- `@GITDIR@` - absolute path to dir where scripts will clone SVN repos to and then use them and then use it for generating data
+- `@DOCWEB@` - absolute path to `/www/` directory
+- `@PHDDIR@` - absolute path to directory with PhD installed from Git master
+- `@SCRIPTSDIR@`- absolute path to `/scripts/` directory
+- `@SQLITEDIR@` - absolute path to `/sqlite/` directory
+- `@SRCDIR@` - path to the directory with PHP source code in GIT repo
 4. You need to run the scripts/populatedocs.sh to fetch all the required documentation for the site.
-6. You need to run the scripts/generation.sh to generate the database and graphs (Time of generation: 921.84918999672 s)
+6. You need to run the scripts/generation.sh to generate the database and graphs (Time of generation: 2.5009639263153 s)
 7. Configure the virtual host under Apache. Current suggested settings are:
 ```
 <VirtualHost 127.0.0.1:80>
diff --git a/include/lib_revcheck.inc.php b/include/lib_revcheck.inc.php
index fa7eb72..72d5237 100644
--- a/include/lib_revcheck.inc.php
+++ b/include/lib_revcheck.inc.php
@@ -26,23 +26,16 @@ function get_dirs($idx, $lang) {
         b.path AS dir,
         a.name AS name
     FROM
-        files a,
-        dirs b,
-        enfiles c
+        translated a,
+        dirs b
     WHERE
-        a.lang= '$lang'
-    AND
-         a.id = b.id
-    AND
-         c.id = a.id
-    AND
-         a.name = c.name
-    AND
-        a.revision != c.revision
-    AND
-        a.revision != 'n/a'
+        a.lang = '$lang'
+    AND a.id = b.id
+    AND (a.syncStatus = 'TranslatedOld'
+     OR a.syncStatus = 'TranslatedCritial'
+     OR a.syncStatus = 'TranslatedWip')
     ORDER BY
-        b.path";
+        b.id";
 
     $result = $idx->query($sql);
 
@@ -58,10 +51,12 @@ function get_dirs($idx, $lang) {
 function get_outdated_files($idx, $lang, $filter = null, $value = null)
 {
     $sql = "SELECT a.status, a.name AS file, a.maintainer, c.revision AS en_rev, a.revision AS trans_rev, b.path AS dir
-    FROM files a, dirs b, enfiles c
+    FROM translated a, dirs b, enfiles c
     WHERE a.lang = '$lang'
-     AND a.revision != c.revision AND a.revision != 'n/a'
-     AND c.name = a.name AND c.id = a.id AND b.id = a.id";
+      AND c.name = a.name AND c.id = a.id AND b.id = a.id
+      AND (a.syncStatus = 'TranslatedOld'
+      OR a.syncStatus = 'TranslatedCritial'
+      OR a.syncStatus = 'TranslatedWip')";
 
     if ($filter == 'dir') {
         $sql .= " AND b.path = '$value'";
@@ -90,7 +85,7 @@ function get_outdated_files($idx, $lang, $filter = null, $value = null)
 // Return an array of available languages for manual
 function revcheck_available_languages($idx)
 {
-    $result = $idx->query('SELECT lang FROM description');
+    $result = $idx->query('SELECT lang FROM descriptions');
     while ($row = $result->fetchArray(SQLITE3_NUM)) {
 		$tmp[] = $row[0];
 	}
@@ -110,24 +105,23 @@ function count_en_files($idx)
 
 function get_missfiles($idx, $lang)
 {
-    $sql = 'SELECT
+    $sql = "SELECT
         d.path as dir,
-        b.size as size,
+        a.name as file,
         b.revision as revision,
-        a.name as file
+        a.size as size
     FROM
-        utfiles a,
+        Untranslated a,
+        enfiles b,
         dirs d
-    LEFT JOIN
-        enfiles b
-    ON
-        a.id = b.id
+    WHERE
+        a.lang = '$lang'
     AND
         a.name = b.name
-    WHERE
-        a.lang="' . $lang . '"
     AND
-        a.id = d.id';
+        a.id = b.id
+    AND
+        a.id = d.id";
     $result = $idx->query($sql);
 
     while ($r = $result->fetchArray()) {
@@ -139,38 +133,26 @@ function get_missfiles($idx, $lang)
 
 function get_oldfiles($idx, $lang)
 {
-    $sql = 'SELECT
-     path, file, size
-
-     FROM
-     old_files
-
-     WHERE
-     lang="' . $lang . '"';
+    $sql = "SELECT path, name, size
+     FROM  notinen
+     WHERE lang = '$lang'";
 
     $result = $idx->query($sql);
-
     $tmp = array();
-    $special_files = array(
-        'translation.xml'=>1,
-    );
 
     while ($r = $result->fetchArray()) {
-        if (isset($special_files[$r['file']])) continue; // skip some files
-        $tmp[] = array('dir' => $r['path'], 'size' => $r['size'], 'file' => $r['file']);
+        $tmp[] = array('dir' => $r['path'], 'size' => $r['size'], 'file' => $r['name']);
     }
     return $tmp;
 }
 
 function get_misstags($idx, $lang)
 {
-    $sql = 'SELECT
-     d.path AS dir, a.size AS en_size, b.size AS trans_size, a.name AS name
-     FROM enfiles a, dirs d
-     LEFT JOIN files b ON a.id = b.id AND a.name = b.name AND a.id = d.id
-     WHERE b.lang="'.$lang.'" AND (b.revision IS NULL OR b.revision = "n/a")
-     AND b.size IS NOT NULL
-     ORDER BY dir, name';
+    $sql = "SELECT d.path AS dir, a.size AS en_size, b.size AS trans_size, a.name AS name
+     FROM enfiles a, translated b, dirs d
+     WHERE b.lang = '$lang' AND b.syncStatus = 'RevTagProblem'
+     AND a.id = b.id AND a.name = b.name AND a.id = d.id
+     ORDER BY dir, name";
     $tmp = NULL;
     $result = $idx->query($sql);
     while($row = $result->fetchArray()) {
@@ -190,29 +172,22 @@ function get_misstags($idx, $lang)
  */
 function get_translators_stats($idx, $lang, $status) {
     if ($status == 'wip') { // special case, ehh; does anyone still use this status?
-        $sql = "SELECT COUNT(name) AS total, person AS maintainer
-        FROM wip
+        $sql = "SELECT files_wip AS total, nick AS maintainer
+        FROM translators
+        WHERE lang = '$lang'
+        GROUP BY maintainer";
+    } elseif ($status == 'uptodate') {
+        $sql = "SELECT files_uptodate AS total, nick AS maintainer
+        FROM translators
+        WHERE lang = '$lang'
+        GROUP BY maintainer";
+    } elseif ($status == 'outdated') {
+        $sql = "SELECT files_outdated AS total, nick AS maintainer
+        FROM translators
         WHERE lang = '$lang'
         GROUP BY maintainer";
     }
-    else {
-        $sql = "SELECT COUNT(a.name) AS total, a.maintainer
-        FROM files a
-        LEFT JOIN enfiles b ON a.name = b.name AND a.id = b.id
-        WHERE a.lang = '$lang' AND a.size IS NOT NULL AND ";
-
-        if ($status == 'uptodate') {
-            $sql .= 'a.revision = b.revision';
-        }
-        elseif ($status == 'outdated') {
-            $sql .= 'b.revision != a.revision';
-        }
-
-        $sql .= ' GROUP BY a.maintainer';
-    }
-
     $result = $idx->query($sql);
-
     $tmp = array();
     while ($r = $result->fetchArray()) {
         $tmp[$r['maintainer']] = $r['total'];
@@ -223,11 +198,11 @@ function get_translators_stats($idx, $lang, $status) {
 
 function get_translators($idx, $lang)
 {
-    $sql = "SELECT nick, name, mail, karma FROM translators WHERE lang = '$lang' ORDER BY nick COLLATE NOCASE";
+    $sql = "SELECT nick, name, mail, vcs FROM translators WHERE lang = '$lang' ORDER BY nick COLLATE NOCASE";
     $persons = array();
     $result = $idx->query($sql);
     while ($r = $result->fetchArray()) {
-        $persons[$r['nick']] = array('name' => $r['name'], 'mail' => $r['mail'], 'karma' => $r['karma']);
+        $persons[$r['nick']] = array('name' => $r['name'], 'mail' => $r['mail'], 'karma' => $r['vcs']);
     }
     return $persons;
 }
@@ -242,33 +217,32 @@ function get_translators($idx, $lang)
  * @return array
  */
 function get_stats($idx, $lang, $status) {
-    if ($status == 'wip') { // special case, ehh; does anyone still use this status?
-        $sql = "SELECT COUNT(*) AS total, 0 AS size
-        FROM files a, dirs b, enfiles c
-        WHERE lang = '$lang' AND a.status ='wip' AND b.id = a.id AND b.id = c.id AND a.name = c.name";
-    }
-    elseif ($status == 'notrans') {
-        $sql = "SELECT COUNT(a.name) AS total, SUM(c.size) AS size FROM utfiles a, dirs b, enfiles c WHERE a.lang = '$lang' AND b.id = a.id AND b.id = c.id AND a.name = c.name";
-    }
-    else {
-        $sql = "SELECT COUNT(a.name) AS total, SUM(b.size) AS size
-        FROM enfiles a
-        LEFT JOIN files b ON a.name = b.name AND a.id = b.id
-        WHERE b.lang = '$lang' AND ";
+    if ($status == 'wip') {
+        $sql = "SELECT COUNT(name) AS total, SUM(size) AS size
+        FROM wip
+        WHERE lang = '$lang' ";
+    } elseif ($status == 'notrans') {
+        $sql = "SELECT COUNT(name) AS total, SUM(size) AS size
+        FROM Untranslated
+        WHERE lang = '$lang'";
+    } elseif ($status == 'uptodate') {
+        $sql = "SELECT COUNT(name) AS total, SUM(size) AS size
+        FROM translated
+        WHERE lang = '$lang' AND syncStatus = 'TranslatedOk'";
+    } elseif ($status == 'outdated') {
+        $sql = "SELECT COUNT(name) AS total, SUM(size) AS size
+        FROM translated
+        WHERE lang = '$lang' AND syncStatus = 'TranslatedOld'";
+    } elseif ($status == 'norev') {
+        $sql = "SELECT COUNT(name) AS total, SUM(size) AS size
+        FROM translated
+        WHERE lang = '$lang' AND syncStatus = 'RevTagProblem'";
+    } else { //notinen
+        $sql = "SELECT COUNT(name) AS total, SUM(size) AS size
+        FROM notinen WHERE lang = '$lang'";
 
-        if ($status == 'uptodate') {
-            $sql .= 'a.revision = b.revision';
-        }
-        elseif ($status == 'outdated') {
-            $sql .= 'b.revision != a.revision AND a.revision != "n/a" AND a.size IS NOT NULL';
-        }
-        elseif ($status == 'norev') {
-            $sql .= '(a.revision IS NULL OR a.revision = "n/a") AND a.size IS NOT NULL';
-        }
     }
-
     $result = $idx->query($sql)->fetchArray();
-
     return array($result['total'], $result['size']);
 }
 
diff --git a/scripts/gen_picture_info.php b/scripts/gen_picture_info.php
index c655908..c43a9f6 100644
--- a/scripts/gen_picture_info.php
+++ b/scripts/gen_picture_info.php
@@ -59,7 +59,7 @@ function generate_image($lang, $idx) {
     $legend = array($percent[0] . '%% up to date ('.$up_to_date.')', $percent[1] . '%% outdated ('.$outdated.')', $percent[2] . '%% missing ('.$missing.')', $percent[3] . '%% without EN-Revision ('.$no_tag.')');
     $title = 'Details for '.$LANGUAGES[$lang].' PHP Manual';
 
-    $graph = new PieGraph(630,400);
+    $graph = new PieGraph(680,300);
     $graph->SetShadow();
 
     $graph->title->Set($title);
diff --git a/scripts/rev.php b/scripts/rev.php
index 2b56088..fd5ea34 100644
--- a/scripts/rev.php
+++ b/scripts/rev.php
@@ -23,7 +23,6 @@
 |                   Maciej Sobaczewski    <sobak at php dot net>       |
 +----------------------------------------------------------------------+
 */
-
 error_reporting(E_ALL);
 set_time_limit(0);
 
@@ -49,7 +48,7 @@
 
 $CREATE = <<<SQL
 
-CREATE TABLE description (
+CREATE TABLE descriptions (
   lang TEXT,
   intro TEXT,
   UNIQUE (lang)
@@ -60,398 +59,404 @@
   nick TEXT,
   name TEXT,
   mail TEXT,
-  karma TEXT,
-  editor TEXT,
+   vcs TEXT,
+  files_uptodate INT,
+  files_outdated INT,
+  files_wip INT,
+  files_sum INT,
+  files_other INT,
   UNIQUE (lang, nick)
 );
 
-CREATE TABLE wip (
+CREATE TABLE translated (
+  id INT,
   lang TEXT,
   name TEXT,
-  person TEXT,
-  type TEXT
+  revision TEXT,
+  size INT,
+  maintainer TEXT,
+  status TEXT,
+  syncStatus TEXT,
+  UNIQUE(lang, id, name)
 );
 
+CREATE INDEX translated_1 ON translated (lang, id, name);
+
 CREATE TABLE dirs (
   id INT,
   path TEXT,
   UNIQUE (path)
 );
 
-CREATE INDEX dirs_1 ON dirs (id);
+CREATE INDEX dirs_1 ON dirs (path);
 
 CREATE TABLE enfiles (
   id INT,
   name TEXT,
   revision TEXT,
-  size TEXT,
-  mdate TEXT,
+  size INT,
   UNIQUE(id, name)
 );
 
 CREATE INDEX enfiles_1 ON enfiles (id, name);
 
-CREATE TABLE files (
+CREATE TABLE Untranslated (
   id INT,
   lang TEXT,
   name TEXT,
-  revision TEXT,
-  size TEXT,
-  mdate TEXT,
-  maintainer TEXT,
-  status TEXT,
+  size INT,
   UNIQUE(lang, id, name)
 );
 
-CREATE INDEX files_1 ON files (lang, id, name, revision);
-CREATE INDEX files_2 ON files (lang, id, name, mdate, revision);
-CREATE INDEX files_3 ON files (lang, id, name, maintainer, mdate, revision);
+CREATE INDEX Untrans_1 ON Untranslated (lang, id, name);
 
-CREATE TABLE utfiles (
-  id INT,
+CREATE TABLE notinen (
   lang TEXT,
+  path TEXT,
   name TEXT,
-  UNIQUE(lang, id, name)
+  size INT,
+  UNIQUE(lang, path, name)
 );
 
-CREATE TABLE old_files (
+CREATE INDEX notinen_1 ON notinen (lang, path, name);
+
+CREATE TABLE wip (
+  id INT,
   lang TEXT,
-  path TEXT,
-  file TEXT,
-  size INT
+  name TEXT,
+  size INT,
+  person TEXT
 );
 
 SQL;
 
-$SQL_BUFF = "INSERT INTO dirs VALUES (1, '/');\n";
+$SQL_BUFF = "";
 
-/**
-*   Functions
-**/
+$enFiles = populateFileTree( 'en' );
+captureGitValues( $gitData );
+foreach ($LANGS as $lang){
+    $trFiles[$lang] = populateFileTree( $lang );
+}
 
-function parse_translation($lang)
+class FileStatusInfo
 {
-    global $SQL_BUFF, $DOCS, $LANGUAGES;
-    echo "Parsing intro..\n";
-
-    // Path to find translation.xml file, set default values,
-    // in case we can't find the translation file
-    $translation_xml = $DOCS . $lang . "/translation.xml";
-
-    $intro = "No intro available for the {$LANGUAGES[$lang]} translation of the manual.";
-    $charset  = 'utf-8';
+    public $path;
+    public $name;
+    public $size;
+    public $hash;
+    public $syncStatus;
+    public $maintainer;
+    public $completion;
+    public $credits;
+
+    public function getKey()
+    {
+        return trim( $this->path . '/' . $this->name , '/' );
+    }
+}
 
-    if (file_exists($translation_xml)) {
-        // Else go on, and load in the file, replacing all
-        // space type chars with one space
-        $txml = join("", file($translation_xml));
-        $txml = preg_replace("/\\s+/", " ", $txml);
-
-        // Get encoding for the output, from the translation.xml
-        // file encoding (should be the same as the used encoding
-        // in HTML)
-        if (preg_match("!<\?xml(.+)\?>!U", $txml, $match)) {
-            $xmlinfo = parse_attr_string($match);
-            if (isset($xmlinfo[1]["encoding"])) {
-                $charset = $xmlinfo[1]["encoding"];
-            }
-        }
+class FileStatusEnum
+{
+    const Untranslated      = 'Untranslated';
+    const RevTagProblem     = 'RevTagProblem';
+    const TranslatedWip     = 'TranslatedWip';
+    const TranslatedOk      = 'TranslatedOk';
+    const TranslatedOld     = 'TranslatedOld';
+    const TranslatedCritial = 'TranslatedCritial';
+    const NotInEnTree       = 'NotInEnTree';
+}
 
-        // Get intro text
-        if (preg_match("!<intro>(.+)</intro>!s", $txml, $match)) {
-            $intro = SQLite3::escapeString(@iconv($charset, 'UTF-8//IGNORE', trim($match[1])));
-        }
+class TranslatorInfo
+{
+    public $name;
+    public $email;
+    public $nick;
+    public $vcs;
+
+    public $files_uptodate;
+    public $files_outdated;
+    public $files_wip;
+    public $files_sum;
+    public $files_other;
+
+    public function __construct() {
+        $this->files_uptodate = 0;
+        $this->files_outdated = 0;
+        $this->files_wip = 0;
+        $this->files_sum = 0;
+        $this->files_other = 0;
     }
 
-    $SQL_BUFF .= "INSERT INTO description VALUES ('$lang', '$intro');\n";
-
-    if (isset($txml)) {
-        // Find all persons matching the pattern
-        if (preg_match_all("!<person (.+)/\\s?>!U", $txml, $matches)) {
-            $default = array('vcs' => 'n/a', 'nick' => 'n/a', 'editor' => 'n/a', 'email' => 'n/a', 'name' => 'n/a');
-            $persons = parse_attr_string($matches[1]);
-
-            foreach ($persons as $person) {
-                $person = array_merge($default, $person);
-                $nick   = SQLite3::escapeString($person['nick']);
-                $name   = SQLite3::escapeString(@iconv($charset, 'UTF-8//IGNORE', $person['name']));
-                $email  = SQLite3::escapeString($person['email']);
-                $vcs    = SQLite3::escapeString($person['vcs']);
-                $editor = SQLite3::escapeString($person['editor']);
-                $SQL_BUFF .= "INSERT INTO translators VALUES ('$lang', '$nick', '$name', '$email', '$vcs', '$editor');\n";
-            }
-        }
-
-        // Get list of work in progress files
-        if (preg_match_all("!<file(.+)/\\s?>!U", $txml, $matches)) {
-            $files = parse_attr_string($matches[1]);
-            foreach ($files as $file) {
-                $name = SQLite3::escapeString($file['name']);
-                $person = SQLite3::escapeString($file['person']);
-                $type = SQLite3::escapeString(isset($file['type']) ? $file['type'] : 'translation');
-                $SQL_BUFF .= "INSERT INTO wip VALUES ('$lang', '$name', '$person', '$type');\n";
-            }
+    public static function getKey( $fileStatus ) {
+        switch ( $fileStatus ) {
+             case FileStatusEnum::RevTagProblem:
+             case FileStatusEnum::TranslatedOld:
+             case FileStatusEnum::TranslatedCritial:
+             case FileStatusEnum::NotInEnTree:
+                return "files_outdated";
+                break;
+            case FileStatusEnum::TranslatedWip:
+                return "files_wip";
+                break;
+            case FileStatusEnum::TranslatedOk:
+                return "files_uptodate";
+                break;
+            default:
+                return "files_other";
         }
     }
-} // parse_translation() function end()
-
+}
 
 // Get a multidimensional array with tag attributes
-function parse_attr_string($tags_attrs)
-{
+function parse_attr_string ( $tags_attrs ) {
     $tag_attrs_processed = array();
 
-    // Go through the tag attributes
-    foreach ($tags_attrs as $attrib_list) {
-
-        // Get attr name and values
+    foreach($tags_attrs as $attrib_list) {
         preg_match_all("!(.+)=\\s*([\"'])\\s*(.+)\\2!U", $attrib_list, $attribs);
 
-        // Assign all attributes to one associative array
         $attrib_array = array();
         foreach ($attribs[1] as $num => $attrname) {
             $attrib_array[trim($attrname)] = trim($attribs[3][$num]);
         }
-        // Collect in order of tags received
+
         $tag_attrs_processed[] = $attrib_array;
     }
-    // Retrun with collected attributes
+
     return $tag_attrs_processed;
 }
 
-function dir_sort($a, $b) {
-    global $DOCS, $dir;
-    $a = $DOCS . 'en' . $dir . '/' . $a;
-    $b = $DOCS . 'en' . $dir . '/' . $b;
-    if (is_dir($a) && is_dir($b)) {
-        return 0;
-    } elseif (is_file($a) && is_file($b)) {
-        return 0;
-    } elseif (is_file($a) && is_dir($b)) {
-        return -1;
-    } elseif (is_dir($a) && is_file($b)) {
-        return 1;
-    } else {
-        return -1;
-    }
-}
+function computeTranslatorStatus( $lang, $enFiles, $trFiles )
+{
+    global $SQL_BUFF, $DOCS, $LANGUAGES;
+    $translation_xml = $DOCS . $lang . "/translation.xml";
+    $charset  = 'utf-8';
 
-function dir_sort_old($a, $b) {
-    global $DOCS, $dir, $lang;
-    $a = $DOCS . $lang . $dir . '/' . $a;
-    $b = $DOCS . $lang . $dir . '/' . $b;
-    if (is_dir($a) && is_dir($b)) {
-        return 0;
-    } elseif (is_file($a) && is_file($b)) {
-        return 0;
-    } elseif (is_file($a) && is_dir($b)) {
-        return -1;
-    } elseif (is_dir($a) && is_file($b)) {
-        return 1;
-    } else {
-        return -1;
+    if (!file_exists($translation_xml)) {
+        return [];
     }
-}
 
-function do_revcheck($dir = '') {
-    global $LANGS, $DOCS, $SQL_BUFF;
-    static $id = 1;
-    global $idx;
-
-    if ($dh = opendir($DOCS . 'en/' . $dir)) {
-
-        $entriesDir = array();
-        $entriesFiles = array();
-
-        while (($file = readdir($dh)) !== false) {
-            if (
-            (!is_dir($DOCS . 'en' . $dir.'/' .$file) && !in_array(substr($file, -3), array('xml','ent')) && substr($file, -13) != 'PHPEditBackup' )
-            || strpos($file, 'entities.') === 0
-            || $dir == '/chmonly' || $dir == '/internals' || $dir == '/internals2'
-            || $file == 'contributors.ent' || $file == 'contributors.xml'
-            || ($dir == '/appendices' && ($file == 'reserved.constants.xml' || $file == 'extensions.xml'))
-            || $file == '.editorconfig'
-            || $file == '.gitignore'
-            || $file == 'README'
-            || $file == 'README.md'
-            || $file == 'DO_NOT_TRANSLATE'
-            || $file == 'rsusi.txt'
-            || $file == 'missing-ids.xml'
-            || $file == 'license.xml'
-            || $file == 'versions.xml'
-            ) {
-                continue;
-            }
+    $txml = join("", file($translation_xml));
+    $txml = preg_replace("/\\s+/", " ", $txml);
 
-            if ($file != '.' && $file != '..' && $file != '.git' && $dir != '/functions' && $dir != '/.git' && $dir != '/.github' && $file != '.github') {
-
-                if (is_dir($DOCS . 'en' . $dir.'/' .$file)) {
-                    $entriesDir[] = $file;
-                } elseif (is_file($DOCS . 'en' . $dir.'/' .$file)) {
-                    $entriesFiles[] = $file;
-                }
-            }
-        }
-        $cwd = getcwd();
-        // Files first
-        $maintainer = NULL;
-        $status = NULL;
-        if (sizeof($entriesFiles) > 0 ) {
-            foreach($entriesFiles as $file) {
-                $path = $DOCS . 'en' . $dir . '/';
-                chdir ($path);
-                $size = intval(filesize($file) / 1024);
-                $date = filemtime($file);
-                $revision = `git log -n1 --format=format:"%H" -- {$file};`;
-                $revision = ($revision == 0) ? 'NULL' : "'$revision'";
-                $SQL_BUFF .= "INSERT INTO enfiles VALUES ($id, '$file', $revision, '$size', '$date');\n";
-
-                foreach ($LANGS as $lang) {
-                    $path = $DOCS . $lang . $dir . '/' . $file;
-                    if (is_file($path)) {
-                        $size = intval(filesize($path) / 1024);
-                        $date = filemtime($path);
-
-                        list($revision, $maintainer, $status) = get_tags($path);
-                        echo " Adding file: {$id}, {$lang}, {$file},{$revision}, {$size}, {$date}, {$maintainer}, {$status}\n";
-
-                        $SQL_BUFF .= "INSERT INTO files VALUES ($id, '$lang', '$file', '$revision', '$size', '$date', '$maintainer', '$status');\n";
-                    } else {
-                        $SQL_BUFF .= "INSERT INTO utfiles VALUES ($id, '$lang', '$file');\n";
-                    }
-                }
-            }
-        }
-        chdir($cwd);
-
-        // Directories..
-        if (sizeof($entriesDir) > 0) {
-            usort($entriesDir, 'dir_sort');
-            reset($entriesDir);
-
-            foreach ($entriesDir as $Edir) {
-                if ($Edir != 'figures') {
-                    $path = $DOCS . 'en/' . $dir . '/' . $Edir;
-                    $id++;
-                    echo "Adding directory: $dir/$Edir (id: $id)\n";
-
-                    $SQL_BUFF .= "INSERT INTO dirs VALUES ($id, '$dir/$Edir');\n";
-                    do_revcheck($dir . '/' . $Edir);
-                }
-            }
-        }
-    }
-    closedir($dh);
-}
+    $intro = "No intro available for the {$LANGUAGES[$lang]} translation of the manual.";
+    if ( preg_match("!<intro>(.+)</intro>!s", $txml, $match) )
+        $intro = SQLite3::escapeString(@iconv($charset, 'UTF-8//IGNORE', trim($match[1])));
 
-function check_old_files($lang, $dir = '') {
-    global $DOCS, $SQL_BUFF;
-    static $id = 1;
-
-    if ($dh = opendir($DOCS . $lang . $dir)) {
-
-        $entriesDir = array();
-        $entriesFiles = array();
-
-        while (($file = readdir($dh)) !== false) {
-            if (
-            (!is_dir($DOCS . $lang . $dir.'/' .$file) && !in_array(substr($file, -3), array('xml','ent')) && substr($file, -13) != 'PHPEditBackup' )
-            || strpos($file, 'entities.') === 0
-            || $dir == '/chmonly' || $dir == '/internals' || $dir == '/internals2' || $dir == '/.git' || $dir == '/.github'
-            || $file == 'contributors.ent' || $file == 'contributors.xml'
-            || ($dir == '/appendices' && ($file == 'reserved.constants.xml' || $file == 'extensions.xml'))
-            || $file == 'README'
-            || $file == 'README.md'
-            || $file == 'DO_NOT_TRANSLATE'
-            || $file == 'rsusi.txt'
-            || $file == 'missing-ids.xml'
-            || $file == 'translation.xml'
-            ) {
-                continue;
-            }
+    $SQL_BUFF .= "INSERT INTO descriptions VALUES ('$lang', '$intro');\n";
 
-            if ($file != '.' && $file != '..' && $file != '.svn' && $dir != '/functions') {
+    $pattern = "!<person(.+)/\\s?>!U";
+    preg_match_all($pattern, $txml, $matches);
+    $translators = parse_attr_string($matches[1]);
 
-                if (is_dir($DOCS . $lang . $dir.'/' .$file)) {
-                    $entriesDir[] = $file;
-                } elseif (is_file($DOCS . $lang . $dir.'/' .$file)) {
-                    $entriesFiles[] = $file;
-                }
-            }
-        }
+    $translatorInfos = [];
+    $unknownInfo = new TranslatorInfo();
+    $unknownInfo->nick = "unknown";
+    $translatorInfos["unknown"] = $unknownInfo;
 
-        // Files first
-        if (sizeof($entriesFiles) > 0 ) {
+    foreach ($translators as $key => $translator)
+    {
+        $info = new TranslatorInfo();
+        $info->name = $translator["name"];
+        $info->email = $translator["email"];
+        $info->nick = $translator["nick"];
+        $info->vcs = isset($translator["vcs"]) ? $translator["vcs"] : '';
 
-            foreach($entriesFiles as $file) {
-                $path_en = $DOCS . 'en/' . $dir . '/' . $file;
-                $path = $DOCS . $lang . $dir . '/' . $file;
+        $translatorInfos[$info->nick] = $info;
+    }
 
-                if( !@is_file($path_en) ) {
-                   $size = intval(filesize($path) / 1024);
-                   $SQL_BUFF .= "INSERT INTO old_files VALUES ('$lang', '$dir', '$file', '$size');\n";
-                }
+    foreach( $enFiles as $key => $enFile ) {
+        $info_exists = false;
+        if (array_key_exists($enFile->getKey(), $trFiles)) {
+            $trFile = $trFiles[$enFile->getKey()];
+            $statusKey = TranslatorInfo::getKey($trFile->syncStatus);
+            if (array_key_exists($trFile->maintainer, $translatorInfos)) {
+                $translatorInfos[$trFile->maintainer]->$statusKey++;
+                $translatorInfos[$trFile->maintainer]->files_sum++;
+                $info_exists = true;
             }
         }
+        if (!$info_exists) {
+            $translatorInfos["unknown"]->$statusKey++;
+            $translatorInfos["unknown"]->files_sum++;
+        }
+    }
+    foreach ($translatorInfos as $key => $person)
+    {
+        if ($person->nick != "unknown" )
+        {
+            $nick   = SQLite3::escapeString($person->nick);
+            $name   = SQLite3::escapeString(@iconv($charset, 'UTF-8//IGNORE', $person->name));
+            $email  = SQLite3::escapeString($person->email);
+            $vcs    = SQLite3::escapeString($person->vcs);
+
+            $SQL_BUFF .= "INSERT INTO translators VALUES ('$lang',
+            '$nick', '$name', '$email', '$vcs', $person->files_uptodate,
+            $person->files_outdated, $person->files_wip,
+            $person->files_sum, $person->files_other);\n";
+        }
+    }
+}
 
-        // Directories..
-        if (sizeof($entriesDir) > 0) {
-            usort($entriesDir, 'dir_sort_old');
-            reset($entriesDir);
+function populateFileTree( $lang )
+{
+    global $DOCS;
+    $dir = new \DirectoryIterator( $DOCS . $lang );
+    if ( $dir === false )
+    {
+        print "$lang is not a directory.\n";
+        exit;
+    }
+    $cwd = getcwd();
+    $ret = array();
+    chdir( $DOCS . $lang );
+    populateFileTreeRecurse( $lang , "." , $ret );
+    chdir( $cwd );
+    return $ret;
+}
 
-            foreach ($entriesDir as $Edir) {
-                check_old_files($lang, $dir . '/' . $Edir);
-            }
+function populateFileTreeRecurse( $lang , $path , & $output )
+{
+    global $DOCS, $SQL_BUFF;
+    $dir = new DirectoryIterator( $path );
+    if ( $dir === false )
+    {
+        print "$path is not a directory.\n";
+        exit;
+    }
+    $todoPaths = [];
+    $trimPath = ltrim( $path , "./");
+    foreach( $dir as $entry )
+    {
+        $filename = $entry->getFilename();
+        if ( $filename[0] == '.' )
+            continue;
+        if ( substr( $filename , 0 , 9 ) == "entities." )
+            continue;
+        if ( $entry->isDir() )
+        {
+            $todoPaths[] = $path . '/' . $entry->getFilename();
+            continue;
         }
+        if ( $entry->isFile() )
+        {
+            $ignoredFileNames = [
+                'README.md',
+                'translation.xml',
+                'readme.first',
+                'license.xml',
+                'extensions.xml',
+                'versions.xml',
+                'book.developer.xml',
+                'contributors.ent',
+                'contributors.xml',
+                'README',
+                'DO_NOT_TRANSLATE',
+                'rsusi.txt',
+                'missing-ids.xml',
+            ];
+
+            $ignoredDirectories = [
+                'chmonly',
+            ];
+
+            if(
+                in_array($trimPath, $ignoredDirectories, true)
+                || in_array($filename, $ignoredFileNames, true)
+                || (strpos($filename, 'entities.') === 0)
+                || !in_array(substr($filename, -3), ['xml','ent'], true)
+                || (substr($filename, -13) === 'PHPEditBackup')
+                || ($trimPath === 'appendices' && (in_array($filename, ['reserved.constants.xml', 'extensions.xml'], true)))
+            ) continue;
+
+            $file = new FileStatusInfo;
+            $file->path = $trimPath;
+            $file->name = $filename;
+            $file->size = filesize( $path . '/' . $filename );
+            $file->syncStatus = null;
+            if ( $lang != 'en' )
+            {
+                parseRevisionTag( $entry->getPathname() , $file );
+                $path_en = $DOCS . 'en/' . $trimPath . '/' . $filename;
+                if( !is_file($path_en) ) //notinen
+                {
+                    $filesize = $file->size < 1024 ? 1 : floor( $file->size / 1024 );
+                    $SQL_BUFF .= "INSERT INTO notinen VALUES ('$lang', '$trimPath', '$filename', $filesize);\n";
+                 } else {
+                    $output[ $file->getKey() ] = $file;
+                 }
+             } else {
+                 $output[ $file->getKey() ] = $file;
+             }
+         }
     }
-    closedir($dh);
+    sort( $todoPaths );
+    foreach( $todoPaths as $path )
+        populateFileTreeRecurse( $lang , $path , $output );
 }
 
-function get_tags($file) {
-    // Read the first 500 chars. The comment should be at
-    // the begining of the file
-    $fp = @fopen($file, "r") or die("Unable to read $file.");
-    $line = fread($fp, 1024);
-    fclose($fp);
+function parseRevisionTag( $filename , FileStatusInfo $file )
+{
+    $fp = fopen( $filename , "r" );
+    $contents = fread( $fp , 1024 );
+    fclose( $fp );
 
     // No match before the preg
     $match = array ();
 
-    // Check for the translations "revision tag"
-    $regex = "/<!--\s*EN-Revision:\s*(.+)\s*Maintainer:\s*(.+)\s*Status:\s*(.+)\s*-->/U";
-    if (preg_match ( $regex , $line , $match )) {
-        // note the simple quotes
-        return array(trim($match[1]),trim($match[2]),trim($match[3]));
-    }
-
-    // The tag with revision number is not found so search
-    // for n/a revision comment (comment where revision is not known)
-    if (preg_match("'<!--\s*EN-Revision:\s*(n/a)\s*Maintainer:\s*(\\S*)\s*Status:\s*(.+)\s*-->'U",
-    $line, $match)) {
-        // note the simple quotes
-        return array("'" . trim($match[1]) . "'", "'" . trim($match[2]) . "'", "'" . trim($match[3]) . "'");
+    $regex = "'<!--\s*EN-Revision:\s*(.+)\s*Maintainer:\s*(.+)\s*Status:\s*(.+)\s*-->'U";
+    if (preg_match ($regex , $contents , $match )) {
+        $file->hash = trim( $match[1] );
+        $file->maintainer = trim( $match[2] );
+        $file->completion = trim( $match[3] );
     }
+    if ( $file->hash == null or strlen( $file->hash ) != 40 or
+         $file->maintainer == null or
+         $file->completion == null )
+         $file->syncStatus = FileStatusEnum::RevTagProblem;
+
+    $regex = "/<!--\s*CREDITS:\s*(.+)\s*-->/U";
+    $match = array();
+    preg_match ( $regex , $contents , $match );
+    if ( count( $match ) == 2 )
+        $file->credits = str_replace( ' ' , '' , trim( $match[1] ) );
+    else
+        $file->credits = '';
+}
 
-    // Nothing, return with NULL values
-    return array ("NULL", "NULL", "NULL");
-
-} // get_tags() function end
-
-function get_original_rev($file) {
-    // Read the first 500 chars. The comment should be at
-    // the begining of the file
-    $fp = @fopen($file, "r") or die ("Unable to read $file.");
-    $line = fread($fp, 1024);
-    fclose($fp);
-
-    // Return if this was needed (it should be there)
-    // . is for $ in the preg!
-    preg_match("/<!-- .Revision: (\d+) . -->/", $line, $match);
-    if (!empty($match)) {
-        return $match[1];
-    } else {
-        return 0;
+function captureGitValues( & $output )
+{
+    global $DOCS;
+    $cwd = getcwd();
+    chdir( $DOCS . 'en' );
+    $fp = popen( "git --no-pager log --name-only" , "r" );
+    $hash = null;
+    $date = null;
+    $utct = new DateTimeZone( "UTC" );
+    while ( ( $line = fgets( $fp ) ) !== false )
+    {
+        if ( substr( $line , 0 , 7 ) == "commit " )
+        {
+            $hash = trim( substr( $line , 7 ) );
+            continue;
+        }
+        if ( strpos( $line , 'Date:' ) === 0 )
+        {
+            $date = trim( substr( $line , 5 ) );
+            continue;
+        }
+        if ( trim( $line ) == "" )
+            continue;
+        if ( substr( $line , 0 , 4 ) == '    ' )
+            continue;
+        if ( strpos( $line , ': ' ) > 0 )
+            continue;
+        $filename = trim( $line );
+        if ( isset( $output[$filename] ) )
+            continue;
+        $output[$filename]['hash'] = $hash;
     }
+    pclose( $fp );
+    chdir( $cwd );
 }
 
 /**
@@ -460,6 +465,61 @@ function get_original_rev($file) {
 
 $time_start = microtime(true);
 
+$path = null;
+$id = 0;
+asort( $enFiles );
+foreach( $enFiles as $key => $en )
+{
+    if ( $path !== $en->path )
+    {
+        $id++;
+        $path = $en->path;
+        $path2 = $path == '' ? '/' : $path;
+        $SQL_BUFF .= "INSERT INTO dirs VALUES ($id, '$path2');\n";
+    }
+
+    $size = $en->size < 1024 ? 1 : floor( $en->size / 1024 );
+    $filename = $path . ($path == '' ? '' : '/') . $en->name;
+    $en->hash = null;
+    if ( isset( $gitData[ $filename ] ) )
+    {
+        $en->hash = $gitData[ $filename ]['hash'];
+    }
+    else
+        print "Warn: No hash for en/$filename\n";
+
+    $SQL_BUFF .= "INSERT INTO enfiles VALUES ($id, '$en->name', '$en->hash', $size);\n";
+
+    foreach( $LANGS as $lang )
+    {
+        $trFile = isset( $trFiles[$lang][$filename] ) ? $trFiles[$lang][$filename] : null;
+        if ( $trFile == null ) // Untranslated
+        {
+            $SQL_BUFF .= "INSERT INTO Untranslated VALUES ($id, '$lang',
+            '$en->name', $size);\n";
+        } else {
+            if ( $trFile->completion != null && $trFile->completion != "ready" )
+            {
+                $trFile->syncStatus = FileStatusEnum::TranslatedWip;
+                $SQL_BUFF .= "INSERT INTO wip VALUES ($id, '$lang', '$en->name', $size, '$trFile->maintainer');\n";
+                 continue;
+            }
+            if ( $en->hash == $trFile->hash ){
+                $trFile->syncStatus = FileStatusEnum::TranslatedOk;
+            } elseif ( strlen( $trFile->hash ) == 40 ) {
+                $trFile->syncStatus = FileStatusEnum::TranslatedOld;
+            }
+            $SQL_BUFF .= "INSERT INTO translated VALUES ($id, '$lang',
+            '$en->name', '$trFile->hash', $size, '$trFile->maintainer',
+            '$trFile->completion', '$trFile->syncStatus');\n";
+        }
+    }
+}
+
+foreach( $LANGS as $lang ) {
+    computeTranslatorStatus( $lang, $enFiles, $trFiles[$lang] );
+}
+
 $db_name = SQLITE_DIR . 'rev.php.sqlite';
 $tmp_db = SQLITE_DIR . 'rev.php.tmp.sqlite';
 
@@ -491,18 +551,10 @@ function get_original_rev($file) {
 
 // 3 - Fill in the description table while cleaning the langs
 // without revision.xml file
-foreach ($LANGS as $id => $lang) {
-    echo "Fetching the $lang description\n";
-    parse_translation($lang);
-}
-
 // 4 - Recurse in the manual seeking for files and fill $SQL_BUFF
-do_revcheck();
 
-// 4:1 - Recurse in the manuel seeking for old files for each language and fill $SQL_BUFF
-foreach ($LANGS as $lang) {
-    check_old_files($lang, '');
-}
+
+
 
 // 5 - Query $SQL_BUFF and exit
 $db->exec('BEGIN TRANSACTION');
diff --git a/www/revcheck.php b/www/revcheck.php
index 5205c16..87dc8ee 100644
--- a/www/revcheck.php
+++ b/www/revcheck.php
@@ -4,18 +4,11 @@
 include '../include/init.inc.php';
 include '../include/lib_revcheck.inc.php';
 
-// Revision marks used to flag files
-define("REV_UPTODATE", 1); // Up to date files
-define("REV_OUTDATED", 2); // Outdated files
-define("REV_NOREV",    3); // file with revision comment without revision
-define("REV_NOTRANS",  4); // file without translation (utfiles)
-define("REV_WIP",      5); // Work in progress
-
 if (isset($_GET['lang']) && in_array($_GET['lang'], array_keys($LANGUAGES))) {
-	$lang = $_GET['lang'];
+    $lang = $_GET['lang'];
 }
 else {
-	$lang = 'en';
+    $lang = 'en';
 }
 
 if ($lang != 'en' ) $lang_name = $LANGUAGES[$lang];
@@ -23,19 +16,19 @@
 $tool = '';
 
 if (isset($_GET['p'])) {
-	$tool = $_GET['p'];
+    $tool = $_GET['p'];
 }
 
 // Prevent viewing other tools in EN
 if ($lang == 'en') {
-	$tool = 'default';
+    $tool = 'default';
 }
 
 $DBLANG = SQLITE_DIR . 'rev.php.sqlite';
 
 // Check if db connection can be established and if revcheck for requested lang exists
 if ($dbhandle = new SQLite3($DBLANG)) {
-    $check_lang_tmp = $dbhandle->query("SELECT COUNT(lang) AS count FROM description WHERE lang = '$lang'");
+    $check_lang_tmp = $dbhandle->query("SELECT COUNT(lang) AS count FROM descriptions WHERE lang = '$lang'");
     $check_lang = $check_lang_tmp->fetchArray();
     if ($lang != 'en' && $check_lang['count'] < 0) {
         site_header();
@@ -45,33 +38,33 @@
     }
 }
 else {
-	site_header();
-	echo "<p>Database connection couldn't be established</p>";
-	site_footer();
-	die;
+    site_header();
+    echo "<p>Database connection couldn't be established</p>";
+    site_footer();
+    die;
 }
 
 site_header();
 switch($tool) {
-	case 'translators':
-		$translators = get_translators($dbhandle, $lang);
-
-		if (empty($translators)) {
-			echo '<p>Error: no translators info found in database.</p>';
-		}
-		else {
-			$uptodate = get_translators_stats($dbhandle, $lang, 'uptodate');
-			$outdated = get_translators_stats($dbhandle, $lang, 'outdated');
-			$wip      = get_translators_stats($dbhandle, $lang, 'wip');
-
-			foreach($translators as $nick =>$data) {
-				$files_w[$nick] = array('uptodate' => '', 'outdated' => '', 'norev' => '', 'wip' => '');
-				$files_w[$nick]['uptodate'] = isset($uptodate[$nick]) ? $uptodate[$nick] : '';
-				$files_w[$nick]['wip'] = isset($wip[$nick]) ? $wip[$nick] : '';
-				$files_w[$nick]['outdated'] = isset($outdated[$nick]) ? $outdated[$nick] : '';
-			}
-
-			echo <<<TRANSLATORS_HEAD
+ case 'translators':
+    $translators = get_translators($dbhandle, $lang);
+
+    if (empty($translators)) {
+        echo '<p>Error: no translators info found in database.</p>';
+    }
+    else {
+        $uptodate = get_translators_stats($dbhandle, $lang, 'uptodate');
+        $outdated = get_translators_stats($dbhandle, $lang, 'outdated');
+        $wip      = get_translators_stats($dbhandle, $lang, 'wip');
+
+        foreach($translators as $nick =>$data) {
+        $files_w[$nick] = array('uptodate' => '', 'outdated' => '', 'norev' => '', 'wip' => '');
+        $files_w[$nick]['uptodate'] = isset($uptodate[$nick]) ? $uptodate[$nick] : '';
+        $files_w[$nick]['wip'] = isset($wip[$nick]) ? $wip[$nick] : '';
+        $files_w[$nick]['outdated'] = isset($outdated[$nick]) ? $outdated[$nick] : '';
+    }
+
+    echo <<<TRANSLATORS_HEAD
 <table border="0" cellpadding="4" cellspacing="1">
 <tr>
 <th rowspan="2">Name</th>
@@ -87,225 +80,256 @@
 </tr>
 TRANSLATORS_HEAD;
 
-			foreach ($translators as $nick => $data) {
-				echo '<tr>',
-				'<td><a href="mailto:'.$data['mail'].'">'.$data['name'].'</a></td>',
-				'<td><a href="/revcheck.php?p=files&amp;user='.$nick.'&amp;lang='.$lang.'">'.$nick.'</a></td>',
-				'<td>'.(($data['karma'] == 'yes') ? '✓' : '&nbsp;').'</td>',
-				'<td>' , @$files_w[$nick]['uptodate'], '</td>',
-				'<td>' , $files_w[$nick]['outdated'], '</td>',
-				'<td>', $files_w[$nick]['wip'], '</td>',
-				'<th>' , @array_sum($files_w[$nick]), '</th>',
-				'</tr>';
-			}
-			echo '</table>';
-		}
-		echo gen_date($DBLANG);
-	break;
-
-	case 'missfiles':
-		$missfiles = get_missfiles($dbhandle, $lang);
-		if (!$missfiles) {
-			echo '<p>All files translated? Would be nice... but it\'s probably an error :(</p>';
-		}
-		else {
-			$num = count($missfiles);
-			echo '<table border="0" cellpadding="3" cellspacing="1" style="text-align:center">';
-			echo '<tr><th rowspan="1">Available for translation ('.$num.' files):</th><th>Commit Hash</th><th colspan="1">kB</th></tr>';
-
-			$last_dir = false;
-			$total_size = 0;
-			foreach ($missfiles as $miss) {
-				if (!$last_dir || $last_dir != $miss['dir']) {
-					echo '<tr><th colspan="3">'.$miss['dir'].'</th></tr>';
-					$last_dir = $miss['dir'];
-				}
-				echo '<tr><td>'.$miss['file'].'</td><td>'.$miss['revision'].'</td><td>'.$miss['size'].'</td></tr>';
-				$total_size += $miss['size'];
-				// flush every 200 kbytes
-				if (($total_size % 200) == 0) {
-					flush();
-				}
-			}
-			echo '<tr><th colspan="3">Total Size ('.$num.' files): '.$total_size.' kB</th></tr>';
-			echo '</table>';
-		}
-		echo gen_date($DBLANG);
-	break;
-
-	case 'oldfiles':
-		$oldfiles = get_oldfiles($dbhandle, $lang);
-		if (!$oldfiles) {
-			echo '<p>Good, it seems that this translation doesn\'t contain any file which is not present in English tree.</p>';
-		}
-		else {
-			$num = count($oldfiles);
-			echo '<table width="400" border="0" cellpadding="3" cellspacing="1" style="text-align:center">';
-			echo '<tr><th rowspan="1">Not in EN tree ('.$num.' files):</th><th colspan="1">kB</th></tr>';
-
-			$last_dir = false;
-			$total_size = 0;
-			foreach ($oldfiles as $old) {
-				if (!$last_dir || $last_dir != $old['dir']) {
-					echo '<tr><th colspan="2">'.$old['dir'].'</th></tr>';
-					$last_dir = $old['dir'];
-				}
-				echo '<tr><td>', $old['file'], '</td><td class="r">'.$old['size'].'</td></tr>';
-				$total_size += $old['size'];
-				// flush every 200 kbytes
-				if (($total_size % 200) == 0) {
-					flush();
-				}
-			}
-			echo '<tr><th colspan="2">Total Size ('.$num.' files): '.$total_size.' kB</th></tr>';
-			echo '</table>';
-		}
-		echo gen_date($DBLANG);
-	break;
-
-	case 'misstags':
-		$misstags = get_misstags($dbhandle, $lang);
-
-		if ($misstags == NULL) {
-			echo '<p>Good, all files contain revision numbers.</p>';
-		}
-		else {
-		 $num = count($misstags);
-			echo '<table border="0" cellpadding="3" cellspacing="1" style="text-align:center">';
-			echo '<tr><th rowspan="2">Files without EN-Revision number ('.$num.' files):</th><th colspan="3">Sizes in kB</th></tr>';
-			echo '<tr><th>en</th><th>'.$lang.'</th><th>diff</th></</tr>';
-
-			$last_dir = false;
-
-			foreach ($misstags as $row) {
-				if (!$last_dir || $last_dir != $row['dir']) {
-					echo '<tr><th colspan="4">'.$row['dir'].'</th></tr>';
-					$last_dir = $row['dir'];
-				}
-				echo '<tr><td>'.$row['name'].'</td><td>'.$row['en_size'].'</td><td>'.$row['trans_size'].'</td><td>'.(intval($row['en_size'] - $row['trans_size'])).'</td></tr>';
-			}
-			echo '</table>';
-		}
-		echo gen_date($DBLANG);
-	break;
-
-	case 'filesummary':
-		$file_types = array(
-			array (REV_UPTODATE, 'Up to date files'),
-			array (REV_OUTDATED, 'Outdated files'),
-			array (REV_WIP,      'Work in progress'),
-			array (REV_NOREV,    'Files without revision number'),
-			array (REV_NOTRANS,  'Files available for translation')
-		);
-
-		$file_summary_array = array(
-			REV_UPTODATE => array(0,0),
-			REV_OUTDATED => array(0,0),
-			REV_NOREV    => array(0,0),
-			REV_NOTRANS  => array(0,0),
-			REV_WIP      => array(0,0)
-		);
-
-		$file_summary_array[REV_UPTODATE] = get_stats($dbhandle, $lang, 'uptodate');
-		$file_summary_array[REV_OUTDATED] = get_stats($dbhandle, $lang, 'outdated');
-		$file_summary_array[REV_NOREV]    = get_stats($dbhandle, $lang, 'norev');
-		$file_summary_array[REV_NOTRANS]  = get_stats($dbhandle, $lang, 'notrans');
-		$file_summary_array[REV_WIP]      = get_stats($dbhandle, $lang, 'wip');
-
-		echo '<table border="0" cellpadding="4" cellspacing="1" style="text-align:center;">';
-		echo '<tr><th>File status type</th><th>Number of files</th><th>Percent of files</th><th>Size of files (kB)</th><th>Percent of size</th></tr>';
-
-		$percent = array(0, 0);
-
-		foreach($file_summary_array as $t => $a) {
-			$percent[0] += $a[0];
-			$percent[1] += $a[1];
-		}
-
-		foreach ($file_types as $num => $type) {
-			$tmp_num_percent_0 = ($percent[0] == 0) ? 0 : number_format($file_summary_array[$type[0]][0] * 100 / $percent[0], 2 );
-			$tmp_num_percent_1 = ($percent[0] == 0) ? 0 : number_format($file_summary_array[$type[0]][1] * 100 / $percent[1], 2);
-
-			echo '<tr>';
-			echo '<td>'.$type[1].'</td>';
-			echo '<td>'.$file_summary_array[$type[0]][0].'</td>';
-			echo '<td>'.$tmp_num_percent_0.'%</td>';
-			echo '<td>'.$file_summary_array[$type[0]][1].'</td>';
-			echo '<td>'.$tmp_num_percent_1.'%</td>';
-			echo '</tr>';
-		}
-
-		echo '<tr><th>Files total</th><th>'.$percent[0].'</th><th>100%</th><th>'.$percent[1].'</th><th>100%</th></tr>';
-		echo '</table>';
-		echo gen_date($DBLANG);
-	break;
-
-
-	case 'files' :
-		// we need a dir to browse
-		$dirs = get_dirs($dbhandle, $lang);
-		$users = get_translators($dbhandle, $lang);
-
-		if (empty($dirs)) {
-			echo '<p>Error: no directories found in database.</p>';
-			$sidebar = nav_tools($lang);
-			site_footer($sidebar);
-			die;
-		}
-
-		echo '<p>This tool allows you to check which files in your translation need updates. To show the list ';
-		echo 'choose a directory (it doesn\'t work recursively) or translator.</p>';
-		echo '<p>When you click on the filename you will see the plaintext diff showing changes between revisions, so ';
-		echo 'you will know what has changed in the English version and which information you need to update.';
-		echo 'You can also click on [diff] to show the colored diff.</p>';
-		echo '<p>Choose a directory:</p>';
-		echo '<form method="get" action="revcheck.php"><p><select name="dir">';
-		foreach ($dirs as $id => $name) {
-			if (isset($_GET['dir']) && $_GET['dir'] == $id) {
-				$selected = ' selected="selected"';
-			}
-			else {
-				$selected = '';
-			}
-			echo '<option value="'.$id.'"'.$selected.'>'.$name.'</option>';
-		}
-		echo '</select>';
-		echo '<input type="hidden" name="p" value="files">';
-		echo '<input type="hidden" name="lang" value="'.$lang.'">';
-		echo '<input type="submit" value="See outdated files"></p></form>';
-
-		echo '<p>Or choose a translator:</p>';
-		echo '<form method="get" action="revcheck.php"><p><select name="user">';
-		foreach ($users as $id => $user) {
-			if (isset($_GET['user']) && $_GET['user'] == $id) {
-				$selected = ' selected="selected"';
-			}
-			else {
-				$selected = '';
-			}
-			echo '<option value="'.$id.'"'.$selected.'>'.$id.'</option>';
-		}
-		echo '</select>';
-		echo '<input type="hidden" name="p" value="files">';
-		echo '<input type="hidden" name="lang" value="'.$lang.'">';
-		echo '<input type="submit" value="See outdated files"></p></form>';
-
-		// Get outdated files filtered as requested
-		if (isset($_GET['user'])) {
-			$outdated = get_outdated_files($dbhandle, $lang, 'translator', $_GET['user']);
-		}
-		elseif (isset($_GET['dir'])) {
-			$outdated = get_outdated_files($dbhandle, $lang, 'dir', $_GET['dir']);
-		}
-		else {
-			$outdated = get_outdated_files($dbhandle, $lang, 'all');
-		}
-
-		if (empty($outdated)) {
-			echo '<p>Good, it seems that all files are up to date for these conditions.</p>';
-		}
-		else {
-			echo <<<END_OF_MULTILINE
+    foreach ($translators as $nick => $data) {
+        echo '<tr>',
+        '<td><a href="mailto:'.$data['mail'].'">'.$data['name'].'</a></td>',
+        '<td><a href="/revcheck.php?p=files&amp;user='.$nick.'&amp;lang='.$lang.'">'.$nick.'</a></td>',
+        '<td>'.(($data['karma'] == 'yes') ? '✓' : '&nbsp;').'</td>',
+        '<td>' , @$files_w[$nick]['uptodate'], '</td>',
+        '<td>' , $files_w[$nick]['outdated'], '</td>',
+        '<td>', $files_w[$nick]['wip'], '</td>',
+        '<th>' , @array_sum($files_w[$nick]), '</th>',
+        '</tr>';
+    }
+    echo '</table>';
+ }
+ echo gen_date($DBLANG);
+ break;
+
+ case 'missfiles':
+     $missfiles = get_missfiles($dbhandle, $lang);
+     if (!$missfiles) {
+         echo '<p>All files translated? Would be nice... but it\'s probably an error :(</p>';
+     } else {
+         $num = count($missfiles);
+         echo '<table border="0" cellpadding="3" cellspacing="1" style="text-align:center">';
+         echo '<tr><th rowspan="1">Available for translation ('.$num.' files):</th><th>Commit Hash</th><th colspan="1">kB</th></tr>';
+
+         $last_dir = false;
+         $total_size = 0;
+         foreach ($missfiles as $miss) {
+         if (!$last_dir || $last_dir != $miss['dir']) {
+         echo '<tr><th colspan="3">'.$miss['dir'].'</th></tr>';
+         $last_dir = $miss['dir'];
+     }
+     $key = $miss['dir'] == '' ? "/" : $miss['dir']."/". $miss['file'];
+     echo "<tr><td><a href='/gitweb/?p=doc/en.git;a=blob;f=$key;hb={$miss['revision']}'>{$miss['file']}</a></td><td>{$miss['revision']}</td><td>{$miss['size']}</td></tr>";
+     $total_size += $miss['size'];
+     // flush every 200 kbytes
+     if (($total_size % 200) == 0)
+         flush();
+     }
+     echo "<tr><th colspan='3'>Total Size ($num files): $total_size kB</th></tr>";
+     echo '</table>';
+ }
+	echo gen_date($DBLANG);
+ break;
+
+ case 'oldfiles':
+     $oldfiles = get_oldfiles($dbhandle, $lang);
+     if (!$oldfiles) {
+         echo '<p>Good, it seems that this translation doesn\'t contain any file which is not present in English tree.</p>';
+     } else {
+         $num = count($oldfiles);
+         echo '<table width="400" border="0" cellpadding="3" cellspacing="1" style="text-align:center">';
+         echo '<tr><th rowspan="1">Not in EN tree ('.$num.' files):</th><th colspan="1">kB</th></tr>';
+
+         $last_dir = false;
+         $total_size = 0;
+         foreach ($oldfiles as $old) {
+         if (!$last_dir || $last_dir != $old['dir']) {
+         echo '<tr><th colspan="2">'.$old['dir'].'</th></tr>';
+         $last_dir = $old['dir'];
+     }
+     echo '<tr><td>', $old['file'], '</td><td class="r">'.$old['size'].'</td></tr>';
+     $total_size += $old['size'];
+     // flush every 200 kbytes
+     if (($total_size % 200) == 0)
+         flush();
+ }
+ echo '<tr><th colspan="2">Total Size ('.$num.' files): '.$total_size.' kB</th></tr>';
+ echo '</table>';
+ }
+ echo gen_date($DBLANG);
+ break;
+
+ case 'misstags':
+     $misstags = get_misstags($dbhandle, $lang);
+
+     if ($misstags == NULL) {
+         echo '<p>Good, all files contain revision numbers.</p>';
+     } else {
+         $num = count($misstags);
+         echo '<table border="0" cellpadding="3" cellspacing="1" style="text-align:center">';
+         echo '<tr><th rowspan="2">Files without EN-Revision number ('.$num.' files):</th><th colspan="3">Sizes in kB</th></tr>';
+         echo '<tr><th>en</th><th>'.$lang.'</th><th>diff</th></tr>';
+
+         $last_dir = false;
+
+         foreach ($misstags as $row) {
+             if (!$last_dir || $last_dir != $row['dir']) {
+             echo '<tr><th colspan="4">'.$row['dir'].'</th></tr>';
+             $last_dir = $row['dir'];
+          }
+          echo '<tr><td>'.$row['name'].'</td><td>'.$row['en_size'].'</td><td>'.$row['trans_size'].'</td><td>'.(intval($row['en_size'] - $row['trans_size'])).'</td></tr>';
+     }
+     echo '</table>';
+ }
+ echo gen_date($DBLANG);
+ break;
+
+ case 'filesummary':
+     $files_uptodate = get_stats($dbhandle, $lang, 'uptodate');
+     $files_outdated = get_stats($dbhandle, $lang, 'outdated');
+     $files_norev    = get_stats($dbhandle, $lang, 'norev');
+     $files_notrans  = get_stats($dbhandle, $lang, 'notrans');
+     $files_wip      = get_stats($dbhandle, $lang, 'wip');
+     $files_notinen  = get_stats($dbhandle, $lang, 'notinen');
+
+     echo '<table border="0" cellpadding="4" cellspacing="1" style="text-align:center;">';
+     echo '<tr><th>File status type</th><th>Number of files</th><th>Percent of files</th><th>Size of files (kB)</th><th>Percent of size</th></tr>';
+
+     $percent[0] = 0;
+     $percent[1] = 0;
+     #$percent[0] = count_en_files($dbhandle);
+
+     $percent[0] += $files_uptodate[0];
+     $percent[0] += $files_outdated[0];
+     $percent[0] += $files_norev[0];
+     $percent[0] += $files_notrans[0];
+     $percent[0] += $files_wip[0];
+     $percent[0] += $files_notinen[0];
+
+     $percent[1] += $files_uptodate[1];
+     $percent[1] += $files_outdated[1];
+     $percent[1] += $files_norev[1];
+     $percent[1] += $files_notrans[1];
+     $percent[1] += $files_wip[1];
+     $percent[1] += $files_notinen[1];
+
+
+     $num_uptodate_percent = number_format($files_uptodate[0] * 100 / $percent[0], 2 );
+     $num_outdated_percent = number_format($files_outdated[0] * 100 / $percent[0], 2 );
+     $num_wip_percent = number_format($files_wip[0] * 100 / $percent[0], 2 );
+     $num_norev_percent = number_format($files_norev[0] * 100 / $percent[0], 2 );
+     $num_notinen_percent = number_format($files_notinen[0] * 100 / $percent[0], 2 );
+     $num_notrans_percent = number_format($files_notrans[0] * 100 / $percent[0], 2 );
+
+     $size_uptodate_percent = number_format($files_uptodate[1] * 100 / $percent[1], 2 );
+     $size_outdated_percent = number_format($files_outdated[1] * 100 / $percent[1], 2 );
+     $size_wip_percent = number_format($files_wip[1] * 100 / $percent[1], 2 );
+     $size_norev_percent = number_format($files_norev[1] * 100 / $percent[1], 2 );
+     $size_notinen_percent = number_format($files_notinen[1] * 100 / $percent[1], 2 );
+     $size_notrans_percent = number_format($files_notrans[1] * 100 / $percent[1], 2 );
+     print <<<HTML
+<tr>
+<td>Up to date files</td>
+<td>{$files_uptodate[0]}</td>
+<td>{$num_uptodate_percent}%</td>
+<td>{$files_uptodate[1]}</td>
+<td>{$size_uptodate_percent}%</td>
+</tr><tr>
+<td>Outdated files</td>
+<td>{$files_outdated[0]}</td>
+<td>{$num_outdated_percent}%</td>
+<td>{$files_outdated[1]}</td>
+<td>{$size_outdated_percent}%</td>
+</tr><tr>
+<td>Work in progress</td>
+<td>{$files_wip[0]}</td>
+<td>{$num_wip_percent}%</td>
+<td>{$files_wip[1]}</td>
+<td>{$size_wip_percent}%</td>
+</tr><tr>
+<td>Files without revision number</td>
+<td>{$files_norev[0]}</td>
+<td>{$num_norev_percent}%</td>
+<td>{$files_norev[1]}</td>
+<td>{$size_norev_percent}%</td>
+</tr><tr>
+<td>Not in EN tree</td>
+<td>{$files_notinen[0]}</td>
+<td>{$num_notinen_percent}%</td>
+<td>{$files_notinen[1]}</td>
+<td>{$size_notinen_percent}%</td>
+</tr><tr>
+<td>Files available for translation	</td>
+<td>{$files_notrans[0]}</td>
+<td>{$num_notrans_percent}%</td>
+<td>{$files_notrans[1]}</td>
+<td>{$size_notrans_percent}%</td>
+</tr><tr>
+<th>Files total</th>
+<th>{$percent[0]}</th>
+<th>100%</th>
+<th>{$percent[1]}</th
+><th>100%</th>
+</tr></table>
+HTML;
+ echo gen_date($DBLANG);
+ break;
+
+
+ case 'files' :
+     // we need a dir to browse
+     $dirs = get_dirs($dbhandle, $lang);
+     $users = get_translators($dbhandle, $lang);
+     /*
+     if (empty($dirs)) {
+         echo '<p>Error: no directories found in database.</p>';
+         $sidebar = nav_tools($lang);
+         site_footer($sidebar);
+         die;
+     }
+     */
+     echo '<p>This tool allows you to check which files in your translation need updates. To show the list ';
+     echo 'choose a directory (it doesn\'t work recursively) or translator.</p>';
+     echo '<p>When you click on the filename you will see the plaintext diff showing changes between revisions, so ';
+     echo 'you will know what has changed in the English version and which information you need to update.';
+     echo 'You can also click on [diff] to show the colored diff.</p>';
+     echo '<p>Choose a directory:</p>';
+     echo '<form method="get" action="revcheck.php"><p><select name="dir">';
+     foreach ($dirs as $id => $name) {
+         if (isset($_GET['dir']) && $_GET['dir'] == $id) {
+         $selected = ' selected="selected"';
+         } else {
+             $selected = '';
+         }
+         echo '<option value="'.$id.'"'.$selected.'>'.$name.'</option>';
+     }
+     echo '</select>';
+     echo '<input type="hidden" name="p" value="files">';
+     echo '<input type="hidden" name="lang" value="'.$lang.'">';
+     echo '<input type="submit" value="See outdated files"></p></form>';
+
+     echo '<p>Or choose a translator:</p>';
+     echo '<form method="get" action="revcheck.php"><p><select name="user">';
+     foreach ($users as $id => $user) {
+         if (isset($_GET['user']) && $_GET['user'] == $id) {
+         $selected = ' selected="selected"';
+         } else {
+             $selected = '';
+         }
+         echo '<option value="'.$id.'"'.$selected.'>'.$id.'</option>';
+     }
+     echo '</select>';
+     echo '<input type="hidden" name="p" value="files">';
+     echo '<input type="hidden" name="lang" value="'.$lang.'">';
+     echo '<input type="submit" value="See outdated files"></p></form>';
+
+     // Get outdated files filtered as requested
+     if (isset($_GET['user'])) {
+         $outdated = get_outdated_files($dbhandle, $lang, 'translator', $_GET['user']);
+     } elseif (isset($_GET['dir'])) {
+         $outdated = get_outdated_files($dbhandle, $lang, 'dir', $_GET['dir']);
+     } else {
+         $outdated = get_outdated_files($dbhandle, $lang, 'all');
+     }
+
+     if (empty($outdated)) {
+         echo '<p>Good, it seems that all files are up to date for these conditions.</p>';
+     } else {
+        echo <<<END_OF_MULTILINE
 <table border="0" cellpadding="4" cellspacing="1" style="text-align:center">
 <tr>
 <th rowspan="2">Translated file</th>
@@ -319,80 +343,76 @@
 </tr>
 <tr><th colspan="5">{$outdated[0]['name']}</th></tr>
 END_OF_MULTILINE;
-			$last_dir = false;
-			$prev_name = $outdated[0]['name'];
-
-			foreach ($outdated as $r) {
-				if ($r['name'] != $prev_name) {
-				   echo '<tr><th colspan="5">'.$r['name'].'</th></tr>';
-				   $prev_name = $r['name'];
-				}
-
-				// Make the maintainer a link, if we have that maintainer in the list
-				if ($r['maintainer'] && $r["maintainer"] != 'nobody') {
-					$r["maintainer"] = '<a href="?p=translators&amp;lang=' . $lang . '">' . $r["maintainer"] . '</a>';
-				}
-
-				// Make a link to the GIT repository's diff script
-				$key = substr($r['name'] . '/' . $r['file'], 1);
-				if ($r['name'] == '/') {
-				    $key = $r['file'];
-				}
-				//text
-				$d1 = "/gitweb/?p=doc/en.git;a=blobdiff_plain;f=$key;hb={$r['en_rev']};hpb={$r['trans_rev']};";
-
-				//html
-				$d2 = "/gitweb/?p=doc/en.git;a=blobdiff;f=$key;hb={$r['en_rev']};hpb={$r['trans_rev']};";
-
-				$nm = "<a href='$d1'>{$r['file']}</a> <a href='$d2'>(html)</a>";
-
-				$h1 = "<a href='/gitweb/?p=doc/en.git;a=blob;f=$key;hb={$r['en_rev']}'>{$r['en_rev']}</a>";
-
-				$h2 = "<a href='/gitweb/?p=doc/en.git;a=blob;f=$key;hb={$r['trans_rev']}'>{$r['trans_rev']}</a>";
-
-				// Write out the line for the current file (get file name shorter)
-				echo '<tr>'.
-				"<td style='white-space:nowrap'>{$nm}</td>".
-				"<td>{$h1}</td>" .
-				"<td>{$h2}</td>" .
-				"<td> {$r['maintainer']}</td>" .
-				"<td> {$r['status']}</td></tr>\n";
-			}
-			echo '</table>';
-		}
-		echo gen_date($DBLANG);
-	break;
+        $last_dir = false;
+        $prev_name = $outdated[0]['name'];
+
+        foreach ($outdated as $r) {
+            if ($r['name'] != $prev_name) {
+            echo '<tr><th colspan="5">'.$r['name'].'</th></tr>';
+            $prev_name = $r['name'];
+        }
+
+        // Make the maintainer a link, if we have that maintainer in the list
+        if ($r['maintainer'] && $r["maintainer"] != 'nobody') {
+            $r["maintainer"] = '<a href="?p=translators&amp;lang=' . $lang . '">' . $r["maintainer"] . '</a>';
+        }
+
+        // Make a link to the GIT repository's diff script
+        $key = $r['name'] . '/' . $r['file'];
+        if ($r['name'] == '/')
+            $key = $r['file'];
+
+        //text
+        $d1 = "/gitweb/?p=doc/en.git;a=blobdiff_plain;f=$key;hb={$r['en_rev']};hpb={$r['trans_rev']};";
+        //html
+        $d2 = "/gitweb/?p=doc/en.git;a=blobdiff;f=$key;hb={$r['en_rev']};hpb={$r['trans_rev']};";
+
+        $h1 = "<a href='/gitweb/?p=doc/en.git;a=blob;f=$key;hb={$r['en_rev']}'>{$r['en_rev']}</a>";
+        $h2 = "<a href='/gitweb/?p=doc/en.git;a=blob;f=$key;hb={$r['trans_rev']}'>{$r['trans_rev']}</a>";
+
+        $nm = "<a href='$d1'>{$r['file']}</a> <a href='$d2'>(html)</a>";
+
+        // Write out the line for the current file (get file name shorter)
+        echo '<tr>'.
+        "<td style='white-space:nowrap'>{$nm}</td>".
+        "<td>{$h1}</td>" .
+        "<td>{$h2}</td>" .
+        "<td> {$r['maintainer']}</td>" .
+        "<td> {$r['status']}</td></tr>\n";
+     }
+     echo '</table>';
+ }
+ echo gen_date($DBLANG);
+ break;
 
 	case 'graph':
-		$path = "images/revcheck/info_revcheck_php_$lang.png";
-		if (is_readable($path)) {
-			echo '<img src="'.$path.'" alt="info">';
-			echo gen_date($DBLANG);
-		}
-		else {
-			echo "<p>Can't find graph.</p>";
-		}
-	break;
-
-	default:
-		if ($lang == 'en') {
-			echo '<img src="images/revcheck/info_revcheck_php_all_lang.png" alt="Info" class="chart">';
-			echo '<p>This is all what we can show for original manual. To get more tools, please select translation language.</p>';
-			echo gen_date($DBLANG);
-			$sidebar = nav_languages();
-			site_footer($sidebar);
-		}
-		else {
-			$intro_result = $dbhandle->query("SELECT intro FROM description WHERE lang = '$lang'");
-			$intro = $intro_result->fetchArray();
-			echo '<h2>Intro for language</h2>';
-			echo '<p>'.$intro[0].'</p>';
-			echo '<p>Links to available tools are placed on the right sidebar.</p>';
-		}
+     $path = "images/revcheck/info_revcheck_php_$lang.png";
+     if (is_readable($path)) {
+         echo '<img src="'.$path.'" alt="info">';
+         echo gen_date($DBLANG);
+     } else {
+         echo "<p>Can't find graph.</p>";
+     }
+ break;
+
+ default:
+     if ($lang == 'en') {
+         echo '<img src="images/revcheck/info_revcheck_php_all_lang.png" alt="Info" class="chart">';
+         echo '<p>This is all what we can show for original manual. To get more tools, please select translation language.</p>';
+         echo gen_date($DBLANG);
+         $sidebar = nav_languages();
+         site_footer($sidebar);
+     } else {
+         $intro_result = $dbhandle->query("SELECT intro FROM descriptions WHERE lang = '$lang'");
+         $intro = $intro_result->fetchArray();
+         echo '<h2>Intro for language</h2>';
+         echo '<p>'.$intro[0].'</p>';
+         echo '<p>Links to available tools are placed on the right sidebar.</p>';
+		   }
 	break;
 }
 
 if ($lang != 'en') {
-	$sidebar = nav_tools($lang);
-	site_footer($sidebar);
+    $sidebar = nav_tools($lang);
+    site_footer($sidebar);
 }