这似乎是一个愚蠢的问题,但我在 QT 5.12 中让国际化正常运行时遇到了很多麻烦。
我至少想做两件事:
- 可以保存用户选择的语言,并在用户下次运行其选择的应用程序时(但可能至少需要一个文件来保存该语言),或者以该语言的母语运行应用程序SO。
- 动态翻译工作,我的意思是在应用程序运行时自动更改语言。
关于第一点,我知道要安装系统本地语言的翻译,例如 Translator.load("qt_"+ QLocale::system().name(),QLibraryInfo::location(可以使用 QLibraryInfo::TranslationsPath))
。
第二点,我找到了一个解决方案,但它要求我在发布/调试文件夹中放置一个名为 translation
的文件夹(在本例中),我在其中放置各个 .qm
文件。
我将提供一个简单的示例来说明我迄今为止所发现的内容:
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QFontDatabase>
#include <QFont>
#include <QtQml>
#include "trans.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QTranslator Translator;
Translator.load(":/translations/translating-qml_ru.qm");
app.installTranslator(&Translator);
QQmlApplicationEngine engine;
// object of our class with "magic" property for translation
Trans trans(&engine);
// make this object available from QML side
engine.rootContext()->setContextProperty("trans", &trans);
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
return app.exec();
}
main.qml
import QtQuick 2.7
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.0
import QtQuick.Window 2.2
ApplicationWindow {
id: root
width: 800
minimumWidth: 500
height: 600
minimumHeight: 600
visible: true
title: "Translating QML application"
Column {
width: parent.width * 0.95
spacing: 15
padding: 15
RowLayout {
anchors.horizontalCenter: parent.horizontalCenter
Button {
Layout.preferredWidth: 76
Layout.preferredHeight: 53
text:"EN"
onClicked: {
onClicked: trans.selectLanguage("en");
}
}
Rectangle
{
Layout.preferredWidth: 2
Layout.fillHeight: true
Layout.margins: 10
color: "black"
}
Button {
text: "RU"
Layout.preferredWidth: 76
Layout.preferredHeight: 53
onClicked: {
onClicked: trans.selectLanguage("ru");
}
}
Rectangle
{
Layout.preferredWidth: 2
Layout.fillHeight: true
Layout.margins: 10
color: "black"
}
Button {
text: "NO"
Layout.preferredWidth: 76
Layout.preferredHeight: 53
onClicked: {
onClicked: trans.selectLanguage("no");
}
}
Rectangle
{
Layout.preferredWidth: 2
Layout.fillHeight: true
Layout.margins: 10
color: "black"
}
Button {
text: "DE"
Layout.preferredWidth: 76
Layout.preferredHeight: 53
onClicked: {
onClicked: trans.selectLanguage("de");
}
}
}
Label {
font.pixelSize: 16
text: qsTr("I woke up after midnight and realised - <b>IT DOES</b>!<br/>"
+ "Everything goes according to the plan.")
}
}
}
trans.cpp
#include "trans.h"
Trans::Trans(QQmlEngine *engine)
{
_translator = new QTranslator(this);
_engine = engine;
}
void Trans::selectLanguage(QString language)
{
QString languagesArray[] = { "en", "pt", "es", "br", "de", "dk", "fi", "fr", "it", "lt", "no", "ro", "tr", "hu" };
QDir dir = QDir(qApp->applicationDirPath()).absolutePath();
for(int i=0;i<languagesArray->length();i++){
if(languagesArray[i] != language){
_translator->load(QString("Lang-%1").arg(languagesArray[i]),QString("%1/translation").arg(dir.path()));
qApp->removeTranslator(_translator);
}
}
if (!_translator->load(
QString("translating-qml_%1").arg(language),
// look for the file in translations folder within working directory
QString("%1/translations").arg(dir.path())
)
)
{
qDebug() << "Failed to load translation file, falling back to English";
}
// it's a global thing, we can use it anywhere (after #including <QGuiApplication>)
qApp->installTranslator(_translator);
_engine->retranslate();
emit languageChanged();
}
trans.h
#ifndef TRANS_H
#define TRANS_H
#include <QObject>
#include <QTranslator>
#include <QDebug>
#include <QGuiApplication>
#include <QDir>
#include <QQmlEngine>
class Trans : public QObject
{
Q_OBJECT
public:
Trans(QQmlEngine *engine);
Q_INVOKABLE void selectLanguage(QString language);
signals:
void languageChanged();
private:
QTranslator *_translator;
QQmlEngine *_engine;
};
#endif // TRANS_H
我想一步步知道我必须做什么才能让这个系统完全正常工作,因为我在网上找到的信息(包括 qt 文档)让我感到困惑。
最佳答案
- 对于第一点,只需通过QSettings将标识语言的信息保存在硬盘上即可。当应用程序启动时,应读取 QSettings,并相应地完成翻译,并在修改语言时保存它。
- 您的第二点不是很清楚,但我想您想知道使用 Qt 国际化的步骤是什么,有多种方法,因为有些任务可以手动完成,有些任务可以自动化。
首先将以下指令添加到.pro:
TRANSLATIONS = /path/of/some_name1.ts \
/path/of/some_name2.ts \
/path/of/some_name3.ts
在我的示例中,我使用以下结构:
TARGET = AppTranslations
# ...
TRANSLATIONS = i18n/$${TARGET}_en.ts \
i18n/$${TARGET}_de.ts \
i18n/$${TARGET}_no.ts \
i18n/$${TARGET}_ru.ts
然后您必须在.pro所在的文件夹中打开终端或CMD并执行以下命令:
lupdate your_project.pro
这会在您指定的位置生成 .ts,然后您必须使用 Qt Linguist 编辑该文件来进行翻译。
然后将 .ts 转换为 .qm:
lrelease your_project.pro
然后您可以将 .qm 添加到应用程序中的 qresource 嵌入中,但就我而言,我更喜欢将它放在可执行文件一侧的文件夹中,这样可执行文件的重量不会太大,并且可以添加更多翻译而无需重新编译项目,并使其自动化,将下一个命令复制到可执行文件的一侧。
COPY_CONFIG = $$files(i18n/*.qm, true)
copy_cmd.input = COPY_CONFIG
copy_cmd.output = i18n/${QMAKE_FILE_IN_BASE}${QMAKE_FILE_EXT}
copy_cmd.commands = $$QMAKE_COPY_DIR ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT}
copy_cmd.CONFIG += no_link_no_clean
copy_cmd.variable_out = PRE_TARGETDEPS
QMAKE_EXTRA_COMPILERS += copy_cmd
所以最终构建文件夹将具有以下结构:
├── AppTranslations
├── i18n
│ ├── AppTranslations_de.qm
│ ├── AppTranslations_en.qm
│ ├── AppTranslations_no.qm
│ └── AppTranslations_ru.qm
│ ...
现在您已经有了 .qm,在应用程序中使用它的逻辑已经实现。在 Qt 5.10 之前,您必须添加一个空字符串才能使翻译正常工作,但最新版本不需要它。
另一方面,在我的例子中,我实现了一个逻辑来获取 .qm 以及可用的语言,因为我使用默认格式:
{Name_Of_Application}_{lang}.qm
逻辑的其他部分与您的类似,因此我不会详细介绍,我将向您展示代码:
翻译器.h
#ifndef TRANSLATOR_H
#define TRANSLATOR_H
#include <QDir>
#include <QObject>
#include <QQmlEngine>
#include <QTranslator>
class Translator : public QObject
{
Q_OBJECT
Q_PROPERTY(QStringList languages READ languages NOTIFY languagesChanged)
Q_PROPERTY(QString currentLanguage READ currentLanguage NOTIFY currentLanguageChanged)
public:
explicit Translator(QQmlEngine *engine, QObject *parent = nullptr);
Q_INVOKABLE void selectLanguage(const QString & language);
QStringList languages() const;
QString currentLanguage() const;
Q_INVOKABLE static QString languageByCode(const QString & code);
signals:
void languageChanged();
void languagesChanged();
void currentLanguageChanged();
private:
const QString extension = ".qm";
QQmlEngine *m_engine;
QTranslator *m_translator;
QStringList m_languages;
QString m_currentLanguage;
QDir m_dir;
};
#endif // TRANSLATOR_H
翻译器.cpp
#include "translator.h"
#include <QGuiApplication>
#include <QDirIterator>
#include <QSettings>
Translator::Translator(QQmlEngine *engine, QObject *parent) :
QObject(parent),
m_engine(engine)
{
m_translator = new QTranslator(this);
m_dir = QDir(QGuiApplication::applicationDirPath(),
"*"+extension,
QDir::Name|QDir::IgnoreCase,
QDir::Files);
m_dir.cd("i18n");
m_languages.clear();
for(QString entry: m_dir.entryList()){
entry.remove(0, QGuiApplication::applicationName().length()+1);
entry.chop(extension.length());
m_languages.append(entry);
}
emit languagesChanged();
QSettings settings;
QString lang =settings.value("Language/current", QLocale::system().bcp47Name()).toString();
selectLanguage(lang);
}
QStringList Translator::languages() const
{
return m_languages;
}
QString Translator::currentLanguage() const
{
return m_currentLanguage;
}
QString Translator::languageByCode(const QString &code)
{
QLocale lo(code);
return QLocale::languageToString(lo.language());
}
void Translator::selectLanguage(const QString &language)
{
qApp->removeTranslator(m_translator);
if(m_languages.contains(language)){
QString file = QString("%1_%2%3").arg(QGuiApplication::applicationName()).arg(language).arg(extension);
if(m_translator->load(m_dir.absoluteFilePath(file))){
m_currentLanguage = language;
QSettings settings;
settings.setValue("Language/current", language);
emit currentLanguageChanged();
}
}
qApp->installTranslator(m_translator);
m_engine->retranslate();
emit languageChanged();
}
然后它适用于您的项目:
main.cpp
#include "translator.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QCoreApplication::setOrganizationName("Translations INC");
QCoreApplication::setOrganizationDomain("translations.com");
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
Translator trans(&engine);
engine.rootContext()->setContextProperty("trans", &trans);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
main.qml
import QtQuick 2.7
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.0
import QtQuick.Window 2.2
ApplicationWindow {
id: root
width: 800
minimumWidth: 500
height: 600
minimumHeight: 600
visible: true
title: "Translating QML application"
Column {
width: parent.width * 0.95
spacing: 15
padding: 15
RowLayout {
anchors.horizontalCenter: parent.horizontalCenter
Repeater{
model: trans.languages
Button{
id: btn
property string code: modelData
text: trans.languageByCode(code)
onClicked: trans.selectLanguage(btn.code)
Layout.preferredWidth: 100
Layout.preferredHeight: 50
highlighted: code == trans.currentLanguage
}
}
}
Label {
font.pixelSize: 16
text: qsTr("I woke up after midnight and realised - <b>IT DOES</b>!<br/>"
+ "Everything goes according to the plan.")
}
}
}
您找到的完整示例here .
关于qt - 如何使用QT国际化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53673924/