3

I'm trying to import translator file on my Qt project (Qt 5.6 on Linux system), but I can't upload translation file because the QTranslator::load method always returns false.

I have the following "testTrl" project structure:

On project root I have "resources" folder that includes "qml.qrc", "translations.qrc" and "translations" folder:

/resources/qml.qrc
/resources/translations.qrc
/resources/translations/testTrl_it.ts
/resources/translations/testTrl_it.qm
/resources/translations/testTrl_en.ts
/resources/translations/testTrl_en.qm
...

I have obtained ".ts" and ".qm" files with "lrelease" and "lupdate" commands.

Project files:

testTrl.pro file:

TEMPLATE = app

QT += qml quick core widgets
CONFIG += c++11

SOURCES += main.cpp

RESOURCES += $$PWD/resources/qml.qrc \
             $$PWD/resources/translations.qrc

TRANSLATIONS += $$PWD/resources/translations/testTrl_it.ts \
                $$PWD/resources/translations/testTrl_en.ts

# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =

# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =

# The following define makes your compiler emit warnings if you use
# any feature of Qt which as 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 you use 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

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

translations.qrc file:

<RCC>
    <qresource prefix="/translations" lang="it">
        <file alias="testTrl.qm">translations/testTrl_it.qm</file>
    </qresource>
    <qresource prefix="/translations" lang="en">
        <file alias="testTrl.qm">translations/testTrl_en.qm</file>
    </qresource>
</RCC>

main.cpp file:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QTranslator>
#include <QDebug>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QTranslator translator;

    const QString lang = "en";
    QLocale::setDefault(lang);

    bool isTrlsFileLoaded = translator.load(":/translations/testTrl.qm");

    if(!isTrlsFileLoaded) {
        qDebug() << "FILE NOT LOADED";
    }
    else {
        qDebug() << "FILE LOADED";
        qApp->installTranslator(&translator);
    }

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

"isFileTranslatorLoaded" is always "false". How can I solve this issue?

daniele86
  • 147
  • 3
  • 14

1 Answers1

4

First, your .qrc file is bad writen: the second tag <qresource> should be </qresource>, and the last <RCC> should be </RCC>.

Although your source code is partial, I guess the line you are looking for is

bool isFileTranslatorLoaded = translator->load(":/translations/translations/app_it.qm");

QTranslator::load can only load compiled (.qm) files. Remove .ts file from resources (in addition, it is a security measure since they usually expose part of your project structure, source lines, etc).

A different approach

As a suggestion, you can reduce the associated code when loading a translation by setting the language in your resources file.

<RCC>
  <qresource prefix="/translations">
    <file alias="app.qm">translations/app_en.qm</file>
  </qresource>
  <qresource prefix="/translations" lang="it">
    <file alias="app.qm">translations/app_it.qm</file>
  </qresource>
</RCC>

Then, you simply load a generic translator:

bool isFileTranslatorLoaded = translator->load(":/translations/app.qm");

and Qt will take care of using the appropriate file for current locale. It is specially useful for other resources that are specified in design time, like images, or simply to reduce code cluttering.

Note: see that the alias allows you to remove the double translations/translations if you want.

Setting locale

As mentioned, the above code uses current locale for choosing the right file from resources. A translation loader may look like

bool loadTranslationsForLanguage(const QString& lang) {
  QLocale::setDefault(lang);

  std::unique_ptr<QTranslator> translator(new QTranslator());
  if (!translator->load(":/translations/app.qm")) return false;

  qApp->installTranslator(translator.release()); // possible memory-leak, see below

  return true;
}

More about setting locale in this answer.

Replacing translators

If you have already loaded a translator, then you'll face new challenges, since Qt will allow you to install the new one but will keep using the old file (when searching for translations, it stops on the first match).

To achieve the language change you have to keep track of all the translators you've installed, and remove them when switching.

std::unique_ptr<QTranslator> m_currentTranslator; // use one for each .qm

bool loadTranslationsForLanguage(const QString& lang) {
  QLocale::setDefault(lang);

  std::unique_ptr<QTranslator> translator(new QTranslator());
  if (!translator->load(":/translations/app.qm")) return false;

  qApp->removeTranslator(m_currentTranslator.get());
  qApp->installTranslator(translator.get());
  m_currentTranslator.swap(translator);

  return true;
}
Community
  • 1
  • 1
cbuchart
  • 10,847
  • 9
  • 53
  • 93
  • I have followed your suggestions but the isFileTranslatorLoaded returns always false. I have modified my source code: bool isFileTranslatorLoaded = translator->load(":/translations/navisit.qm"); and resource file is: translations/navis_it.qm translations/navis_en.qm I don't know... – daniele86 Apr 12 '17 at 06:59
  • OK, two points: remove the it and en suffixes from alias, both aliases should be the same: navis.qm. On the other hand, are you setting the current locale before loading your custom translations? Something like `QLocale::setDefault("it");` ? – cbuchart Apr 12 '17 at 07:04
  • No, I haven't set QLocale. How can I configure QLocale in main.cpp file before calling load function? Thanks in advice – daniele86 Apr 12 '17 at 07:15
  • Nothing, I have followed your suggestions but the .qm file does not loaded, probably there is some issue with qt 5.6 kit. I have also made a project on Windows as described on http://doc.qt.io/qt-5/qtlinguist-hellotr-example.html, but loading the .qm file fails. I don't know how to use qtranslator. It seems to be easy but isn't work. – daniele86 Apr 13 '17 at 14:17
  • It is not hard, may be tricky at some point, but not hard. I've been using them for several years and are amazing. There may be many other points of failure so I suggest you edit your question and publish a [mcve], a simple project with a single class derived from `QObject`, and with something like `qDebug() << tr("Hello world!");` in the constructor. In your `main()` function, just create the `QApplication`, load the translation, create the class and exit (the string will be printed out in the constructor). Then, run the `lupdate` and `lrelease` tools to create the translations. – cbuchart Apr 18 '17 at 07:28
  • Do not put the `.qm` in a resource file, but try loading it manually (be aware of the current working directory, that may depend on how you are running the compiled code: IDE, command line...). Please, publish the whole code in your question so we can help you to find the error. From that point we can step back until your original question. – cbuchart Apr 18 '17 at 07:30
  • Your code seems correct. Minor concerns about if the `QTranslator translator;` line should be _after_ setting the locale, but it only affects the language used. – cbuchart Apr 18 '17 at 10:51
  • Please try with `if (QFile::exist(":/translations/testTrl.qm")) qDebug() << "Exists!";` to check you have access to the file. If not, then the problem is when generating the resources. – cbuchart Apr 18 '17 at 10:53
  • Have you tried loaded the `.qm` file directly from outside the resources? I mean, load it using an absolute path, so you are sure you don't have problems with current working directory. – cbuchart Apr 18 '17 at 10:54