QT利用tr实现翻译

Python3.8

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

1. 目的

代码中待翻译文本(如tr()/QCoreApplication::translate/宏内文本/动态库文本)更新到.ts翻译文件的操作流程,确保所有待翻译文本被lupdate工具识别并纳入翻译管理。

2. 适用场景

  • 主程序代码(含QObject类/无QObject类)新增翻译文本;
  • 动态库(DLL/so)新增翻译文本;

3. 前置工具

  • Qt Linguist工具集(核心:lupdate.exe生成.ts、lrelease.exe编译.qm);
    • Qt5.10(安装的QT开发程序)
  • 文本编辑器/linguist.exe(用于编辑.ts文件)

在这里插入图片描述

一、前置准备

1. 代码规范(必遵守)

新增待翻译文本需按以下规则标记,否则lupdate无法识别:

场景标记方式
QObject子类直接用tr("待翻译文本")(上下文默认是类名)
无QObject类/全局函数QCoreApplication::translate("上下文", "待翻译文本") + 可选QT_TR_NOOP("待翻译文本")
宏内文本(暂无法处理拆分QT_TRANSLATE_NOOP("上下文", "待翻译文本")为独立宏,避免嵌套在translate参数中(5.10,5.13版本lupdate验证未生效

宏内部翻译文本处理方式

在这里插入图片描述

代码示例
//QtWidgetsApplication1.h
#pragma once

#include <QtWidgets/QMainWindow>
#include "ui_QtWidgetsApplication1.h"
#include <QObject>  // 必须包含,QT_TRANSLATE_NOOP依赖此头文件



class CDefineTextTranslate :public QObject
{
    Q_OBJECT
private:
    CDefineTextTranslate();

public:

    static CDefineTextTranslate* getCDefineTextTranslateInstance();
    static CDefineTextTranslate* mInstance;

    const QString m_MSG_CODE_ERROR_str;
};


class QtWidgetsApplication1 : public QMainWindow
{
    Q_OBJECT

public:
    QtWidgetsApplication1(QWidget* parent = nullptr);
    ~QtWidgetsApplication1();

private:
    Ui::QtWidgetsApplication1Class ui;
};




// 带参数的宏定义
#define MSG_CODE_ERROR(code) \
             CDefineTextTranslate::getCDefineTextTranslateInstance()->m_MSG_CODE_ERROR_str.arg(code)


//QtWidgetsApplication1.cpp
#include "QtWidgetsApplication1.h"
#include<qmutex.h>


CDefineTextTranslate::CDefineTextTranslate() :
    m_MSG_CODE_ERROR_str(tr("1231231 %1 xdgdfg"))
{

}


CDefineTextTranslate* CDefineTextTranslate::getCDefineTextTranslateInstance()
{
    static QMutex mutex;
    if (!mInstance) {
        QMutexLocker lock(&mutex);
        if (!mInstance)
            mInstance = new CDefineTextTranslate;
    }

    return mInstance;
}

CDefineTextTranslate* CDefineTextTranslate::mInstance = nullptr;


QtWidgetsApplication1::QtWidgetsApplication1(QWidget* parent)
    : QMainWindow(parent)
{
    //g_pCDefineTextTranslate = new CDefineTextTranslate;
    ui.setupUi(this);
    ui.label->setText(MSG_CODE_ERROR(502));
    QString Text2 = tr("12314134");
    ui.label_2->setText(Text2);

}

QtWidgetsApplication1::~QtWidgetsApplication1()
{
}

//main.cpp
#include "QtWidgetsApplication1.h"
#include <QtWidgets/QApplication>
#include <QTranslator>
int main(int argc, char* argv[])
{
    QApplication app(argc, argv);


    // load translat language
    QTranslator translator;
    QString qmPath = "D:/workdir/code/Test/QtWidgetsApplication1/QtWidgetsApplication1/en_US.qm";
    if (translator.load(qmPath))
    {
        app.installTranslator(&translator);
    }

    QtWidgetsApplication1 window;
    window.show();
    return app.exec();
}


2. 环境检查

  • 确保lupdate.exe在系统环境变量中(或使用完整路径,如C:\Qt\5.10.0\msvc2015_64\bin\lupdate.exe);

  • 待翻译文件编码统一为UTF-8(避免中文乱码)。

二、核心操作流程

步骤1:标记新增翻译文本

前置准备

步骤2:执行lupdate命令(显式指定扫描文件/目录)

.ts文件会记录翻译文本所在行数,需要每次编辑完代码后实时更新,直接通过命令行执行

C:\Qt\Qt5.10.0\5.10.0\msvc2015_64\bin\lupdate.exe "D:\workdir\code\HmsVisionCode\Code\HmsVisonV1.0.0.0\HmsVision\Language\.." "D:\workdir\code\HmsVisionCode\Code\HmsVisonV1.0.0.0\HmsVision\..\include" -ts "D:\workdir\code\HmsVisionCode\Code\HmsVisonV1.0.0.0\HmsVision\Language\en_US.ts",将所有包含新增翻译文本的文件/目录,生成.ts文件:
在这里插入图片描述

生成成功:

在这里插入图片描述

生成到源码目录下
在这里插入图片描述

lupdate命令说明
子场景命令示例(Windows)说明
扫描单个/多个文件lupdate D:\MyApp\MainWindow.cpp D:\MyApp\MacroDefs.h -ts D:\MyApp\translations\all_lang.ts精准扫描指定文件
递归扫描目录C:\Qt\Qt5.10.0\5.10.0\msvc2015_64\bin\lupdate.exe "D:\workdir\code\HmsVisionCode\Code\HmsVisonV1.0.0.0\HmsVision\Language\.." "D:\workdir\code\HmsVisionCode\Code\HmsVisonV1.0.0.0\HmsVision\..\include" -ts "D:\workdir\code\HmsVisionCode\Code\HmsVisonV1.0.0.0\HmsVision\Language\en_US.ts"扫描目录下所有.h/.cpp
路径含空格/中文lupdate "D:\我的项目\MainWindow.cpp" -ts "D:\我的项目\translations\all_lang.ts"路径用双引号包裹
指定编码lupdate D:\MyApp -recursive -codecfortr UTF-8 -ts D:\MyApp\translations\all_lang.ts强制UTF-8扫描,避免乱码
排除第三方文件(Qt5.15+)lupdate D:\MyApp -recursive -exclude D:\MyApp\third_party -ts D:\MyApp\translations\all_lang.ts跳过无需翻译的目录

三、编辑翻译.ts文件

执行lupdate后,需验证新增文本是否被正确识别:

  1. 打开生成的.ts文件(用Qt Linguist/文本编辑器);
  2. 检查「上下文」列是否包含新增文件
  3. 上下文下方是否列出新增的源文本(如「新增按钮」「宏内新增文本」);

在这里插入图片描述

或者有条件直接使用python脚本增量生成新的翻译文件

在这里插入图片描述

python脚本

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
TS文件翻译脚本
使用百度翻译API自动翻译TS文件中的中文文本
"""

import xml.etree.ElementTree as ET
import http.client
import hashlib
import urllib.parse
import random
import json
import time
import os


class BaiduTranslator:
    def __init__(self, appid, secret_key, domain='it'):
        self.appid = appid
        self.secret_key = secret_key
        self.domain = domain
        self.api_url = '/api/trans/vip/fieldtranslate'

    def translate(self, text, from_lang='auto', to_lang='en'):
        """翻译单个文本"""
        if not text.strip():
            return text

        salt = random.randint(32768, 65536)
        sign = self.appid + text + str(salt) + self.domain + self.secret_key
        sign = hashlib.md5(sign.encode()).hexdigest()

        url = (f"{self.api_url}?appid={self.appid}&q={urllib.parse.quote(text)}"
               f"&from={from_lang}&to={to_lang}&salt={str(salt)}"
               f"&domain={self.domain}&sign={sign}")

        try:
            http_client = http.client.HTTPConnection('api.fanyi.baidu.com')
            http_client.request('GET', url)
            response = http_client.getresponse()
            result_all = response.read().decode("utf-8")
            result = json.loads(result_all)

            if 'trans_result' in result:
                return result['trans_result'][0]['dst']
            else:
                print(f"翻译失败: {result}")
                return text

        except Exception as e:
            print(f"翻译请求出错: {e}")
            return text
        finally:
            if 'http_client' in locals():
                http_client.close()


class TSTranslator:
    def __init__(self, translator):
        self.translator = translator
        self.translated_count = 0

    def parse_ts_file(self, file_path):
        """解析TS文件"""
        try:
            tree = ET.parse(file_path)
            root = tree.getroot()
            return tree, root
        except ET.ParseError as e:
            print(f"解析XML文件失败: {e}")
            return None, None

    def needs_translation(self, message):
        """检查message是否需要翻译"""
        source = message.find('source')
        translation = message.find('translation')

        if source is None or translation is None:
            return False

        source_text = source.text or ""
        translation_text = translation.text or ""
        translation_type = translation.get('type', '')

        # 需要翻译的条件:source有中文内容,且translation为空或标记为unfinished
        has_chinese = any('\u4e00' <= char <= '\u9fff' for char in source_text)
        needs_trans = (not translation_text.strip() and
                       (translation_type == 'unfinished' or not translation_type))

        return has_chinese and needs_trans

    def translate_ts_file(self, input_file, output_file=None):
        """翻译TS文件"""
        if output_file is None:
            output_file = input_file.replace('.ts', '_translated.ts')

        tree, root = self.parse_ts_file(input_file)
        if not tree:
            return False

        total_to_translate = 0
        translated_count = 0

        # 统计需要翻译的数量
        for context in root.findall('context'):
            for message in context.findall('message'):
                if self.needs_translation(message):
                    total_to_translate += 1

        print(f"发现 {total_to_translate} 个需要翻译的文本")

        # 开始翻译
        for context in root.findall('context'):
            for message in context.findall('message'):
                if self.needs_translation(message):
                    source = message.find('source')
                    translation = message.find('translation')

                    source_text = source.text
                    print(f"翻译: '{source_text}'")

                    # 调用翻译API
                    translated_text = self.translator.translate(source_text)

                    # 更新translation标签
                    translation.text = translated_text
                    if 'type' in translation.attrib and translation.attrib['type'] == 'unfinished':
                        del translation.attrib['type']

                    translated_count += 1
                    print(f"进度: {translated_count}/{total_to_translate} - {source_text} -> {translated_text}")

                    # 添加延迟避免API限制
                    time.sleep(0.1)

        # 保存翻译后的文件
        tree.write(output_file, encoding='utf-8', xml_declaration=True)
        print(f"翻译完成! 共翻译 {translated_count} 个文本")
        print(f"输出文件: {output_file}")

        return True


def main():
    # 配置百度翻译API
    appid = '1231'  # 请替换为您的appid
    secret_key = 'OqqwzEDtqk3NN5'  # 请替换为您的secret key

    if appid == 'your_appid_here' or secret_key == 'your_secret_key_here':
        print("请先配置百度翻译API的appid和secret key")
        return

    # 创建翻译器实例
    translator = BaiduTranslator(appid, secret_key, domain='it')
    ts_translator = TSTranslator(translator)

    # 输入文件路径
    input_file = 'en_US.ts'  # 请替换为您的TS文件路径
    output_file = 'en_USout.ts'  # 输出文件路径

    if not os.path.exists(input_file):
        print(f"输入文件不存在: {input_file}")
        return

    # 执行翻译
    ts_translator.translate_ts_file(input_file, output_file)


if __name__ == '__main__':
    main()

四、后续操作

  1. 编译.qm文件:将生成.qm的命令添加到工程中的后期生成事件,编译代码会自动编译.qm文件,生成到可执行文件目录下的language目录下保证运行时可以加载.qm文件,一定要有编译过程才会执行后期生成事件的命令行
    在这里插入图片描述
    在这里插入图片描述

  2. 加载.qm文件:主程序/动态库启动时加载.qm(动态库需独立QTranslator,保证生命周期)。实时的切换语言过于麻烦,子窗口都需要重写相应界面刷新函数(所有控件都需要刷新,繁琐工程量大),切换语言后重启程序能够100%保证所有界面都加载翻译器

//main.cpp
#include "QtWidgetsApplication1.h"
#include <QtWidgets/QApplication>
#include <QTranslator>
int main(int argc, char* argv[])
{
    QApplication app(argc, argv);


    // load translat language
    QTranslator translator;
    QString qmPath = "D:/workdir/code/Test/QtWidgetsApplication1/QtWidgetsApplication1/en_US.qm";
    if (translator.load(qmPath))
    {
        app.installTranslator(&translator);
    }

    QtWidgetsApplication1 window;
    window.show();
    return app.exec();
}

五、常见问题与避坑指南

1. lupdate未识别新增文本

问题原因解决方法
未指定扫描文件/目录命令行显式指定文件路径
路径含空格/中文未加引号所有路径用双引号包裹(如"D:\我的项目\MainWindow.cpp"

2. 中文乱码

  • 执行lupdate时添加-codecfortr UTF-8 -codecforsrc UTF-8参数;

  • 确保所有代码文件编码为UTF-8(无BOM)。

3. 动态库翻译文本未识别

  • 确保动态库源码文件被lupdate扫描(显式指定路径);
  • 修改动态库源码会改变翻译文本位置,导致与.ts中标记的翻译位置对不上需要动态库作者提供翻译.ts文件。
    在这里插入图片描述

4. 翻译后文本不生效

  • 检查QCoreApplication::translate的上下文与.ts中一致(大小写/符号无差异);

  • 确保QTranslator为全局/成员变量(非局部变量,避免销毁),或者在主函数中保证程序运行过程中不会释放对象内存;

  • 验证.qm文件路径正确(用QCoreApplication::applicationDirPath()拼接绝对路径)。

六、总结

新增翻译文本更新到.ts文件的核心流程可归纳为:

  1. 规范标记:按场景选择tr()/与宏的处理方式;

  2. 扫描文件:命令行执行lupdate指定扫描路径;

  3. 验证结果:检查.ts文件是否包含新增文本及对应上下文;

  4. 编译加载:翻译.ts后编译为.qm,主程序/动态库加载.qm生效。

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值