background-shape
feature-image

Qt Series S01E05 Translation

Translating Qt applications is quite an easy process that requires only 3 steps and a translator.

Generating TS files

Using the lupdate tool, we can create TS files that are readable by QLinguist.

lupdate *.cpp *.h *.ui -ts translations/MyProgram_fr.ts

Translating

The translation is made using QLinguist, the graphical tool provided by Qt.

Integrating translations

The TS files must now be converted into QM files to be read by our Program at runtime.

With qmake:

TRANSLATIONS = \	 
 	../translations/MyProgram_fr.ts 
  qtPrepareTool(LRELEASE, lrelease)	 
  updateqm.input = TRANSLATIONS	 
  updateqm.output = ${QMAKE_VAR_OBJECTS_DIR}/${QMAKE_FILE_BASE}.qm	 
  updateqm.commands = $$LRELEASE -silent ${QMAKE_FILE_IN} -qm ${QMAKE_FILE_OUT}	 
  updateqm.CONFIG += no_link target_predeps	 
  QMAKE_EXTRA_COMPILERS += updateqm	 

With CMake:

find_package(Qt${QT_VERSION_MAJOR} COMPONENTS LinguistTools REQUIRED)
set(TS_FILES MyProgram_fr.ts)
set(PROJECT_SOURCES
        traductions/${TS_FILES}
)
qt_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})

Applying translation

The program must be started with the correct language to have an adequate translation. The easiest way is to:

  1. Save the wanted language using QSettings.
  2. Close the program.
  3. Start the program and retrieve the language using QSettings.
  4. Apply translation and set the local.

We need to tell the program where are the translations relative to the executable (the QM files must be copied in these locations for deployment):

  • macOS: ../Resources/
  • Linux: ../share/openjournal/
  • Window: ./
void MainWindow::loadLanguages() {
  lang = settings->value("settings/language", "en").toString(); // Read language from QSettings
  QString appDir = QCoreApplication::applicationDirPath();
  QStringList translationLocation = {appDir, appDir + "/../Resources/", appDir + "/../share/openjournal/"};  // Different OS, different path {Windows, Mac bundle, Linux}
  for (auto const &a : translationLocation) { // Read from the three locations
    QStringList availableLang = QDir(a).entryList({"*.qm"}); // Find all qm files
    if (!availableLang.isEmpty()) {
      translator.load("openjournal_" + lang, a); // Load translation
      QLocale::setDefault(QLocale(lang)); // Set the default locale
      this->setLocale(QLocale(lang)); // Set the widget's locale
      qApp->installTranslator(&translator); // Apply translation
      for (const auto &i : availableLang) {  // Append one action by language in a menu, if clicked, change settings language then reboot to apply the change
        QAction *langAction = new QAction(i.mid(12, 2), this);
        langAction->setCheckable(true);
        if (lang == i.mid(12, 2)) {
          langAction->setChecked(true);
        }
        connect(langAction, &QAction::triggered, [this, i]() {
          lang = i.mid(12, 2);
          settings->setValue("lang");
  	  qApp->quit(); // Quit app 
  	  QProcess::startDetached(qApp->arguments()[0], qApp->arguments()); // Restart app
        });
        ui->menuLanguage->addAction(langAction);
      }
    }
  }
}

Conclusion

Once the translation process is implemented, the translation task can be performed without modifying the code. QLinguist allows non-technical users to generate and translate TS files that will be transformed automatically in QM files used at runtime to load translation.