Qt - 语言家

发布者:承担了全面发布应用程序的责任。通常,他们协调开发者和翻译者的工作,可以使用lupdate工具同步源代码,进行翻译,使用lrelease同步工具为发布应用程序创建运行时使用的翻译文件。
翻译者:可以使用Qt Linguist工具翻译应用程序的文本。当然,这必须要有专业的翻译知识。
开发者:必须创建Qt应用程序能够使用的翻译文本。也应该帮助翻译者识别短语出现的场景。
以上有三种角色-发布者、翻译者、开发者,当然很多情况下,其实就是一种,那就是程序猿自己,大家都懂的。
二、使用流程
1. 使用tr包裹字符串
如果想让你的程序实现国际化,那么就在用户所有可见的字符串处都使用QObject::tr()。
[static] QString QObject::tr(const char *sourceText, const char *disambiguation = nullptr, int n = -1)
2. 修改pro文件
在.pro文件中添加翻译文件名称。
TRANSLATIONS += translations/Chinese.ts \
                translations/English.ts \
                translations/Japanese.ts
3. 生成翻译文件
点击 菜单栏->工具->外部->Qt语言家->更新翻译(lupdae),此时会在translations目录下面生成Chinese.ts和English.ts,Japanese.ts文件。


4. 打开翻译文件
4.1 修改xml,翻译
ts文件实际上是一个xml文件,直接可以用文本编辑器打开。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="en">                            <!-- 版本和语言 -->
<context>
    <name>MainWindow</name>
    <message>
        <location filename="../mainwindow.ui" line="14"/>   <!-- 文本位置-->
        <source>MainWindow</source>                         <!-- 源文本-->
        <translatorcomment>title</translatorcomment>        <!-- 注释 -->
        <translation>Maye</translation>                     <!-- 翻译文本 -->
    </message>
    <message>
        <location filename="../mainwindow.ui" line="27"/>
        <source>用户名</source>
        <translation>username</translation>
    </message>
    <message>
        <location filename="../mainwindow.ui" line="40"/>
        <source>密码</source>
        <translation>password</translation>
    </message>
    <message>
        <location filename="../mainwindow.ui" line="73"/>
        <source>登录</source>
        <translation>login</translation>
    </message>
    <message>
        <location filename="../mainwindow.ui" line="86"/>
        <source>注册</source>
        <translation>register</translation>
    </message>
    <message>
        <location filename="../mainwindow.ui" line="100"/>
        <source>中文</source>
        <translation>chinese</translation>
    </message>
    <message>
        <location filename="../mainwindow.ui" line="105"/>
        <source>英文</source>
        <translation type="unfinished">English</translation>
    </message>
    <message>
        <location filename="../mainwindow.ui" line="119"/>
        <source>语言</source>
        <translation type="unfinished">language</translation>
    </message>
</context>
</TS>
4.1 使用语言家翻译
找到Linguist预言家打开,点击菜单栏->文件->打开,选择上面生成的.ts文件,并打开。

编辑-》翻译文件设置,可以设置源语言和目标语言。


打开之后可以看到如下界面,主要就是对语言进行翻译。

翻译前面的图标及含义:
| 图标 | 含义 | 
|---|---|
| 未翻译 | |
| 已翻译,未标记完成 | |
| 已翻译,且已标记完成 | 
4.2 使用短语书翻译
短语书就是一个提前写好的翻译对照文件,在翻译ts文件的时候,可以打开短语书,很方便的就可以看到翻译。

(1)新建短语书
然后把需要的翻译提前写好,以后也可以重复使用。选择源语言和目标语言。

(2)编辑短语书
短语书创建完成之后,就可以开始编辑短语书了。

如下:先新建条目,再写上源文、译文、以及准确度(可以不写,也可以随便写点东西),最后点击保存,就可以关掉窗口了

(3)使用短语书
如果使用已经写好的短语书,而不是刚刚创建的,那么需要先打开短语书。如果是刚在预言家上创建的,则是打开状态的。


5. 发布翻译文件
翻译完成之后,就可以发布翻译了,为什么要发布呢?发布是什么意思?
- 
ts文件是文本文件,占用内存比较大,发布之后会生成对应的二进制文件,内存较小
 - 
通过发布就可以把ts文件转换成二进制文件
 
发布的方式有两种:
- 
通过语言家发布
- 
点击 菜单栏->文件->发布全部即可发布所有ts文件
 

 - 
 - 
通过Qt Creator发布
- 
点击 菜单栏->工具->外部->Qt语言家->发布翻译(lrelease),会在translations目录中生成zc_CN.qm和en.qm两个文件。
 
 - 
 

发布成功后也会在translations目录下面生成Chinese.qm和English.qm,Japanese.qm文件。

6. 加载语言文件
QTranslator类为文本输出提供国际化支持。
该类的对象包含一组从源语言到目标语言的翻译。 QTranslator提供了在翻译文件中查找翻译的功能。 翻译文件使用Qt Linguist创建。
QTranslator translator;
if(translator.load("linguist_en.qm","F:\\MyCode\\QtCode\\Lingguist\\translate"))
{
      qApp->installTranslator(&translator);
      ui->retranslateUi(this);
}
注意:翻译文件加载的位置必须在界面实例化之前完成,否则是没有效果的.
7. 动态切换语言
注意:如果界面是通过Ui生成的,切换语言之后,可以通过调用函数retranslateUi翻译界面,否则需要重启程序.
- 
下拉框切换语言
 
void MainWindow::on_comboBox_currentIndexChanged(int index)
{
    QString filename;
    switch (index)
    {
    case 0:
        filename = "linguist_zh_CN.qm";      
        break;
    case 1:
        filename = "linguist_en.qm";
        break;
    }
    QTranslator translator;
    if(!translator.load(filename,"F:\\MyCode\\QtCode\\Lingguist\\translate"))
    {
        qDebug()<<"翻译文件加载失败";
        return;
    }
    if(qApp->installTranslator(&translator))
    {
        qDebug()<<"安装成功";
    }
    else
    {
        qDebug()<<"安装失败";
    }
    ui->retranslateUi(this);
}
- 
保存语言选择和恢复语言
 
保存
void MainWindow::on_comboBox_currentIndexChanged(int index)
{
    QString filename;
    switch (index)
    {
    case 0:
        filename = "linguist_zh_CN.qm";
        break;
    case 1:
        filename = "linguist_en.qm";
        break;
    }
    //保存配置
    QSettings setting("config.ini",QSettings::Format::IniFormat);
    setting.setValue("ts",filename);
    ...
}
恢复
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QSettings setting("config.ini",QSettings::Format::IniFormat);
    QString filename = setting.value("ts").toString();
    QTranslator translator;
    if(!translator.load(filename,"F:\\MyCode\\QtCode\\Lingguist\\translate"))
    {
        qDebug()<<"翻译文件加载失败";
    }
    if(qApp->installTranslator(&translator))
    {
        qDebug()<<"安装成功";
    }else
    {
        qDebug()<<"安装失败";
    }
    MainWindow w;
    w.show();
    return a.exec();
}
- 
重启程序
 
//重启程序才能生效,是否重启
auto ret = QMessageBox::information(this,"hit","是否重启",QMessageBox::StandardButton::Ok,QMessageBox::No);
if(ret == QMessageBox::Ok)
{
    QString exe =  QApplication::applicationDirPath()+"/"+qAppName()+".exe";
    QProcess::startDetached(exe);
    qApp->quit();
}
在论坛中漂,经常遇到有人遇到tr相关的问题。用tr的有两类人:
- 
(1)因为发现中文老出问题,然后搜索,发现很多人用tr,于是他也开始用tr
 - 
(2)另一类人,确实是出于国际化的需要,将需要在界面上显示的文件都用tr包起来,这有分两种:
- 
(2a) 用tr包住英文(最最推荐的用法,源码英文,然后提供英文到其他语言的翻译包)
 - 
(2b) 用tr包住中文(源码用中文,然后提供中文到其他语言的翻译包)
 
 - 
 
注意哦,如果你正在用tr包裹中文字符,却不属于(2b),那么:
- 
你在误用tr
 - 
你需要的是QString,而不是tr
 
如果你确实属于(2b),请做好心理准备,你可能还会遇到很多困难,
tr 是做什么的?下面二者的区别是什么?
QString text1 = QObject::tr("hello"); 
QString text2 = QString("hello");
tr是用来实现国际化,如果你为这个程序提供了中文翻译包(其中hello被翻译成中文"你好"),那么text1的内容将是中文"你好";如果你为程序提供且使用日文翻译包,那么text1的内容将是日文。
tr是经过多级函数调用才实现了翻译操作,是有代价的,所以不该用的时候最好不要用。
8. 项目示例代码
工程文件预览

MyApplication.pro
QT       += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
    controller.cpp \
    global_function.cpp \
    main.cpp \
    mainwindow.cpp \
    settingsdialog.cpp
HEADERS += \
    controller.h \
    global_function.h \
    mainwindow.h \
    settingsdialog.h
FORMS += \
    mainwindow.ui \
    settingsdialog.ui
TRANSLATIONS += translations/Chinese.ts \
                translations/English.ts \
                translations/Japanese.ts
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
RESOURCES += \
    res.qrc
controller.h
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include <QObject>
class SettingsDialog;
class AutoCloseFrame;
class Titlebar;
class Controller : public QObject
{
    Q_OBJECT
public:
    ~Controller();
    static Controller* GetInstance();
    void RetranslateUi();//重译所有界面(总接口)
    //注册界面,用处是Controller可以访问其他子界面的接口
    void RegisterVolumeAutoCloseFrame(AutoCloseFrame *w);
    void RegisterSettingWindow(SettingsDialog *w);
    void RegisterTitleBar(Titlebar* w);
signals:
private:
    Controller(QObject *parent = nullptr);
    SettingsDialog			*m_SettingsDialog;
    AutoCloseFrame			*m_AutoCloseFrame;
    Titlebar				*m_Titlebar;
};
#endif // CONTROLLER_H
global_function.h
#ifndef GLOBAL_FUNCTION_H
#define GLOBAL_FUNCTION_H
#include <QString>
extern void g_SetAppStyle(const QString strStyle);
extern QString g_GetStrStyle();
#endif // GLOBAL_FUNCTION_H
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "controller.h"
#include "settingsdialog.h"
#include "ui_mainwindow.h"
class MainWindow : public QMainWindow,public Ui_MainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
public slots:
    void SettingsSlot();
    void slotSwitchLanguage(LANGUAGE language);
protected:
    //void changeEvent(QEvent *event);
private:
    //Ui::MainWindow *ui;
    Controller* m_Controller;
    SettingsDialog* m_SettingsDialog;
};
#endif // MAINWINDOW_H
settingsdialog.h
#ifndef SETTINGSDIALOG_H
#define SETTINGSDIALOG_H
#include <QDialog>
#include "ui_settingsdialog.h"
#include "controller.h"
typedef enum{
    UI_ZH,
    UI_EN,
    UI_JP
}LANGUAGE;
Q_DECLARE_METATYPE(LANGUAGE)
class SettingsDialog : public QDialog,public Ui_SettingsDialog
{
    Q_OBJECT
public:
    explicit SettingsDialog(Controller* ctrl,QWidget *parent = nullptr);
    ~SettingsDialog();
    void CreateListWidget();
    void InitGeneralSetting();//初始化常规设置
    void InitVideo();          //初始化视频设置
    void InitAudio();          //初始化音频设置
    void InitSubtitle();       //初始化字幕设置
    void InitHotkeys();        //初始化快捷键设置
    void RetranslateUi();
signals:
    void signalSwitchLanguage(LANGUAGE language);
public slots:
    void onIndexChanged(int index);
    //void onSelectChanged(int);
protected:
    //void changeEvent(QEvent *event);
private:
    //Ui::SettingsDialog *ui;
    Controller*				m_ctrl;
    QListWidgetItem *General;
    QListWidgetItem *Video;
    QListWidgetItem *Audio;
    QListWidgetItem *Subtitles;
    QListWidgetItem *Shortcuts;
};
#endif // SETTINGSDIALOG_H
controller.cpp
#include "controller.h"
#include <QDebug>
#include "settingsdialog.h"
//Controller类的作用:就是相当于主界面与其他界面中间的一个桥梁,Controller可以访问子界面的接口,子界面也可以访Controller的接口
Controller::Controller(QObject *parent) : QObject(parent)
{
    qDebug() << "Controller构造函数";
}
Controller::~Controller()
{
    qDebug() << "~Controller析构函数";
}
Controller* Controller::GetInstance()
{
    static Controller* controller = NULL;
    if (controller == NULL)
    {
        controller = new Controller;
    }
    return controller;
}
void Controller::RetranslateUi()//重译所有界面(总接口)
{
    m_SettingsDialog->RetranslateUi(); //刷新设置页面的翻译
    //m_Titlebar->RetranslateUi();       //刷新标题栏的翻译
    //m_PlayListWidget->RetranslateUi(); //刷新播放列表的翻译
}
void Controller::RegisterVolumeAutoCloseFrame(AutoCloseFrame *w)
{
    m_AutoCloseFrame = w;
}
void Controller::RegisterSettingWindow(SettingsDialog *w)
{
    m_SettingsDialog = w;
}
void Controller::RegisterTitleBar(Titlebar* w)
{
    m_Titlebar = w;
    //connect(m_Titlebar, SIGNAL(sigMove(int)), this, SLOT(slotPLMove(int)));
}
global_function.cpp
#include "global_function.h"
#include <QApplication>
#include <QFont>
#include <QFile>
void g_SetAppStyle(const QString strStyle)//设置App的整体样式
{
    qApp->setStyleSheet(strStyle);//设置App样式
}
QString g_GetStrStyle()
{
    QFile qss("C:\\Users\\Administrator\\Documents\\MyApplication\\qss\\Style.qss");
    if(!qss.open(QFile::ReadOnly| QIODevice::Text))
    {
        qWarning("Style.css open falied");
        return 0;
    }
    QString strStyle = qss.readAll();
    qss.close();
    return strStyle;
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QTranslator>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
    setupUi(this);
    m_Controller = NULL;
    m_Controller = Controller::GetInstance();
    /*嵌入窗体*/
    m_SettingsDialog = new SettingsDialog(m_Controller,this);
    m_SettingsDialog->setHidden(true);
    connect(BtnSettings,  SIGNAL(clicked()), this, SLOT(SettingsSlot()));
    connect(m_SettingsDialog, SIGNAL(signalSwitchLanguage(LANGUAGE)), this, SLOT(slotSwitchLanguage(LANGUAGE)));
}
MainWindow::~MainWindow()
{
    //delete ui;
}
void MainWindow::SettingsSlot()
{
    m_SettingsDialog->exec();
}
void MainWindow::slotSwitchLanguage(LANGUAGE index)
{
    QString filename;
    switch(index)
    {
    case UI_ZH:
        filename = QString("Chinese.qm");
        break;
    case UI_EN:
        filename = QString("English.qm");
        break;
    case UI_JP:
        filename = QString("Japanese.qm");
        break;
    }
    QTranslator translator;
    if(!translator.load(filename,"C:\\Users\\Administrator\\Documents\\MyApplication\\translations"))
    {
        qDebug()<<"翻译文件加载失败";
        return;
    }
    else
    {
        if(qApp->installTranslator(&translator))
        {
            qDebug()<<"安装成功";
        }
        else
        {
            qDebug()<<"安装失败";
        }
    }
    m_Controller->RetranslateUi();
    retranslateUi(this);
}
settingsdialog.cpp
#include "settingsdialog.h"
SettingsDialog::SettingsDialog(Controller* ctrl,QWidget *parent) :QDialog(parent), m_ctrl(ctrl)
{
    setupUi(this);
    ctrl->RegisterSettingWindow(this);//注册界面
    CreateListWidget();
    InitGeneralSetting();
    connect(combo_language,  SIGNAL(activated(int)), this, SLOT(onIndexChanged(int)));
    connect(listWidget,  SIGNAL(currentRowChanged(int)), stackedWidget, SLOT(setCurrentIndex(int)));
}
SettingsDialog::~SettingsDialog()
{
    //delete ui;
}
void SettingsDialog::CreateListWidget()
{
    General = new QListWidgetItem(QIcon(":/resources/general.png"), tr("General"), listWidget);
    Video = new QListWidgetItem(QIcon(":/resources/video.png"), tr("Video"), listWidget);
    Audio = new QListWidgetItem(QIcon(":/resources/audio.png"), tr("Audio"), listWidget);
    Subtitles = new QListWidgetItem(QIcon(":/resources/subtitle.png"), tr("Subtitles"), listWidget);
    Shortcuts = new QListWidgetItem(QIcon(":/resources/shortcut.png"), tr("KeyShortcuts"), listWidget);
    General->setSizeHint(QSize(80,60));
    Video->setSizeHint(QSize(80,60));
    Audio->setSizeHint(QSize(80,60));
    Subtitles->setSizeHint(QSize(80,60));
    Shortcuts->setSizeHint(QSize(80,60));
    listWidget->addItem(General);
    listWidget->addItem(Video);
    listWidget->addItem(Audio);
    listWidget->addItem(Subtitles);
    listWidget->addItem(Shortcuts);
}
void SettingsDialog::InitGeneralSetting()
{
    combo_language->clear();
    combo_sking->clear();
    combo_language->addItem("Chinese", QVariant::fromValue(UI_ZH));
    combo_language->addItem("English", QVariant::fromValue(UI_EN));
    combo_language->addItem("Japanese", QVariant::fromValue(UI_JP));
    combo_language->setCurrentIndex(UI_EN);
    combo_sking->addItem(tr("Dark"));
    combo_sking->addItem(tr("Light"));
}
void SettingsDialog::RetranslateUi()
{
    this->setWindowTitle(tr("setting dialog"));
    General->setText(tr("General"));
    Video->setText(tr("Video"));
    Audio->setText(tr("Audio"));
    Subtitles->setText(tr("Subtitles"));
    Shortcuts->setText(tr("KeyShortcuts"));
    combo_language->setItemText(UI_ZH, tr("Chinese"));
    combo_language->setItemText(UI_EN, tr("English"));
    combo_language->setItemText(UI_JP, tr("Japanese"));
    combo_sking->setItemText(0,tr("Dark"));
    combo_sking->setItemText(1,tr("Light"));
    retranslateUi(this);
}
void SettingsDialog::onIndexChanged(int index)
{
    LANGUAGE language = (LANGUAGE)index;
    emit signalSwitchLanguage(language);
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <QDebug>
#include <QFile>
#include "global_function.h"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    //qApp->setStyleSheet(g_GetStrStyle());//错误,需要界面显示后再设置app的全部样式
    MainWindow w;
    w.show();
    qApp->setStyleSheet(g_GetStrStyle());
    return a.exec();
}
运行结果:

翻译后:

9. 各国语言代码
查看各国语言代码网页链接:http://www.lingoes.cn/zh/translator/langcode.htm
.ts文件中language字段对应的就是语言代码,如下图所示:



                
            
        
浙公网安备 33010602011771号