{
Q_DECLARE_PUBLIC(QTranslator)
public:
- enum { Contexts = 0x2f, Hashes = 0x42, Messages = 0x69, NumerusRules = 0x88 };
+ enum { Contexts = 0x2f, Hashes = 0x42, Messages = 0x69, NumerusRules = 0x88, Dependencies = 0x96 };
QTranslatorPrivate() :
#if defined(QT_USE_MMAP)
char *unmapPointer; // owned memory (mmap or new)
quint32 unmapLength;
+ // used if the translator has dependencies
+ QList<QTranslator*> subTranslators;
+
// Pointers and offsets into unmapPointer[unmapLength] array, or user
// provided data array
const uchar *messageArray;
uint contextLength;
uint numerusRulesLength;
- bool do_load(const QString &filename);
- bool do_load(const uchar *data, int len);
+ bool do_load(const QString &filename, const QString &directory);
+ bool do_load(const uchar *data, int len, const QString &directory);
QString do_translate(const char *context, const char *sourceText, const char *comment,
int n) const;
void clear();
}
// realname is now the fully qualified name of a readable file.
- return d->do_load(realname);
+ return d->do_load(realname, directory);
}
-bool QTranslatorPrivate::do_load(const QString &realname)
+bool QTranslatorPrivate::do_load(const QString &realname, const QString &directory)
{
QTranslatorPrivate *d = this;
bool ok = false;
}
}
- if (ok && d->do_load(reinterpret_cast<const uchar *>(d->unmapPointer), d->unmapLength))
+ if (ok && d->do_load(reinterpret_cast<const uchar *>(d->unmapPointer), d->unmapLength, directory))
return true;
#if defined(QT_USE_MMAP)
Q_D(QTranslator);
d->clear();
QString fname = find_translation(locale, filename, prefix, directory, suffix);
- return !fname.isEmpty() && d->do_load(fname);
+ return !fname.isEmpty() && d->do_load(fname, directory);
}
/*!
The data is not copied. The caller must be able to guarantee that \a data
will not be deleted or modified.
+
+ \a directory is only used to specify the base directory when loading the dependencies
+ of a QM file. If the file does not have dependencies, this argument is ignored.
*/
-bool QTranslator::load(const uchar *data, int len)
+bool QTranslator::load(const uchar *data, int len, const QString &directory)
{
Q_D(QTranslator);
d->clear();
if (!data || len < MagicLength || memcmp(data, magic, MagicLength))
return false;
- return d->do_load(data, len);
+ return d->do_load(data, len, directory);
}
static quint8 read8(const uchar *data)
return qFromBigEndian<quint32>(data);
}
-bool QTranslatorPrivate::do_load(const uchar *data, int len)
+bool QTranslatorPrivate::do_load(const uchar *data, int len, const QString &directory)
{
bool ok = true;
const uchar *end = data + len;
data += MagicLength;
+ QStringList dependencies;
while (data < end - 4) {
quint8 tag = read8(data++);
quint32 blockLen = read32(data);
} else if (tag == QTranslatorPrivate::NumerusRules) {
numerusRulesArray = data;
numerusRulesLength = blockLen;
+ } else if (tag == QTranslatorPrivate::Dependencies) {
+ QDataStream stream(QByteArray::fromRawData((const char*)data, blockLen));
+ QString dep;
+ while (!stream.atEnd()) {
+ stream >> dep;
+ dependencies.append(dep);
+ }
}
data += blockLen;
}
- if (!offsetArray || !messageArray)
+ if (dependencies.isEmpty() && (!offsetArray || !messageArray))
ok = false;
- if (!isValidNumerusRules(numerusRulesArray, numerusRulesLength))
+ if (ok && !isValidNumerusRules(numerusRulesArray, numerusRulesLength))
ok = false;
+ if (ok) {
+ const int dependenciesCount = dependencies.count();
+ subTranslators.reserve(dependenciesCount);
+ for (int i = 0 ; i < dependenciesCount; ++i) {
+ QTranslator *translator = new QTranslator;
+ subTranslators.append(translator);
+ ok = translator->load(dependencies.at(i), directory);
+ if (!ok)
+ break;
+ }
+
+ // In case some dependencies fail to load, unload all the other ones too.
+ if (!ok) {
+ qDeleteAll(subTranslators);
+ subTranslators.clear();
+ }
+ }
if (!ok) {
messageArray = 0;
if (comment == 0)
comment = "";
+ uint numerus = 0;
+ size_t numItems = 0;
+
if (!offsetLength)
- return QString();
+ goto searchDependencies;
/*
Check if the context belongs to this QTranslator. If many
}
}
- size_t numItems = offsetLength / (2 * sizeof(quint32));
+ numItems = offsetLength / (2 * sizeof(quint32));
if (!numItems)
- return QString();
+ goto searchDependencies;
- uint numerus = 0;
if (n >= 0)
numerus = numerusHelper(n, numerusRulesArray, numerusRulesLength);
break;
comment = "";
}
+
+searchDependencies:
+ foreach (QTranslator *translator, subTranslators) {
+ QString tn = translator->translate(context, sourceText, comment, n);
+ if (!tn.isNull())
+ return tn;
+ }
return QString();
}
offsetLength = 0;
numerusRulesLength = 0;
+ qDeleteAll(subTranslators);
+ subTranslators.clear();
+
if (QCoreApplicationPrivate::isTranslatorInstalled(q))
QCoreApplication::postEvent(QCoreApplication::instance(),
new QEvent(QEvent::LanguageChange));
{
Q_D(const QTranslator);
return !d->unmapPointer && !d->unmapLength && !d->messageArray &&
- !d->offsetArray && !d->contextArray;
+ !d->offsetArray && !d->contextArray && d->subTranslators.isEmpty();
}
QT_END_NAMESPACE
void translate_qm_file_generated_with_msgfmt();
void loadFromResource();
void loadDirectory();
+ void dependencies();
private:
int languageChangeEventCounter;
QVERIFY(tor.isEmpty());
}
+void tst_QTranslator::dependencies()
+{
+ {
+ // load
+ QTranslator tor;
+ tor.load("dependencies_la");
+ QVERIFY(!tor.isEmpty());
+ QCOMPARE(tor.translate("QPushButton", "Hello world!"), QString::fromLatin1("Hallo Welt!"));
+
+ // plural
+ QCoreApplication::installTranslator(&tor);
+ QCoreApplication::Encoding e = QCoreApplication::UnicodeUTF8;
+ QCOMPARE(QCoreApplication::translate("QPushButton", "Hello %n world(s)!", 0, e, 0), QString::fromLatin1("Hallo 0 Welten!"));
+ QCOMPARE(QCoreApplication::translate("QPushButton", "Hello %n world(s)!", 0, e, 1), QString::fromLatin1("Hallo 1 Welt!"));
+ QCOMPARE(QCoreApplication::translate("QPushButton", "Hello %n world(s)!", 0, e, 2), QString::fromLatin1("Hallo 2 Welten!"));
+
+ // pick up translation from the file with dependencies
+ QCOMPARE(tor.translate("QPushButton", "It's a small world"), QString::fromLatin1("Es ist eine kleine Welt"));
+ }
+
+ {
+ QTranslator tor( 0 );
+ QFile file("dependencies_la.qm");
+ file.open(QFile::ReadOnly);
+ QByteArray data = file.readAll();
+ tor.load((const uchar *)data.constData(), data.length());
+ QVERIFY(!tor.isEmpty());
+ QCOMPARE(tor.translate("QPushButton", "Hello world!"), QString::fromLatin1("Hallo Welt!"));
+ }
+}
+
+
QTEST_MAIN(tst_QTranslator)
#include "tst_qtranslator.moc"