Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QObject::tr() is not working
Forum Updated to NodeBB v4.3 + New Features

QObject::tr() is not working

Scheduled Pinned Locked Moved Solved General and Desktop
13 Posts 6 Posters 5.6k Views 4 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • ? Offline
    ? Offline
    A Former User
    wrote on last edited by A Former User
    #1

    Hello,
    I'm creating an application in which I have used placeholder QStrings wrapped into tr() to have them later replaced by the translation from a qm file. I have gotten to the point where I have a working qm file loaded into a QTranslator and the QTranslator installed into my main application:

    int main(int argc, char* argv[])
    {
      launcher::gui::Application application(argc, argv);
      application.connect(&application, SIGNAL(lastWindowClosed()),
                          &application, SLOT(quit()));
    
      QTranslator translator;
      qDebug() << translator.load("lang.en_US.qm");
      application.installTranslator(&translator);
    }
    

    In the class itself, the code looks like this:

    namespace launcher
    {
      namespace gui
      {
        namespace dialog
        {
          NewObject::NewObject(..., QWidget* parent) 
          : Base(parent)
          {
            ...
            QLabel* name = new QLabel(tr("object_name"))
          }
        }
      }
    }
    

    In the documentation, there's a hint that the Q_OBJECT macro automatically sets the context for the class correctly, i.e. it defines tr(x) inside the class as qApp->translate("NewObject", x).

    And this seems to be where my translation is broken. The following two lines should - as far as I understand - generate the exact same translated output.

    qDebug() << tr("object_name");
    qDebug() << QCoreApplication::translate("NewObject", "object_name");
    

    But The outputs are different with the second one being the actual translation from the qm file:

    "object_name"
    "Object Name*"
    

    What am I missing here? Is it something with the namespaces and if so, how and where can I factor them in?

    Thanks a lot!
    Tobias

    Pablo J. RoginaP 1 Reply Last reply
    0
    • ? A Former User

      Hello,
      I'm creating an application in which I have used placeholder QStrings wrapped into tr() to have them later replaced by the translation from a qm file. I have gotten to the point where I have a working qm file loaded into a QTranslator and the QTranslator installed into my main application:

      int main(int argc, char* argv[])
      {
        launcher::gui::Application application(argc, argv);
        application.connect(&application, SIGNAL(lastWindowClosed()),
                            &application, SLOT(quit()));
      
        QTranslator translator;
        qDebug() << translator.load("lang.en_US.qm");
        application.installTranslator(&translator);
      }
      

      In the class itself, the code looks like this:

      namespace launcher
      {
        namespace gui
        {
          namespace dialog
          {
            NewObject::NewObject(..., QWidget* parent) 
            : Base(parent)
            {
              ...
              QLabel* name = new QLabel(tr("object_name"))
            }
          }
        }
      }
      

      In the documentation, there's a hint that the Q_OBJECT macro automatically sets the context for the class correctly, i.e. it defines tr(x) inside the class as qApp->translate("NewObject", x).

      And this seems to be where my translation is broken. The following two lines should - as far as I understand - generate the exact same translated output.

      qDebug() << tr("object_name");
      qDebug() << QCoreApplication::translate("NewObject", "object_name");
      

      But The outputs are different with the second one being the actual translation from the qm file:

      "object_name"
      "Object Name*"
      

      What am I missing here? Is it something with the namespaces and if so, how and where can I factor them in?

      Thanks a lot!
      Tobias

      Pablo J. RoginaP Offline
      Pablo J. RoginaP Offline
      Pablo J. Rogina
      wrote on last edited by
      #2

      @tobiSF said in QObject::tr() is not working:

      Q_OBJECT macro

      Just in case, could you please post the NewObject class definition (usually .h file). Remember that:

      The Q_OBJECT macro must appear in the private section of a class definition that declares its own signals and slots or that uses other services provided by Qt's meta-object system.

      Upvote the answer(s) that helped you solve the issue
      Use "Topic Tools" button to mark your post as Solved
      Add screenshots via postimage.org
      Don't ask support requests via chat/PM. Please use the forum so others can benefit from the solution in the future

      1 Reply Last reply
      1
      • ? Offline
        ? Offline
        A Former User
        wrote on last edited by
        #3

        Hi Pablo,

        here's the relevant part of the class definition:

        namespace launcher
        {
          namespace gui
          {
            namespace dialog
            {
              class NewObject : public launcher::gui::dialog::BaseDialog
              {
                Q_OBJECT
                
                public:
              
                  NewObject(..., QWidget* parent = nullptr);
         
                  ...
         
             };
            }
          }
        }
        

        As you see, NewObject inherits from a Base class. This Base dialog class inherits from QDialog.
        And all the signal and slot connections work perfectly fine in the class, so I would assume, the Q_OBJECT macro is placed correctly.

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          Hi,

          @tobiSF said in QObject::tr() is not working:

          qDebug() << translator.load("lang.en_US.qm");

          Might be a silly question but since that's relative path, did you put the file in the same folder as the executable ?

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          0
          • ? Offline
            ? Offline
            A Former User
            wrote on last edited by A Former User
            #5

            Hi @SGaist,

            I have a folder called installation in which I have various subfolders:

            bin/     // contains all executables
            doc/     // contains html help files, the Qt help (myHelp.qhc), and the translation file(s)
            

            Is it necessary to have the translation files in the same folder? Loading into the QTranslater worked with no problem and - as stated - the qApp->translate() method works fine when I give the context. I have simplified the code in my initial question but I am using the relative path to the .qm file as ../doc.

            jsulmJ 1 Reply Last reply
            0
            • ? A Former User

              Hi @SGaist,

              I have a folder called installation in which I have various subfolders:

              bin/     // contains all executables
              doc/     // contains html help files, the Qt help (myHelp.qhc), and the translation file(s)
              

              Is it necessary to have the translation files in the same folder? Loading into the QTranslater worked with no problem and - as stated - the qApp->translate() method works fine when I give the context. I have simplified the code in my initial question but I am using the relative path to the .qm file as ../doc.

              jsulmJ Offline
              jsulmJ Offline
              jsulm
              Lifetime Qt Champion
              wrote on last edited by
              #6

              @tobiSF said in QObject::tr() is not working:

              Is it necessary to have the translation files in the same folder?

              If you use relative paths as @SGaist pointed out then yes.

              https://forum.qt.io/topic/113070/qt-code-of-conduct

              1 Reply Last reply
              0
              • ? Offline
                ? Offline
                A Former User
                wrote on last edited by A Former User
                #7

                I have tracked the problem down, together with a colleague, to the namespaces around the classes. For some reason, lupdate extracts only the class name as context for the translation, not the fully qualified name that includes all namespaces. In my example the context in my *.ts file is

                NewObject
                

                while it should be

                launcher::gui::dialog::NewObject
                

                in the moc source file moc_NewObject.cpp the context is listed as the latter.

                If I overwrite the context in the ts file using the full namespaces, everything works and my class displays the translated texts. So the question now is, how do I make sure, lupdate recognizes and factors in the namespaces around my classes. I found some posts online that said to include a translator specific comment:

                /*
                  TRANSLATOR launcher::gui::dialog::NewObject
                */
                

                But that was not working either.

                When running lupdate the strings wrapped in tr() are detected, but there is also this warning:

                Qualifying with unknown namespace/class ::NewObject
                

                I'm also not using a *.pro file but feed in the source and header files:

                lupdate ../src/launcher/gui/dialog/*Object.* -ts translate.ts
                
                raven-worxR 1 Reply Last reply
                1
                • ? A Former User

                  I have tracked the problem down, together with a colleague, to the namespaces around the classes. For some reason, lupdate extracts only the class name as context for the translation, not the fully qualified name that includes all namespaces. In my example the context in my *.ts file is

                  NewObject
                  

                  while it should be

                  launcher::gui::dialog::NewObject
                  

                  in the moc source file moc_NewObject.cpp the context is listed as the latter.

                  If I overwrite the context in the ts file using the full namespaces, everything works and my class displays the translated texts. So the question now is, how do I make sure, lupdate recognizes and factors in the namespaces around my classes. I found some posts online that said to include a translator specific comment:

                  /*
                    TRANSLATOR launcher::gui::dialog::NewObject
                  */
                  

                  But that was not working either.

                  When running lupdate the strings wrapped in tr() are detected, but there is also this warning:

                  Qualifying with unknown namespace/class ::NewObject
                  

                  I'm also not using a *.pro file but feed in the source and header files:

                  lupdate ../src/launcher/gui/dialog/*Object.* -ts translate.ts
                  
                  raven-worxR Offline
                  raven-worxR Offline
                  raven-worx
                  Moderators
                  wrote on last edited by raven-worx
                  #8

                  @tobiSF
                  just a shot into the dark, but worth a try.
                  Add the Q_NAMESPACE macro to your namespaces.
                  But i would be surprised when lupdate would depend on MOC.

                  I also have the faint feeling that i also already stumbled upon this issue. But i think i didn't track it down to a solution. Also it still was in Qt4.

                  --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
                  If you have a question please use the forum so others can benefit from the solution in the future

                  1 Reply Last reply
                  3
                  • SGaistS Offline
                    SGaistS Offline
                    SGaist
                    Lifetime Qt Champion
                    wrote on last edited by
                    #9

                    Can you recreate that situation with a minimal project using only one of your classes ?

                    Interested in AI ? www.idiap.ch
                    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                    ? 1 Reply Last reply
                    1
                    • Christian EhrlicherC Online
                      Christian EhrlicherC Online
                      Christian Ehrlicher
                      Lifetime Qt Champion
                      wrote on last edited by
                      #10

                      lupdate is not very good in handling complex namespaces. See https://bugreports.qt.io/issues/?jql=status in (Open%2C "In Progress"%2C Reopened%2C Accepted%2C Reported) AND text ~ "lupdate namespace" ORDER BY key DESC

                      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                      Visit the Qt Academy at https://academy.qt.io/catalog

                      1 Reply Last reply
                      2
                      • SGaistS SGaist

                        Can you recreate that situation with a minimal project using only one of your classes ?

                        ? Offline
                        ? Offline
                        A Former User
                        wrote on last edited by
                        #11

                        @SGaist I have not tried that out yet, will do today and then post it here.
                        @raven-worx, I'm not saying lupdate depends on MOC but the context that lupdate extracts is a different one than what is set by the Q_OBJECT macro. I'll try the Q_NAMESPACE macro, maybe that'll do the trick.
                        @Christian-Ehrlicher, is there another tool that is better at this?

                        1 Reply Last reply
                        0
                        • ? Offline
                          ? Offline
                          A Former User
                          wrote on last edited by A Former User
                          #12

                          So, here's the small(ish) example program to reproduce the problem. In the full project, the namespaces in the source and header files correspond to the location in (sub)folders of the project.

                          main.cpp

                          #include <NewObject.hpp>
                          
                          #include <QtWidgets/QApplication>
                          #include <QtCore/QTranslator>
                          #include <QtCore/QDebug>
                          
                          int main(int argc, char* argv[])
                          {
                            QApplication application(argc, argv);
                            application.connect(&application, SIGNAL(lastWindowClosed()),
                                                &application, SLOT(quit()));
                          
                            QTranslator translator;
                            qDebug() << "Translator loaded: "<< translator.load("test.qm");
                            application.installTranslator(&translator);
                          
                            launcher::gui::dialog::NewObject object;
                            object.show();
                          
                            return application.exec();
                          }
                          

                          NewObject.hpp

                          #pragma once
                          
                          #include <QtWidgets/QDialog>
                          
                          namespace launcher
                          {
                            namespace gui
                            {
                              namespace dialog
                              {
                                class NewObject : public QDialog
                                {
                                  Q_OBJECT
                          
                                  public:
                          
                                    NewObject(QWidget* parent = nullptr);
                                };
                              }
                            }
                          }
                          

                          NewObject.cpp

                          #include <NewObject.hpp>
                          
                          #include <QtWidgets/QLabel>
                          #include <QtWidgets/QLineEdit>
                          #include <QtWidgets/QPushButton>
                          #include <QtWidgets/QHBoxLayout>
                          #include <QtWidgets/QFormLayout>
                          #include <QtCore/QDebug>
                          
                          namespace launcher
                          {
                            namespace gui
                            {
                              namespace dialog
                              {
                                NewObject::NewObject(QWidget* parent) : QDialog(parent)
                                {
                                  QLabel* username_label = new QLabel(tr("username"));
                                  QLineEdit* username_edit = new QLineEdit();
                          
                                  QLineEdit* password_edit = new QLineEdit();
                                  password_edit->setEchoMode(QLineEdit::Password);
                          
                                  QPushButton* ok = new QPushButton(tr("ok"));
                                  connect(ok, &QPushButton::clicked, this, &QDialog::accept);
                                  
                                  QPushButton* cancel = new QPushButton(tr("cancel"));
                                  connect(cancel, &QPushButton::clicked, this, &QDialog::reject);
                          
                                  auto button_layout = new QHBoxLayout();
                                  button_layout->addWidget(ok);
                                  button_layout->addWidget(cancel);
                          
                                  auto layout = new QFormLayout();
                                  layout->addRow(username_label, username_edit);
                                  layout->addRow(tr("password"), password_edit);
                                  layout->addRow("", button_layout);
                          
                                  setLayout(layout);
                                }
                              }
                            }
                          }
                          

                          CMakeLists.txt

                          cmake_minimum_required (VERSION 3.9)
                          project (NamespaceTest  LANGUAGES CXX)
                          
                          set (CMAKE_CXX_STANDARD 11)
                          set (CMAKE_CXX_STANDARD_REQUIRED true)
                          set (CMAKE_INCLUDE_CURRENT_DIR ON)
                          set (CMAKE_AUTOMOC ON)
                          
                          find_package (Qt5 REQUIRED
                              Core
                              Gui
                              Help
                              Widgets
                          )
                          
                          add_definitions ( ${Qt5Widgets_DEFINITIONS} )
                          
                          include_directories (${CMAKE_SOURCE_DIR})
                          
                          set (NamespaceTestSources
                              main.cpp
                              NewObject.cpp
                              )
                          
                          set (NamespaceTestQtHeaders
                              NewObject.hpp
                              )
                          
                          add_executable (NamespaceTest
                              ${NamespaceTestSources}
                          )
                          
                          target_link_libraries (NamespaceTest ${Qt5Core_LIBRARIES} ${Qt5Widgets_LIBRARIES})
                          

                          To generate the help files, I do

                          1. lupdate ./*.cpp -ts test.ts
                          2. Use Qt 5 Linguist to do the actual translations and update the test.ts file
                          3. lrelease -nounfinished test.ts -qm test.qm
                          4. Copy the resulting test.qm file into the same directory as the executable

                          The debug output in the main.cpp confirms that the translation file was loaded correctly, but the translations are not applied to the gui because of the context in the ts file being "NewObject" and not "launcher::gui::dialog::NewObject".

                          1 Reply Last reply
                          1
                          • ? Offline
                            ? Offline
                            A Former User
                            wrote on last edited by
                            #13

                            All, the mystery is solved after I asked Qt support about the issue. Turns out, it is associated with the lupdate routine not finding the header files for the source files scanned. In order to get the correct and fully namespace qualified context, you'll have to run this (assuming your sources are in a folder src):

                            lupdate ./src -ts test.ts -I ./src
                            

                            With the -I flag, the include path for the header file is handed to lupdate and with this information it produces a correct ts file.

                            Thanks all for trying and your help!

                            1 Reply Last reply
                            7

                            • Login

                            • Login or register to search.
                            • First post
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • Users
                            • Groups
                            • Search
                            • Get Qt Extensions
                            • Unsolved