329 lines
10 KiB
PHP
329 lines
10 KiB
PHP
<?php
|
|
/**----------------------------------------------------+
|
|
* 多语言版本翻译处理
|
|
* @author whjing2012@gmail.com
|
|
+-----------------------------------------------------*/
|
|
error_reporting(E_ALL ^E_NOTICE);
|
|
set_time_limit(1800);
|
|
ini_set("memory_limit", "2048M");
|
|
define('MOD', str_replace('\\', '/', realpath(dirname(__FILE__))));
|
|
define('ROOT', MOD.'/../..');
|
|
define('CLIENT_DIR', ROOT.'/client');
|
|
define('SERVER_DIR', ROOT.'/server');
|
|
define('TOOLS_DIR', ROOT.'/tools');
|
|
define('LANG_DATA', MOD.'/data');
|
|
define('LANG_XML_TPL', MOD.'/lang.xml'); // xml模板
|
|
define('LANG_DATA_CLI', 'client.php'); // 客户端相关抽取结果
|
|
define('LANG_DATA_SRV', 'server.php'); // 服务端相关抽取结果
|
|
define('LANG_DATA_ALL', 'all.php'); // 所有抽取翻译结果集合
|
|
define('LANG_DATA_XML', 'lang.xml'); // 抽取结果需翻译输出
|
|
define('LANG_DATA_CONF_CLI', 'lang.lua'); // 客户端语言
|
|
define('LANG_DATA_CONF_SRV', 'lang.erl'); // 服务端语言
|
|
define('LANG_TYPES', "tw,jp,en"); // 多语言版本类型
|
|
|
|
require_once(MOD."/lang_cli.php");
|
|
require_once(MOD."/lang_srv.php");
|
|
|
|
/* 是否为需要过滤的文件 */
|
|
function is_filter($file) {
|
|
// 过滤指定文件/目录
|
|
$array = array(
|
|
"lang.lua",
|
|
"log.hrl",
|
|
"gm_tools.erl", "lang.erl", "keyword_ad_data.erl", "keywords_data.erl",
|
|
"item_flag_data.erl"
|
|
);
|
|
$basefile = basename($file);
|
|
return in_array($basefile, $array);
|
|
}
|
|
|
|
// 获取客户端代码目录
|
|
function cli_dir($lang){
|
|
if(is_dir(CLIENT_DIR.'_'.$lang)){
|
|
return CLIENT_DIR.'_'.$lang;
|
|
}
|
|
return CLIENT_DIR;
|
|
}
|
|
|
|
// 获取服务端代码目录
|
|
function srv_dir($lang){
|
|
if(is_dir(SERVER_DIR.'_'.$lang)){
|
|
return SERVER_DIR.'_'.$lang;
|
|
}
|
|
return SERVER_DIR;
|
|
}
|
|
|
|
// 文件保存
|
|
function save_file($file, $content){
|
|
file_put_contents($file, $content);
|
|
}
|
|
|
|
// 读取文件
|
|
function read_file($file){
|
|
return file_get_contents($file);
|
|
}
|
|
|
|
// 保存成xml文件
|
|
function save_xml($file, $arr, $flag = false){
|
|
$str = "";
|
|
foreach($arr as $k => $v){
|
|
$str .= "<Row>";
|
|
$str .= "<Cell ss:Index='1'><Data ss:Type='String'>".str2xml_replace($k)."</Data></Cell>";
|
|
if($flag){
|
|
$str .= "<Cell ss:Index='2'><Data ss:Type='String'>".str2xml_replace($v)."</Data></Cell>";
|
|
}
|
|
$str .= "</Row>\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 = "<?php\n\$words=array();";
|
|
foreach($arr as $k => $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; $i<count($res->Worksheet); $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);
|