Revision control
Copy as Markdown
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
// IMPORTANT!!!! If you want to add testdata to this file,
// always add it to the end in order to not change the linenumbers of translations!!!
int main(int argc, char **argv)
{
//Size size = QSize(1,1);
}
#include <QtCore>
QString qt_detectRTLLanguage()
{
return QCoreApplication::tr("QT_LAYOUT_DIRECTION",
"Translate this string to the string 'LTR' in left-to-right"
" languages or to 'RTL' in right-to-left languages (such as Hebrew"
" and Arabic) to get proper widget layout.");// == QLatin1String("RTL");
}
class Dialog2
{
Q_OBJECT
void func();
void func3();
int getCount() const { return 2; }
};
void Dialog2::func()
{
int n = getCount();
tr("%n files", "plural form", n);
tr("%n cars", 0, n);
tr("&Find %n cars", 0, n);
tr("Search in %n items?", 0, n);
tr("%1. Search in %n items?", 0, n);
tr("Age: %1");
tr("There are %n house(s)", "Plurals and function call", getCount());
QCoreApplication::translate("Plurals, QCoreApplication", "%n house(s)", "Plurals and identifier", n);
QCoreApplication::translate("Plurals, QCoreApplication", "%n car(s)", "Plurals and literal number", 1);
QCoreApplication::translate("Plurals, QCoreApplication", "%n horse(s)", "Plurals and function call", getCount());
QTranslator trans;
trans.translate("QTranslator", "Simple");
trans.translate("QTranslator", "Simple", 0);
trans.translate("QTranslator", "Simple with comment", "with comment");
trans.translate("QTranslator", "Plural without comment", 0, 1);
trans.translate("QTranslator", "Plural with comment", "comment 1", n);
trans.translate("QTranslator", "Plural with comment", "comment 2", getCount());
trans.translate("QTranslator", "Plural with comment and static cast", "comment 3",
static_cast<long>(getCount()));
}
/* This is actually a test of how many alternative ways a struct/class can be found in a source file.
* Due to the simple parser in lupdate, it will actually not treat the remaining lines in the define
* as a macro, which is a case the 'Tok_Class' parser block might not consider, and it might loop infinite
* if it just tries to fetch the next token until it gets a '{' or a ';'. Another pitfall is that the
* context of tr("func3") might not be parsed, it won't resume normal evaluation until the '{' after the function
* signature.
*
*/
typedef struct S_
{
int a;
} S, *SPtr;
class ForwardDecl;
#define FT_DEFINE_SERVICE( name ) \
typedef struct FT_Service_ ## name ## Rec_ \
FT_Service_ ## name ## Rec ; \
typedef struct FT_Service_ ## name ## Rec_ \
const * FT_Service_ ## name ; \
struct FT_Service_ ## name ## Rec_
void Dialog2::func3()
{
tr("func3");
}
namespace Gui { class BaseClass {}; }
class TestClass : QObject {
Q_OBJECT
inline QString inlineFunc1() {
return tr("inline function", "TestClass");
}
QString inlineFunc2() {
return tr("inline function 2", "TestClass");
}
static inline QString staticInlineFunc() {
return tr("static inline function", "TestClass");
}
class NoQObject : public Gui::BaseClass {
public:
inline QString hello() { return QString("hello"); }
};
};
class Testing : QObject {
Q_OBJECT
inline QString f1() {
//: this is an extra comment for the translator
return tr("extra-commented string");
return tr("not extra-commented string");
/*: another extra-comment */
return tr("another extra-commented string");
/*: blah! */
return QCoreApplication::translate("scope", "works in translate, too", "blabb", 0);
}
};
//: extra comment for NOOP
//: which spans multiple lines
const char *c_1 = QT_TRANSLATE_NOOP("scope", "string") /*: complain & ignore */; // 4.4 says the line of this is at the next statement
//: extra comment for NOOP3
const char *c_2[2] = QT_TRANSLATE_NOOP3_UTF8("scope", "string", "comment"); // 4.4 doesn't see this
const char *c_3 = QT_TRANSLATE_NOOP("scope", "string " // this is an interleaved comment
"continuation on next line");
class TestingTake17 : QObject {
Q_OBJECT
void function(void)
{
//: random comment
//= this_is_an_id
//~ loc-layout_id fooish_bar
//~ po-ignore_me totally foo-barred nonsense
tr("something cool");
tr("less cool");
//= another_id
tr("even more cool");
}
};
//: again an extra comment, this time for id-based NOOP
//% "This is supposed\tto be quoted \" newline\n"
//% "backslashed \\ stuff."
const char *c_4 = QT_TRID_NOOP("this_a_id");
//~ some thing
//% "This needs to be here. Really."
QString test = qtTrId("this_another_id", 2);
class YetAnotherTest : QObject {
Q_OBJECT
void function(void)
{
//
//:
//=
//~
//#
//=============
//~~~~~~~~~~~~~
//:::::::::::::
tr("nothing");
}
};
//: This is a message without a source string
QString test1 = qtTrId("yet_another_id");
// QTBUG-9276: context in static initializers
class Bogus : QObject {
Q_OBJECT
static const char * const s_stringss[];
static const char * const s_strings[];
};
const char * const Bogus::s_strings[] = {
QT_TR_NOOP("this should be in Bogus")
};
const char * const Bogus::s_stringss[] = {
QT_TR_NOOP("this should be in Bogus")
};
void bogosity()
{
// no spaces here. test collateral damage from ignoring equal sign
QString toto=QObject::tr("just QObject");
}
namespace Internal {
class Message : public QObject
{
Q_OBJECT
public:
Message(QObject *parent = 0);
};
} // The temporary closing of the namespace triggers the problem
namespace Internal {
static inline QString message1()
{
return Message::tr("message1"); // Had no namespace
}
static inline QString message2()
{
return Message::tr("message2"); // Already had namespace
}
}
// QTBUG-11426: operator overloads
class LotsaFun : public QObject
{
Q_OBJECT
public:
LotsaFun *operator<<(int i);
};
LotsaFun *LotsaFun::operator<<(int i)
{
tr("this is inside operator<<");
return this;
}
// QTBUG-12683: define in re-opened namespace
namespace NameSchpace {
class YetMoreFun : public QObject
{
Q_OBJECT
public:
void funStuff();
};
}
namespace NameSchpace {
#define somevar 1
void YetMoreFun::funStuff()
{
tr("funStuff!");
}
}
// QTBUG-29998: tr() macro inside square brackets
void blubb()
{
QMap<QString, QString> d;
d[LotsaFun::tr("bracketed")] = "plain";
}
// QTBUG-9276 part 2: QT_TR_NOOP in static member initializers
class TestClass2
{
Q_DECLARE_TR_FUNCTIONS(TestClass);
public:
static const char TEST_STRING[];
};
const char TestClass2::TEST_STRING[] = QT_TR_NOOP("Test value");
// derivation from namespaced class
class Class42 : public NameSchpace::YetMoreFun, Gui::BaseClass
{
Q_OBJECT
void foo();
Class42() :
NameSchpace::YetMoreFun(),
Gui::BaseClass()
{
tr("does that make sense?");
}
void hello(int something, QString str);
};
void Class42::foo()
{
tr("and does that?");
}
// QTBUG-11866: magic comment parsing is too greedy
void Class42::hello(int something /*= 17 */, QString str = Class42::tr("eyo"))
{
}
// QTBUG-27974: strings from included sources are not collected
#include "included.cpp"
// test TR_EXCLUDE
#include "notincluded.cpp"
// failure to update index on insertion messes up subsequent de-duplication
void dupeFail()
{
// First just the Id.
qtTrId("dupe_id");
// Then with source
//% "This is the source"
qtTrId("dupe_id");
// Finally, same source, but without ID.
QCoreApplication::translate("", "This is the source");
}
// QTBUG-42735: lupdate confused by `final` specifier (C++11)
namespace Abc {
class NamespacedFinalClass;
}
class FinalClass final : public QObject
{
Q_OBJECT
class SubClass final
{
void f()
{
tr("nested class context with final");
}
};
void f()
{
tr("class context with final");
}
};
class Abc::NamespacedFinalClass final : public QObject
{
Q_OBJECT
void f()
{
tr("namespaced class with final");
}
};
// QTBUG-48776: lupdate fails to recognize translator comment in ternary
// operator construct
void ternary()
{
const auto aaa =
true ?
//: comment, aaa, true
QObject::tr("ternary, true, aaa") :
QObject::tr("ternary, failure, aaa");
const auto bbb =
true ?
//: comment, bbb, true
QObject::tr("ternary, bbb, true") :
//: comment, bbb, false
QObject::tr("ternary, bbb, false");
}
class TernaryClass : public QObject
{
Q_OBJECT
void f()
{
const auto ccc =
true ?
//: comment, ccc, true
tr("ternary, ccc, true") :
tr("ternary, ccc, false");
const auto ddd =
true ?
//: comment, ddd, true
tr("ternary, ddd, true") :
//: comment, ddd, false
tr("ternary, ddd, false");
}
};
// QTBUG-47467: lupdate confused by nullptr in case of plural forms
void nullptrInPlural()
{
QObject::tr("%n nullptr(s)", nullptr, 3);
QCoreApplication::translate("Plurals, nullptr", "%n car(s)", nullptr, 1);
}
class nullptrClass : public QObject
{
Q_OBJECT
void f()
{
tr("%n car(s)", nullptr, 2);
}
};
// QTBUG-34265: lupdate does not detect NULL and Q_NULLPTR as 0 when being passed as context
void nullMacroInPlural()
{
QObject::tr("%n NULL(s)", NULL, 3);
QObject::tr("%n Q_NULLPTR(s)", Q_NULLPTR, 3);
}
// QTBUG-34128: lupdate ignores tr() calls in constructor if a member is
// initialized with C++11 initializer list
class ListInitializationClass : public NameSchpace::YetMoreFun, Gui::BaseClass
{
Q_OBJECT
ListInitializationClass() :
NameSchpace::YetMoreFun(),
Gui::BaseClass{ },
a{ 0 },
b(1),
c(tr("Hello World"))
{
tr("ListInitializationClass in-class constructor");
}
ListInitializationClass(int a);
ListInitializationClass(int a, int b, int c);
int a;
int b;
QString c;
};
ListInitializationClass::ListInitializationClass(int a)// :
// b{ { 2, 3 }}[a]
{
tr("ListInitializationClass out-of-class single member initializer");
}
ListInitializationClass::ListInitializationClass(int a, int b, int c) :
NameSchpace::YetMoreFun{ },
Gui::BaseClass(),
a{ 2 + (a/3) },
b(b),
c{ tr("%n item(s)", Q_NULLPTR, c) }
{
tr("ListInitializationClass out-of-class multi member initializer");
}
// QTBUG-42166: lupdate is confused by C++11 lambdas in constructor initializer lists
class LambdaMemberClass : public Gui::BaseClass
{
Q_OBJECT
LambdaMemberClass() :
Gui::BaseClass(),
a{ [](){ /*std::cout << */QObject::tr("Hello"); } },
b([](){ /*std::cout << "World\n";*/ })
{
tr("LambdaMemberClass in-class constructor");
}
LambdaMemberClass(void *);
std::function<void()> a;
std::function<void()> b;
};
LambdaMemberClass::LambdaMemberClass(void *) :
Gui::BaseClass{ },
a([](){ /*std::cout <<*/ QObject::tr("Hallo "); }),
b{ [](){ /*std::cout << "Welt\n";*/ } }
{
tr("LambdaMemberClass out-of-class constructor");
}
// Template parameters in base class initialization
class TemplateClass : QVarLengthArray<char, sizeof(std::size_t)>, std::vector<int>
{
Q_DECLARE_TR_FUNCTIONS(TemplateClass)
QString member;
public:
TemplateClass() :
QVarLengthArray<char, sizeof(std::size_t)>(),
std::vector<int>(3),
member(tr("TemplateClass() in-class member initialization"))
{
tr("TemplateClass() in-class body");
}
TemplateClass(void *);
TemplateClass(int);
};
// supported: combination of parens in base class template parameter with direct initialization (parens)
TemplateClass::TemplateClass(void *) :
QVarLengthArray<char, sizeof(std::size_t)>(),
std::vector<int>{ 1, 2 },
member{ tr("TemplateClass(void *) out-of-class member initialization") }
{
tr("TemplateClass(void *) out-of-class body");
}
// not supported: combination of parens in base class template parameter with list initialization (braces)
TemplateClass::TemplateClass(int) :
QVarLengthArray<char, sizeof(std::size_t)>{ 3, 4, 5 },
member(tr("[unsupported] TemplateClass(int) out-of-class member initialization"))
{
tr("[unsupported] TemplateClass(int) out-of-class body");
}
// Related to QTBUG-53644, adapted from qglobal.h.
// Namespace Private must be parsed correctly for TranslatedAfterPrivate to work.
namespace Private {
template <class T> struct Class1 { T t; };
template <class T> struct Class1<T &> : Class1<T> {};
template <class T> struct Class2 { enum { Value = sizeof(T) }; };
} // namespace Private
class TranslatedAfterPrivate
{
Q_OBJECT
TranslatedAfterPrivate()
{
tr("Must be in context TranslatedAfterPrivate");
}
};
#include<QObject>
class AClass {
QString aa = QObject::tr("message after system include without space");
};
#include"qobject.h"
class AAClass {
QString aa = QObject::tr("message after local include without space");
};
// QTBUG-35164: handling of \uNNNN escapes
QString unicodeEscape()
{
return QCoreApplication::tr("Context", "soft\u00ADhyphen");
}
// QTBUG-63364: C++17 nested namespaces
namespace Outer::Inner {
class Class
{
Q_OBJECT
void function()
{
tr("MoreFunStuff!");
}
};
}
// test of translation for _N_ family
static const char * const test_string_n1[] = {
QT_TRANSLATE_N_NOOP("scope", "string %n")
};
static const char * const test_string_n2[] =
QT_TRANSLATE_N_NOOP3("scope", "string %n", "comment")
;
class testing { Q_OBJECT
void test(); };
void testing::test() { static const char * const test_string_n3[] = {
QT_TR_N_NOOP("%n test")
};
}
// QTBUG-91521: context in static initializers with parentheses
class Hogus : QObject {
Q_OBJECT
static const QString myString;
};
const QString Hogus::myString(QT_TR_NOOP("this should be in Hogus"));
// QTBUG-99415: multiple specifiers after method parameter list
class QTBUG99415 : QObject {
Q_OBJECT
const QString text1() const noexcept { return tr("text1"); }
const QString text2() const noexcept;
};
const QString QTBUG99415::text2() const noexcept { return tr("text2"); }
// QTBUG-110630: Support quoting in extras field to allow whitespace preservation
class QTBUG110630 : QObject {
Q_OBJECT
const QString txt() {
//~ quoted " string with spaces "
tr("translation with extras-quoted field");
}
};
// enum class - C++11
enum class Bar : unsigned short;
// QTBUG-36589: Don't treat enum classes as a normal class
class QTBUG36589 : QObject {
Q_OBJECT
const QString txt() {
tr("string after an enum class");
}
};
class TestMetaStrings : QObject
{
Q_OBJECT
void func()
{
//= id1
//@ label1
tr("msg with id1, invalid usage of label in text-based");
//@ label2
tr("invalid usage of label in text-based");
//@ label3
//% "propagating label"
qtTrId("id2");
qtTrId("id2");
//% "invalid usage of label, contradicting labels for id"
//@ label4
qtTrId("id4");
//@ label5
qtTrId("id4");
//@ label6
}
};
namespace Core {
struct Tr
{
Q_DECLARE_TR_FUNCTIONS(Core)
};
}
using namespace Core;
class SaveItemsDialog {
void adjustButtonWidths();
};
void SaveItemsDialog::adjustButtonWidths()
{
QStringList possibleTexts;
possibleTexts << Tr::tr("Save Selected");
}
// ============================================================================
// AUTO LABELS TESTS
// ============================================================================
// Auto labels testing
namespace FileOps {
class FileManager : QObject
{
Q_OBJECT
void testAutoLabels()
{
//% "Open file"
//@ <context>
qtTrId("autolabel.context");
//% "Save file"
//@ <class>
qtTrId("autolabel.class");
//% "Export"
//@ <file>
qtTrId("autolabel.file");
//% "Close file"
//@ FileOperations
qtTrId("autolabel.literal");
}
};
} // namespace FileOps
// Test <context> with nested namespace
namespace App {
namespace UI {
class DialogManager : QObject
{
Q_OBJECT
void show()
{
//% "Show dialog"
//@ <context>
qtTrId("autolabel.nested");
//% "Hide dialog"
//@ <class>
qtTrId("autolabel.nested.class");
}
};
} // namespace UI
} // namespace App
// Test auto labels with qtTrId at global scope (empty context)
//% "Global message"
//@ <context>
QString global_autolabel = qtTrId("autolabel.global");
//% "Global class label"
//@ <class>
QString global_class_autolabel = qtTrId("autolabel.global.class");
//% "Global file label"
//@ <file>
QString global_file_autolabel = qtTrId("autolabel.global.file");
// Test that auto labels are ignored for text-based tr() (should generate warning)
class WarningTest : QObject
{
Q_OBJECT
void test()
{
//@ <context>
tr("This should warn");
}
};
// Test flexible placeholder combinations
namespace FlexLabels {
class Combiner : QObject
{
Q_OBJECT
void testCombinations()
{
//% "Test file:class combination"
//@ <file>:<class>
qtTrId("file_class");
//% "Test complex pattern"
//@ module_<file>_<class>_v1
qtTrId("complex");
//% "Test file:context combination"
//@ <file>_<context>-label
qtTrId("file_context");
}
};
} // namespace FlexLabels
namespace Level1 {
namespace Level2 {
namespace Level3 {
namespace Level4 {
class DeepClass : QObject
{
Q_OBJECT
void deepMethod()
{
//% "Deep nested context"
//@ <context>
qtTrId("deep.nested.context");
//% "Deep class only"
//@ <class>
qtTrId("deep.nested.class");
}
};
} // namespace Level4
} // namespace Level3
} // namespace Level2
} // namespace Level1
// Test static variables at namespace level (empty context)
namespace StaticTests {
//% "Static at namespace level"
//@ <context>
static QString staticGlobal = qtTrId("static.namespace.context");
//% "Static with file:context combo"
//@ <file>:<context>
static QString staticCombo = qtTrId("static.namespace.combo");
//% "Static with file:class combo"
//@ <file>:<class>
static QString staticComboClass = qtTrId("static.noclass");
} // namespace StaticTests
// Test namespace alias
namespace VeryLongNamespaceName {
class AliasedClass : QObject
{
Q_OBJECT
void method();
};
} // namespace VeryLongNamespaceName
namespace Short = VeryLongNamespaceName;
void Short::AliasedClass::method()
{
//% "Namespace alias"
//@ <context>
qtTrId("alias.context");
}
// Test lambda expressions
namespace Lambdas {
class LambdaTest : QObject
{
Q_OBJECT
void testLambdas()
{
auto lambda = [this]() {
//% "Lambda with capture"
//@ <context>-lambda
return qtTrId("lambda.capture");
};
}
};
} // namespace Lambdas