Pour l'exemple j'ai créé un tout petit projet (en annexe) qui illustre bien le souci. Voici la structure des fichiers:

project.pro
main.pro
sub/sub.pro
sub/include/test.h
sub/src/test.cpp

Fichiers principaux

L'idée est que le sous-projet sub.pro va créé une librairie statique avec les fichiers test.h et test.cpp. Le fichier main.pro va ensuite créer un exécutable qui va afficher le texte internationalisé dans test.cpp. Notez bien l'utilisation du namespace nm.

//test.h
#include <QObject>
 
namespace nm {
    class Test : public QObject {
        Q_OBJECT
 
    public:
        Test(void);
    };
}
//test.cpp
#include <iostream>
#include "test.h"
 
using namespace nm;
 
Test::Test(void) {
    QString value = tr("MyText");
    std::cout << "Value: " << value.toStdString() << std::endl;
}

Et voici comment j'ai déclaré mes différents fichiers pro (le fichier main.pro n'étant pas pertinent, je ne l'ai pas mis):

#project.pro
TEMPLATE=subdirs
CONFIG=ordered
SUBDIRS=sub/sub.pro main.pro
 
TRANSLATIONS=texts_fr.ts
#sub/sub.pro
TARGET=sub
TEMPLATE=lib
QT+=core
CONFIG+=staticlib
DESTDIR=..
 
INCLUDEPATH=include
HEADERS=include/test.h
SOURCES=src/test.cpp

Pour compiler le projet, il suffit de faire un répertoire build et d'utiliser les commandes standards:

mkdir "build"
cd "build"
qmake "../project.pro"
make

Et finalement il faut exécuter le programme dans le dossier build:

cd "build"
./trans 
#Value: MyText

Le problème

L'idée maintenant est d'utiliser les commandes lupdate et lrelease pour internationaliser le texte MyText. La commande lupdate s'exécute sans souci (toutefois, notez bien le warning):

../qttest/sub/src/test.cpp:12: Qualifying with unknown namespace/class ::Test
Updating 'texts_fr.ts'...
    Found 1 source text(s) (1 new and 0 already existing

Toutefois, après la traduction du fichier texts_fr.ts avec linguist et le l'utilisation de lrelease, la traduction ne fonctionne pas ! L'exécution du programme montrera toujours MyText.

Voici une partie du fichier créé par lupdate:

<TS version="2.0" language="fr_FR">
<context>
    <name>Test</name>
    ...
</context>
</TS>

La solution

Après recherche, je suis tombé sur un post de stackoverflow qui m'a permis de tomber sur ce ticket encore ouvert. Le souci est que lupdate ne trouve pas le header correspondant à test.cpp est qu'il ne détecte donc pas le namespace.

Il semble que lupdate et lrelease ne se comportent pas de la même manière qu'un qmake qui prend toujours les chemins relatifs par rapport à l'emplacement du fichier. C'est cela qui permet de déclarer les fichiers tests.h et test.cpp de manière relative dans sub.pro. Par contre, lupdate et lrelease semblent utiliser l'emplacement du fichier project.pro comme base.

J'ai trouvé deux solutions pour contourner le problème. La première consiste à rajouter la ligne suivante dans sub.pro:

INCLUDEPATH += sub/include

La seconde est de modifier test.cpp pour référencer le header depuis son emplacement actuel:

//au lieu de "test.h"
#include "../include/test.h"

Après avoir fait l'une ou l'autre, voici le fichier généré par lupdate:

<TS version="2.0" language="fr_FR">
<context>
    <name>nm::Test</name>
    ...
</context>
</TS>