summaryrefslogtreecommitdiffstats
path: root/tools/linguist
diff options
context:
space:
mode:
Diffstat (limited to 'tools/linguist')
-rw-r--r--tools/linguist/lrelease/main.cpp83
-rw-r--r--tools/linguist/lupdate/cpp.cpp76
-rw-r--r--tools/linguist/shared/qm.cpp35
-rw-r--r--tools/linguist/shared/translator.h1
4 files changed, 112 insertions, 83 deletions
diff --git a/tools/linguist/lrelease/main.cpp b/tools/linguist/lrelease/main.cpp
index 2867849..ecaed27 100644
--- a/tools/linguist/lrelease/main.cpp
+++ b/tools/linguist/lrelease/main.cpp
@@ -79,6 +79,9 @@ static void printUsage()
" -removeidentical\n"
" If the translated text is the same as\n"
" the source text, do not include the message\n"
+ " -markuntranslated <prefix>\n"
+ " If a message has no real translation, use the source text\n"
+ " prefixed with the given string instead\n"
" -silent\n"
" Do not explain what is being done\n"
" -version\n"
@@ -100,15 +103,14 @@ static bool loadTsFile(Translator &tor, const QString &tsFileName, bool /* verbo
}
static bool releaseTranslator(Translator &tor, const QString &qmFileName,
- bool verbose, bool ignoreUnfinished,
- bool removeIdentical, bool idBased, TranslatorSaveMode mode)
+ ConversionData &cd, bool removeIdentical)
{
- Translator::reportDuplicates(tor.resolveDuplicates(), qmFileName, verbose);
+ Translator::reportDuplicates(tor.resolveDuplicates(), qmFileName, cd.isVerbose());
- if (verbose)
+ if (cd.isVerbose())
printOut(QCoreApplication::tr( "Updating '%1'...\n").arg(qmFileName));
if (removeIdentical) {
- if ( verbose )
+ if (cd.isVerbose())
printOut(QCoreApplication::tr( "Removing translations equal to source text in '%1'...\n").arg(qmFileName));
tor.stripIdenticalSourceTranslations();
}
@@ -120,12 +122,7 @@ static bool releaseTranslator(Translator &tor, const QString &qmFileName,
return false;
}
- ConversionData cd;
tor.normalizeTranslations(cd);
- cd.m_verbose = verbose;
- cd.m_ignoreUnfinished = ignoreUnfinished;
- cd.m_idBased = idBased;
- cd.m_saveMode = mode;
bool ok = tor.release(&file, cd);
file.close();
@@ -139,11 +136,11 @@ static bool releaseTranslator(Translator &tor, const QString &qmFileName,
return true;
}
-static bool releaseTsFile(const QString& tsFileName, bool verbose,
- bool ignoreUnfinished, bool removeIdentical, bool idBased, TranslatorSaveMode mode)
+static bool releaseTsFile(const QString& tsFileName,
+ ConversionData &cd, bool removeIdentical)
{
Translator tor;
- if (!loadTsFile(tor, tsFileName, verbose))
+ if (!loadTsFile(tor, tsFileName, cd.isVerbose()))
return false;
QString qmFileName = tsFileName;
@@ -155,7 +152,7 @@ static bool releaseTsFile(const QString& tsFileName, bool verbose,
}
qmFileName += QLatin1String(".qm");
- return releaseTranslator(tor, qmFileName, verbose, ignoreUnfinished, removeIdentical, idBased, mode);
+ return releaseTranslator(tor, qmFileName, cd, removeIdentical);
}
int main(int argc, char **argv)
@@ -166,37 +163,40 @@ int main(int argc, char **argv)
if (translator.load(QLatin1String("lrelease_") + QLocale::system().name()))
app.installTranslator(&translator);
- bool verbose = true; // the default is true starting with Qt 4.2
- bool ignoreUnfinished = false;
- bool idBased = false;
- // the default mode is SaveEverything starting with Qt 4.2
- TranslatorSaveMode mode = SaveEverything;
+ ConversionData cd;
+ cd.m_verbose = true; // the default is true starting with Qt 4.2
bool removeIdentical = false;
Translator tor;
+ QStringList inputFiles;
QString outputFile;
- int numFiles = 0;
for (int i = 1; i < argc; ++i) {
if (args[i] == QLatin1String("-compress")) {
- mode = SaveStripped;
+ cd.m_saveMode = SaveStripped;
continue;
} else if (args[i] == QLatin1String("-idbased")) {
- idBased = true;
+ cd.m_idBased = true;
continue;
} else if (args[i] == QLatin1String("-nocompress")) {
- mode = SaveEverything;
+ cd.m_saveMode = SaveEverything;
continue;
} else if (args[i] == QLatin1String("-removeidentical")) {
removeIdentical = true;
continue;
} else if (args[i] == QLatin1String("-nounfinished")) {
- ignoreUnfinished = true;
+ cd.m_ignoreUnfinished = true;
continue;
+ } else if (args[i] == QLatin1String("-markuntranslated")) {
+ if (i == argc - 1) {
+ printUsage();
+ return 1;
+ }
+ cd.m_unTrPrefix = args[++i];
} else if (args[i] == QLatin1String("-silent")) {
- verbose = false;
+ cd.m_verbose = false;
continue;
} else if (args[i] == QLatin1String("-verbose")) {
- verbose = true;
+ cd.m_verbose = true;
continue;
} else if (args[i] == QLatin1String("-version")) {
printOut(QCoreApplication::tr( "lrelease version %1\n").arg(QLatin1String(QT_VERSION_STR)) );
@@ -206,41 +206,37 @@ int main(int argc, char **argv)
printUsage();
return 1;
}
- i++;
- outputFile = args[i];
+ outputFile = args[++i];
} else if (args[i] == QLatin1String("-help")) {
printUsage();
return 0;
- } else if (args[i][0] == QLatin1Char('-')) {
+ } else if (args[i].startsWith(QLatin1Char('-'))) {
printUsage();
return 1;
} else {
- numFiles++;
+ inputFiles << args[i];
}
}
- if (numFiles == 0) {
+ if (inputFiles.isEmpty()) {
printUsage();
return 1;
}
- for (int i = 1; i < argc; ++i) {
- if (args[i][0] == QLatin1Char('-') || args[i] == outputFile)
- continue;
-
- if (args[i].endsWith(QLatin1String(".pro"), Qt::CaseInsensitive)
- || args[i].endsWith(QLatin1String(".pri"), Qt::CaseInsensitive)) {
+ foreach (const QString &inputFile, inputFiles) {
+ if (inputFile.endsWith(QLatin1String(".pro"), Qt::CaseInsensitive)
+ || inputFile.endsWith(QLatin1String(".pri"), Qt::CaseInsensitive)) {
QHash<QByteArray, QStringList> varMap;
- bool ok = evaluateProFile(args[i], verbose, &varMap );
+ bool ok = evaluateProFile(inputFile, cd.isVerbose(), &varMap);
if (ok) {
QStringList translations = varMap.value("TRANSLATIONS");
if (translations.isEmpty()) {
qWarning("lrelease warning: Met no 'TRANSLATIONS' entry in"
" project file '%s'\n",
- qPrintable(args[i]));
+ qPrintable(inputFile));
} else {
foreach (const QString &trans, translations)
- if (!releaseTsFile(trans, verbose, ignoreUnfinished, removeIdentical, idBased, mode))
+ if (!releaseTsFile(trans, cd, removeIdentical))
return 1;
}
} else {
@@ -251,18 +247,17 @@ int main(int argc, char **argv)
}
} else {
if (outputFile.isEmpty()) {
- if (!releaseTsFile(args[i], verbose, ignoreUnfinished, removeIdentical, idBased, mode))
+ if (!releaseTsFile(inputFile, cd, removeIdentical))
return 1;
} else {
- if (!loadTsFile(tor, args[i], verbose))
+ if (!loadTsFile(tor, inputFile, cd.isVerbose()))
return 1;
}
}
}
if (!outputFile.isEmpty())
- return releaseTranslator(tor, outputFile, verbose, ignoreUnfinished,
- removeIdentical, idBased, mode) ? 0 : 1;
+ return releaseTranslator(tor, outputFile, cd, removeIdentical) ? 0 : 1;
return 0;
}
diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp
index 4d89156..fb95a95 100644
--- a/tools/linguist/lupdate/cpp.cpp
+++ b/tools/linguist/lupdate/cpp.cpp
@@ -135,6 +135,11 @@ struct Namespace {
// Nested classes may be forward-declared inside a definition, and defined in another file.
// The latter will detach the class' child list, so clones need a backlink to the original
// definition (either one in case of multiple definitions).
+ // Namespaces can have tr() functions as well, so we need to track parent definitions for
+ // them as well. The complication is that we may have to deal with a forrest instead of
+ // a tree - in that case the parent will be arbitrary. However, it seem likely that
+ // Q_DECLARE_TR_FUNCTIONS would be used either in "class-like" namespaces with a central
+ // header or only locally in a file.
Namespace *classDef;
QString trQualification;
@@ -256,17 +261,20 @@ private:
bool qualifyOneCallbackUsing(const Namespace *ns, void *context) const;
bool qualifyOne(const NamespaceList &namespaces, int nsCnt, const HashString &segment,
NamespaceList *resolved) const;
- bool fullyQualify(const NamespaceList &namespaces, const QList<HashString> &segments,
- bool isDeclaration,
+ bool fullyQualify(const NamespaceList &namespaces, int nsCnt,
+ const QList<HashString> &segments, bool isDeclaration,
NamespaceList *resolved, QStringList *unresolved) const;
- bool fullyQualify(const NamespaceList &namespaces, const QString &segments,
- bool isDeclaration,
+ bool fullyQualify(const NamespaceList &namespaces,
+ const QList<HashString> &segments, bool isDeclaration,
+ NamespaceList *resolved, QStringList *unresolved) const;
+ bool fullyQualify(const NamespaceList &namespaces,
+ const QString &segments, bool isDeclaration,
NamespaceList *resolved, QStringList *unresolved) const;
bool findNamespaceCallback(const Namespace *ns, void *context) const;
const Namespace *findNamespace(const NamespaceList &namespaces, int nsCount = -1) const;
void enterNamespace(NamespaceList *namespaces, const HashString &name);
void truncateNamespaces(NamespaceList *namespaces, int lenght);
- Namespace *modifyNamespace(NamespaceList *namespaces, bool tryOrigin = true);
+ Namespace *modifyNamespace(NamespaceList *namespaces, bool haveLast = true);
enum {
Tok_Eof, Tok_class, Tok_friend, Tok_namespace, Tok_using, Tok_return,
@@ -780,7 +788,7 @@ uint CppParser::getToken()
if (yyCh == EOF) {
qWarning("%s:%d: Unterminated C++ comment\n",
qPrintable(yyFileName), yyLineNo);
- return Tok_Comment;
+ break;
}
*ptr++ = yyCh;
@@ -958,7 +966,7 @@ void CppParser::loadState(const SavedState *state)
pendingContext = state->pendingContext;
}
-Namespace *CppParser::modifyNamespace(NamespaceList *namespaces, bool tryOrigin)
+Namespace *CppParser::modifyNamespace(NamespaceList *namespaces, bool haveLast)
{
Namespace *pns, *ns = &results->rootNamespace;
for (int i = 1; i < namespaces->count(); ++i) {
@@ -966,7 +974,7 @@ Namespace *CppParser::modifyNamespace(NamespaceList *namespaces, bool tryOrigin)
if (!(ns = pns->children.value(namespaces->at(i)))) {
do {
ns = new Namespace;
- if (tryOrigin)
+ if (haveLast || i < namespaces->count() - 1)
if (const Namespace *ons = findNamespace(*namespaces, i + 1))
ns->classDef = ons->classDef;
pns->children.insert(namespaces->at(i), ns);
@@ -1052,7 +1060,18 @@ bool CppParser::qualifyOneCallbackOwn(const Namespace *ns, void *context) const
}
QHash<HashString, NamespaceList>::ConstIterator nsai = ns->aliases.constFind(data->segment);
if (nsai != ns->aliases.constEnd()) {
- *data->resolved = *nsai;
+ const NamespaceList &nsl = *nsai;
+ if (nsl.last().value().isEmpty()) { // Delayed alias resolution
+ NamespaceList &nslIn = *const_cast<NamespaceList *>(&nsl);
+ nslIn.removeLast();
+ NamespaceList nslOut;
+ if (!fullyQualify(data->namespaces, data->nsCount, nslIn, false, &nslOut, 0)) {
+ const_cast<Namespace *>(ns)->aliases.remove(data->segment);
+ return false;
+ }
+ nslIn = nslOut;
+ }
+ *data->resolved = nsl;
return true;
}
return false;
@@ -1081,8 +1100,8 @@ bool CppParser::qualifyOne(const NamespaceList &namespaces, int nsCnt, const Has
return visitNamespace(namespaces, nsCnt, &CppParser::qualifyOneCallbackUsing, &data);
}
-bool CppParser::fullyQualify(const NamespaceList &namespaces, const QList<HashString> &segments,
- bool isDeclaration,
+bool CppParser::fullyQualify(const NamespaceList &namespaces, int nsCnt,
+ const QList<HashString> &segments, bool isDeclaration,
NamespaceList *resolved, QStringList *unresolved) const
{
int nsIdx;
@@ -1099,7 +1118,7 @@ bool CppParser::fullyQualify(const NamespaceList &namespaces, const QList<HashSt
nsIdx = 0;
} else {
initSegIdx = 0;
- nsIdx = namespaces.count() - 1;
+ nsIdx = nsCnt - 1;
}
do {
@@ -1122,8 +1141,16 @@ bool CppParser::fullyQualify(const NamespaceList &namespaces, const QList<HashSt
return false;
}
-bool CppParser::fullyQualify(const NamespaceList &namespaces, const QString &quali,
- bool isDeclaration,
+bool CppParser::fullyQualify(const NamespaceList &namespaces,
+ const QList<HashString> &segments, bool isDeclaration,
+ NamespaceList *resolved, QStringList *unresolved) const
+{
+ return fullyQualify(namespaces, namespaces.count(),
+ segments, isDeclaration, resolved, unresolved);
+}
+
+bool CppParser::fullyQualify(const NamespaceList &namespaces,
+ const QString &quali, bool isDeclaration,
NamespaceList *resolved, QStringList *unresolved) const
{
static QString strColons(QLatin1String("::"));
@@ -1633,9 +1660,8 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions)
}
if (fullName.isEmpty())
break;
- NamespaceList nsl;
- if (fullyQualify(namespaces, fullName, false, &nsl, 0))
- modifyNamespace(&namespaces, false)->aliases[ns] = nsl;
+ fullName.append(HashString(QString())); // Mark as unresolved
+ modifyNamespace(&namespaces)->aliases[ns] = fullName;
}
} else if (yyTok == Tok_LeftBrace) {
// Anonymous namespace
@@ -1661,7 +1687,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions)
}
NamespaceList nsl;
if (fullyQualify(namespaces, fullName, false, &nsl, 0))
- modifyNamespace(&namespaces, false)->usings << HashStringList(nsl);
+ modifyNamespace(&namespaces)->usings << HashStringList(nsl);
} else {
QList<HashString> fullName;
if (yyTok == Tok_ColonColon)
@@ -1676,9 +1702,13 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions)
}
if (fullName.isEmpty())
break;
- NamespaceList nsl;
- if (fullyQualify(namespaces, fullName, false, &nsl, 0))
- modifyNamespace(&namespaces, true)->aliases[nsl.last()] = nsl;
+ // using-declarations cannot rename classes, so the last element of
+ // fullName is already the resolved name we actually want.
+ // As we do no resolution here, we'll collect useless usings of data
+ // members and methods as well. This is no big deal.
+ HashString &ns = fullName.last();
+ fullName.append(HashString(QString())); // Mark as unresolved
+ modifyNamespace(&namespaces)->aliases[ns] = fullName;
}
break;
case Tok_tr:
@@ -1875,7 +1905,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions)
break;
case Tok_Q_DECLARE_TR_FUNCTIONS:
if (getMacroArgs()) {
- Namespace *ns = modifyNamespace(&namespaces, true);
+ Namespace *ns = modifyNamespace(&namespaces);
ns->hasTrFunctions = true;
ns->trQualification = yyWord;
ns->trQualification.detach();
@@ -1883,7 +1913,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions)
yyTok = getToken();
break;
case Tok_Q_OBJECT:
- modifyNamespace(&namespaces, true)->hasTrFunctions = true;
+ modifyNamespace(&namespaces)->hasTrFunctions = true;
yyTok = getToken();
break;
case Tok_Ident:
diff --git a/tools/linguist/shared/qm.cpp b/tools/linguist/shared/qm.cpp
index 317a07e..5965aac 100644
--- a/tools/linguist/shared/qm.cpp
+++ b/tools/linguist/shared/qm.cpp
@@ -172,8 +172,8 @@ public:
bool save(QIODevice *iod);
- void insert(const TranslatorMessage &msg, bool forceComment);
- void insertIdBased(const TranslatorMessage &message);
+ void insert(const TranslatorMessage &msg, const QStringList &tlns, bool forceComment);
+ void insertIdBased(const TranslatorMessage &message, const QStringList &tlns);
void squeeze(TranslatorSaveMode mode);
@@ -186,7 +186,8 @@ private:
// on turn should be the same as passed to the actual tr(...) calls
QByteArray originalBytes(const QString &str, bool isUtf8) const;
- void insertInternal(const TranslatorMessage &message, bool forceComment, bool isUtf8);
+ void insertInternal(const TranslatorMessage &message, const QStringList &tlns,
+ bool forceComment, bool isUtf8);
static Prefix commonPrefix(const ByteTranslatorMessage &m1, const ByteTranslatorMessage &m2);
@@ -413,12 +414,13 @@ void Releaser::squeeze(TranslatorSaveMode mode)
}
}
-void Releaser::insertInternal(const TranslatorMessage &message, bool forceComment, bool isUtf8)
+void Releaser::insertInternal(const TranslatorMessage &message, const QStringList &tlns,
+ bool forceComment, bool isUtf8)
{
ByteTranslatorMessage bmsg(originalBytes(message.context(), isUtf8),
originalBytes(message.sourceText(), isUtf8),
originalBytes(message.comment(), isUtf8),
- message.translations());
+ tlns);
if (!forceComment) {
ByteTranslatorMessage bmsg2(
bmsg.context(), bmsg.sourceText(), QByteArray(""), bmsg.translations());
@@ -430,20 +432,15 @@ void Releaser::insertInternal(const TranslatorMessage &message, bool forceCommen
m_messages.insert(bmsg, 0);
}
-void Releaser::insert(const TranslatorMessage &message, bool forceComment)
+void Releaser::insert(const TranslatorMessage &message, const QStringList &tlns, bool forceComment)
{
- insertInternal(message, forceComment, message.isUtf8());
+ insertInternal(message, tlns, forceComment, message.isUtf8());
if (message.isUtf8() && message.isNonUtf8())
- insertInternal(message, forceComment, false);
+ insertInternal(message, tlns, forceComment, false);
}
-void Releaser::insertIdBased(const TranslatorMessage &message)
+void Releaser::insertIdBased(const TranslatorMessage &message, const QStringList &tlns)
{
- QStringList tlns = message.translations();
- if (message.type() == TranslatorMessage::Unfinished)
- for (int i = 0; i < tlns.size(); ++i)
- if (tlns.at(i).isEmpty())
- tlns[i] = message.sourceText();
ByteTranslatorMessage bmsg("", originalBytes(message.id(), false), "", tlns);
m_messages.insert(bmsg, 0);
}
@@ -725,10 +722,16 @@ static bool saveQM(const Translator &translator, QIODevice &dev, ConversionData
} else {
++finished;
}
+ QStringList tlns = msg.translations();
+ if (msg.type() == TranslatorMessage::Unfinished
+ && (cd.m_idBased || !cd.m_unTrPrefix.isEmpty()))
+ for (int j = 0; j < tlns.size(); ++j)
+ if (tlns.at(j).isEmpty())
+ tlns[j] = cd.m_unTrPrefix + msg.sourceText();
if (cd.m_idBased) {
if (!msg.context().isEmpty() || !msg.comment().isEmpty())
++droppedData;
- releaser.insertIdBased(msg);
+ releaser.insertIdBased(msg, tlns);
} else {
// Drop the comment in (context, sourceText, comment),
// unless the context is empty,
@@ -739,7 +742,7 @@ static bool saveQM(const Translator &translator, QIODevice &dev, ConversionData
msg.comment().isEmpty()
|| msg.context().isEmpty()
|| translator.contains(msg.context(), msg.sourceText(), QString());
- releaser.insert(msg, forceComment);
+ releaser.insert(msg, tlns, forceComment);
}
}
}
diff --git a/tools/linguist/shared/translator.h b/tools/linguist/shared/translator.h
index 1dd6a59..ef81d2a 100644
--- a/tools/linguist/shared/translator.h
+++ b/tools/linguist/shared/translator.h
@@ -86,6 +86,7 @@ public:
QString m_defaultContext;
QByteArray m_codecForSource; // CPP, PO & QM specific
QByteArray m_outputCodec; // PO specific
+ QString m_unTrPrefix; // QM specific
QString m_sourceFileName;
QString m_targetFileName;
QDir m_sourceDir;