$v){
$str .= "";
$str .= "| ".str2xml_replace($k)." | ";
if($flag){
$str .= "".str2xml_replace($v)." | ";
}
$str .= "
\n";
}
$tpl = read_file(LANG_XML_TPL);
$str = str_replace("{{rows}}", $str, $tpl);
save_file($file, $str);
}
// xml特殊字符替换处理
function str2xml_replace($str){
$str = str_replace("<", "<", $str);
$str = str_replace(">", ">", $str);
$str = str_replace("\n", "
", $str);
$str = str_replace("\"", """, $str);
return trim($str);
}
// 写数组文件
function save_array($file, $arr){
$str = " $v){
$k = trim(str_replace("'", "\'", $k));
$v = trim(str_replace("'", "\'", $v));
$str .= "\n\$words['$k'] = '$v';";
}
$str .= "\nreturn \$words;";
save_file($file, $str);
}
// 获取数组文件中数组
function get_file_array($file){
if(!is_file($file)) return array();
return require($file);
}
// 比对数组获取未翻译集合
function diff_array($all, $need){
$arr = array();
foreach($need as $k => $v){
if(!isset($all[$k])){
$arr[$k] = $v;
}
}
return $arr;
}
// 目录历遍处理
function fordir($path, $callfun, $funparams = array(), $is_next = true){
$handle = @opendir($path);
while($f = readdir($handle)){
if($f == '.' || $f == '..' || $f == '.svn' || $f == '.git') continue;
$file = $path.'/'.$f;
if(is_file($file) || $is_next){
call_user_func_array($callfun, array_merge(array($file), $funparams));
}
if(is_dir($file))
fordir($file, $callfun, $funparams, $is_next);
}
closedir($handle);
}
// 匹配多语言
function match_lang($lang){
$cli = array();
$srv = array();
// cli_config_match(cli_dir($lang)."/src/config", $cli, false);
cli_match(cli_dir($lang)."/src", $cli, true);
srv_match(srv_dir($lang)."/src/mod", $srv, true);
echo("需翻译客户端内容数量:".count($cli)."\n");
echo("需翻译服务端内容数量:".count($srv)."\n");
$all = get_file_array(LANG_DATA."/$lang/".LANG_DATA_ALL);
# $oldcli = get_file_array(LANG_DATA."/$lang/".LANG_DATA_CLI);
# $oldsrv = get_file_array(LANG_DATA."/$lang/".LANG_DATA_SRV);
# $cli = array_merge($cli, $oldcli);
# $srv = array_merge($srv, $oldsrv);
$need = array_merge($cli, $srv);
$diff = diff_array($all, $need);
save_array(LANG_DATA."/$lang/".LANG_DATA_CLI, $cli);
save_array(LANG_DATA."/$lang/".LANG_DATA_SRV, $srv);
save_xml(LANG_DATA."/$lang/".LANG_DATA_XML, $diff);
echo("需翻译内容数量:".count($diff)."\n");
echo("生成待翻译文件,请手动翻译:". LANG_DATA."/$lang/".LANG_DATA_XML. "\n");
}
// 合并翻译结果
function merge_lang($lang){
$rows = parse_xml(LANG_DATA."/$lang/".LANG_DATA_XML, "语言转换或翻译");
$all = get_file_array(LANG_DATA."/$lang/".LANG_DATA_ALL);
$cli = get_file_array(LANG_DATA."/$lang/".LANG_DATA_CLI);
$srv = get_file_array(LANG_DATA."/$lang/".LANG_DATA_SRV);
$need = array_merge($cli, $srv);
$num = 0;
foreach($rows as $row){
// echo("===============".$row['cn']."\n");
if(!isset($need[$row['cn']])) continue;
if(!isset($row['ret'])) continue;
if($row['ret'] == '') continue;
if(isset($all[$row['cn']]))
if($all[$row['cn']] == $row['ret']) continue;
if(!check_lang_ret($row['cn'], $row['ret'])) continue;
$all[$row['cn']] = $row['ret']; // 未做校验
++$num;
}
echo("正确翻译合并数量:$num\n");
if($num){
save_array(LANG_DATA."/$lang/".LANG_DATA_ALL, $all);
$diff = diff_array($all, $need);
save_xml(LANG_DATA."/$lang/".LANG_DATA_XML, $diff);
}
}
// 判断2个字符串包含某字符的数量是否一致
function check_lang_ret($str1, $str2, $arr = array('~ts','~s','~w','~f','{','}','[',']',',','%s','%d')){
foreach($arr as $v){
if(substr_count($str1, $v) != substr_count($str2, $v)) {
echo("翻译不正确: $str1 <> $str2\n");
return false;
}
}
return true;
}
// 判断语言类型
function check_lang_type($lang){
$types = explode(",", LANG_TYPES);
if(!in_array($lang, $types)){
exit("多语言类型[$lang]不正确:" . LANG_TYPES . "\n");
}
if(!is_dir(LANG_DATA."/$lang")){
mkdir(LANG_DATA."/$lang",0777,true);
}
}
// xml解析
function parse_xml($xmlfile, $sheetName, $headIndex = 1){
$res = simplexml_load_file($xmlfile);
$table = null;
$keys = array();
$rows = array();
$index = 0;
for($i=0; $iWorksheet); $i++){
if($res->Worksheet[$i]->attributes('ss', true)->Name == $sheetName){
$table = $res->Worksheet[$i]->Table;
break;
}
}
foreach($table->Row[$headIndex] as $cell){
$keys[trim($cell->Data)] = $index;
++$index;
};
$index = 0;
foreach($table->Row as $row){
if(($index++)<=$headIndex) continue; //排除首行
if(!$row->Cell[0]->Data) continue;
$tmp = array();
foreach($keys as $key => $col){
$val = (string)$row->Cell[$col]->Data;
if(!$row->Cell[$col]){
$val = "";
}elseif($val == null){
$cell_ss = $row->Cell[$col]->children('ss', true);
if($cell_ss->Data){
$val = (string)$cell_ss->Data->children()->Font;
}
}
$tmp[$key] = trim($val);
}
$rows[] = $tmp;
}
return $rows;
}
/* 控制台颜色 */
function colorize($text, $status = "INFO"){
$out = "";
$status = strtoupper($status);
switch($status) {
case "INFO":
$out = "[92m"; //Green background
break;
case "ERROR":
$out = "[91m"; //Red background
break;
case "WARNING":
$out = "[93m"; //Yellow background
break;
default:
throw new Exception("Invalid status: " . $status);
}
return chr(27) . "$out" . "$text" . chr(27) . "[0m";
}
/* 警告、错误、Notice等抛出*/
function error_handler($errno, $errstr, $errfile, $errline, array $errcontext) {
if (0 === error_reporting()) {
return false;
}
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
// 帮助接口
function help(){
echo("php lang.php cin {FILE} // 对客户端指定文件注入多语言函数\n");
echo("php lang.php sin {FILE} // 对服务端指定文件注入多语言函数\n");
echo("php lang.php match {LANG} // 匹配客户端/服务端多语言信息并生成需翻译文件\n");
echo("php lang.php merge {LANG} // 合并翻译结果\n");
echo("php lang.php gen {LANG} // 导出生成客户端/服务端翻译结果文件\n");
exit();
}
// 入口函数
function main($argc, $argv){
if($argc < 3){
help();
}
$cmd = $argv[1];
set_error_handler('error_handler');
try {
if($cmd == 'cin'){
check_lang_type($argv[2]);
cli_infun(cli_dir($argv[2])."/src/".$argv[3]);
}else if($cmd == 'sin'){
check_lang_type($argv[2]);
$sinDir = "";
if($argv[3] == 'inc')
$sinDir = srv_dir($argv[2])."/inc";
else
$sinDir = srv_dir($argv[2])."/src/mod/".$argv[3];
srv_infun($sinDir);
}else if($cmd == 'match'){
check_lang_type($argv[2]);
match_lang($argv[2]);
}else if($cmd == 'merge'){
check_lang_type($argv[2]);
merge_lang($argv[2]);
}else if($cmd == 'gen'){
check_lang_type($argv[2]);
cli_lang($argv[2]);
srv_lang($argv[2]);
}else{
help();
}
restore_error_handler();
}
catch (ErrorException $e) {
echo colorize("Code: ".$e->getCode()."\n", "ERROR");
echo colorize("File: ".$e->getFile()."\n", "ERROR");
echo colorize("Line: ".$e->getLine()."\n", "ERROR");
echo colorize("Message: ".$e->getMessage()."\n", "ERROR");
restore_error_handler();
exit;
}
}
main($argc, $argv);