使用 AI 对 QT应用程序进行翻译
前言
之前应朋友要求,帮其对 QGC 进行二次开发,其中一个要求是“汉化”。看了一下,虽然官方也有翻译,但还有很多没有翻译,如果要人工来做的话,纯属体力劳动。不如让 AI 帮着翻译。
经过一番调查和测试,找到了翻译 QT
的 .ts
文件的方法和流程。总共不到两天时间就将95%以上的文字翻译成功。大大节省我的工作量。而且该方法可以适用于 任意 QT 程序的 任意语言翻译。
之后虽然因为朋友有其他的解决方案,最后没有采用QGC。因此我也就不再需要对其保密,因此将相关信息共享并开源。
核心步骤
- 使用 python 程序将 .ts 文件中对应
translation type="unfinished"
(未翻译) 的文字全部提取出来,整理出"原始文字":"TODO"
格式的原始 key-value 对; - 将
key-value
对丢给 AI(如 deepseek), 让其翻译。由于这个时候只有需要翻译的文本,AI 能高效的完成。 - 将翻译以后的文本
key-value
对, 放置到代码中定义的 dict 变量中,再用 python 代码处理, 将其写回.ts
文件对应的地方, 并去除translation type="unfinished"
部分(表示翻译成功)。 - 以上步骤,循环多次以后,即可将需要的文字大部分翻译成功。有部分原始文字是多行的,处理起来比较麻烦,而且考虑到不多,可以手动处理。
核心代码
- 通过正则处理
.ts
文件的内容,解析出key-value
对
def process_message(self, match):# nonlocal processed_count, translated_countself.processed_count += 1message_content = match.group(1)# extract source contentsource_match = re.search(r'<source>(.*?)</source>', message_content, re.DOTALL)if not source_match:return message_contentsource_text = source_match.group(1).strip()# logger.info(f"handle source_text={source_text}")if 'type="unfinished"' not in message_content:return message_content # already translate# try translatetranslate_result = self.translate_text(source_text)if translate_result is None:# can not translate, just add the original text to missing setself.missings.add(source_text.strip())return message_contentself.translated_count += 1# Display only the first 50 characters to avoid overly long output.source_preview = source_text[:50] + '...' if len(source_text) > 50 else source_texttranslation_preview = translate_result[:50] + '...' if len(translate_result) > 50 else translate_resultlogger.info(f"[{self.translated_count}]: '{source_preview}' => '{translation_preview}'")# Replace the content of the translation and remove type="unfinished"return re.sub(r'<translation type="unfinished">.*?</translation>',f'<translation>{translate_result}</translation>',message_content,flags=re.DOTALL)
- 翻译部分: 传入原始的英文key, 从翻译的词典中找是否有匹配项,找到就进行翻译
def translate_text(self, english_text: str, keep_space: bool = False):if not self.dictionary:d = self.get_dict()self.dictionary = {}for k, v in d.items():self.dictionary[k.strip()] = v.strip()# Remove leading and trailing spaces for matchingstripped_text = english_text.strip()# Convert character entity references to plain characters for matchingcompare_text = self.decode_html_entities(stripped_text)if compare_text in self.dictionary:if keep_space:leading_spaces = len(english_text) - len(english_text.lstrip())trailing_spaces = len(english_text) - len(english_text.rstrip())translation = self.dictionary[compare_text]return self.encode_html_entities(' ' * leading_spaces + translation + ' ' * trailing_spaces)return self.encode_html_entities(self.dictionary[compare_text])# return None to indicate untranslatablereturn None
- 放置 AI 翻译后生成的
原文-翻译
对的变量。注意:不是单词,而是整个翻译句子对应的部分。
class DictZhCN(DictBase):def get_dict(self) -> dict[str, str]:""" Return translate items """return {"""Help""": """帮助""",}
翻译提示词
- 需要告诉 AI 合适的提示词,不然他会乱改格式,尤其是
.ts
中的分隔符等. - 测试了几个AI进行翻译, 发现
deepseek
最慢,但相对来说准确率高一些。而豆包、元宝等虽然速度快了很多,但有明显的错误。
以下文本都是 "英文":"TODO", 的形式, 这些英文是无人机相关的英文, 将他们翻译成中文, 并替换成 "英文": """中文""", 的格式.
注意:
1.不要更改原始输入英文的格式,在输出的中文中也保留对应的格式字符,只要 txt 的纯文本格式, 不要转换成其他格式.输入示例:
"Forward": "TODO",
"Frame Class": "TODO",
"Currently set to frame class '%1'": "TODO",
"All Files (*)": "TODO",
"Receiving signal. Perform range test & confirm.": "TODO",输出示例:
"Forward": """前进""",
"Frame Class": """机架类别""",
"Currently set to frame class '%1'": """当前设置为机架类别 '%1'""",
"All Files (*)": """所有文件 (*)""",
"Receiving signal. Perform range test & confirm.": """正在接收信号。执行距离测试 & 确认""",以下是对应要翻译部分的列表:
源码
- 目前已经创建 PR#13411 , 尝试将其合并到 QGC 中。需要源码的自行获取。