Index: /trunk/coverager/common-en.lang.php
===================================================================
--- /trunk/coverager/common-en.lang.php	(revision 124)
+++ /trunk/coverager/common-en.lang.php	(revision 124)
@@ -0,0 +1,5 @@
+<?php
+
+$GLOBALS['show_todo_strings'] = false;
+
+?>
Index: /trunk/coverager/common-zh-simplified-utf-8.lang.php
===================================================================
--- /trunk/coverager/common-zh-simplified-utf-8.lang.php	(revision 124)
+++ /trunk/coverager/common-zh-simplified-utf-8.lang.php	(revision 124)
@@ -0,0 +1,25 @@
+<?php
+
+$strings = array(
+		'root'
+		=> '开始',
+		'Directory'
+		=> '目录',
+		'File'
+		=> '文件',
+		'Percent'
+		=> '覆盖率',
+		'Hits'
+		=> '命中',
+		'Lines'
+		=> '行数',
+		'TODO'
+		=> '闲置文件',
+		'XCache PHP Code Coverage Viewer'
+		=> 'XCache PHP 代码覆盖查看器',
+		'module'
+		=> '模块',
+		''
+		=> '',
+		);
+
Index: /trunk/coverager/common.php
===================================================================
--- /trunk/coverager/common.php	(revision 124)
+++ /trunk/coverager/common.php	(revision 124)
@@ -0,0 +1,75 @@
+<?php
+
+function get_language_file_ex($name, $l, $s)
+{
+	static $map = array(
+			'zh'    => 'zh-simplified',
+			'zh-hk' => 'zh-traditional',
+			'zh-tw' => 'zh-traditional',
+			);
+
+	if (isset($map[$l])) {
+		$l = $map[$l];
+	}
+	if (file_exists($file = "$name-$l-$s.lang.php")) {
+		return $file;
+	}
+	if (file_exists($file = "$name-$l.lang.php")) {
+		return $file;
+	}
+	return null;
+}
+
+function get_language_file($name)
+{
+	global $charset, $lang;
+	$s = strtolower($charset);
+	if (isset($lang)) {
+		$file = get_language_file_ex($name, strtolower($lang), $s);
+	}
+	else if (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
+		foreach (explode(',', str_replace(' ', '', $_SERVER['HTTP_ACCEPT_LANGUAGE'])) as $l) {
+			$l = strtok($l, ';');
+			$file = get_language_file_ex($name, $l, $s);
+			if (isset($file)) {
+				$lang = $l;
+				break;
+			}
+			if (strpos($l, '-') !== false) {
+				$ll = strtok($l, '-');
+				$file = get_language_file_ex($name, $ll, $s);
+				if (isset($file)) {
+					$lang = $l;
+					break;
+				}
+			}
+		}
+	}
+	return isset($file) ? $file : "$name-en.lang.php";
+}
+
+function _T($str)
+{
+	if (isset($GLOBALS['strings'][$str])) {
+		return $GLOBALS['strings'][$str];
+	}
+	if (!empty($GLOBALS['show_todo_strings'])) {
+		return '<span style="color:red">' . htmlspecialchars($str) . '</span>';
+	}
+	return $str;
+}
+
+error_reporting(E_ALL);
+define('REQUEST_TIME', time());
+
+$charset = "UTF-8";
+if (file_exists("./config.php")) {
+	include("./config.php");
+}
+
+include(get_language_file("common"));
+if (!isset($lang)) {
+	$lang = 'en-us';
+}
+
+?>
Index: /trunk/coverager/config.php.example
===================================================================
--- /trunk/coverager/config.php.example	(revision 123)
+++ /trunk/coverager/config.php.example	(revision 124)
@@ -1,7 +1,15 @@
 <?php
 
-// should be named as config.php
+// this is an example only
+// write your own config and name it as config.php
+
+// detected by browser
+// $lang = 'en-us';
 
 $charset = "UTF-8";
+
+// developers only
+$show_todo_strings = false;
+
 // $include_paths = array("/www/my-php-project/");
 // $exclude_paths = array("/www/my-php-project/tmp/");
@@ -13,7 +21,36 @@
 function ob_filter_path_nicer($o)
 {
+	$o = str_replace($_SERVER['DOCUMENT_ROOT'],  "{DOCROOT}/", $o);
+	$xcachedir = realpath(dirname(__FILE__) . "/../");
+	$o = str_replace($xcachedir . "/", "{XCache}/", $o);
 	$o = str_replace("/home/", "{H}/", $o);
 	return $o;
 }
 
+// implement your auth here if needed
+// {{{ home made login example
+// this is an example only, it's won't work for you without your implemention.
+function check_admin_auth()
+{
+	require("/path/to/user-login-and-permission-lib.php");
+	session_start();
+
+	if (!user_logined()) {
+		if (!ask_the_user_to_login()) {
+			exit;
+		}
+	}
+
+	user_load_permissions();
+	if (!user_is_admin()) {
+		die("Permission denied");
+	}
+
+	return true;
+}
+
+// uncomment:
+// check_admin_auth()
+// }}}
+
 ?>
Index: /trunk/coverager/coverager.css
===================================================================
--- /trunk/coverager/coverager.css	(revision 123)
+++ /trunk/coverager/coverager.css	(revision 124)
@@ -1,7 +1,8 @@
+h1 { text-align: center; }
 input, table { font-family: monospace; font-size: 11px; }
 table.cycles { border: 1px solid black; background: white; margin-top: 5px; margin-bottom: 5px; }
 table.cycles .col1 { background-color: #f5f5f5; }
 table.cycles .col2 { background-color: #e0e0e0; }
-table.cycles th { background-color: #707090; color: white; font-weight: bold; height: 20px; line-height: 16px; font-family: serif; }
+table.cycles th { background-color: #707090; color: white; font-weight: bold; height: 20px; line-height: 18px; font-family: serif; }
 th a { color: white; font-weight: bold; display: block; width: 100%; height: 100%; }
 
@@ -34,5 +35,5 @@
 	width: 100%;
 }
-.coverBarHi, .coverBarMed, .coverBarLo { left: 1px; top: 1px; }
+.coverBarHi, .coverBarMed, .coverBarLo { left: 1px; top: 1px; height: 14px; }
 .coverBarHi  { background-color: #A7FC9D; }
 .coverBarMed { background-color: #FFEA20; }
@@ -56,2 +57,4 @@
 	border: 1px solid gray;
 }
+
+.footnote { text-align: right; font-size: 12px; }
Index: /trunk/coverager/coverager.php
===================================================================
--- /trunk/coverager/coverager.php	(revision 123)
+++ /trunk/coverager/coverager.php	(revision 124)
@@ -1,6 +1,5 @@
 <?php
 
-error_reporting(E_ALL);
-define('REQUEST_TIME', time());
+include("./common.php");
 
 class Cycle
@@ -41,4 +40,9 @@
 	var $exclude_paths = array();
 	var $charset = 'UTF-8';
+	var $lang = 'en-us';
+	var $datadir = null;
+	var $datadir_len = null;
+	var $path = null;
+	var $outpath = null;
 
 	function XcacheCoverageViewer()
@@ -47,12 +51,12 @@
 
 		// copy config
-		foreach (array('charset', 'include_paths', 'exclude_paths', 'syntaxhiglight', 'usecache', 'datadir') as $k) {
-			if (isset($GLOBALS['usecache'])) {
-				$this->{$k} = $GLOBALS['usecache'];
+		foreach (array('charset', 'include_paths', 'exclude_paths', 'syntaxhiglight', 'usecache', 'datadir', 'lang') as $k) {
+			if (isset($GLOBALS[$k])) {
+				$this->{$k} = $GLOBALS[$k];
 			}
 		}
 
 		$this->datadir = preg_replace('!/$!', '', $this->datadir);
-		$this->datadir_len =  strlen($this->datadir);
+		$this->datadir_len = strlen($this->datadir);
 
 		$this->path = isset($_GET['path']) ? $_GET['path'] : '';
@@ -125,4 +129,5 @@
 		}
 
+		$xcache_version = XCACHE_VERSION;
 		include("coverager.tpl.php");
 	}
@@ -304,8 +309,4 @@
 }
 
-if (file_exists("config.php")) {
-	include("config.php");
-}
-
 $app = new XcacheCoverageViewer();
 $app->main();
Index: /trunk/coverager/coverager.tpl.php
===================================================================
--- /trunk/coverager/coverager.tpl.php	(revision 123)
+++ /trunk/coverager/coverager.tpl.php	(revision 124)
@@ -6,4 +6,5 @@
 echo <<<HEAD
 	<meta http-equiv="Content-Type" content="text/html; charset=$this->charset" />
+	<meta http-equiv="Content-Language" content="{$this->lang}" />
 	<script type="text/javascript" src="tablesort.js" charset="$this->charset"></script>
 HEAD;
@@ -11,7 +12,8 @@
 
 	<link rel="stylesheet" type="text/css" href="coverager.css" />
-	<title>XCache Coverage Viewer</title>
+	<title><?php echo _T("XCache PHP Code Coverage Viewer"); ?></title>
 </head>
 <body>
+<h1><?php echo _T("XCache PHP Code Coverage Viewer"); ?></h1>
 
 <?php
@@ -49,8 +51,13 @@
 	global $cycle;
 	$cycle = new Cycle('class="col1"', 'class="col2"');
+	$l_dir = _T("Directory");
+	$l_per = _T("Percent");
+	$l_hit = _T("Hits");
+	$l_lns = _T("Lines");
+	$l_tds = _T("TODO");
 	return <<<EOS
 	<table align="center" cellpadding="2" cellspacing="1" border="0" class="cycles">
 	<tr>
-		<th>Directory</th><th>Percent</th><th>Hits</th><th>Lines</th><th>TODO</th>
+		<th>{$l_dir}</th><th>{$l_per}</th><th>{$l_hit}</th><th>{$l_lns}</th><th>{$l_tds}</th>
 	</tr>
 EOS;
@@ -105,9 +112,13 @@
 	global $cycle;
 	$cycle = new Cycle('class="col1"', 'class="col2"');
+	$l_fil = _T("File");
+	$l_per = _T("Percent");
+	$l_hit = _T("Hits");
+	$l_lns = _T("Lines");
 	return <<<EOS
 	<br>
 	<table align="center" cellpadding="2" cellspacing="1" border="0" class="cycles">
 	<tr>
-		<th>File</th><th>Percent</th><th>Hits</th><th>Lines</th>
+		<th>{$l_fil}</th><th>{$l_per}</th><th>{$l_hit}</th><th>{$l_lns}</th>
 	</tr>
 EOS;
@@ -154,8 +165,12 @@
 }
 
+$l_root = _T("root");
 if ($action == 'dir') {
+	if (function_exists('ob_filter_path_nicer')) {
+		ob_start('ob_filter_path_nicer');
+	}
 	$path_html = htmlspecialchars($path);
 	echo <<<EOS
-	<a href="?">root</a> $path<br />
+	<a href="?">$l_root</a> $path<br />
 EOS;
 	echo dir_head($dirinfo);
@@ -178,8 +193,11 @@
 }
 else if ($action == 'file') {
+	if (function_exists('ob_filter_path_nicer')) {
+		ob_start('ob_filter_path_nicer');
+	}
 	$dir_url = urlencode($dir);
 	$dir_html = htmlspecialchars($dir);
 	echo <<<EOS
-	<a href="?">root</a> <a href="?path={$dir_url}">{$dir_html}</a>/<b>{$filename}</b><br />
+	<a href="?">$l_root</a> <a href="?path={$dir_url}">{$dir_html}</a>/<b>{$filename}</b><br />
 EOS;
 
@@ -194,4 +212,7 @@
 EOS;
 	}
+	if (function_exists('ob_filter_path_nicer')) {
+		ob_end_flush();
+	}
 	echo <<<EOS
 	<pre class="code"><ol>{$filecov}</ol></pre>
@@ -209,4 +230,8 @@
 ?>
 
+<div class="footnote">
+Powered By: XCache <?php echo $xcache_version; ?> coverager <?php echo _T("module"); ?>
+</div>
+
 </body>
 </html>
