使用Apertium API批量转换网站多语言内容遇异常求助
我尝试使用apertium.org提供的API将网站部分内容从一种语言转换为另一种语言,但转换效果不佳。具体流程为:先构建包含带HTML代码长句的变量数组,目标是将这些长句转换为外文,每种语言最终生成对应JSON格式的htm文件,在PHP脚本中调用
gettextinlanguage("por","variable")即可获取对应文本,但结果时好时坏。我发现若使用换行符作为分隔符,转换效果极差;尝试用HTML注释作为分隔符也无明显改善。查看PHP错误日志未得到有效信息。请问是该语言转换器本身问题,还是我的实现方式有误?另外无法直接传入JSON格式数据,因为API不支持。相关代码如下:
function gettextinlanguage($lang, $txt) { $res = json_decode(file_get_contents(langfol() . "/" . $lang . ".htm"), true); return $res[$txt]; } function langfol() { return "/path/to/languagefiles"; } function loadwords() { //our words. $words = array( "Ball" => 'This <b ID="English">ball</p> is bouncy', "Apple" => 'Apples <i ID="England">are</i> red' ); } function buildbaseconv() { //build our english data in JSON format $fol = langfol(); $w = loadwords(); $ww = ''; foreach ($w as $n => $v) { $ww .= $v . "<!--delim1-->"; } $x = fopen($fol . "/eng.htm", "w"); fwrite($x, rawlangtojson($ww)); fclose($x); } function rawlangfromjson($fi) { $d = json_decode($fi, true); if (!is_array($d)) { echo "ERROR: No Array "; return; } $ww = ''; foreach ($d as $naa => $vaa) { $ww .= $vaa . "<!--delim1-->"; } return $ww; } function rawlangtojson($fi) { if (strpos($fi, "<!--delim1-->") === false) { echo "ERROR: data delimiter not received!"; return; } $valz = explode("<!--delim1-->", $fi); $c = 0; $w = loadwords('', 0); foreach ($w as $naa => $vaa) { if (!isset($valz[$c])) { echo "ERROR: Value offset " . $c . " not found "; break; } $wds[$naa] = $valz[$c]; $c++; } return json_encode($wds, true); } function test() { buildbaseconv(); $fol = langfol(); //do language conversion $sourcelang = 'eng'; $destlang = 'por'; //our language files are JSON encoded but //the remote server cant handle JSON so we have to //convert it to values with delimiters $data = rawlangfromjson(file_get_contents($fol . "/" . $sourcelang . ".htm")); //Make the file acceptable for the remote translator $f = fopen($fol . "/Lfr.htm", "w"); fwrite($f, $data); fclose($f); langexec($fol, $sourcelang, $destlang); //Convert the result back to JSON $data = rawlangtojson(file_get_contents($fol . "/Lto.htm")); //and save it as its own language file $f = fopen($fol . "/" . $destlang . ".htm", "w"); fwrite($f, $data); fclose($f); } function langexec($fol, $fr, $to) { //actual language converter system("curl -sk --form 'file=@" . $fol . "/Lfr.htm' 'https://www.apertium.org/apy/translateDoc?markUnknown=no\&langpair=" . $fr . "|" . $to . "' > " . $fol . "/Lto.htm"); }
我已尝试更换分隔符,但问题仍未解决。
排查与分析
1. 实现逻辑的核心问题
你当前的方案是把多个带HTML的文本用分隔符拼接成单个文件传给API,再拆分还原成JSON。但Apertium的文档翻译接口是针对完整文档设计的,它会把整个文件内容当作连续文本处理,而非多个独立条目,这会导致:
- 分隔符可能被API的分词/翻译逻辑误处理(比如把HTML注释当成内容的一部分,或分隔符前后的文本被当成连续句子翻译,破坏语义)
- 带HTML标签的文本连续拼接后,API无法识别每个条目是独立单元,翻译时上下文混乱,导致结果时好时坏
2. API本身的限制
Apertium的翻译API对HTML的支持有限,更适合处理结构简单的纯文本或基础HTML文档。如果你的文本里有嵌套标签、不闭合标签(比如示例中<b>未闭合却用了</p>),会进一步干扰API的解析,加剧翻译异常。
解决方案
1. 改为逐个条目调用API
放弃批量拼接的方式,对每个文本条目单独调用Apertium的文本翻译接口(而非文档翻译接口),确保每个条目独立处理,避免上下文干扰。示例修改:
function translateSingleText($sourceLang, $targetLang, $text) { $url = "https://www.apertium.org/apy/translate"; $data = http_build_query([ 'langpair' => "$sourceLang|$targetLang", 'q' => $text, 'markUnknown' => 'no' ]); $options = [ 'http' => [ 'header' => "Content-type: application/x-www-form-urlencoded\r\n", 'method' => 'POST', 'content' => $data ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); $response = json_decode($result, true); return $response['responseData']['translatedText'] ?? $text; } // 修改test函数,逐个翻译条目 function test() { $fol = langfol(); $sourceLang = 'eng'; $targetLang = 'por'; // 加载原始英文数据 $words = loadwords(); $translatedWords = []; foreach ($words as $key => $text) { $translatedWords[$key] = translateSingleText($sourceLang, $targetLang, $text); } // 保存为目标语言JSON文件 file_put_contents($fol . "/$targetLang.htm", json_encode($translatedWords)); }
2. 修复HTML标签问题
确保输入的HTML标签合法闭合,比如把示例中的'This <b ID="English">ball</p> is bouncy'改为'This <b ID="English">ball</b> is bouncy',避免API解析HTML时出错。
3. 优化分隔符方案(若坚持批量)
如果必须使用文档翻译接口,改用API无法识别、且不会出现在文本中的特殊分隔符,比如|||SEPARATOR|||,同时确保每个条目是独立段落(用换行分隔):
// 修改拼接逻辑 function rawlangfromjson($fi) { $d = json_decode($fi, true); if (!is_array($d)) { echo "ERROR: No Array\n"; return; } $ww = ''; foreach ($d as $naa => $vaa) { $ww .= $vaa . "\n|||SEPARATOR|||\n"; } return $ww; } // 修改拆分逻辑 function rawlangtojson($fi) { $valz = explode("\n|||SEPARATOR|||\n", $fi); // 后续逻辑不变... }
内容的提问来源于stack exchange,提问作者mike_s

